Merging latest changes from main line canvas
authorAnton Epple <toni.epple@eppleton.de>
Tue, 11 Feb 2014 13:31:42 +0100
branchcanvas
changeset 14396c04b26f9a9a
parent 1438 03cd1b3e2e70
parent 1437 3ec3ae9699ef
child 1440 c943709738df
Merging latest changes from main line
dew/nbactions.xml
dew/pom.xml
dew/src/main/java/org/apidesign/bck2brwsr/dew/Compile.java
dew/src/main/java/org/apidesign/bck2brwsr/dew/Dew.java
dew/src/main/java/org/apidesign/bck2brwsr/dew/DewLauncher.java
dew/src/main/resources/org/apidesign/bck2brwsr/dew/css/app.css
dew/src/main/resources/org/apidesign/bck2brwsr/dew/css/bootstrap-combined.min.css
dew/src/main/resources/org/apidesign/bck2brwsr/dew/img/error.png
dew/src/main/resources/org/apidesign/bck2brwsr/dew/img/glyphicons-halflings-white.png
dew/src/main/resources/org/apidesign/bck2brwsr/dew/img/glyphicons-halflings.png
dew/src/main/resources/org/apidesign/bck2brwsr/dew/img/html5.png
dew/src/main/resources/org/apidesign/bck2brwsr/dew/img/java.png
dew/src/main/resources/org/apidesign/bck2brwsr/dew/index.html
dew/src/main/resources/org/apidesign/bck2brwsr/dew/js/angular/angular.min.js
dew/src/main/resources/org/apidesign/bck2brwsr/dew/js/app.js
dew/src/main/resources/org/apidesign/bck2brwsr/dew/js/codemirror/codemirror.css
dew/src/main/resources/org/apidesign/bck2brwsr/dew/js/codemirror/codemirror.js
dew/src/main/resources/org/apidesign/bck2brwsr/dew/js/codemirror/mode/clike.js
dew/src/main/resources/org/apidesign/bck2brwsr/dew/js/codemirror/mode/xml.js
dew/src/main/resources/org/apidesign/bck2brwsr/dew/js/codemirror/theme/elegant.css
dew/src/test/java/org/apidesign/bck2brwsr/dew/CompileTest.java
ide/editor/pom.xml
ide/editor/src/main/java/org/apidesign/bck2brwsr/ide/editor/JNIHelper.java
ide/editor/src/main/java/org/apidesign/bck2brwsr/ide/editor/JSEmbeddingProvider.java
ide/editor/src/main/java/org/apidesign/bck2brwsr/ide/editor/JSNI2JavaScriptBody.java
ide/editor/src/main/java/org/apidesign/bck2brwsr/ide/editor/JsniCommentTokenizer.java
ide/editor/src/main/java/org/apidesign/bck2brwsr/ide/editor/ManglingSink.java
ide/editor/src/main/nbm/manifest.mf
ide/editor/src/main/resources/org/netbeans/modules/jackpot30/test/hints/Bundle.properties
ide/editor/src/test/java/org/apidesign/bck2brwsr/ide/editor/DejsniReaderTest.java
ide/editor/src/test/java/org/apidesign/bck2brwsr/ide/editor/JSNI2JavaScriptBodyTest.java
ide/editor/src/test/java/org/apidesign/bck2brwsr/ide/editor/JsniCommentTokenizerTest.java
ide/editor/src/test/java/org/apidesign/bck2brwsr/ide/editor/ManglingSinkTest.java
ide/pom.xml
javaquery/api/pom.xml
javaquery/demo-twitter/bck2brwsr-assembly.xml
javaquery/demo-twitter/nb-configuration.xml
javaquery/demo-twitter/nbactions.xml
javaquery/demo-twitter/pom.xml
javaquery/demo-twitter/src/main/java/org/apidesign/bck2brwsr/demo/twitter/TwitterClient.java
javaquery/demo-twitter/src/main/resources/org/apidesign/bck2brwsr/demo/twitter/index.html
javaquery/demo-twitter/src/main/resources/org/apidesign/bck2brwsr/demo/twitter/twitterExample.css
javaquery/demo-twitter/src/test/java/org/apidesign/bck2brwsr/demo/twitter/TwitterClientTest.java
javaquery/demo-twitter/src/test/java/org/apidesign/bck2brwsr/demo/twitter/TwitterProtocolTest.java
javaquery/pom.xml
ko/bck2brwsr/src/main/java/org/apidesign/bck2brwsr/ko2brwsr/BrwsrCtxImpl.java
ko/bck2brwsr/src/main/java/org/apidesign/bck2brwsr/ko2brwsr/BrwsrCtxPrvdr.java
ko/bck2brwsr/src/main/java/org/apidesign/bck2brwsr/ko2brwsr/ConvertTypes.java
ko/bck2brwsr/src/main/java/org/apidesign/bck2brwsr/ko2brwsr/Knockout.java
ko/bck2brwsr/src/main/java/org/apidesign/bck2brwsr/ko2brwsr/LoadWS.java
ko/bck2brwsr/src/main/resources/org/apidesign/bck2brwsr/htmlpage/knockout-2.2.1.js
launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/Run.java
pom.xml
rt/emul/compact/src/main/java/java/lang/System.java
     1.1 --- a/.hgtags	Tue Feb 11 10:48:24 2014 +0100
     1.2 +++ b/.hgtags	Tue Feb 11 13:31:42 2014 +0100
     1.3 @@ -11,3 +11,4 @@
     1.4  23572dc719bd630817d11eaabdee4565f63ef8e1 release-0.7.1
     1.5  56abd247f421febd8b2c5e59d666968692e11555 release-0.7.2
     1.6  a83e16b8b825399bb21461e578c32d86982e4ed3 release-0.8
     1.7 +1b30bba2b38db83c7a232039cfd2eaf7e0e25f3f release-0.8.1
     2.1 --- a/dew/nbactions.xml	Tue Feb 11 10:48:24 2014 +0100
     2.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.3 @@ -1,52 +0,0 @@
     2.4 -<?xml version="1.0" encoding="UTF-8"?>
     2.5 -<!--
     2.6 -
     2.7 -    Back 2 Browser Bytecode Translator
     2.8 -    Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
     2.9 -
    2.10 -    This program is free software: you can redistribute it and/or modify
    2.11 -    it under the terms of the GNU General Public License as published by
    2.12 -    the Free Software Foundation, version 2 of the License.
    2.13 -
    2.14 -    This program is distributed in the hope that it will be useful,
    2.15 -    but WITHOUT ANY WARRANTY; without even the implied warranty of
    2.16 -    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    2.17 -    GNU General Public License for more details.
    2.18 -
    2.19 -    You should have received a copy of the GNU General Public License
    2.20 -    along with this program. Look for COPYING file in the top folder.
    2.21 -    If not, see http://opensource.org/licenses/GPL-2.0.
    2.22 -
    2.23 --->
    2.24 -<actions>
    2.25 -        <action>
    2.26 -            <actionName>run</actionName>
    2.27 -            <goals>
    2.28 -                <goal>process-classes</goal>
    2.29 -                <goal>org.codehaus.mojo:exec-maven-plugin:1.2.1:exec</goal>
    2.30 -            </goals>
    2.31 -        </action>
    2.32 -        <action>
    2.33 -            <actionName>debug</actionName>
    2.34 -            <goals>
    2.35 -                <goal>process-classes</goal>
    2.36 -                <goal>org.codehaus.mojo:exec-maven-plugin:1.2.1:exec</goal>
    2.37 -            </goals>
    2.38 -            <properties>
    2.39 -                <exec.args>-Xdebug -Xrunjdwp:transport=dt_socket,server=n,address=${jpda.address} -classpath %classpath org.apidesign.bck2brwsr.dew.Dew</exec.args>
    2.40 -                <exec.executable>java</exec.executable>
    2.41 -                <jpda.listen>true</jpda.listen>
    2.42 -            </properties>
    2.43 -        </action>
    2.44 -        <action>
    2.45 -            <actionName>profile</actionName>
    2.46 -            <goals>
    2.47 -                <goal>process-classes</goal>
    2.48 -                <goal>org.codehaus.mojo:exec-maven-plugin:1.2.1:exec</goal>
    2.49 -            </goals>
    2.50 -            <properties>
    2.51 -                <exec.args>${profiler.args} -classpath %classpath org.apidesign.bck2brwsr.dew.Dew</exec.args>
    2.52 -                <exec.executable>${profiler.java}</exec.executable>
    2.53 -            </properties>
    2.54 -        </action>
    2.55 -    </actions>
     3.1 --- a/dew/pom.xml	Tue Feb 11 10:48:24 2014 +0100
     3.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.3 @@ -1,91 +0,0 @@
     3.4 -<?xml version="1.0"?>
     3.5 -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     3.6 -  <modelVersion>4.0.0</modelVersion>
     3.7 -  <parent>
     3.8 -    <groupId>org.apidesign</groupId>
     3.9 -    <artifactId>bck2brwsr</artifactId>
    3.10 -    <version>0.9-SNAPSHOT</version>
    3.11 -  </parent>
    3.12 -  <groupId>org.apidesign.bck2brwsr</groupId>
    3.13 -  <artifactId>dew</artifactId>
    3.14 -  <version>0.9-SNAPSHOT</version>
    3.15 -  <name>Development Environment for Web</name>
    3.16 -  <url>http://maven.apache.org</url>
    3.17 -    <build>
    3.18 -        <plugins>
    3.19 -            <plugin>
    3.20 -                <groupId>org.apache.maven.plugins</groupId>
    3.21 -                <artifactId>maven-compiler-plugin</artifactId>
    3.22 -                <version>2.3.2</version>
    3.23 -                <configuration>
    3.24 -                    <source>1.7</source>
    3.25 -                    <target>1.7</target>
    3.26 -                </configuration>
    3.27 -            </plugin>
    3.28 -            <plugin>
    3.29 -                <groupId>org.codehaus.mojo</groupId>
    3.30 -                <artifactId>exec-maven-plugin</artifactId>
    3.31 -                <version>1.2.1</version>
    3.32 -                <executions>
    3.33 -                    <execution>
    3.34 -                        <goals>
    3.35 -                            <goal>exec</goal>
    3.36 -                        </goals>
    3.37 -                    </execution>
    3.38 -                </executions>
    3.39 -                <configuration>
    3.40 -                    <executable>java</executable>
    3.41 -                     <arguments>
    3.42 -                        <argument>-classpath</argument>
    3.43 -                        <classpath />
    3.44 -                        <argument>org.apidesign.bck2brwsr.dew.Dew</argument>
    3.45 -                    </arguments>
    3.46 -                </configuration>
    3.47 -            </plugin>
    3.48 -            <plugin>
    3.49 -                <groupId>org.apache.maven.plugins</groupId>
    3.50 -                <artifactId>maven-deploy-plugin</artifactId>
    3.51 -                <version>2.7</version>
    3.52 -                <configuration>
    3.53 -                    <skip>true</skip>
    3.54 -                </configuration>
    3.55 -            </plugin>      
    3.56 -        </plugins>
    3.57 -    </build>
    3.58 -    <properties>
    3.59 -    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    3.60 -  </properties>
    3.61 -  <dependencies>
    3.62 -    <dependency>
    3.63 -      <groupId>org.glassfish.grizzly</groupId>
    3.64 -      <artifactId>grizzly-http-server</artifactId>
    3.65 -      <version>2.2.19</version>
    3.66 -    </dependency>
    3.67 -    <dependency>
    3.68 -      <groupId>${project.groupId}</groupId>
    3.69 -      <artifactId>vm4brwsr</artifactId>
    3.70 -      <version>${project.version}</version>
    3.71 -    </dependency>
    3.72 -    <dependency>
    3.73 -      <groupId>org.json</groupId>
    3.74 -      <artifactId>json</artifactId>
    3.75 -      <version>20090211</version>
    3.76 -    </dependency>
    3.77 -    <dependency>
    3.78 -      <groupId>org.testng</groupId>
    3.79 -      <artifactId>testng</artifactId>
    3.80 -      <scope>test</scope>
    3.81 -      <exclusions>
    3.82 -        <exclusion>
    3.83 -          <artifactId>junit</artifactId>
    3.84 -          <groupId>junit</groupId>
    3.85 -        </exclusion>
    3.86 -      </exclusions>
    3.87 -    </dependency>
    3.88 -    <dependency>
    3.89 -      <groupId>${project.groupId}</groupId>
    3.90 -      <artifactId>javaquery.api</artifactId>
    3.91 -      <version>${project.version}</version>
    3.92 -    </dependency>
    3.93 -  </dependencies>
    3.94 -</project>
     4.1 --- a/dew/src/main/java/org/apidesign/bck2brwsr/dew/Compile.java	Tue Feb 11 10:48:24 2014 +0100
     4.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.3 @@ -1,203 +0,0 @@
     4.4 -/**
     4.5 - * Back 2 Browser Bytecode Translator
     4.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
     4.7 - *
     4.8 - * This program is free software: you can redistribute it and/or modify
     4.9 - * it under the terms of the GNU General Public License as published by
    4.10 - * the Free Software Foundation, version 2 of the License.
    4.11 - *
    4.12 - * This program is distributed in the hope that it will be useful,
    4.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
    4.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    4.15 - * GNU General Public License for more details.
    4.16 - *
    4.17 - * You should have received a copy of the GNU General Public License
    4.18 - * along with this program. Look for COPYING file in the top folder.
    4.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
    4.20 - */
    4.21 -package org.apidesign.bck2brwsr.dew;
    4.22 -
    4.23 -import java.io.ByteArrayInputStream;
    4.24 -import java.io.ByteArrayOutputStream;
    4.25 -import java.io.IOException;
    4.26 -import java.io.InputStream;
    4.27 -import java.io.OutputStream;
    4.28 -import java.net.URI;
    4.29 -import java.net.URISyntaxException;
    4.30 -import java.util.ArrayList;
    4.31 -import java.util.Arrays;
    4.32 -import java.util.HashMap;
    4.33 -import java.util.List;
    4.34 -import java.util.Map;
    4.35 -import java.util.regex.Matcher;
    4.36 -import java.util.regex.Pattern;
    4.37 -import javax.tools.Diagnostic;
    4.38 -import javax.tools.DiagnosticListener;
    4.39 -import javax.tools.FileObject;
    4.40 -import javax.tools.ForwardingJavaFileManager;
    4.41 -import javax.tools.JavaFileManager;
    4.42 -import javax.tools.JavaFileObject;
    4.43 -import javax.tools.JavaFileObject.Kind;
    4.44 -import javax.tools.SimpleJavaFileObject;
    4.45 -import javax.tools.StandardJavaFileManager;
    4.46 -import javax.tools.StandardLocation;
    4.47 -import javax.tools.ToolProvider;
    4.48 -
    4.49 -/**
    4.50 - *
    4.51 - * @author Jaroslav Tulach <jtulach@netbeans.org>
    4.52 - */
    4.53 -final class Compile implements DiagnosticListener<JavaFileObject> {
    4.54 -    private final List<Diagnostic<? extends JavaFileObject>> errors = new ArrayList<>();
    4.55 -    private final Map<String, byte[]> classes;
    4.56 -    private final String pkg;
    4.57 -    private final String cls;
    4.58 -    private final String html;
    4.59 -
    4.60 -    private Compile(String html, String code) throws IOException {
    4.61 -        this.pkg = findPkg(code);
    4.62 -        this.cls = findCls(code);
    4.63 -        this.html = html;
    4.64 -        classes = compile(html, code);
    4.65 -    }
    4.66 -
    4.67 -    /** Performs compilation of given HTML page and associated Java code
    4.68 -     */
    4.69 -    public static Compile create(String html, String code) throws IOException {
    4.70 -        return new Compile(html, code);
    4.71 -    }
    4.72 -    
    4.73 -    /** Checks for given class among compiled resources */
    4.74 -    public byte[] get(String res) {
    4.75 -        return classes.get(res);
    4.76 -    }
    4.77 -    
    4.78 -    /** Obtains errors created during compilation.
    4.79 -     */
    4.80 -    public List<Diagnostic<? extends JavaFileObject>> getErrors() {
    4.81 -        List<Diagnostic<? extends JavaFileObject>> err = new ArrayList<>();
    4.82 -        for (Diagnostic<? extends JavaFileObject> diagnostic : errors) {
    4.83 -            if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
    4.84 -                err.add(diagnostic);
    4.85 -            }
    4.86 -        }
    4.87 -        return err;
    4.88 -    }
    4.89 -    
    4.90 -    private Map<String, byte[]> compile(final String html, final String code) throws IOException {
    4.91 -        StandardJavaFileManager sjfm = ToolProvider.getSystemJavaCompiler().getStandardFileManager(this, null, null);
    4.92 -
    4.93 -        final Map<String, ByteArrayOutputStream> class2BAOS = new HashMap<>();
    4.94 -
    4.95 -        JavaFileObject file = new SimpleJavaFileObject(URI.create("mem://mem"), Kind.SOURCE) {
    4.96 -            @Override
    4.97 -            public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
    4.98 -                return code;
    4.99 -            }
   4.100 -        };
   4.101 -        final JavaFileObject htmlFile = new SimpleJavaFileObject(URI.create("mem://mem2"), Kind.OTHER) {
   4.102 -            @Override
   4.103 -            public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
   4.104 -                return html;
   4.105 -            }
   4.106 -
   4.107 -            @Override
   4.108 -            public InputStream openInputStream() throws IOException {
   4.109 -                return new ByteArrayInputStream(html.getBytes());
   4.110 -            }
   4.111 -        };
   4.112 -        
   4.113 -        final URI scratch;
   4.114 -        try {
   4.115 -            scratch = new URI("mem://mem3");
   4.116 -        } catch (URISyntaxException ex) {
   4.117 -            throw new IOException(ex);
   4.118 -        }
   4.119 -        
   4.120 -        JavaFileManager jfm = new ForwardingJavaFileManager<JavaFileManager>(sjfm) {
   4.121 -            @Override
   4.122 -            public JavaFileObject getJavaFileForOutput(Location location, String className, Kind kind, FileObject sibling) throws IOException {
   4.123 -                if (kind  == Kind.CLASS) {
   4.124 -                    final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
   4.125 -
   4.126 -                    class2BAOS.put(className.replace('.', '/') + ".class", buffer);
   4.127 -                    return new SimpleJavaFileObject(sibling.toUri(), kind) {
   4.128 -                        @Override
   4.129 -                        public OutputStream openOutputStream() throws IOException {
   4.130 -                            return buffer;
   4.131 -                        }
   4.132 -                    };
   4.133 -                }
   4.134 -                
   4.135 -                if (kind == Kind.SOURCE) {
   4.136 -                    return new SimpleJavaFileObject(scratch/*sibling.toUri()*/, kind) {
   4.137 -                        private final ByteArrayOutputStream data = new ByteArrayOutputStream();
   4.138 -                        @Override
   4.139 -                        public OutputStream openOutputStream() throws IOException {
   4.140 -                            return data;
   4.141 -                        }
   4.142 -
   4.143 -                        @Override
   4.144 -                        public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
   4.145 -                            data.close();
   4.146 -                            return new String(data.toByteArray());
   4.147 -                        }
   4.148 -                    };
   4.149 -                }
   4.150 -                
   4.151 -                throw new IllegalStateException();
   4.152 -            }
   4.153 -
   4.154 -            @Override
   4.155 -            public FileObject getFileForInput(Location location, String packageName, String relativeName) throws IOException {
   4.156 -                if (location == StandardLocation.SOURCE_PATH) {
   4.157 -                    if (packageName.equals(pkg)) {
   4.158 -                        return htmlFile;
   4.159 -                    }
   4.160 -                }
   4.161 -                
   4.162 -                return null;
   4.163 -            }
   4.164 -            
   4.165 -        };
   4.166 -
   4.167 -        ToolProvider.getSystemJavaCompiler().getTask(null, jfm, this, /*XXX:*/Arrays.asList("-source", "1.7", "-target", "1.7"), null, Arrays.asList(file)).call();
   4.168 -
   4.169 -        Map<String, byte[]> result = new HashMap<>();
   4.170 -
   4.171 -        for (Map.Entry<String, ByteArrayOutputStream> e : class2BAOS.entrySet()) {
   4.172 -            result.put(e.getKey(), e.getValue().toByteArray());
   4.173 -        }
   4.174 -
   4.175 -        return result;
   4.176 -    }
   4.177 -
   4.178 -
   4.179 -    @Override
   4.180 -    public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
   4.181 -        errors.add(diagnostic);
   4.182 -    }
   4.183 -    private static String findPkg(String java) throws IOException {
   4.184 -        Pattern p = Pattern.compile("package\\p{javaWhitespace}*([\\p{Alnum}\\.]+)\\p{javaWhitespace}*;", Pattern.MULTILINE);
   4.185 -        Matcher m = p.matcher(java);
   4.186 -        if (!m.find()) {
   4.187 -            throw new IOException("Can't find package declaration in the java file");
   4.188 -        }
   4.189 -        String pkg = m.group(1);
   4.190 -        return pkg;
   4.191 -    }
   4.192 -    private static String findCls(String java) throws IOException {
   4.193 -        Pattern p = Pattern.compile("class\\p{javaWhitespace}*([\\p{Alnum}\\.]+)\\p{javaWhitespace}", Pattern.MULTILINE);
   4.194 -        Matcher m = p.matcher(java);
   4.195 -        if (!m.find()) {
   4.196 -            throw new IOException("Can't find package declaration in the java file");
   4.197 -        }
   4.198 -        String cls = m.group(1);
   4.199 -        return cls;
   4.200 -    }
   4.201 -
   4.202 -    String getHtml() {
   4.203 -        String fqn = "'" + pkg + '.' + cls + "'";
   4.204 -        return html.replace("'${fqn}'", fqn);
   4.205 -    }
   4.206 -}
     5.1 --- a/dew/src/main/java/org/apidesign/bck2brwsr/dew/Dew.java	Tue Feb 11 10:48:24 2014 +0100
     5.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.3 @@ -1,138 +0,0 @@
     5.4 -/**
     5.5 - * Back 2 Browser Bytecode Translator
     5.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
     5.7 - *
     5.8 - * This program is free software: you can redistribute it and/or modify
     5.9 - * it under the terms of the GNU General Public License as published by
    5.10 - * the Free Software Foundation, version 2 of the License.
    5.11 - *
    5.12 - * This program is distributed in the hope that it will be useful,
    5.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
    5.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    5.15 - * GNU General Public License for more details.
    5.16 - *
    5.17 - * You should have received a copy of the GNU General Public License
    5.18 - * along with this program. Look for COPYING file in the top folder.
    5.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
    5.20 - */
    5.21 -package org.apidesign.bck2brwsr.dew;
    5.22 -
    5.23 -import java.io.ByteArrayInputStream;
    5.24 -import java.io.IOException;
    5.25 -import java.io.InputStream;
    5.26 -import java.io.InputStreamReader;
    5.27 -import java.io.OutputStream;
    5.28 -import java.util.List;
    5.29 -import java.util.Locale;
    5.30 -import javax.tools.Diagnostic;
    5.31 -import javax.tools.JavaFileObject;
    5.32 -import org.apidesign.vm4brwsr.Bck2Brwsr;
    5.33 -import org.glassfish.grizzly.http.Method;
    5.34 -import org.glassfish.grizzly.http.server.HttpHandler;
    5.35 -import org.glassfish.grizzly.http.server.HttpServer;
    5.36 -import org.glassfish.grizzly.http.server.Request;
    5.37 -import org.glassfish.grizzly.http.server.Response;
    5.38 -import org.glassfish.grizzly.http.util.HttpStatus;
    5.39 -import org.json.JSONArray;
    5.40 -import org.json.JSONObject;
    5.41 -import org.json.JSONTokener;
    5.42 -
    5.43 -/**
    5.44 - *
    5.45 - * @author phrebejk
    5.46 - */
    5.47 -final class Dew extends HttpHandler implements Bck2Brwsr.Resources {
    5.48 -    private Compile data;
    5.49 -
    5.50 -    public static void main(String... args) throws Exception {
    5.51 -        DewLauncher l = new DewLauncher(null);
    5.52 -        l.addClassLoader(DewLauncher.class.getClassLoader());
    5.53 -        final Dew dew = new Dew();
    5.54 -        HttpServer s = l.initServer(dew);
    5.55 -        s.getServerConfiguration().addHttpHandler(dew, "/dew/");
    5.56 -        l.launchServerAndBrwsr(s, "/dew/");
    5.57 -        System.in.read();
    5.58 -    }
    5.59 -    
    5.60 -    @Override
    5.61 -    public void service(Request request, Response response) throws Exception {
    5.62 -        
    5.63 -        if ( request.getMethod() == Method.POST ) {
    5.64 -            InputStream is = request.getInputStream();
    5.65 -            JSONTokener tok = new JSONTokener(new InputStreamReader(is));
    5.66 -            JSONObject obj = new JSONObject(tok);
    5.67 -            String tmpHtml = obj.getString("html");
    5.68 -            String tmpJava = obj.getString("java");
    5.69 -            
    5.70 -            Compile res = Compile.create(tmpHtml, tmpJava);
    5.71 -            List<Diagnostic<? extends JavaFileObject>> err = res.getErrors();
    5.72 -            if (err.isEmpty()) {
    5.73 -                data = res;
    5.74 -                response.getOutputStream().write("[]".getBytes());
    5.75 -                response.setStatus(HttpStatus.OK_200);
    5.76 -            } else {
    5.77 -                
    5.78 -                JSONArray errors = new JSONArray();
    5.79 -                
    5.80 -                for (Diagnostic<? extends JavaFileObject> d : err) {
    5.81 -                    JSONObject e = new JSONObject();
    5.82 -                    e.put("col", d.getColumnNumber());
    5.83 -                    e.put("line", d.getLineNumber());
    5.84 -                    e.put("kind", d.getKind().toString());
    5.85 -                    e.put("msg", d.getMessage(Locale.ENGLISH));
    5.86 -                    errors.put(e);
    5.87 -                }
    5.88 -                
    5.89 -                errors.write(response.getWriter());                
    5.90 -                response.setStatus(HttpStatus.PRECONDITION_FAILED_412);
    5.91 -            }
    5.92 -            
    5.93 -            return;
    5.94 -        }
    5.95 -        
    5.96 -        String r = request.getHttpHandlerPath();
    5.97 -        if (r == null || r.equals("/")) {
    5.98 -            r = "index.html";
    5.99 -        }
   5.100 -        if (r.equals("/result.html")) {
   5.101 -            response.setContentType("text/html");
   5.102 -            if (data != null) {
   5.103 -                response.getOutputBuffer().write(data.getHtml());
   5.104 -            }
   5.105 -            response.setStatus(HttpStatus.OK_200);
   5.106 -            return;
   5.107 -        }
   5.108 -        
   5.109 -        if (r.startsWith("/")) {
   5.110 -            r = r.substring(1);
   5.111 -        }
   5.112 -        
   5.113 -        if (r.endsWith(".html") || r.endsWith(".xhtml")) {
   5.114 -            response.setContentType("text/html");
   5.115 -        }
   5.116 -        OutputStream os = response.getOutputStream();
   5.117 -        try (InputStream is = Dew.class.getResourceAsStream(r) ) {
   5.118 -            copyStream(is, os, request.getRequestURL().toString() );
   5.119 -        } catch (IOException ex) {
   5.120 -            response.setDetailMessage(ex.getLocalizedMessage());
   5.121 -            response.setError();
   5.122 -            response.setStatus(404);
   5.123 -        }
   5.124 -    }
   5.125 -    
   5.126 -    static void copyStream(InputStream is, OutputStream os, String baseURL) throws IOException {
   5.127 -        for (;;) {
   5.128 -            int ch = is.read();
   5.129 -            if (ch == -1) {
   5.130 -                break;
   5.131 -            }
   5.132 -            os.write(ch);            
   5.133 -        }
   5.134 -    }
   5.135 -
   5.136 -    @Override
   5.137 -    public InputStream get(String r) throws IOException {
   5.138 -        byte[] arr = data == null ? null : data.get(r);
   5.139 -        return arr == null ? null : new ByteArrayInputStream(arr);
   5.140 -    }
   5.141 -}
     6.1 --- a/dew/src/main/java/org/apidesign/bck2brwsr/dew/DewLauncher.java	Tue Feb 11 10:48:24 2014 +0100
     6.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.3 @@ -1,203 +0,0 @@
     6.4 -/**
     6.5 - * Back 2 Browser Bytecode Translator
     6.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
     6.7 - *
     6.8 - * This program is free software: you can redistribute it and/or modify
     6.9 - * it under the terms of the GNU General Public License as published by
    6.10 - * the Free Software Foundation, version 2 of the License.
    6.11 - *
    6.12 - * This program is distributed in the hope that it will be useful,
    6.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
    6.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    6.15 - * GNU General Public License for more details.
    6.16 - *
    6.17 - * You should have received a copy of the GNU General Public License
    6.18 - * along with this program. Look for COPYING file in the top folder.
    6.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
    6.20 - */
    6.21 -package org.apidesign.bck2brwsr.dew;
    6.22 -
    6.23 -import java.io.IOException;
    6.24 -import java.io.InputStream;
    6.25 -import java.io.Writer;
    6.26 -import java.net.URI;
    6.27 -import java.net.URISyntaxException;
    6.28 -import java.net.URL;
    6.29 -import java.util.Arrays;
    6.30 -import java.util.Enumeration;
    6.31 -import java.util.LinkedHashSet;
    6.32 -import java.util.Set;
    6.33 -import java.util.logging.Level;
    6.34 -import java.util.logging.Logger;
    6.35 -import org.apidesign.vm4brwsr.Bck2Brwsr;
    6.36 -import org.glassfish.grizzly.PortRange;
    6.37 -import org.glassfish.grizzly.http.server.HttpHandler;
    6.38 -import org.glassfish.grizzly.http.server.HttpServer;
    6.39 -import org.glassfish.grizzly.http.server.NetworkListener;
    6.40 -import org.glassfish.grizzly.http.server.Request;
    6.41 -import org.glassfish.grizzly.http.server.Response;
    6.42 -import org.glassfish.grizzly.http.server.ServerConfiguration;
    6.43 -
    6.44 -/**
    6.45 - * Lightweight server to launch dew - the Development Environment for Web.
    6.46 - */
    6.47 -final class DewLauncher {
    6.48 -    private static final Logger LOG = Logger.getLogger(DewLauncher.class.getName());
    6.49 -    private Set<ClassLoader> loaders = new LinkedHashSet<>();
    6.50 -    private Set<Bck2Brwsr.Resources> xRes = new LinkedHashSet<>();
    6.51 -    private final Res resources = new Res();
    6.52 -    private final String cmd;
    6.53 -
    6.54 -    public DewLauncher(String cmd) {
    6.55 -        this.cmd = cmd;
    6.56 -    }
    6.57 -    
    6.58 -    public void addClassLoader(ClassLoader url) {
    6.59 -        this.loaders.add(url);
    6.60 -    }
    6.61 -
    6.62 -    final HttpServer initServer(Bck2Brwsr.Resources... extraResources) throws IOException {
    6.63 -        xRes.addAll(Arrays.asList(extraResources));
    6.64 -        
    6.65 -        HttpServer s = HttpServer.createSimpleServer(".", new PortRange(8080, 65535));
    6.66 -
    6.67 -        final ServerConfiguration conf = s.getServerConfiguration();
    6.68 -        conf.addHttpHandler(new VM(resources), "/bck2brwsr.js");
    6.69 -        conf.addHttpHandler(new VMInit(), "/vm.js");
    6.70 -        conf.addHttpHandler(new Classes(resources), "/classes/");
    6.71 -        return s;
    6.72 -    }
    6.73 -    
    6.74 -    final Object[] launchServerAndBrwsr(HttpServer server, final String page) throws IOException, URISyntaxException, InterruptedException {
    6.75 -        server.start();
    6.76 -        NetworkListener listener = server.getListeners().iterator().next();
    6.77 -        int port = listener.getPort();
    6.78 -        
    6.79 -        URI uri = new URI("http://localhost:" + port + page);
    6.80 -        LOG.log(Level.INFO, "Showing {0}", uri);
    6.81 -        if (cmd == null) {
    6.82 -            try {
    6.83 -                LOG.log(Level.INFO, "Trying Desktop.browse on {0} {2} by {1}", new Object[] {
    6.84 -                    System.getProperty("java.vm.name"),
    6.85 -                    System.getProperty("java.vm.vendor"),
    6.86 -                    System.getProperty("java.vm.version"),
    6.87 -                });
    6.88 -                java.awt.Desktop.getDesktop().browse(uri);
    6.89 -                LOG.log(Level.INFO, "Desktop.browse successfully finished");
    6.90 -                return null;
    6.91 -            } catch (UnsupportedOperationException ex) {
    6.92 -                LOG.log(Level.INFO, "Desktop.browse not supported: {0}", ex.getMessage());
    6.93 -                LOG.log(Level.FINE, null, ex);
    6.94 -            }
    6.95 -        }
    6.96 -        {
    6.97 -            String cmdName = cmd == null ? "xdg-open" : cmd;
    6.98 -            String[] cmdArr = { 
    6.99 -                cmdName, uri.toString()
   6.100 -            };
   6.101 -            LOG.log(Level.INFO, "Launching {0}", Arrays.toString(cmdArr));
   6.102 -            final Process process = Runtime.getRuntime().exec(cmdArr);
   6.103 -            return new Object[] { process, null };
   6.104 -        }
   6.105 -    }
   6.106 -
   6.107 -    private class Res implements Bck2Brwsr.Resources {
   6.108 -        @Override
   6.109 -        public InputStream get(String resource) throws IOException {
   6.110 -            for (ClassLoader l : loaders) {
   6.111 -                URL u = null;
   6.112 -                Enumeration<URL> en = l.getResources(resource);
   6.113 -                while (en.hasMoreElements()) {
   6.114 -                    u = en.nextElement();
   6.115 -                }
   6.116 -                if (u != null) {
   6.117 -                    return u.openStream();
   6.118 -                }
   6.119 -            }
   6.120 -            for (Bck2Brwsr.Resources r : xRes) {
   6.121 -                InputStream is = r.get(resource);
   6.122 -                if (is != null) {
   6.123 -                    return is;
   6.124 -                }
   6.125 -            }
   6.126 -            throw new IOException("Can't find " + resource);
   6.127 -        }
   6.128 -    }
   6.129 -
   6.130 -    private static class VM extends HttpHandler {
   6.131 -        private final String bck2brwsr;
   6.132 -
   6.133 -        public VM(Res loader) throws IOException {
   6.134 -            StringBuilder sb = new StringBuilder();
   6.135 -            Bck2Brwsr.generate(sb, loader);
   6.136 -            this.bck2brwsr = sb.toString();
   6.137 -        }
   6.138 -
   6.139 -        @Override
   6.140 -        public void service(Request request, Response response) throws Exception {
   6.141 -            response.setCharacterEncoding("UTF-8");
   6.142 -            response.setContentType("text/javascript");
   6.143 -            response.getWriter().write(bck2brwsr);
   6.144 -        }
   6.145 -    }
   6.146 -    private static class VMInit extends HttpHandler {
   6.147 -        public VMInit() {
   6.148 -        }
   6.149 -
   6.150 -        @Override
   6.151 -        public void service(Request request, Response response) throws Exception {
   6.152 -            response.setCharacterEncoding("UTF-8");
   6.153 -            response.setContentType("text/javascript");
   6.154 -            response.getWriter().append(
   6.155 -                "function ldCls(res) {\n"
   6.156 -                + "  var request = new XMLHttpRequest();\n"
   6.157 -                + "  request.open('GET', '/classes/' + res, false);\n"
   6.158 -                + "  request.send();\n"
   6.159 -                + "  var arr = eval('(' + request.responseText + ')');\n"
   6.160 -                + "  return arr;\n"
   6.161 -                + "}\n"
   6.162 -                + "var vm = new bck2brwsr(ldCls);\n");
   6.163 -        }
   6.164 -    }
   6.165 -
   6.166 -    private static class Classes extends HttpHandler {
   6.167 -        private final Res loader;
   6.168 -
   6.169 -        public Classes(Res loader) {
   6.170 -            this.loader = loader;
   6.171 -        }
   6.172 -
   6.173 -        @Override
   6.174 -        public void service(Request request, Response response) throws Exception {
   6.175 -            String res = request.getHttpHandlerPath();
   6.176 -            if (res.startsWith("/")) {
   6.177 -                res = res.substring(1);
   6.178 -            }
   6.179 -            try (InputStream is = loader.get(res)) {
   6.180 -                response.setContentType("text/javascript");
   6.181 -                Writer w = response.getWriter();
   6.182 -                w.append("[");
   6.183 -                for (int i = 0;; i++) {
   6.184 -                    int b = is.read();
   6.185 -                    if (b == -1) {
   6.186 -                        break;
   6.187 -                    }
   6.188 -                    if (i > 0) {
   6.189 -                        w.append(", ");
   6.190 -                    }
   6.191 -                    if (i % 20 == 0) {
   6.192 -                        w.write("\n");
   6.193 -                    }
   6.194 -                    if (b > 127) {
   6.195 -                        b = b - 256;
   6.196 -                    }
   6.197 -                    w.append(Integer.toString(b));
   6.198 -                }
   6.199 -                w.append("\n]");
   6.200 -            } catch (IOException ex) {
   6.201 -                response.setError();
   6.202 -                response.setDetailMessage(ex.getMessage());
   6.203 -            }
   6.204 -        }
   6.205 -    }
   6.206 -}
     7.1 --- a/dew/src/main/resources/org/apidesign/bck2brwsr/dew/css/app.css	Tue Feb 11 10:48:24 2014 +0100
     7.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.3 @@ -1,54 +0,0 @@
     7.4 -/* app css stylesheet */
     7.5 -.code-editor, .mono-font, .CodeMirror {
     7.6 -    font-family: "Inconsolata","Monaco","Consolas","Andale Mono","Bitstream Vera Sans Mono","Courier New",Courier,monospace;
     7.7 -    font-size: 13px;
     7.8 -    line-height: 15px;
     7.9 -}
    7.10 -
    7.11 -.CodeMirror {                    
    7.12 -    border: 1px solid #d9edf7;      
    7.13 -    height: 300px;
    7.14 -}
    7.15 -      
    7.16 -.CodeMirror-scroll {
    7.17 -    overflow-y: auto;
    7.18 -    overflow-x: auto;
    7.19 -}
    7.20 -
    7.21 -.error-hover:hover {
    7.22 -    text-decoration: underline;
    7.23 -    cursor: pointer;
    7.24 -} 
    7.25 -
    7.26 -.ic-html5 {
    7.27 -  display: inline-block;  
    7.28 -  height: 20px;
    7.29 -  width: 20px;
    7.30 -  vertical-align: text-bottom;
    7.31 -  background-repeat: no-repeat;  
    7.32 -  background-image: url("../img/html5.png");  
    7.33 -}
    7.34 -
    7.35 -.ic-java {
    7.36 -  display: inline-block;  
    7.37 -  height: 20px;
    7.38 -  width: 20px;
    7.39 -  vertical-align: text-bottom;
    7.40 -  background-repeat: no-repeat;  
    7.41 -  background-image: url("../img/java.png"); 
    7.42 - 
    7.43 -}
    7.44 -
    7.45 -.issues {    
    7.46 -    width: 16px;
    7.47 -}
    7.48 -
    7.49 -.issue { 
    7.50 -    height: 16px;
    7.51 -    width: 16px;
    7.52 -    vertical-align: middle;
    7.53 -    background-repeat: no-repeat;  
    7.54 -    background-image: url("../img/error.png"); 
    7.55 -    /* color: #822; */
    7.56 -}
    7.57 -
     8.1 --- a/dew/src/main/resources/org/apidesign/bck2brwsr/dew/css/bootstrap-combined.min.css	Tue Feb 11 10:48:24 2014 +0100
     8.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.3 @@ -1,18 +0,0 @@
     8.4 -/*!
     8.5 - * Bootstrap v2.2.2
     8.6 - *
     8.7 - * Copyright 2012 Twitter, Inc
     8.8 - * Licensed under the Apache License v2.0
     8.9 - * http://www.apache.org/licenses/LICENSE-2.0
    8.10 - *
    8.11 - * Designed and built with all the love in the world @twitter by @mdo and @fat.
    8.12 - */article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}audio:not([controls]){display:none}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}a:hover,a:active{outline:0}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{width:auto\9;height:auto;max-width:100%;vertical-align:middle;border:0;-ms-interpolation-mode:bicubic}#map_canvas img,.google-maps img{max-width:none}button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle}button,input{*overflow:visible;line-height:normal}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}button,html input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button}label,select,button,input[type="button"],input[type="reset"],input[type="submit"],input[type="radio"],input[type="checkbox"]{cursor:pointer}input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none}textarea{overflow:auto;vertical-align:top}@media print{*{color:#000!important;text-shadow:none!important;background:transparent!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100%!important}@page{margin:.5cm}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;line-height:0;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:20px;color:#333;background-color:#fff}a{color:#08c;text-decoration:none}a:hover{color:#005580;text-decoration:underline}.img-rounded{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.img-polaroid{padding:4px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.1);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.1);box-shadow:0 1px 3px rgba(0,0,0,0.1)}.img-circle{-webkit-border-radius:500px;-moz-border-radius:500px;border-radius:500px}.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:20px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}.span12{width:940px}.span11{width:860px}.span10{width:780px}.span9{width:700px}.span8{width:620px}.span7{width:540px}.span6{width:460px}.span5{width:380px}.span4{width:300px}.span3{width:220px}.span2{width:140px}.span1{width:60px}.offset12{margin-left:980px}.offset11{margin-left:900px}.offset10{margin-left:820px}.offset9{margin-left:740px}.offset8{margin-left:660px}.offset7{margin-left:580px}.offset6{margin-left:500px}.offset5{margin-left:420px}.offset4{margin-left:340px}.offset3{margin-left:260px}.offset2{margin-left:180px}.offset1{margin-left:100px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.127659574468085%;*margin-left:2.074468085106383%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.127659574468085%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.48936170212765%;*width:91.43617021276594%}.row-fluid .span10{width:82.97872340425532%;*width:82.92553191489361%}.row-fluid .span9{width:74.46808510638297%;*width:74.41489361702126%}.row-fluid .span8{width:65.95744680851064%;*width:65.90425531914893%}.row-fluid .span7{width:57.44680851063829%;*width:57.39361702127659%}.row-fluid .span6{width:48.93617021276595%;*width:48.88297872340425%}.row-fluid .span5{width:40.42553191489362%;*width:40.37234042553192%}.row-fluid .span4{width:31.914893617021278%;*width:31.861702127659576%}.row-fluid .span3{width:23.404255319148934%;*width:23.351063829787233%}.row-fluid .span2{width:14.893617021276595%;*width:14.840425531914894%}.row-fluid .span1{width:6.382978723404255%;*width:6.329787234042553%}.row-fluid .offset12{margin-left:104.25531914893617%;*margin-left:104.14893617021275%}.row-fluid .offset12:first-child{margin-left:102.12765957446808%;*margin-left:102.02127659574467%}.row-fluid .offset11{margin-left:95.74468085106382%;*margin-left:95.6382978723404%}.row-fluid .offset11:first-child{margin-left:93.61702127659574%;*margin-left:93.51063829787232%}.row-fluid .offset10{margin-left:87.23404255319149%;*margin-left:87.12765957446807%}.row-fluid .offset10:first-child{margin-left:85.1063829787234%;*margin-left:84.99999999999999%}.row-fluid .offset9{margin-left:78.72340425531914%;*margin-left:78.61702127659572%}.row-fluid .offset9:first-child{margin-left:76.59574468085106%;*margin-left:76.48936170212764%}.row-fluid .offset8{margin-left:70.2127659574468%;*margin-left:70.10638297872339%}.row-fluid .offset8:first-child{margin-left:68.08510638297872%;*margin-left:67.9787234042553%}.row-fluid .offset7{margin-left:61.70212765957446%;*margin-left:61.59574468085106%}.row-fluid .offset7:first-child{margin-left:59.574468085106375%;*margin-left:59.46808510638297%}.row-fluid .offset6{margin-left:53.191489361702125%;*margin-left:53.085106382978715%}.row-fluid .offset6:first-child{margin-left:51.063829787234035%;*margin-left:50.95744680851063%}.row-fluid .offset5{margin-left:44.68085106382979%;*margin-left:44.57446808510638%}.row-fluid .offset5:first-child{margin-left:42.5531914893617%;*margin-left:42.4468085106383%}.row-fluid .offset4{margin-left:36.170212765957444%;*margin-left:36.06382978723405%}.row-fluid .offset4:first-child{margin-left:34.04255319148936%;*margin-left:33.93617021276596%}.row-fluid .offset3{margin-left:27.659574468085104%;*margin-left:27.5531914893617%}.row-fluid .offset3:first-child{margin-left:25.53191489361702%;*margin-left:25.425531914893618%}.row-fluid .offset2{margin-left:19.148936170212764%;*margin-left:19.04255319148936%}.row-fluid .offset2:first-child{margin-left:17.02127659574468%;*margin-left:16.914893617021278%}.row-fluid .offset1{margin-left:10.638297872340425%;*margin-left:10.53191489361702%}.row-fluid .offset1:first-child{margin-left:8.51063829787234%;*margin-left:8.404255319148938%}[class*="span"].hide,.row-fluid [class*="span"].hide{display:none}[class*="span"].pull-right,.row-fluid [class*="span"].pull-right{float:right}.container{margin-right:auto;margin-left:auto;*zoom:1}.container:before,.container:after{display:table;line-height:0;content:""}.container:after{clear:both}.container-fluid{padding-right:20px;padding-left:20px;*zoom:1}.container-fluid:before,.container-fluid:after{display:table;line-height:0;content:""}.container-fluid:after{clear:both}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:21px;font-weight:200;line-height:30px}small{font-size:85%}strong{font-weight:bold}em{font-style:italic}cite{font-style:normal}.muted{color:#999}a.muted:hover{color:#808080}.text-warning{color:#c09853}a.text-warning:hover{color:#a47e3c}.text-error{color:#b94a48}a.text-error:hover{color:#953b39}.text-info{color:#3a87ad}a.text-info:hover{color:#2d6987}.text-success{color:#468847}a.text-success:hover{color:#356635}h1,h2,h3,h4,h5,h6{margin:10px 0;font-family:inherit;font-weight:bold;line-height:20px;color:inherit;text-rendering:optimizelegibility}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;line-height:1;color:#999}h1,h2,h3{line-height:40px}h1{font-size:38.5px}h2{font-size:31.5px}h3{font-size:24.5px}h4{font-size:17.5px}h5{font-size:14px}h6{font-size:11.9px}h1 small{font-size:24.5px}h2 small{font-size:17.5px}h3 small{font-size:14px}h4 small{font-size:14px}.page-header{padding-bottom:9px;margin:20px 0 30px;border-bottom:1px solid #eee}ul,ol{padding:0;margin:0 0 10px 25px}ul ul,ul ol,ol ol,ol ul{margin-bottom:0}li{line-height:20px}ul.unstyled,ol.unstyled{margin-left:0;list-style:none}ul.inline,ol.inline{margin-left:0;list-style:none}ul.inline>li,ol.inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-bottom:20px}dt,dd{line-height:20px}dt{font-weight:bold}dd{margin-left:10px}.dl-horizontal{*zoom:1}.dl-horizontal:before,.dl-horizontal:after{display:table;line-height:0;content:""}.dl-horizontal:after{clear:both}.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}hr{margin:20px 0;border:0;border-top:1px solid #eee;border-bottom:1px solid #fff}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999}abbr.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:0 0 0 15px;margin:0 0 20px;border-left:5px solid #eee}blockquote p{margin-bottom:0;font-size:16px;font-weight:300;line-height:25px}blockquote small{display:block;line-height:20px;color:#999}blockquote small:before{content:'\2014 \00A0'}blockquote.pull-right{float:right;padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0}blockquote.pull-right p,blockquote.pull-right small{text-align:right}blockquote.pull-right small:before{content:''}blockquote.pull-right small:after{content:'\00A0 \2014'}q:before,q:after,blockquote:before,blockquote:after{content:""}address{display:block;margin-bottom:20px;font-style:normal;line-height:20px}code,pre{padding:0 3px 2px;font-family:Monaco,Menlo,Consolas,"Courier New",monospace;font-size:12px;color:#333;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}code{padding:2px 4px;color:#d14;white-space:nowrap;background-color:#f7f7f9;border:1px solid #e1e1e8}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:20px;word-break:break-all;word-wrap:break-word;white-space:pre;white-space:pre-wrap;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.15);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}pre.prettyprint{margin-bottom:20px}pre code{padding:0;color:inherit;white-space:pre;white-space:pre-wrap;background-color:transparent;border:0}.pre-scrollable{max-height:340px;overflow-y:scroll}form{margin:0 0 20px}fieldset{padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:40px;color:#333;border:0;border-bottom:1px solid #e5e5e5}legend small{font-size:15px;color:#999}label,input,button,select,textarea{font-size:14px;font-weight:normal;line-height:20px}input,button,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif}label{display:block;margin-bottom:5px}select,textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{display:inline-block;height:20px;padding:4px 6px;margin-bottom:10px;font-size:14px;line-height:20px;color:#555;vertical-align:middle;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}input,textarea,.uneditable-input{width:206px}textarea{height:auto}textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{background-color:#fff;border:1px solid #ccc;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border linear .2s,box-shadow linear .2s;-moz-transition:border linear .2s,box-shadow linear .2s;-o-transition:border linear .2s,box-shadow linear .2s;transition:border linear .2s,box-shadow linear .2s}textarea:focus,input[type="text"]:focus,input[type="password"]:focus,input[type="datetime"]:focus,input[type="datetime-local"]:focus,input[type="date"]:focus,input[type="month"]:focus,input[type="time"]:focus,input[type="week"]:focus,input[type="number"]:focus,input[type="email"]:focus,input[type="url"]:focus,input[type="search"]:focus,input[type="tel"]:focus,input[type="color"]:focus,.uneditable-input:focus{border-color:rgba(82,168,236,0.8);outline:0;outline:thin dotted \9;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6)}input[type="radio"],input[type="checkbox"]{margin:4px 0 0;margin-top:1px \9;*margin-top:0;line-height:normal}input[type="file"],input[type="image"],input[type="submit"],input[type="reset"],input[type="button"],input[type="radio"],input[type="checkbox"]{width:auto}select,input[type="file"]{height:30px;*margin-top:4px;line-height:30px}select{width:220px;background-color:#fff;border:1px solid #ccc}select[multiple],select[size]{height:auto}select:focus,input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.uneditable-input,.uneditable-textarea{color:#999;cursor:not-allowed;background-color:#fcfcfc;border-color:#ccc;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);box-shadow:inset 0 1px 2px rgba(0,0,0,0.025)}.uneditable-input{overflow:hidden;white-space:nowrap}.uneditable-textarea{width:auto;height:auto}input:-moz-placeholder,textarea:-moz-placeholder{color:#999}input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#999}input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#999}.radio,.checkbox{min-height:20px;padding-left:20px}.radio input[type="radio"],.checkbox input[type="checkbox"]{float:left;margin-left:-20px}.controls>.radio:first-child,.controls>.checkbox:first-child{padding-top:5px}.radio.inline,.checkbox.inline{display:inline-block;padding-top:5px;margin-bottom:0;vertical-align:middle}.radio.inline+.radio.inline,.checkbox.inline+.checkbox.inline{margin-left:10px}.input-mini{width:60px}.input-small{width:90px}.input-medium{width:150px}.input-large{width:210px}.input-xlarge{width:270px}.input-xxlarge{width:530px}input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"]{float:none;margin-left:0}.input-append input[class*="span"],.input-append .uneditable-input[class*="span"],.input-prepend input[class*="span"],.input-prepend .uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"],.row-fluid .input-prepend [class*="span"],.row-fluid .input-append [class*="span"]{display:inline-block}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:20px}input.span12,textarea.span12,.uneditable-input.span12{width:926px}input.span11,textarea.span11,.uneditable-input.span11{width:846px}input.span10,textarea.span10,.uneditable-input.span10{width:766px}input.span9,textarea.span9,.uneditable-input.span9{width:686px}input.span8,textarea.span8,.uneditable-input.span8{width:606px}input.span7,textarea.span7,.uneditable-input.span7{width:526px}input.span6,textarea.span6,.uneditable-input.span6{width:446px}input.span5,textarea.span5,.uneditable-input.span5{width:366px}input.span4,textarea.span4,.uneditable-input.span4{width:286px}input.span3,textarea.span3,.uneditable-input.span3{width:206px}input.span2,textarea.span2,.uneditable-input.span2{width:126px}input.span1,textarea.span1,.uneditable-input.span1{width:46px}.controls-row{*zoom:1}.controls-row:before,.controls-row:after{display:table;line-height:0;content:""}.controls-row:after{clear:both}.controls-row [class*="span"],.row-fluid .controls-row [class*="span"]{float:left}.controls-row .checkbox[class*="span"],.controls-row .radio[class*="span"]{padding-top:5px}input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{cursor:not-allowed;background-color:#eee}input[type="radio"][disabled],input[type="checkbox"][disabled],input[type="radio"][readonly],input[type="checkbox"][readonly]{background-color:transparent}.control-group.warning .control-label,.control-group.warning .help-block,.control-group.warning .help-inline{color:#c09853}.control-group.warning .checkbox,.control-group.warning .radio,.control-group.warning input,.control-group.warning select,.control-group.warning textarea{color:#c09853}.control-group.warning input,.control-group.warning select,.control-group.warning textarea{border-color:#c09853;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.warning input:focus,.control-group.warning select:focus,.control-group.warning textarea:focus{border-color:#a47e3c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e}.control-group.warning .input-prepend .add-on,.control-group.warning .input-append .add-on{color:#c09853;background-color:#fcf8e3;border-color:#c09853}.control-group.error .control-label,.control-group.error .help-block,.control-group.error .help-inline{color:#b94a48}.control-group.error .checkbox,.control-group.error .radio,.control-group.error input,.control-group.error select,.control-group.error textarea{color:#b94a48}.control-group.error input,.control-group.error select,.control-group.error textarea{border-color:#b94a48;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.error input:focus,.control-group.error select:focus,.control-group.error textarea:focus{border-color:#953b39;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392}.control-group.error .input-prepend .add-on,.control-group.error .input-append .add-on{color:#b94a48;background-color:#f2dede;border-color:#b94a48}.control-group.success .control-label,.control-group.success .help-block,.control-group.success .help-inline{color:#468847}.control-group.success .checkbox,.control-group.success .radio,.control-group.success input,.control-group.success select,.control-group.success textarea{color:#468847}.control-group.success input,.control-group.success select,.control-group.success textarea{border-color:#468847;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.success input:focus,.control-group.success select:focus,.control-group.success textarea:focus{border-color:#356635;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b}.control-group.success .input-prepend .add-on,.control-group.success .input-append .add-on{color:#468847;background-color:#dff0d8;border-color:#468847}.control-group.info .control-label,.control-group.info .help-block,.control-group.info .help-inline{color:#3a87ad}.control-group.info .checkbox,.control-group.info .radio,.control-group.info input,.control-group.info select,.control-group.info textarea{color:#3a87ad}.control-group.info input,.control-group.info select,.control-group.info textarea{border-color:#3a87ad;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.info input:focus,.control-group.info select:focus,.control-group.info textarea:focus{border-color:#2d6987;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3}.control-group.info .input-prepend .add-on,.control-group.info .input-append .add-on{color:#3a87ad;background-color:#d9edf7;border-color:#3a87ad}input:focus:invalid,textarea:focus:invalid,select:focus:invalid{color:#b94a48;border-color:#ee5f5b}input:focus:invalid:focus,textarea:focus:invalid:focus,select:focus:invalid:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;-moz-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7}.form-actions{padding:19px 20px 20px;margin-top:20px;margin-bottom:20px;background-color:#f5f5f5;border-top:1px solid #e5e5e5;*zoom:1}.form-actions:before,.form-actions:after{display:table;line-height:0;content:""}.form-actions:after{clear:both}.help-block,.help-inline{color:#595959}.help-block{display:block;margin-bottom:10px}.help-inline{display:inline-block;*display:inline;padding-left:5px;vertical-align:middle;*zoom:1}.input-append,.input-prepend{margin-bottom:5px;font-size:0;white-space:nowrap}.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input,.input-append .dropdown-menu,.input-prepend .dropdown-menu{font-size:14px}.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input{position:relative;margin-bottom:0;*margin-left:0;vertical-align:top;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-append input:focus,.input-prepend input:focus,.input-append select:focus,.input-prepend select:focus,.input-append .uneditable-input:focus,.input-prepend .uneditable-input:focus{z-index:2}.input-append .add-on,.input-prepend .add-on{display:inline-block;width:auto;height:20px;min-width:16px;padding:4px 5px;font-size:14px;font-weight:normal;line-height:20px;text-align:center;text-shadow:0 1px 0 #fff;background-color:#eee;border:1px solid #ccc}.input-append .add-on,.input-prepend .add-on,.input-append .btn,.input-prepend .btn,.input-append .btn-group>.dropdown-toggle,.input-prepend .btn-group>.dropdown-toggle{vertical-align:top;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-append .active,.input-prepend .active{background-color:#a9dba9;border-color:#46a546}.input-prepend .add-on,.input-prepend .btn{margin-right:-1px}.input-prepend .add-on:first-child,.input-prepend .btn:first-child{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.input-append input,.input-append select,.input-append .uneditable-input{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.input-append input+.btn-group .btn:last-child,.input-append select+.btn-group .btn:last-child,.input-append .uneditable-input+.btn-group .btn:last-child{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-append .add-on,.input-append .btn,.input-append .btn-group{margin-left:-1px}.input-append .add-on:last-child,.input-append .btn:last-child,.input-append .btn-group:last-child>.dropdown-toggle{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-prepend.input-append input,.input-prepend.input-append select,.input-prepend.input-append .uneditable-input{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-prepend.input-append input+.btn-group .btn,.input-prepend.input-append select+.btn-group .btn,.input-prepend.input-append .uneditable-input+.btn-group .btn{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-prepend.input-append .add-on:first-child,.input-prepend.input-append .btn:first-child{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.input-prepend.input-append .add-on:last-child,.input-prepend.input-append .btn:last-child{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-prepend.input-append .btn-group:first-child{margin-left:0}input.search-query{padding-right:14px;padding-right:4px \9;padding-left:14px;padding-left:4px \9;margin-bottom:0;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.form-search .input-append .search-query,.form-search .input-prepend .search-query{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.form-search .input-append .search-query{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px}.form-search .input-append .btn{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}.form-search .input-prepend .search-query{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}.form-search .input-prepend .btn{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px}.form-search input,.form-inline input,.form-horizontal input,.form-search textarea,.form-inline textarea,.form-horizontal textarea,.form-search select,.form-inline select,.form-horizontal select,.form-search .help-inline,.form-inline .help-inline,.form-horizontal .help-inline,.form-search .uneditable-input,.form-inline .uneditable-input,.form-horizontal .uneditable-input,.form-search .input-prepend,.form-inline .input-prepend,.form-horizontal .input-prepend,.form-search .input-append,.form-inline .input-append,.form-horizontal .input-append{display:inline-block;*display:inline;margin-bottom:0;vertical-align:middle;*zoom:1}.form-search .hide,.form-inline .hide,.form-horizontal .hide{display:none}.form-search label,.form-inline label,.form-search .btn-group,.form-inline .btn-group{display:inline-block}.form-search .input-append,.form-inline .input-append,.form-search .input-prepend,.form-inline .input-prepend{margin-bottom:0}.form-search .radio,.form-search .checkbox,.form-inline .radio,.form-inline .checkbox{padding-left:0;margin-bottom:0;vertical-align:middle}.form-search .radio input[type="radio"],.form-search .checkbox input[type="checkbox"],.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:left;margin-right:3px;margin-left:0}.control-group{margin-bottom:10px}legend+.control-group{margin-top:20px;-webkit-margin-top-collapse:separate}.form-horizontal .control-group{margin-bottom:20px;*zoom:1}.form-horizontal .control-group:before,.form-horizontal .control-group:after{display:table;line-height:0;content:""}.form-horizontal .control-group:after{clear:both}.form-horizontal .control-label{float:left;width:160px;padding-top:5px;text-align:right}.form-horizontal .controls{*display:inline-block;*padding-left:20px;margin-left:180px;*margin-left:0}.form-horizontal .controls:first-child{*padding-left:180px}.form-horizontal .help-block{margin-bottom:0}.form-horizontal input+.help-block,.form-horizontal select+.help-block,.form-horizontal textarea+.help-block,.form-horizontal .uneditable-input+.help-block,.form-horizontal .input-prepend+.help-block,.form-horizontal .input-append+.help-block{margin-top:10px}.form-horizontal .form-actions{padding-left:180px}table{max-width:100%;background-color:transparent;border-collapse:collapse;border-spacing:0}.table{width:100%;margin-bottom:20px}.table th,.table td{padding:8px;line-height:20px;text-align:left;vertical-align:top;border-top:1px solid #ddd}.table th{font-weight:bold}.table thead th{vertical-align:bottom}.table caption+thead tr:first-child th,.table caption+thead tr:first-child td,.table colgroup+thead tr:first-child th,.table colgroup+thead tr:first-child td,.table thead:first-child tr:first-child th,.table thead:first-child tr:first-child td{border-top:0}.table tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed th,.table-condensed td{padding:4px 5px}.table-bordered{border:1px solid #ddd;border-collapse:separate;*border-collapse:collapse;border-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.table-bordered th,.table-bordered td{border-left:1px solid #ddd}.table-bordered caption+thead tr:first-child th,.table-bordered caption+tbody tr:first-child th,.table-bordered caption+tbody tr:first-child td,.table-bordered colgroup+thead tr:first-child th,.table-bordered colgroup+tbody tr:first-child th,.table-bordered colgroup+tbody tr:first-child td,.table-bordered thead:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child td{border-top:0}.table-bordered thead:first-child tr:first-child>th:first-child,.table-bordered tbody:first-child tr:first-child>td:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px}.table-bordered thead:first-child tr:first-child>th:last-child,.table-bordered tbody:first-child tr:first-child>td:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-topright:4px}.table-bordered thead:last-child tr:last-child>th:first-child,.table-bordered tbody:last-child tr:last-child>td:first-child,.table-bordered tfoot:last-child tr:last-child>td:first-child{-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px}.table-bordered thead:last-child tr:last-child>th:last-child,.table-bordered tbody:last-child tr:last-child>td:last-child,.table-bordered tfoot:last-child tr:last-child>td:last-child{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px}.table-bordered tfoot+tbody:last-child tr:last-child td:first-child{-webkit-border-bottom-left-radius:0;border-bottom-left-radius:0;-moz-border-radius-bottomleft:0}.table-bordered tfoot+tbody:last-child tr:last-child td:last-child{-webkit-border-bottom-right-radius:0;border-bottom-right-radius:0;-moz-border-radius-bottomright:0}.table-bordered caption+thead tr:first-child th:first-child,.table-bordered caption+tbody tr:first-child td:first-child,.table-bordered colgroup+thead tr:first-child th:first-child,.table-bordered colgroup+tbody tr:first-child td:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px}.table-bordered caption+thead tr:first-child th:last-child,.table-bordered caption+tbody tr:first-child td:last-child,.table-bordered colgroup+thead tr:first-child th:last-child,.table-bordered colgroup+tbody tr:first-child td:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-topright:4px}.table-striped tbody>tr:nth-child(odd)>td,.table-striped tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}.table-hover tbody tr:hover td,.table-hover tbody tr:hover th{background-color:#f5f5f5}table td[class*="span"],table th[class*="span"],.row-fluid table td[class*="span"],.row-fluid table th[class*="span"]{display:table-cell;float:none;margin-left:0}.table td.span1,.table th.span1{float:none;width:44px;margin-left:0}.table td.span2,.table th.span2{float:none;width:124px;margin-left:0}.table td.span3,.table th.span3{float:none;width:204px;margin-left:0}.table td.span4,.table th.span4{float:none;width:284px;margin-left:0}.table td.span5,.table th.span5{float:none;width:364px;margin-left:0}.table td.span6,.table th.span6{float:none;width:444px;margin-left:0}.table td.span7,.table th.span7{float:none;width:524px;margin-left:0}.table td.span8,.table th.span8{float:none;width:604px;margin-left:0}.table td.span9,.table th.span9{float:none;width:684px;margin-left:0}.table td.span10,.table th.span10{float:none;width:764px;margin-left:0}.table td.span11,.table th.span11{float:none;width:844px;margin-left:0}.table td.span12,.table th.span12{float:none;width:924px;margin-left:0}.table tbody tr.success td{background-color:#dff0d8}.table tbody tr.error td{background-color:#f2dede}.table tbody tr.warning td{background-color:#fcf8e3}.table tbody tr.info td{background-color:#d9edf7}.table-hover tbody tr.success:hover td{background-color:#d0e9c6}.table-hover tbody tr.error:hover td{background-color:#ebcccc}.table-hover tbody tr.warning:hover td{background-color:#faf2cc}.table-hover tbody tr.info:hover td{background-color:#c4e3f3}[class^="icon-"],[class*=" icon-"]{display:inline-block;width:14px;height:14px;margin-top:1px;*margin-right:.3em;line-height:14px;vertical-align:text-top;background-image:url("../img/glyphicons-halflings.png");background-position:14px 14px;background-repeat:no-repeat}.icon-white,.nav-pills>.active>a>[class^="icon-"],.nav-pills>.active>a>[class*=" icon-"],.nav-list>.active>a>[class^="icon-"],.nav-list>.active>a>[class*=" icon-"],.navbar-inverse .nav>.active>a>[class^="icon-"],.navbar-inverse .nav>.active>a>[class*=" icon-"],.dropdown-menu>li>a:hover>[class^="icon-"],.dropdown-menu>li>a:hover>[class*=" icon-"],.dropdown-menu>.active>a>[class^="icon-"],.dropdown-menu>.active>a>[class*=" icon-"],.dropdown-submenu:hover>a>[class^="icon-"],.dropdown-submenu:hover>a>[class*=" icon-"]{background-image:url("../img/glyphicons-halflings-white.png")}.icon-glass{background-position:0 0}.icon-music{background-position:-24px 0}.icon-search{background-position:-48px 0}.icon-envelope{background-position:-72px 0}.icon-heart{background-position:-96px 0}.icon-star{background-position:-120px 0}.icon-star-empty{background-position:-144px 0}.icon-user{background-position:-168px 0}.icon-film{background-position:-192px 0}.icon-th-large{background-position:-216px 0}.icon-th{background-position:-240px 0}.icon-th-list{background-position:-264px 0}.icon-ok{background-position:-288px 0}.icon-remove{background-position:-312px 0}.icon-zoom-in{background-position:-336px 0}.icon-zoom-out{background-position:-360px 0}.icon-off{background-position:-384px 0}.icon-signal{background-position:-408px 0}.icon-cog{background-position:-432px 0}.icon-trash{background-position:-456px 0}.icon-home{background-position:0 -24px}.icon-file{background-position:-24px -24px}.icon-time{background-position:-48px -24px}.icon-road{background-position:-72px -24px}.icon-download-alt{background-position:-96px -24px}.icon-download{background-position:-120px -24px}.icon-upload{background-position:-144px -24px}.icon-inbox{background-position:-168px -24px}.icon-play-circle{background-position:-192px -24px}.icon-repeat{background-position:-216px -24px}.icon-refresh{background-position:-240px -24px}.icon-list-alt{background-position:-264px -24px}.icon-lock{background-position:-287px -24px}.icon-flag{background-position:-312px -24px}.icon-headphones{background-position:-336px -24px}.icon-volume-off{background-position:-360px -24px}.icon-volume-down{background-position:-384px -24px}.icon-volume-up{background-position:-408px -24px}.icon-qrcode{background-position:-432px -24px}.icon-barcode{background-position:-456px -24px}.icon-tag{background-position:0 -48px}.icon-tags{background-position:-25px -48px}.icon-book{background-position:-48px -48px}.icon-bookmark{background-position:-72px -48px}.icon-print{background-position:-96px -48px}.icon-camera{background-position:-120px -48px}.icon-font{background-position:-144px -48px}.icon-bold{background-position:-167px -48px}.icon-italic{background-position:-192px -48px}.icon-text-height{background-position:-216px -48px}.icon-text-width{background-position:-240px -48px}.icon-align-left{background-position:-264px -48px}.icon-align-center{background-position:-288px -48px}.icon-align-right{background-position:-312px -48px}.icon-align-justify{background-position:-336px -48px}.icon-list{background-position:-360px -48px}.icon-indent-left{background-position:-384px -48px}.icon-indent-right{background-position:-408px -48px}.icon-facetime-video{background-position:-432px -48px}.icon-picture{background-position:-456px -48px}.icon-pencil{background-position:0 -72px}.icon-map-marker{background-position:-24px -72px}.icon-adjust{background-position:-48px -72px}.icon-tint{background-position:-72px -72px}.icon-edit{background-position:-96px -72px}.icon-share{background-position:-120px -72px}.icon-check{background-position:-144px -72px}.icon-move{background-position:-168px -72px}.icon-step-backward{background-position:-192px -72px}.icon-fast-backward{background-position:-216px -72px}.icon-backward{background-position:-240px -72px}.icon-play{background-position:-264px -72px}.icon-pause{background-position:-288px -72px}.icon-stop{background-position:-312px -72px}.icon-forward{background-position:-336px -72px}.icon-fast-forward{background-position:-360px -72px}.icon-step-forward{background-position:-384px -72px}.icon-eject{background-position:-408px -72px}.icon-chevron-left{background-position:-432px -72px}.icon-chevron-right{background-position:-456px -72px}.icon-plus-sign{background-position:0 -96px}.icon-minus-sign{background-position:-24px -96px}.icon-remove-sign{background-position:-48px -96px}.icon-ok-sign{background-position:-72px -96px}.icon-question-sign{background-position:-96px -96px}.icon-info-sign{background-position:-120px -96px}.icon-screenshot{background-position:-144px -96px}.icon-remove-circle{background-position:-168px -96px}.icon-ok-circle{background-position:-192px -96px}.icon-ban-circle{background-position:-216px -96px}.icon-arrow-left{background-position:-240px -96px}.icon-arrow-right{background-position:-264px -96px}.icon-arrow-up{background-position:-289px -96px}.icon-arrow-down{background-position:-312px -96px}.icon-share-alt{background-position:-336px -96px}.icon-resize-full{background-position:-360px -96px}.icon-resize-small{background-position:-384px -96px}.icon-plus{background-position:-408px -96px}.icon-minus{background-position:-433px -96px}.icon-asterisk{background-position:-456px -96px}.icon-exclamation-sign{background-position:0 -120px}.icon-gift{background-position:-24px -120px}.icon-leaf{background-position:-48px -120px}.icon-fire{background-position:-72px -120px}.icon-eye-open{background-position:-96px -120px}.icon-eye-close{background-position:-120px -120px}.icon-warning-sign{background-position:-144px -120px}.icon-plane{background-position:-168px -120px}.icon-calendar{background-position:-192px -120px}.icon-random{width:16px;background-position:-216px -120px}.icon-comment{background-position:-240px -120px}.icon-magnet{background-position:-264px -120px}.icon-chevron-up{background-position:-288px -120px}.icon-chevron-down{background-position:-313px -119px}.icon-retweet{background-position:-336px -120px}.icon-shopping-cart{background-position:-360px -120px}.icon-folder-close{background-position:-384px -120px}.icon-folder-open{width:16px;background-position:-408px -120px}.icon-resize-vertical{background-position:-432px -119px}.icon-resize-horizontal{background-position:-456px -118px}.icon-hdd{background-position:0 -144px}.icon-bullhorn{background-position:-24px -144px}.icon-bell{background-position:-48px -144px}.icon-certificate{background-position:-72px -144px}.icon-thumbs-up{background-position:-96px -144px}.icon-thumbs-down{background-position:-120px -144px}.icon-hand-right{background-position:-144px -144px}.icon-hand-left{background-position:-168px -144px}.icon-hand-up{background-position:-192px -144px}.icon-hand-down{background-position:-216px -144px}.icon-circle-arrow-right{background-position:-240px -144px}.icon-circle-arrow-left{background-position:-264px -144px}.icon-circle-arrow-up{background-position:-288px -144px}.icon-circle-arrow-down{background-position:-312px -144px}.icon-globe{background-position:-336px -144px}.icon-wrench{background-position:-360px -144px}.icon-tasks{background-position:-384px -144px}.icon-filter{background-position:-408px -144px}.icon-briefcase{background-position:-432px -144px}.icon-fullscreen{background-position:-456px -144px}.dropup,.dropdown{position:relative}.dropdown-toggle{*margin-bottom:-3px}.dropdown-toggle:active,.open .dropdown-toggle{outline:0}.caret{display:inline-block;width:0;height:0;vertical-align:top;border-top:4px solid #000;border-right:4px solid transparent;border-left:4px solid transparent;content:""}.dropdown .caret{margin-top:8px;margin-left:2px}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);*border-right-width:2px;*border-bottom-width:2px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}.dropdown-menu li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:20px;color:#333;white-space:nowrap}.dropdown-menu li>a:hover,.dropdown-menu li>a:focus,.dropdown-submenu:hover>a{color:#fff;text-decoration:none;background-color:#0081c2;background-image:-moz-linear-gradient(top,#08c,#0077b3);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#0077b3));background-image:-webkit-linear-gradient(top,#08c,#0077b3);background-image:-o-linear-gradient(top,#08c,#0077b3);background-image:linear-gradient(to bottom,#08c,#0077b3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0077b3',GradientType=0)}.dropdown-menu .active>a,.dropdown-menu .active>a:hover{color:#fff;text-decoration:none;background-color:#0081c2;background-image:-moz-linear-gradient(top,#08c,#0077b3);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#0077b3));background-image:-webkit-linear-gradient(top,#08c,#0077b3);background-image:-o-linear-gradient(top,#08c,#0077b3);background-image:linear-gradient(to bottom,#08c,#0077b3);background-repeat:repeat-x;outline:0;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0077b3',GradientType=0)}.dropdown-menu .disabled>a,.dropdown-menu .disabled>a:hover{color:#999}.dropdown-menu .disabled>a:hover{text-decoration:none;cursor:default;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open{*z-index:1000}.open>.dropdown-menu{display:block}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid #000;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}.dropdown-submenu{position:relative}.dropdown-submenu>.dropdown-menu{top:0;left:100%;margin-top:-6px;margin-left:-1px;-webkit-border-radius:0 6px 6px 6px;-moz-border-radius:0 6px 6px 6px;border-radius:0 6px 6px 6px}.dropdown-submenu:hover>.dropdown-menu{display:block}.dropup .dropdown-submenu>.dropdown-menu{top:auto;bottom:0;margin-top:0;margin-bottom:-2px;-webkit-border-radius:5px 5px 5px 0;-moz-border-radius:5px 5px 5px 0;border-radius:5px 5px 5px 0}.dropdown-submenu>a:after{display:block;float:right;width:0;height:0;margin-top:5px;margin-right:-10px;border-color:transparent;border-left-color:#ccc;border-style:solid;border-width:5px 0 5px 5px;content:" "}.dropdown-submenu:hover>a:after{border-left-color:#fff}.dropdown-submenu.pull-left{float:none}.dropdown-submenu.pull-left>.dropdown-menu{left:-100%;margin-left:10px;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px}.dropdown .dropdown-menu .nav-header{padding-right:20px;padding-left:20px}.typeahead{z-index:1051;margin-top:2px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,0.15)}.well-large{padding:24px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.well-small{padding:9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.fade{opacity:0;-webkit-transition:opacity .15s linear;-moz-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;-moz-transition:height .35s ease;-o-transition:height .35s ease;transition:height .35s ease}.collapse.in{height:auto}.close{float:right;font-size:20px;font-weight:bold;line-height:20px;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover{color:#000;text-decoration:none;cursor:pointer;opacity:.4;filter:alpha(opacity=40)}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.btn{display:inline-block;*display:inline;padding:4px 12px;margin-bottom:0;*margin-left:.3em;font-size:14px;line-height:20px;color:#333;text-align:center;text-shadow:0 1px 1px rgba(255,255,255,0.75);vertical-align:middle;cursor:pointer;background-color:#f5f5f5;*background-color:#e6e6e6;background-image:-moz-linear-gradient(top,#fff,#e6e6e6);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#e6e6e6));background-image:-webkit-linear-gradient(top,#fff,#e6e6e6);background-image:-o-linear-gradient(top,#fff,#e6e6e6);background-image:linear-gradient(to bottom,#fff,#e6e6e6);background-repeat:repeat-x;border:1px solid #bbb;*border:0;border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);border-bottom-color:#a2a2a2;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe6e6e6',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);*zoom:1;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05)}.btn:hover,.btn:active,.btn.active,.btn.disabled,.btn[disabled]{color:#333;background-color:#e6e6e6;*background-color:#d9d9d9}.btn:active,.btn.active{background-color:#ccc \9}.btn:first-child{*margin-left:0}.btn:hover{color:#333;text-decoration:none;background-position:0 -15px;-webkit-transition:background-position .1s linear;-moz-transition:background-position .1s linear;-o-transition:background-position .1s linear;transition:background-position .1s linear}.btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}.btn.disabled,.btn[disabled]{cursor:default;background-image:none;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.btn-large{padding:11px 19px;font-size:17.5px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.btn-large [class^="icon-"],.btn-large [class*=" icon-"]{margin-top:4px}.btn-small{padding:2px 10px;font-size:11.9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.btn-small [class^="icon-"],.btn-small [class*=" icon-"]{margin-top:0}.btn-mini [class^="icon-"],.btn-mini [class*=" icon-"]{margin-top:-1px}.btn-mini{padding:0 6px;font-size:10.5px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.btn-block{display:block;width:100%;padding-right:0;padding-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.btn-block+.btn-block{margin-top:5px}input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}.btn-primary.active,.btn-warning.active,.btn-danger.active,.btn-success.active,.btn-info.active,.btn-inverse.active{color:rgba(255,255,255,0.75)}.btn{border-color:#c5c5c5;border-color:rgba(0,0,0,0.15) rgba(0,0,0,0.15) rgba(0,0,0,0.25)}.btn-primary{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#006dcc;*background-color:#04c;background-image:-moz-linear-gradient(top,#08c,#04c);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#04c));background-image:-webkit-linear-gradient(top,#08c,#04c);background-image:-o-linear-gradient(top,#08c,#04c);background-image:linear-gradient(to bottom,#08c,#04c);background-repeat:repeat-x;border-color:#04c #04c #002a80;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0044cc',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-primary:hover,.btn-primary:active,.btn-primary.active,.btn-primary.disabled,.btn-primary[disabled]{color:#fff;background-color:#04c;*background-color:#003bb3}.btn-primary:active,.btn-primary.active{background-color:#039 \9}.btn-warning{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#faa732;*background-color:#f89406;background-image:-moz-linear-gradient(top,#fbb450,#f89406);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fbb450),to(#f89406));background-image:-webkit-linear-gradient(top,#fbb450,#f89406);background-image:-o-linear-gradient(top,#fbb450,#f89406);background-image:linear-gradient(to bottom,#fbb450,#f89406);background-repeat:repeat-x;border-color:#f89406 #f89406 #ad6704;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450',endColorstr='#fff89406',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-warning:hover,.btn-warning:active,.btn-warning.active,.btn-warning.disabled,.btn-warning[disabled]{color:#fff;background-color:#f89406;*background-color:#df8505}.btn-warning:active,.btn-warning.active{background-color:#c67605 \9}.btn-danger{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#da4f49;*background-color:#bd362f;background-image:-moz-linear-gradient(top,#ee5f5b,#bd362f);background-image:-webkit-gradient(linear,0 0,0 100%,from(#ee5f5b),to(#bd362f));background-image:-webkit-linear-gradient(top,#ee5f5b,#bd362f);background-image:-o-linear-gradient(top,#ee5f5b,#bd362f);background-image:linear-gradient(to bottom,#ee5f5b,#bd362f);background-repeat:repeat-x;border-color:#bd362f #bd362f #802420;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b',endColorstr='#ffbd362f',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-danger:hover,.btn-danger:active,.btn-danger.active,.btn-danger.disabled,.btn-danger[disabled]{color:#fff;background-color:#bd362f;*background-color:#a9302a}.btn-danger:active,.btn-danger.active{background-color:#942a25 \9}.btn-success{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#5bb75b;*background-color:#51a351;background-image:-moz-linear-gradient(top,#62c462,#51a351);background-image:-webkit-gradient(linear,0 0,0 100%,from(#62c462),to(#51a351));background-image:-webkit-linear-gradient(top,#62c462,#51a351);background-image:-o-linear-gradient(top,#62c462,#51a351);background-image:linear-gradient(to bottom,#62c462,#51a351);background-repeat:repeat-x;border-color:#51a351 #51a351 #387038;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462',endColorstr='#ff51a351',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-success:hover,.btn-success:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{color:#fff;background-color:#51a351;*background-color:#499249}.btn-success:active,.btn-success.active{background-color:#408140 \9}.btn-info{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#49afcd;*background-color:#2f96b4;background-image:-moz-linear-gradient(top,#5bc0de,#2f96b4);background-image:-webkit-gradient(linear,0 0,0 100%,from(#5bc0de),to(#2f96b4));background-image:-webkit-linear-gradient(top,#5bc0de,#2f96b4);background-image:-o-linear-gradient(top,#5bc0de,#2f96b4);background-image:linear-gradient(to bottom,#5bc0de,#2f96b4);background-repeat:repeat-x;border-color:#2f96b4 #2f96b4 #1f6377;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff2f96b4',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-info:hover,.btn-info:active,.btn-info.active,.btn-info.disabled,.btn-info[disabled]{color:#fff;background-color:#2f96b4;*background-color:#2a85a0}.btn-info:active,.btn-info.active{background-color:#24748c \9}.btn-inverse{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#363636;*background-color:#222;background-image:-moz-linear-gradient(top,#444,#222);background-image:-webkit-gradient(linear,0 0,0 100%,from(#444),to(#222));background-image:-webkit-linear-gradient(top,#444,#222);background-image:-o-linear-gradient(top,#444,#222);background-image:linear-gradient(to bottom,#444,#222);background-repeat:repeat-x;border-color:#222 #222 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff444444',endColorstr='#ff222222',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-inverse:hover,.btn-inverse:active,.btn-inverse.active,.btn-inverse.disabled,.btn-inverse[disabled]{color:#fff;background-color:#222;*background-color:#151515}.btn-inverse:active,.btn-inverse.active{background-color:#080808 \9}button.btn,input[type="submit"].btn{*padding-top:3px;*padding-bottom:3px}button.btn::-moz-focus-inner,input[type="submit"].btn::-moz-focus-inner{padding:0;border:0}button.btn.btn-large,input[type="submit"].btn.btn-large{*padding-top:7px;*padding-bottom:7px}button.btn.btn-small,input[type="submit"].btn.btn-small{*padding-top:3px;*padding-bottom:3px}button.btn.btn-mini,input[type="submit"].btn.btn-mini{*padding-top:1px;*padding-bottom:1px}.btn-link,.btn-link:active,.btn-link[disabled]{background-color:transparent;background-image:none;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.btn-link{color:#08c;cursor:pointer;border-color:transparent;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-link:hover{color:#005580;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover{color:#333;text-decoration:none}.btn-group{position:relative;display:inline-block;*display:inline;*margin-left:.3em;font-size:0;white-space:nowrap;vertical-align:middle;*zoom:1}.btn-group:first-child{*margin-left:0}.btn-group+.btn-group{margin-left:5px}.btn-toolbar{margin-top:10px;margin-bottom:10px;font-size:0}.btn-toolbar>.btn+.btn,.btn-toolbar>.btn-group+.btn,.btn-toolbar>.btn+.btn-group{margin-left:5px}.btn-group>.btn{position:relative;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-group>.btn+.btn{margin-left:-1px}.btn-group>.btn,.btn-group>.dropdown-menu,.btn-group>.popover{font-size:14px}.btn-group>.btn-mini{font-size:10.5px}.btn-group>.btn-small{font-size:11.9px}.btn-group>.btn-large{font-size:17.5px}.btn-group>.btn:first-child{margin-left:0;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-bottomleft:4px;-moz-border-radius-topleft:4px}.btn-group>.btn:last-child,.btn-group>.dropdown-toggle{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-bottomright:4px}.btn-group>.btn.large:first-child{margin-left:0;-webkit-border-bottom-left-radius:6px;border-bottom-left-radius:6px;-webkit-border-top-left-radius:6px;border-top-left-radius:6px;-moz-border-radius-bottomleft:6px;-moz-border-radius-topleft:6px}.btn-group>.btn.large:last-child,.btn-group>.large.dropdown-toggle{-webkit-border-top-right-radius:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;border-bottom-right-radius:6px;-moz-border-radius-topright:6px;-moz-border-radius-bottomright:6px}.btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active{z-index:2}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{*padding-top:5px;padding-right:8px;*padding-bottom:5px;padding-left:8px;-webkit-box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05)}.btn-group>.btn-mini+.dropdown-toggle{*padding-top:2px;padding-right:5px;*padding-bottom:2px;padding-left:5px}.btn-group>.btn-small+.dropdown-toggle{*padding-top:5px;*padding-bottom:4px}.btn-group>.btn-large+.dropdown-toggle{*padding-top:7px;padding-right:12px;*padding-bottom:7px;padding-left:12px}.btn-group.open .dropdown-toggle{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}.btn-group.open .btn.dropdown-toggle{background-color:#e6e6e6}.btn-group.open .btn-primary.dropdown-toggle{background-color:#04c}.btn-group.open .btn-warning.dropdown-toggle{background-color:#f89406}.btn-group.open .btn-danger.dropdown-toggle{background-color:#bd362f}.btn-group.open .btn-success.dropdown-toggle{background-color:#51a351}.btn-group.open .btn-info.dropdown-toggle{background-color:#2f96b4}.btn-group.open .btn-inverse.dropdown-toggle{background-color:#222}.btn .caret{margin-top:8px;margin-left:0}.btn-mini .caret,.btn-small .caret,.btn-large .caret{margin-top:6px}.btn-large .caret{border-top-width:5px;border-right-width:5px;border-left-width:5px}.dropup .btn-large .caret{border-bottom-width:5px}.btn-primary .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret,.btn-success .caret,.btn-inverse .caret{border-top-color:#fff;border-bottom-color:#fff}.btn-group-vertical{display:inline-block;*display:inline;*zoom:1}.btn-group-vertical>.btn{display:block;float:none;max-width:100%;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-group-vertical>.btn+.btn{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:first-child{-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.btn-group-vertical>.btn:last-child{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.btn-group-vertical>.btn-large:first-child{-webkit-border-radius:6px 6px 0 0;-moz-border-radius:6px 6px 0 0;border-radius:6px 6px 0 0}.btn-group-vertical>.btn-large:last-child{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}.alert{padding:8px 35px 8px 14px;margin-bottom:20px;text-shadow:0 1px 0 rgba(255,255,255,0.5);background-color:#fcf8e3;border:1px solid #fbeed5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.alert,.alert h4{color:#c09853}.alert h4{margin:0}.alert .close{position:relative;top:-2px;right:-21px;line-height:20px}.alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.alert-success h4{color:#468847}.alert-danger,.alert-error{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.alert-danger h4,.alert-error h4{color:#b94a48}.alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.alert-info h4{color:#3a87ad}.alert-block{padding-top:14px;padding-bottom:14px}.alert-block>p,.alert-block>ul{margin-bottom:0}.alert-block p+p{margin-top:5px}.nav{margin-bottom:20px;margin-left:0;list-style:none}.nav>li>a{display:block}.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>li>a>img{max-width:none}.nav>.pull-right{float:right}.nav-header{display:block;padding:3px 15px;font-size:11px;font-weight:bold;line-height:20px;color:#999;text-shadow:0 1px 0 rgba(255,255,255,0.5);text-transform:uppercase}.nav li+.nav-header{margin-top:9px}.nav-list{padding-right:15px;padding-left:15px;margin-bottom:0}.nav-list>li>a,.nav-list .nav-header{margin-right:-15px;margin-left:-15px;text-shadow:0 1px 0 rgba(255,255,255,0.5)}.nav-list>li>a{padding:3px 15px}.nav-list>.active>a,.nav-list>.active>a:hover{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.2);background-color:#08c}.nav-list [class^="icon-"],.nav-list [class*=" icon-"]{margin-right:2px}.nav-list .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}.nav-tabs,.nav-pills{*zoom:1}.nav-tabs:before,.nav-pills:before,.nav-tabs:after,.nav-pills:after{display:table;line-height:0;content:""}.nav-tabs:after,.nav-pills:after{clear:both}.nav-tabs>li,.nav-pills>li{float:left}.nav-tabs>li>a,.nav-pills>li>a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14px}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{margin-bottom:-1px}.nav-tabs>li>a{padding-top:8px;padding-bottom:8px;line-height:20px;border:1px solid transparent;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>.active>a,.nav-tabs>.active>a:hover{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-pills>li>a{padding-top:8px;padding-bottom:8px;margin-top:2px;margin-bottom:2px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.nav-pills>.active>a,.nav-pills>.active>a:hover{color:#fff;background-color:#08c}.nav-stacked>li{float:none}.nav-stacked>li>a{margin-right:0}.nav-tabs.nav-stacked{border-bottom:0}.nav-tabs.nav-stacked>li>a{border:1px solid #ddd;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.nav-tabs.nav-stacked>li:first-child>a{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-topleft:4px}.nav-tabs.nav-stacked>li:last-child>a{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomright:4px;-moz-border-radius-bottomleft:4px}.nav-tabs.nav-stacked>li>a:hover{z-index:2;border-color:#ddd}.nav-pills.nav-stacked>li>a{margin-bottom:3px}.nav-pills.nav-stacked>li:last-child>a{margin-bottom:1px}.nav-tabs .dropdown-menu{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}.nav-pills .dropdown-menu{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.nav .dropdown-toggle .caret{margin-top:6px;border-top-color:#08c;border-bottom-color:#08c}.nav .dropdown-toggle:hover .caret{border-top-color:#005580;border-bottom-color:#005580}.nav-tabs .dropdown-toggle .caret{margin-top:8px}.nav .active .dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}.nav-tabs .active .dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}.nav>.dropdown.active>a:hover{cursor:pointer}.nav-tabs .open .dropdown-toggle,.nav-pills .open .dropdown-toggle,.nav>li.dropdown.open.active>a:hover{color:#fff;background-color:#999;border-color:#999}.nav li.dropdown.open .caret,.nav li.dropdown.open.active .caret,.nav li.dropdown.open a:hover .caret{border-top-color:#fff;border-bottom-color:#fff;opacity:1;filter:alpha(opacity=100)}.tabs-stacked .open>a:hover{border-color:#999}.tabbable{*zoom:1}.tabbable:before,.tabbable:after{display:table;line-height:0;content:""}.tabbable:after{clear:both}.tab-content{overflow:auto}.tabs-below>.nav-tabs,.tabs-right>.nav-tabs,.tabs-left>.nav-tabs{border-bottom:0}.tab-content>.tab-pane,.pill-content>.pill-pane{display:none}.tab-content>.active,.pill-content>.active{display:block}.tabs-below>.nav-tabs{border-top:1px solid #ddd}.tabs-below>.nav-tabs>li{margin-top:-1px;margin-bottom:0}.tabs-below>.nav-tabs>li>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.tabs-below>.nav-tabs>li>a:hover{border-top-color:#ddd;border-bottom-color:transparent}.tabs-below>.nav-tabs>.active>a,.tabs-below>.nav-tabs>.active>a:hover{border-color:transparent #ddd #ddd #ddd}.tabs-left>.nav-tabs>li,.tabs-right>.nav-tabs>li{float:none}.tabs-left>.nav-tabs>li>a,.tabs-right>.nav-tabs>li>a{min-width:74px;margin-right:0;margin-bottom:3px}.tabs-left>.nav-tabs{float:left;margin-right:19px;border-right:1px solid #ddd}.tabs-left>.nav-tabs>li>a{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.tabs-left>.nav-tabs>li>a:hover{border-color:#eee #ddd #eee #eee}.tabs-left>.nav-tabs .active>a,.tabs-left>.nav-tabs .active>a:hover{border-color:#ddd transparent #ddd #ddd;*border-right-color:#fff}.tabs-right>.nav-tabs{float:right;margin-left:19px;border-left:1px solid #ddd}.tabs-right>.nav-tabs>li>a{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.tabs-right>.nav-tabs>li>a:hover{border-color:#eee #eee #eee #ddd}.tabs-right>.nav-tabs .active>a,.tabs-right>.nav-tabs .active>a:hover{border-color:#ddd #ddd #ddd transparent;*border-left-color:#fff}.nav>.disabled>a{color:#999}.nav>.disabled>a:hover{text-decoration:none;cursor:default;background-color:transparent}.navbar{*position:relative;*z-index:2;margin-bottom:20px;overflow:visible}.navbar-inner{min-height:40px;padding-right:20px;padding-left:20px;background-color:#fafafa;background-image:-moz-linear-gradient(top,#fff,#f2f2f2);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#f2f2f2));background-image:-webkit-linear-gradient(top,#fff,#f2f2f2);background-image:-o-linear-gradient(top,#fff,#f2f2f2);background-image:linear-gradient(to bottom,#fff,#f2f2f2);background-repeat:repeat-x;border:1px solid #d4d4d4;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#fff2f2f2',GradientType=0);*zoom:1;-webkit-box-shadow:0 1px 4px rgba(0,0,0,0.065);-moz-box-shadow:0 1px 4px rgba(0,0,0,0.065);box-shadow:0 1px 4px rgba(0,0,0,0.065)}.navbar-inner:before,.navbar-inner:after{display:table;line-height:0;content:""}.navbar-inner:after{clear:both}.navbar .container{width:auto}.nav-collapse.collapse{height:auto;overflow:visible}.navbar .brand{display:block;float:left;padding:10px 20px 10px;margin-left:-20px;font-size:20px;font-weight:200;color:#777;text-shadow:0 1px 0 #fff}.navbar .brand:hover{text-decoration:none}.navbar-text{margin-bottom:0;line-height:40px;color:#777}.navbar-link{color:#777}.navbar-link:hover{color:#333}.navbar .divider-vertical{height:40px;margin:0 9px;border-right:1px solid #fff;border-left:1px solid #f2f2f2}.navbar .btn,.navbar .btn-group{margin-top:5px}.navbar .btn-group .btn,.navbar .input-prepend .btn,.navbar .input-append .btn{margin-top:0}.navbar-form{margin-bottom:0;*zoom:1}.navbar-form:before,.navbar-form:after{display:table;line-height:0;content:""}.navbar-form:after{clear:both}.navbar-form input,.navbar-form select,.navbar-form .radio,.navbar-form .checkbox{margin-top:5px}.navbar-form input,.navbar-form select,.navbar-form .btn{display:inline-block;margin-bottom:0}.navbar-form input[type="image"],.navbar-form input[type="checkbox"],.navbar-form input[type="radio"]{margin-top:3px}.navbar-form .input-append,.navbar-form .input-prepend{margin-top:5px;white-space:nowrap}.navbar-form .input-append input,.navbar-form .input-prepend input{margin-top:0}.navbar-search{position:relative;float:left;margin-top:5px;margin-bottom:0}.navbar-search .search-query{padding:4px 14px;margin-bottom:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:1;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.navbar-static-top{position:static;margin-bottom:0}.navbar-static-top .navbar-inner{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030;margin-bottom:0}.navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{border-width:0 0 1px}.navbar-fixed-bottom .navbar-inner{border-width:1px 0 0}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding-right:0;padding-left:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}.navbar-fixed-top{top:0}.navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{-webkit-box-shadow:0 1px 10px rgba(0,0,0,0.1);-moz-box-shadow:0 1px 10px rgba(0,0,0,0.1);box-shadow:0 1px 10px rgba(0,0,0,0.1)}.navbar-fixed-bottom{bottom:0}.navbar-fixed-bottom .navbar-inner{-webkit-box-shadow:0 -1px 10px rgba(0,0,0,0.1);-moz-box-shadow:0 -1px 10px rgba(0,0,0,0.1);box-shadow:0 -1px 10px rgba(0,0,0,0.1)}.navbar .nav{position:relative;left:0;display:block;float:left;margin:0 10px 0 0}.navbar .nav.pull-right{float:right;margin-right:0}.navbar .nav>li{float:left}.navbar .nav>li>a{float:none;padding:10px 15px 10px;color:#777;text-decoration:none;text-shadow:0 1px 0 #fff}.navbar .nav .dropdown-toggle .caret{margin-top:8px}.navbar .nav>li>a:focus,.navbar .nav>li>a:hover{color:#333;text-decoration:none;background-color:transparent}.navbar .nav>.active>a,.navbar .nav>.active>a:hover,.navbar .nav>.active>a:focus{color:#555;text-decoration:none;background-color:#e5e5e5;-webkit-box-shadow:inset 0 3px 8px rgba(0,0,0,0.125);-moz-box-shadow:inset 0 3px 8px rgba(0,0,0,0.125);box-shadow:inset 0 3px 8px rgba(0,0,0,0.125)}.navbar .btn-navbar{display:none;float:right;padding:7px 10px;margin-right:5px;margin-left:5px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#ededed;*background-color:#e5e5e5;background-image:-moz-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:-webkit-gradient(linear,0 0,0 100%,from(#f2f2f2),to(#e5e5e5));background-image:-webkit-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:-o-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:linear-gradient(to bottom,#f2f2f2,#e5e5e5);background-repeat:repeat-x;border-color:#e5e5e5 #e5e5e5 #bfbfbf;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2f2f2',endColorstr='#ffe5e5e5',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075)}.navbar .btn-navbar:hover,.navbar .btn-navbar:active,.navbar .btn-navbar.active,.navbar .btn-navbar.disabled,.navbar .btn-navbar[disabled]{color:#fff;background-color:#e5e5e5;*background-color:#d9d9d9}.navbar .btn-navbar:active,.navbar .btn-navbar.active{background-color:#ccc \9}.navbar .btn-navbar .icon-bar{display:block;width:18px;height:2px;background-color:#f5f5f5;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,0.25);-moz-box-shadow:0 1px 0 rgba(0,0,0,0.25);box-shadow:0 1px 0 rgba(0,0,0,0.25)}.btn-navbar .icon-bar+.icon-bar{margin-top:3px}.navbar .nav>li>.dropdown-menu:before{position:absolute;top:-7px;left:9px;display:inline-block;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-left:7px solid transparent;border-bottom-color:rgba(0,0,0,0.2);content:''}.navbar .nav>li>.dropdown-menu:after{position:absolute;top:-6px;left:10px;display:inline-block;border-right:6px solid transparent;border-bottom:6px solid #fff;border-left:6px solid transparent;content:''}.navbar-fixed-bottom .nav>li>.dropdown-menu:before{top:auto;bottom:-7px;border-top:7px solid #ccc;border-bottom:0;border-top-color:rgba(0,0,0,0.2)}.navbar-fixed-bottom .nav>li>.dropdown-menu:after{top:auto;bottom:-6px;border-top:6px solid #fff;border-bottom:0}.navbar .nav li.dropdown>a:hover .caret{border-top-color:#555;border-bottom-color:#555}.navbar .nav li.dropdown.open>.dropdown-toggle,.navbar .nav li.dropdown.active>.dropdown-toggle,.navbar .nav li.dropdown.open.active>.dropdown-toggle{color:#555;background-color:#e5e5e5}.navbar .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#777;border-bottom-color:#777}.navbar .nav li.dropdown.open>.dropdown-toggle .caret,.navbar .nav li.dropdown.active>.dropdown-toggle .caret,.navbar .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}.navbar .pull-right>li>.dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right{right:0;left:auto}.navbar .pull-right>li>.dropdown-menu:before,.navbar .nav>li>.dropdown-menu.pull-right:before{right:12px;left:auto}.navbar .pull-right>li>.dropdown-menu:after,.navbar .nav>li>.dropdown-menu.pull-right:after{right:13px;left:auto}.navbar .pull-right>li>.dropdown-menu .dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right .dropdown-menu{right:100%;left:auto;margin-right:-1px;margin-left:0;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px}.navbar-inverse .navbar-inner{background-color:#1b1b1b;background-image:-moz-linear-gradient(top,#222,#111);background-image:-webkit-gradient(linear,0 0,0 100%,from(#222),to(#111));background-image:-webkit-linear-gradient(top,#222,#111);background-image:-o-linear-gradient(top,#222,#111);background-image:linear-gradient(to bottom,#222,#111);background-repeat:repeat-x;border-color:#252525;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222',endColorstr='#ff111111',GradientType=0)}.navbar-inverse .brand,.navbar-inverse .nav>li>a{color:#999;text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.navbar-inverse .brand:hover,.navbar-inverse .nav>li>a:hover{color:#fff}.navbar-inverse .brand{color:#999}.navbar-inverse .navbar-text{color:#999}.navbar-inverse .nav>li>a:focus,.navbar-inverse .nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .nav .active>a,.navbar-inverse .nav .active>a:hover,.navbar-inverse .nav .active>a:focus{color:#fff;background-color:#111}.navbar-inverse .navbar-link{color:#999}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .divider-vertical{border-right-color:#222;border-left-color:#111}.navbar-inverse .nav li.dropdown.open>.dropdown-toggle,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle{color:#fff;background-color:#111}.navbar-inverse .nav li.dropdown>a:hover .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-inverse .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#999;border-bottom-color:#999}.navbar-inverse .nav li.dropdown.open>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-inverse .navbar-search .search-query{color:#fff;background-color:#515151;border-color:#111;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);-webkit-transition:none;-moz-transition:none;-o-transition:none;transition:none}.navbar-inverse .navbar-search .search-query:-moz-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query:-ms-input-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query::-webkit-input-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query:focus,.navbar-inverse .navbar-search .search-query.focused{padding:5px 15px;color:#333;text-shadow:0 1px 0 #fff;background-color:#fff;border:0;outline:0;-webkit-box-shadow:0 0 3px rgba(0,0,0,0.15);-moz-box-shadow:0 0 3px rgba(0,0,0,0.15);box-shadow:0 0 3px rgba(0,0,0,0.15)}.navbar-inverse .btn-navbar{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0e0e0e;*background-color:#040404;background-image:-moz-linear-gradient(top,#151515,#040404);background-image:-webkit-gradient(linear,0 0,0 100%,from(#151515),to(#040404));background-image:-webkit-linear-gradient(top,#151515,#040404);background-image:-o-linear-gradient(top,#151515,#040404);background-image:linear-gradient(to bottom,#151515,#040404);background-repeat:repeat-x;border-color:#040404 #040404 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff151515',endColorstr='#ff040404',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.navbar-inverse .btn-navbar:hover,.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active,.navbar-inverse .btn-navbar.disabled,.navbar-inverse .btn-navbar[disabled]{color:#fff;background-color:#040404;*background-color:#000}.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active{background-color:#000 \9}.breadcrumb{padding:8px 15px;margin:0 0 20px;list-style:none;background-color:#f5f5f5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.breadcrumb>li{display:inline-block;*display:inline;text-shadow:0 1px 0 #fff;*zoom:1}.breadcrumb>li>.divider{padding:0 5px;color:#ccc}.breadcrumb>.active{color:#999}.pagination{margin:20px 0}.pagination ul{display:inline-block;*display:inline;margin-bottom:0;margin-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;*zoom:1;-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:0 1px 2px rgba(0,0,0,0.05);box-shadow:0 1px 2px rgba(0,0,0,0.05)}.pagination ul>li{display:inline}.pagination ul>li>a,.pagination ul>li>span{float:left;padding:4px 12px;line-height:20px;text-decoration:none;background-color:#fff;border:1px solid #ddd;border-left-width:0}.pagination ul>li>a:hover,.pagination ul>.active>a,.pagination ul>.active>span{background-color:#f5f5f5}.pagination ul>.active>a,.pagination ul>.active>span{color:#999;cursor:default}.pagination ul>.disabled>span,.pagination ul>.disabled>a,.pagination ul>.disabled>a:hover{color:#999;cursor:default;background-color:transparent}.pagination ul>li:first-child>a,.pagination ul>li:first-child>span{border-left-width:1px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-bottomleft:4px;-moz-border-radius-topleft:4px}.pagination ul>li:last-child>a,.pagination ul>li:last-child>span{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-bottomright:4px}.pagination-centered{text-align:center}.pagination-right{text-align:right}.pagination-large ul>li>a,.pagination-large ul>li>span{padding:11px 19px;font-size:17.5px}.pagination-large ul>li:first-child>a,.pagination-large ul>li:first-child>span{-webkit-border-bottom-left-radius:6px;border-bottom-left-radius:6px;-webkit-border-top-left-radius:6px;border-top-left-radius:6px;-moz-border-radius-bottomleft:6px;-moz-border-radius-topleft:6px}.pagination-large ul>li:last-child>a,.pagination-large ul>li:last-child>span{-webkit-border-top-right-radius:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;border-bottom-right-radius:6px;-moz-border-radius-topright:6px;-moz-border-radius-bottomright:6px}.pagination-mini ul>li:first-child>a,.pagination-small ul>li:first-child>a,.pagination-mini ul>li:first-child>span,.pagination-small ul>li:first-child>span{-webkit-border-bottom-left-radius:3px;border-bottom-left-radius:3px;-webkit-border-top-left-radius:3px;border-top-left-radius:3px;-moz-border-radius-bottomleft:3px;-moz-border-radius-topleft:3px}.pagination-mini ul>li:last-child>a,.pagination-small ul>li:last-child>a,.pagination-mini ul>li:last-child>span,.pagination-small ul>li:last-child>span{-webkit-border-top-right-radius:3px;border-top-right-radius:3px;-webkit-border-bottom-right-radius:3px;border-bottom-right-radius:3px;-moz-border-radius-topright:3px;-moz-border-radius-bottomright:3px}.pagination-small ul>li>a,.pagination-small ul>li>span{padding:2px 10px;font-size:11.9px}.pagination-mini ul>li>a,.pagination-mini ul>li>span{padding:0 6px;font-size:10.5px}.pager{margin:20px 0;text-align:center;list-style:none;*zoom:1}.pager:before,.pager:after{display:table;line-height:0;content:""}.pager:after{clear:both}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.pager li>a:hover{text-decoration:none;background-color:#f5f5f5}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>span{color:#999;cursor:default;background-color:#fff}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop,.modal-backdrop.fade.in{opacity:.8;filter:alpha(opacity=80)}.modal{position:fixed;top:10%;left:50%;z-index:1050;width:560px;margin-left:-280px;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,0.3);*border:1px solid #999;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;outline:0;-webkit-box-shadow:0 3px 7px rgba(0,0,0,0.3);-moz-box-shadow:0 3px 7px rgba(0,0,0,0.3);box-shadow:0 3px 7px rgba(0,0,0,0.3);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box}.modal.fade{top:-25%;-webkit-transition:opacity .3s linear,top .3s ease-out;-moz-transition:opacity .3s linear,top .3s ease-out;-o-transition:opacity .3s linear,top .3s ease-out;transition:opacity .3s linear,top .3s ease-out}.modal.fade.in{top:10%}.modal-header{padding:9px 15px;border-bottom:1px solid #eee}.modal-header .close{margin-top:2px}.modal-header h3{margin:0;line-height:30px}.modal-body{position:relative;max-height:400px;padding:15px;overflow-y:auto}.modal-form{margin-bottom:0}.modal-footer{padding:14px 15px 15px;margin-bottom:0;text-align:right;background-color:#f5f5f5;border-top:1px solid #ddd;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;*zoom:1;-webkit-box-shadow:inset 0 1px 0 #fff;-moz-box-shadow:inset 0 1px 0 #fff;box-shadow:inset 0 1px 0 #fff}.modal-footer:before,.modal-footer:after{display:table;line-height:0;content:""}.modal-footer:after{clear:both}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.tooltip{position:absolute;z-index:1030;display:block;padding:5px;font-size:11px;opacity:0;filter:alpha(opacity=0);visibility:visible}.tooltip.in{opacity:.8;filter:alpha(opacity=80)}.tooltip.top{margin-top:-3px}.tooltip.right{margin-left:3px}.tooltip.bottom{margin-top:3px}.tooltip.left{margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-top-color:#000;border-width:5px 5px 0}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-right-color:#000;border-width:5px 5px 5px 0}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-left-color:#000;border-width:5px 0 5px 5px}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-bottom-color:#000;border-width:0 5px 5px}.popover{position:absolute;top:0;left:0;z-index:1010;display:none;width:236px;padding:1px;text-align:left;white-space:normal;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;-webkit-border-radius:5px 5px 0 0;-moz-border-radius:5px 5px 0 0;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover .arrow,.popover .arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover .arrow{border-width:11px}.popover .arrow:after{border-width:10px;content:""}.popover.top .arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,0.25);border-bottom-width:0}.popover.top .arrow:after{bottom:1px;margin-left:-10px;border-top-color:#fff;border-bottom-width:0}.popover.right .arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,0.25);border-left-width:0}.popover.right .arrow:after{bottom:-10px;left:1px;border-right-color:#fff;border-left-width:0}.popover.bottom .arrow{top:-11px;left:50%;margin-left:-11px;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,0.25);border-top-width:0}.popover.bottom .arrow:after{top:1px;margin-left:-10px;border-bottom-color:#fff;border-top-width:0}.popover.left .arrow{top:50%;right:-11px;margin-top:-11px;border-left-color:#999;border-left-color:rgba(0,0,0,0.25);border-right-width:0}.popover.left .arrow:after{right:1px;bottom:-10px;border-left-color:#fff;border-right-width:0}.thumbnails{margin-left:-20px;list-style:none;*zoom:1}.thumbnails:before,.thumbnails:after{display:table;line-height:0;content:""}.thumbnails:after{clear:both}.row-fluid .thumbnails{margin-left:0}.thumbnails>li{float:left;margin-bottom:20px;margin-left:20px}.thumbnail{display:block;padding:4px;line-height:20px;border:1px solid #ddd;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.055);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.055);box-shadow:0 1px 3px rgba(0,0,0,0.055);-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}a.thumbnail:hover{border-color:#08c;-webkit-box-shadow:0 1px 4px rgba(0,105,214,0.25);-moz-box-shadow:0 1px 4px rgba(0,105,214,0.25);box-shadow:0 1px 4px rgba(0,105,214,0.25)}.thumbnail>img{display:block;max-width:100%;margin-right:auto;margin-left:auto}.thumbnail .caption{padding:9px;color:#555}.media,.media-body{overflow:hidden;*overflow:visible;zoom:1}.media,.media .media{margin-top:15px}.media:first-child{margin-top:0}.media-object{display:block}.media-heading{margin:0 0 5px}.media .pull-left{margin-right:10px}.media .pull-right{margin-left:10px}.media-list{margin-left:0;list-style:none}.label,.badge{display:inline-block;padding:2px 4px;font-size:11.844px;font-weight:bold;line-height:14px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);white-space:nowrap;vertical-align:baseline;background-color:#999}.label{-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.badge{padding-right:9px;padding-left:9px;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px}.label:empty,.badge:empty{display:none}a.label:hover,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.label-important,.badge-important{background-color:#b94a48}.label-important[href],.badge-important[href]{background-color:#953b39}.label-warning,.badge-warning{background-color:#f89406}.label-warning[href],.badge-warning[href]{background-color:#c67605}.label-success,.badge-success{background-color:#468847}.label-success[href],.badge-success[href]{background-color:#356635}.label-info,.badge-info{background-color:#3a87ad}.label-info[href],.badge-info[href]{background-color:#2d6987}.label-inverse,.badge-inverse{background-color:#333}.label-inverse[href],.badge-inverse[href]{background-color:#1a1a1a}.btn .label,.btn .badge{position:relative;top:-1px}.btn-mini .label,.btn-mini .badge{top:0}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-moz-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-ms-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:0 0}to{background-position:40px 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f7f7f7;background-image:-moz-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:-webkit-gradient(linear,0 0,0 100%,from(#f5f5f5),to(#f9f9f9));background-image:-webkit-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:-o-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:linear-gradient(to bottom,#f5f5f5,#f9f9f9);background-repeat:repeat-x;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5',endColorstr='#fff9f9f9',GradientType=0);-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1)}.progress .bar{float:left;width:0;height:100%;font-size:12px;color:#fff;text-align:center;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0e90d2;background-image:-moz-linear-gradient(top,#149bdf,#0480be);background-image:-webkit-gradient(linear,0 0,0 100%,from(#149bdf),to(#0480be));background-image:-webkit-linear-gradient(top,#149bdf,#0480be);background-image:-o-linear-gradient(top,#149bdf,#0480be);background-image:linear-gradient(to bottom,#149bdf,#0480be);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff149bdf',endColorstr='#ff0480be',GradientType=0);-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-moz-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:width .6s ease;-moz-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress .bar+.bar{-webkit-box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15);-moz-box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15)}.progress-striped .bar{background-color:#149bdf;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;-moz-background-size:40px 40px;-o-background-size:40px 40px;background-size:40px 40px}.progress.active .bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-moz-animation:progress-bar-stripes 2s linear infinite;-ms-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-danger .bar,.progress .bar-danger{background-color:#dd514c;background-image:-moz-linear-gradient(top,#ee5f5b,#c43c35);background-image:-webkit-gradient(linear,0 0,0 100%,from(#ee5f5b),to(#c43c35));background-image:-webkit-linear-gradient(top,#ee5f5b,#c43c35);background-image:-o-linear-gradient(top,#ee5f5b,#c43c35);background-image:linear-gradient(to bottom,#ee5f5b,#c43c35);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b',endColorstr='#ffc43c35',GradientType=0)}.progress-danger.progress-striped .bar,.progress-striped .bar-danger{background-color:#ee5f5b;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-success .bar,.progress .bar-success{background-color:#5eb95e;background-image:-moz-linear-gradient(top,#62c462,#57a957);background-image:-webkit-gradient(linear,0 0,0 100%,from(#62c462),to(#57a957));background-image:-webkit-linear-gradient(top,#62c462,#57a957);background-image:-o-linear-gradient(top,#62c462,#57a957);background-image:linear-gradient(to bottom,#62c462,#57a957);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462',endColorstr='#ff57a957',GradientType=0)}.progress-success.progress-striped .bar,.progress-striped .bar-success{background-color:#62c462;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-info .bar,.progress .bar-info{background-color:#4bb1cf;background-image:-moz-linear-gradient(top,#5bc0de,#339bb9);background-image:-webkit-gradient(linear,0 0,0 100%,from(#5bc0de),to(#339bb9));background-image:-webkit-linear-gradient(top,#5bc0de,#339bb9);background-image:-o-linear-gradient(top,#5bc0de,#339bb9);background-image:linear-gradient(to bottom,#5bc0de,#339bb9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff339bb9',GradientType=0)}.progress-info.progress-striped .bar,.progress-striped .bar-info{background-color:#5bc0de;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-warning .bar,.progress .bar-warning{background-color:#faa732;background-image:-moz-linear-gradient(top,#fbb450,#f89406);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fbb450),to(#f89406));background-image:-webkit-linear-gradient(top,#fbb450,#f89406);background-image:-o-linear-gradient(top,#fbb450,#f89406);background-image:linear-gradient(to bottom,#fbb450,#f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450',endColorstr='#fff89406',GradientType=0)}.progress-warning.progress-striped .bar,.progress-striped .bar-warning{background-color:#fbb450;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.accordion{margin-bottom:20px}.accordion-group{margin-bottom:2px;border:1px solid #e5e5e5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.accordion-heading{border-bottom:0}.accordion-heading .accordion-toggle{display:block;padding:8px 15px}.accordion-toggle{cursor:pointer}.accordion-inner{padding:9px 15px;border-top:1px solid #e5e5e5}.carousel{position:relative;margin-bottom:20px;line-height:1}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-moz-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img{display:block;line-height:1}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:40%;left:15px;width:40px;height:40px;margin-top:-20px;font-size:60px;font-weight:100;line-height:30px;color:#fff;text-align:center;background:#222;border:3px solid #fff;-webkit-border-radius:23px;-moz-border-radius:23px;border-radius:23px;opacity:.5;filter:alpha(opacity=50)}.carousel-control.right{right:15px;left:auto}.carousel-control:hover{color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}.carousel-caption{position:absolute;right:0;bottom:0;left:0;padding:15px;background:#333;background:rgba(0,0,0,0.75)}.carousel-caption h4,.carousel-caption p{line-height:20px;color:#fff}.carousel-caption h4{margin:0 0 5px}.carousel-caption p{margin-bottom:0}.hero-unit{padding:60px;margin-bottom:30px;font-size:18px;font-weight:200;line-height:30px;color:inherit;background-color:#eee;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.hero-unit h1{margin-bottom:0;font-size:60px;line-height:1;letter-spacing:-1px;color:inherit}.hero-unit li{line-height:30px}.pull-right{float:right}.pull-left{float:left}.hide{display:none}.show{display:block}.invisible{visibility:hidden}.affix{position:fixed}
    8.13 -/*!
    8.14 - * Bootstrap Responsive v2.2.2
    8.15 - *
    8.16 - * Copyright 2012 Twitter, Inc
    8.17 - * Licensed under the Apache License v2.0
    8.18 - * http://www.apache.org/licenses/LICENSE-2.0
    8.19 - *
    8.20 - * Designed and built with all the love in the world @twitter by @mdo and @fat.
    8.21 - */@-ms-viewport{width:device-width}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;line-height:0;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.hidden{display:none;visibility:hidden}.visible-phone{display:none!important}.visible-tablet{display:none!important}.hidden-desktop{display:none!important}.visible-desktop{display:inherit!important}@media(min-width:768px) and (max-width:979px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-tablet{display:inherit!important}.hidden-tablet{display:none!important}}@media(max-width:767px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-phone{display:inherit!important}.hidden-phone{display:none!important}}@media(min-width:1200px){.row{margin-left:-30px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:30px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:1170px}.span12{width:1170px}.span11{width:1070px}.span10{width:970px}.span9{width:870px}.span8{width:770px}.span7{width:670px}.span6{width:570px}.span5{width:470px}.span4{width:370px}.span3{width:270px}.span2{width:170px}.span1{width:70px}.offset12{margin-left:1230px}.offset11{margin-left:1130px}.offset10{margin-left:1030px}.offset9{margin-left:930px}.offset8{margin-left:830px}.offset7{margin-left:730px}.offset6{margin-left:630px}.offset5{margin-left:530px}.offset4{margin-left:430px}.offset3{margin-left:330px}.offset2{margin-left:230px}.offset1{margin-left:130px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.564102564102564%;*margin-left:2.5109110747408616%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.564102564102564%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.45299145299145%;*width:91.39979996362975%}.row-fluid .span10{width:82.90598290598291%;*width:82.8527914166212%}.row-fluid .span9{width:74.35897435897436%;*width:74.30578286961266%}.row-fluid .span8{width:65.81196581196582%;*width:65.75877432260411%}.row-fluid .span7{width:57.26495726495726%;*width:57.21176577559556%}.row-fluid .span6{width:48.717948717948715%;*width:48.664757228587014%}.row-fluid .span5{width:40.17094017094017%;*width:40.11774868157847%}.row-fluid .span4{width:31.623931623931625%;*width:31.570740134569924%}.row-fluid .span3{width:23.076923076923077%;*width:23.023731587561375%}.row-fluid .span2{width:14.52991452991453%;*width:14.476723040552828%}.row-fluid .span1{width:5.982905982905983%;*width:5.929714493544281%}.row-fluid .offset12{margin-left:105.12820512820512%;*margin-left:105.02182214948171%}.row-fluid .offset12:first-child{margin-left:102.56410256410257%;*margin-left:102.45771958537915%}.row-fluid .offset11{margin-left:96.58119658119658%;*margin-left:96.47481360247316%}.row-fluid .offset11:first-child{margin-left:94.01709401709402%;*margin-left:93.91071103837061%}.row-fluid .offset10{margin-left:88.03418803418803%;*margin-left:87.92780505546462%}.row-fluid .offset10:first-child{margin-left:85.47008547008548%;*margin-left:85.36370249136206%}.row-fluid .offset9{margin-left:79.48717948717949%;*margin-left:79.38079650845607%}.row-fluid .offset9:first-child{margin-left:76.92307692307693%;*margin-left:76.81669394435352%}.row-fluid .offset8{margin-left:70.94017094017094%;*margin-left:70.83378796144753%}.row-fluid .offset8:first-child{margin-left:68.37606837606839%;*margin-left:68.26968539734497%}.row-fluid .offset7{margin-left:62.393162393162385%;*margin-left:62.28677941443899%}.row-fluid .offset7:first-child{margin-left:59.82905982905982%;*margin-left:59.72267685033642%}.row-fluid .offset6{margin-left:53.84615384615384%;*margin-left:53.739770867430444%}.row-fluid .offset6:first-child{margin-left:51.28205128205128%;*margin-left:51.175668303327875%}.row-fluid .offset5{margin-left:45.299145299145295%;*margin-left:45.1927623204219%}.row-fluid .offset5:first-child{margin-left:42.73504273504273%;*margin-left:42.62865975631933%}.row-fluid .offset4{margin-left:36.75213675213675%;*margin-left:36.645753773413354%}.row-fluid .offset4:first-child{margin-left:34.18803418803419%;*margin-left:34.081651209310785%}.row-fluid .offset3{margin-left:28.205128205128204%;*margin-left:28.0987452264048%}.row-fluid .offset3:first-child{margin-left:25.641025641025642%;*margin-left:25.53464266230224%}.row-fluid .offset2{margin-left:19.65811965811966%;*margin-left:19.551736679396257%}.row-fluid .offset2:first-child{margin-left:17.094017094017094%;*margin-left:16.98763411529369%}.row-fluid .offset1{margin-left:11.11111111111111%;*margin-left:11.004728132387708%}.row-fluid .offset1:first-child{margin-left:8.547008547008547%;*margin-left:8.440625568285142%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:30px}input.span12,textarea.span12,.uneditable-input.span12{width:1156px}input.span11,textarea.span11,.uneditable-input.span11{width:1056px}input.span10,textarea.span10,.uneditable-input.span10{width:956px}input.span9,textarea.span9,.uneditable-input.span9{width:856px}input.span8,textarea.span8,.uneditable-input.span8{width:756px}input.span7,textarea.span7,.uneditable-input.span7{width:656px}input.span6,textarea.span6,.uneditable-input.span6{width:556px}input.span5,textarea.span5,.uneditable-input.span5{width:456px}input.span4,textarea.span4,.uneditable-input.span4{width:356px}input.span3,textarea.span3,.uneditable-input.span3{width:256px}input.span2,textarea.span2,.uneditable-input.span2{width:156px}input.span1,textarea.span1,.uneditable-input.span1{width:56px}.thumbnails{margin-left:-30px}.thumbnails>li{margin-left:30px}.row-fluid .thumbnails{margin-left:0}}@media(min-width:768px) and (max-width:979px){.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:20px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:724px}.span12{width:724px}.span11{width:662px}.span10{width:600px}.span9{width:538px}.span8{width:476px}.span7{width:414px}.span6{width:352px}.span5{width:290px}.span4{width:228px}.span3{width:166px}.span2{width:104px}.span1{width:42px}.offset12{margin-left:764px}.offset11{margin-left:702px}.offset10{margin-left:640px}.offset9{margin-left:578px}.offset8{margin-left:516px}.offset7{margin-left:454px}.offset6{margin-left:392px}.offset5{margin-left:330px}.offset4{margin-left:268px}.offset3{margin-left:206px}.offset2{margin-left:144px}.offset1{margin-left:82px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.7624309392265194%;*margin-left:2.709239449864817%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.7624309392265194%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.43646408839778%;*width:91.38327259903608%}.row-fluid .span10{width:82.87292817679558%;*width:82.81973668743387%}.row-fluid .span9{width:74.30939226519337%;*width:74.25620077583166%}.row-fluid .span8{width:65.74585635359117%;*width:65.69266486422946%}.row-fluid .span7{width:57.18232044198895%;*width:57.12912895262725%}.row-fluid .span6{width:48.61878453038674%;*width:48.56559304102504%}.row-fluid .span5{width:40.05524861878453%;*width:40.00205712942283%}.row-fluid .span4{width:31.491712707182323%;*width:31.43852121782062%}.row-fluid .span3{width:22.92817679558011%;*width:22.87498530621841%}.row-fluid .span2{width:14.3646408839779%;*width:14.311449394616199%}.row-fluid .span1{width:5.801104972375691%;*width:5.747913483013988%}.row-fluid .offset12{margin-left:105.52486187845304%;*margin-left:105.41847889972962%}.row-fluid .offset12:first-child{margin-left:102.76243093922652%;*margin-left:102.6560479605031%}.row-fluid .offset11{margin-left:96.96132596685082%;*margin-left:96.8549429881274%}.row-fluid .offset11:first-child{margin-left:94.1988950276243%;*margin-left:94.09251204890089%}.row-fluid .offset10{margin-left:88.39779005524862%;*margin-left:88.2914070765252%}.row-fluid .offset10:first-child{margin-left:85.6353591160221%;*margin-left:85.52897613729868%}.row-fluid .offset9{margin-left:79.8342541436464%;*margin-left:79.72787116492299%}.row-fluid .offset9:first-child{margin-left:77.07182320441989%;*margin-left:76.96544022569647%}.row-fluid .offset8{margin-left:71.2707182320442%;*margin-left:71.16433525332079%}.row-fluid .offset8:first-child{margin-left:68.50828729281768%;*margin-left:68.40190431409427%}.row-fluid .offset7{margin-left:62.70718232044199%;*margin-left:62.600799341718584%}.row-fluid .offset7:first-child{margin-left:59.94475138121547%;*margin-left:59.838368402492065%}.row-fluid .offset6{margin-left:54.14364640883978%;*margin-left:54.037263430116376%}.row-fluid .offset6:first-child{margin-left:51.38121546961326%;*margin-left:51.27483249088986%}.row-fluid .offset5{margin-left:45.58011049723757%;*margin-left:45.47372751851417%}.row-fluid .offset5:first-child{margin-left:42.81767955801105%;*margin-left:42.71129657928765%}.row-fluid .offset4{margin-left:37.01657458563536%;*margin-left:36.91019160691196%}.row-fluid .offset4:first-child{margin-left:34.25414364640884%;*margin-left:34.14776066768544%}.row-fluid .offset3{margin-left:28.45303867403315%;*margin-left:28.346655695309746%}.row-fluid .offset3:first-child{margin-left:25.69060773480663%;*margin-left:25.584224756083227%}.row-fluid .offset2{margin-left:19.88950276243094%;*margin-left:19.783119783707537%}.row-fluid .offset2:first-child{margin-left:17.12707182320442%;*margin-left:17.02068884448102%}.row-fluid .offset1{margin-left:11.32596685082873%;*margin-left:11.219583872105325%}.row-fluid .offset1:first-child{margin-left:8.56353591160221%;*margin-left:8.457152932878806%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:20px}input.span12,textarea.span12,.uneditable-input.span12{width:710px}input.span11,textarea.span11,.uneditable-input.span11{width:648px}input.span10,textarea.span10,.uneditable-input.span10{width:586px}input.span9,textarea.span9,.uneditable-input.span9{width:524px}input.span8,textarea.span8,.uneditable-input.span8{width:462px}input.span7,textarea.span7,.uneditable-input.span7{width:400px}input.span6,textarea.span6,.uneditable-input.span6{width:338px}input.span5,textarea.span5,.uneditable-input.span5{width:276px}input.span4,textarea.span4,.uneditable-input.span4{width:214px}input.span3,textarea.span3,.uneditable-input.span3{width:152px}input.span2,textarea.span2,.uneditable-input.span2{width:90px}input.span1,textarea.span1,.uneditable-input.span1{width:28px}}@media(max-width:767px){body{padding-right:20px;padding-left:20px}.navbar-fixed-top,.navbar-fixed-bottom,.navbar-static-top{margin-right:-20px;margin-left:-20px}.container-fluid{padding:0}.dl-horizontal dt{float:none;width:auto;clear:none;text-align:left}.dl-horizontal dd{margin-left:0}.container{width:auto}.row-fluid{width:100%}.row,.thumbnails{margin-left:0}.thumbnails>li{float:none;margin-left:0}[class*="span"],.uneditable-input[class*="span"],.row-fluid [class*="span"]{display:block;float:none;width:100%;margin-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.span12,.row-fluid .span12{width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="offset"]:first-child{margin-left:0}.input-large,.input-xlarge,.input-xxlarge,input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.input-prepend input,.input-append input,.input-prepend input[class*="span"],.input-append input[class*="span"]{display:inline-block;width:auto}.controls-row [class*="span"]+[class*="span"]{margin-left:0}.modal{position:fixed;top:20px;right:20px;left:20px;width:auto;margin:0}.modal.fade{top:-100px}.modal.fade.in{top:20px}}@media(max-width:480px){.nav-collapse{-webkit-transform:translate3d(0,0,0)}.page-header h1 small{display:block;line-height:20px}input[type="checkbox"],input[type="radio"]{border:1px solid #ccc}.form-horizontal .control-label{float:none;width:auto;padding-top:0;text-align:left}.form-horizontal .controls{margin-left:0}.form-horizontal .control-list{padding-top:0}.form-horizontal .form-actions{padding-right:10px;padding-left:10px}.media .pull-left,.media .pull-right{display:block;float:none;margin-bottom:10px}.media-object{margin-right:0;margin-left:0}.modal{top:10px;right:10px;left:10px}.modal-header .close{padding:10px;margin:-10px}.carousel-caption{position:static}}@media(max-width:979px){body{padding-top:0}.navbar-fixed-top,.navbar-fixed-bottom{position:static}.navbar-fixed-top{margin-bottom:20px}.navbar-fixed-bottom{margin-top:20px}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding:5px}.navbar .container{width:auto;padding:0}.navbar .brand{padding-right:10px;padding-left:10px;margin:0 0 0 -5px}.nav-collapse{clear:both}.nav-collapse .nav{float:none;margin:0 0 10px}.nav-collapse .nav>li{float:none}.nav-collapse .nav>li>a{margin-bottom:2px}.nav-collapse .nav>.divider-vertical{display:none}.nav-collapse .nav .nav-header{color:#777;text-shadow:none}.nav-collapse .nav>li>a,.nav-collapse .dropdown-menu a{padding:9px 15px;font-weight:bold;color:#777;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.nav-collapse .btn{padding:4px 10px 4px;font-weight:normal;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.nav-collapse .dropdown-menu li+li a{margin-bottom:2px}.nav-collapse .nav>li>a:hover,.nav-collapse .dropdown-menu a:hover{background-color:#f2f2f2}.navbar-inverse .nav-collapse .nav>li>a,.navbar-inverse .nav-collapse .dropdown-menu a{color:#999}.navbar-inverse .nav-collapse .nav>li>a:hover,.navbar-inverse .nav-collapse .dropdown-menu a:hover{background-color:#111}.nav-collapse.in .btn-group{padding:0;margin-top:5px}.nav-collapse .dropdown-menu{position:static;top:auto;left:auto;display:none;float:none;max-width:none;padding:0;margin:0 15px;background-color:transparent;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.nav-collapse .open>.dropdown-menu{display:block}.nav-collapse .dropdown-menu:before,.nav-collapse .dropdown-menu:after{display:none}.nav-collapse .dropdown-menu .divider{display:none}.nav-collapse .nav>li>.dropdown-menu:before,.nav-collapse .nav>li>.dropdown-menu:after{display:none}.nav-collapse .navbar-form,.nav-collapse .navbar-search{float:none;padding:10px 15px;margin:10px 0;border-top:1px solid #f2f2f2;border-bottom:1px solid #f2f2f2;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1)}.navbar-inverse .nav-collapse .navbar-form,.navbar-inverse .nav-collapse .navbar-search{border-top-color:#111;border-bottom-color:#111}.navbar .nav-collapse .nav.pull-right{float:none;margin-left:0}.nav-collapse,.nav-collapse.collapse{height:0;overflow:hidden}.navbar .btn-navbar{display:block}.navbar-static .navbar-inner{padding-right:10px;padding-left:10px}}@media(min-width:980px){.nav-collapse.collapse{height:auto!important;overflow:visible!important}}
     9.1 Binary file dew/src/main/resources/org/apidesign/bck2brwsr/dew/img/error.png has changed
    10.1 Binary file dew/src/main/resources/org/apidesign/bck2brwsr/dew/img/glyphicons-halflings-white.png has changed
    11.1 Binary file dew/src/main/resources/org/apidesign/bck2brwsr/dew/img/glyphicons-halflings.png has changed
    12.1 Binary file dew/src/main/resources/org/apidesign/bck2brwsr/dew/img/html5.png has changed
    13.1 Binary file dew/src/main/resources/org/apidesign/bck2brwsr/dew/img/java.png has changed
    14.1 --- a/dew/src/main/resources/org/apidesign/bck2brwsr/dew/index.html	Tue Feb 11 10:48:24 2014 +0100
    14.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.3 @@ -1,98 +0,0 @@
    14.4 -<!--
    14.5 -To change this template, choose Tools | Templates
    14.6 -and open the template in the editor.
    14.7 --->
    14.8 -<!DOCTYPE html>
    14.9 -<html lang="en" ng-app="bck2brwsr" ng-controller="DevCtrl">
   14.10 -    <head>
   14.11 -        <title>Back2Browser - DEW</title>
   14.12 -        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
   14.13 -        <meta name="viewport" content="width=device-width, initial-scale=1.0">
   14.14 -        <link rel="stylesheet" href="css/bootstrap-combined.min.css"/>  
   14.15 -        <link rel="stylesheet" href="js/codemirror/codemirror.css">
   14.16 -        <link rel="stylesheet" href="js/codemirror/theme/elegant.css"/>
   14.17 -        <link rel="stylesheet" href="css/app.css"/>
   14.18 -    </head>
   14.19 -    <body>
   14.20 -                
   14.21 -        <div class="navbar navbar-fixed-top" style="width: 100%"> 
   14.22 -        <div class="navbar-inner" style="padding-left: 12px; padding-right: 12px;">
   14.23 -            <!-- a class="brand" style="font-size: 100%"><span class="text-info"><b>Java and HTML5</b></span><small>- Together at Last!</small></a-->
   14.24 -            <form class="navbar-form pull-right">
   14.25 -                <!-- select class="span2"></select -->
   14.26 -                <button ng-click="post()" class="btn btn-warning">Rebuild</button>
   14.27 -              </form>
   14.28 -            <!-- ul class="nav">                          
   14.29 -                <li><select class="btn-small" type="text"></select></li>
   14.30 -            </ul -->
   14.31 -            <!-- form class="form form-horizontal pull-right">
   14.32 -                <button class="btn btn-warning btn-small pull-right top" ng-click="post()">Rebuild</button>
   14.33 -            </form -->
   14.34 -            <!-- ul class="nav pull-right">
   14.35 -                
   14.36 -            </ul-->     
   14.37 -        </div>  
   14.38 -        </div>
   14.39 -
   14.40 -        <div class="container-fluid">        
   14.41 -        
   14.42 -        <div style="height: 4em;">&nbsp;</div>    
   14.43 -            
   14.44 -        <div class="row-fluid">
   14.45 -            <div class="span6" style="margin-bottom: 10px;"> 
   14.46 -                <table class="table table-condensed" style="margin-bottom: 2px">
   14.47 -                <tr><td><i class="ic-html5"></i> HTML5</td></tr>               
   14.48 -                </table>
   14.49 -                <div>
   14.50 -                    <textarea ui-codemirror='{ lineNumbers : true, mode : "xml", theme : "elegant", matchBrackets : true, lineWrapping : true }' ng-model="html"></textarea>
   14.51 -                    <div class="alert alert-error" ng-show="doc.modelError">
   14.52 -                        <small>{{doc.modelError.toString()}}</small>
   14.53 -                    </div>
   14.54 -                </div>    
   14.55 -            </div>
   14.56 -            
   14.57 -            <div class="span6">  
   14.58 -                <table class="table table-condensed" style="margin-bottom: 2px">
   14.59 -                <tr><td><i class="ic-java"></i> Java</td></tr>               
   14.60 -                </table>                
   14.61 -                <div>
   14.62 -                    <textarea id="editorJava" ui-codemirror='{ lineNumbers : true, mode : "text/x-java", theme : "elegant", matchBrackets : true, lineWrapping : true, gutters: ["CodeMirror-linenumbers", "issues"] }' ng-model="java"></textarea>
   14.63 -                    <div class="alert alert-error" ng-show="doc.modelError">
   14.64 -                        <small>{{doc.modelError.toString()}}</small>
   14.65 -                    </div>
   14.66 -                </div>
   14.67 -            </div>
   14.68 -        
   14.69 -        </div>    
   14.70 -            
   14.71 -        <table class="table table-condensed">
   14.72 -            <tr ng-click="gotoError(e.line, e.col)" ng-repeat="e in errors" ng-class="errorClass(e.kind)">
   14.73 -                <td style="text-align: right">{{e.line}}</td> 
   14.74 -                <td>:</td> 
   14.75 -                <td style="text-align: left">{{e.col}}</td> 
   14.76 -                <td width="100%" class="text-error error-hover">{{e.msg}} <i class="icon-play"/></td>
   14.77 -            </tr>            
   14.78 -        </table>    
   14.79 -            
   14.80 -        
   14.81 -        <div>&nbsp;</div>    
   14.82 -            
   14.83 -        <ul class="nav nav-tabs">
   14.84 -            <li ng-class="'active'"><a href="#">Result</a></li>
   14.85 -        </ul>    
   14.86 -        
   14.87 -        
   14.88 -        <!-- button class="btn" ng-click="reload()">Reload</button -->
   14.89 -        <iframe id="result" frameborder="0" scrolling="yes" width="100%" style="height: 1000px; overflow: auto; border: 1px solid #DFDFDF;" src="result.html">
   14.90 -            <p>Your browser does not support iframes.</p>
   14.91 -        </iframe>
   14.92 -            
   14.93 -        </div>
   14.94 -        
   14.95 -        <script src="js/angular/angular.min.js"></script>
   14.96 -        <script src="js/codemirror/codemirror.js"></script>
   14.97 -        <script src="js/codemirror/mode/xml.js"></script>
   14.98 -        <script src="js/codemirror/mode/clike.js"></script>
   14.99 -        <script src="js/app.js"></script>
  14.100 -    </body>
  14.101 -</html>
    15.1 --- a/dew/src/main/resources/org/apidesign/bck2brwsr/dew/js/angular/angular.min.js	Tue Feb 11 10:48:24 2014 +0100
    15.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.3 @@ -1,159 +0,0 @@
    15.4 -/*
    15.5 - AngularJS v1.0.3
    15.6 - (c) 2010-2012 Google, Inc. http://angularjs.org
    15.7 - License: MIT
    15.8 -*/
    15.9 -(function(U,ca,p){'use strict';function m(b,a,c){var d;if(b)if(N(b))for(d in b)d!="prototype"&&d!="length"&&d!="name"&&b.hasOwnProperty(d)&&a.call(c,b[d],d);else if(b.forEach&&b.forEach!==m)b.forEach(a,c);else if(L(b)&&wa(b.length))for(d=0;d<b.length;d++)a.call(c,b[d],d);else for(d in b)b.hasOwnProperty(d)&&a.call(c,b[d],d);return b}function lb(b){var a=[],c;for(c in b)b.hasOwnProperty(c)&&a.push(c);return a.sort()}function ec(b,a,c){for(var d=lb(b),e=0;e<d.length;e++)a.call(c,b[d[e]],d[e]);return d}
   15.10 -function mb(b){return function(a,c){b(c,a)}}function xa(){for(var b=Z.length,a;b;){b--;a=Z[b].charCodeAt(0);if(a==57)return Z[b]="A",Z.join("");if(a==90)Z[b]="0";else return Z[b]=String.fromCharCode(a+1),Z.join("")}Z.unshift("0");return Z.join("")}function x(b){m(arguments,function(a){a!==b&&m(a,function(a,d){b[d]=a})});return b}function G(b){return parseInt(b,10)}function ya(b,a){return x(new (x(function(){},{prototype:b})),a)}function D(){}function ma(b){return b}function I(b){return function(){return b}}
   15.11 -function t(b){return typeof b=="undefined"}function v(b){return typeof b!="undefined"}function L(b){return b!=null&&typeof b=="object"}function F(b){return typeof b=="string"}function wa(b){return typeof b=="number"}function na(b){return Sa.apply(b)=="[object Date]"}function J(b){return Sa.apply(b)=="[object Array]"}function N(b){return typeof b=="function"}function oa(b){return b&&b.document&&b.location&&b.alert&&b.setInterval}function R(b){return F(b)?b.replace(/^\s*/,"").replace(/\s*$/,""):b}function fc(b){return b&&
   15.12 -(b.nodeName||b.bind&&b.find)}function Ta(b,a,c){var d=[];m(b,function(b,g,i){d.push(a.call(c,b,g,i))});return d}function gc(b,a){var c=0,d;if(J(b)||F(b))return b.length;else if(L(b))for(d in b)(!a||b.hasOwnProperty(d))&&c++;return c}function za(b,a){if(b.indexOf)return b.indexOf(a);for(var c=0;c<b.length;c++)if(a===b[c])return c;return-1}function Ua(b,a){var c=za(b,a);c>=0&&b.splice(c,1);return a}function V(b,a){if(oa(b)||b&&b.$evalAsync&&b.$watch)throw B("Can't copy Window or Scope");if(a){if(b===
   15.13 -a)throw B("Can't copy equivalent objects or arrays");if(J(b)){for(;a.length;)a.pop();for(var c=0;c<b.length;c++)a.push(V(b[c]))}else for(c in m(a,function(b,c){delete a[c]}),b)a[c]=V(b[c])}else(a=b)&&(J(b)?a=V(b,[]):na(b)?a=new Date(b.getTime()):L(b)&&(a=V(b,{})));return a}function hc(b,a){var a=a||{},c;for(c in b)b.hasOwnProperty(c)&&c.substr(0,2)!=="$$"&&(a[c]=b[c]);return a}function ha(b,a){if(b===a)return!0;if(b===null||a===null)return!1;if(b!==b&&a!==a)return!0;var c=typeof b,d;if(c==typeof a&&
   15.14 -c=="object")if(J(b)){if((c=b.length)==a.length){for(d=0;d<c;d++)if(!ha(b[d],a[d]))return!1;return!0}}else if(na(b))return na(a)&&b.getTime()==a.getTime();else{if(b&&b.$evalAsync&&b.$watch||a&&a.$evalAsync&&a.$watch||oa(b)||oa(a))return!1;c={};for(d in b){if(d.charAt(0)!=="$"&&!N(b[d])&&!ha(b[d],a[d]))return!1;c[d]=!0}for(d in a)if(!c[d]&&d.charAt(0)!=="$"&&!N(a[d]))return!1;return!0}return!1}function Va(b,a){var c=arguments.length>2?ia.call(arguments,2):[];return N(a)&&!(a instanceof RegExp)?c.length?
   15.15 -function(){return arguments.length?a.apply(b,c.concat(ia.call(arguments,0))):a.apply(b,c)}:function(){return arguments.length?a.apply(b,arguments):a.call(b)}:a}function ic(b,a){var c=a;/^\$+/.test(b)?c=p:oa(a)?c="$WINDOW":a&&ca===a?c="$DOCUMENT":a&&a.$evalAsync&&a.$watch&&(c="$SCOPE");return c}function da(b,a){return JSON.stringify(b,ic,a?"  ":null)}function nb(b){return F(b)?JSON.parse(b):b}function Wa(b){b&&b.length!==0?(b=E(""+b),b=!(b=="f"||b=="0"||b=="false"||b=="no"||b=="n"||b=="[]")):b=!1;
   15.16 -return b}function pa(b){b=u(b).clone();try{b.html("")}catch(a){}return u("<div>").append(b).html().match(/^(<[^>]+>)/)[1].replace(/^<([\w\-]+)/,function(a,b){return"<"+E(b)})}function Xa(b){var a={},c,d;m((b||"").split("&"),function(b){b&&(c=b.split("="),d=decodeURIComponent(c[0]),a[d]=v(c[1])?decodeURIComponent(c[1]):!0)});return a}function ob(b){var a=[];m(b,function(b,d){a.push(Ya(d,!0)+(b===!0?"":"="+Ya(b,!0)))});return a.length?a.join("&"):""}function Za(b){return Ya(b,!0).replace(/%26/gi,"&").replace(/%3D/gi,
   15.17 -"=").replace(/%2B/gi,"+")}function Ya(b,a){return encodeURIComponent(b).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(a?null:/%20/g,"+")}function jc(b,a){function c(a){a&&d.push(a)}var d=[b],e,g,i=["ng:app","ng-app","x-ng-app","data-ng-app"],f=/\sng[:\-]app(:\s*([\w\d_]+);?)?\s/;m(i,function(a){i[a]=!0;c(ca.getElementById(a));a=a.replace(":","\\:");b.querySelectorAll&&(m(b.querySelectorAll("."+a),c),m(b.querySelectorAll("."+a+"\\:"),c),m(b.querySelectorAll("["+
   15.18 -a+"]"),c))});m(d,function(a){if(!e){var b=f.exec(" "+a.className+" ");b?(e=a,g=(b[2]||"").replace(/\s+/g,",")):m(a.attributes,function(b){if(!e&&i[b.name])e=a,g=b.value})}});e&&a(e,g?[g]:[])}function pb(b,a){b=u(b);a=a||[];a.unshift(["$provide",function(a){a.value("$rootElement",b)}]);a.unshift("ng");var c=qb(a);c.invoke(["$rootScope","$rootElement","$compile","$injector",function(a,b,c,i){a.$apply(function(){b.data("$injector",i);c(b)(a)})}]);return c}function $a(b,a){a=a||"_";return b.replace(kc,
   15.19 -function(b,d){return(d?a:"")+b.toLowerCase()})}function qa(b,a,c){if(!b)throw new B("Argument '"+(a||"?")+"' is "+(c||"required"));return b}function ra(b,a,c){c&&J(b)&&(b=b[b.length-1]);qa(N(b),a,"not a function, got "+(b&&typeof b=="object"?b.constructor.name||"Object":typeof b));return b}function lc(b){function a(a,b,e){return a[b]||(a[b]=e())}return a(a(b,"angular",Object),"module",function(){var b={};return function(d,e,g){e&&b.hasOwnProperty(d)&&(b[d]=null);return a(b,d,function(){function a(c,
   15.20 -d,e){return function(){b[e||"push"]([c,d,arguments]);return j}}if(!e)throw B("No module: "+d);var b=[],c=[],k=a("$injector","invoke"),j={_invokeQueue:b,_runBlocks:c,requires:e,name:d,provider:a("$provide","provider"),factory:a("$provide","factory"),service:a("$provide","service"),value:a("$provide","value"),constant:a("$provide","constant","unshift"),filter:a("$filterProvider","register"),controller:a("$controllerProvider","register"),directive:a("$compileProvider","directive"),config:k,run:function(a){c.push(a);
   15.21 -return this}};g&&k(g);return j})}})}function rb(b){return b.replace(mc,function(a,b,d,e){return e?d.toUpperCase():d}).replace(nc,"Moz$1")}function ab(b,a){function c(){var e;for(var b=[this],c=a,i,f,h,k,j,l;b.length;){i=b.shift();f=0;for(h=i.length;f<h;f++){k=u(i[f]);c?k.triggerHandler("$destroy"):c=!c;j=0;for(e=(l=k.children()).length,k=e;j<k;j++)b.push(ja(l[j]))}}return d.apply(this,arguments)}var d=ja.fn[b],d=d.$original||d;c.$original=d;ja.fn[b]=c}function Q(b){if(b instanceof Q)return b;if(!(this instanceof
   15.22 -Q)){if(F(b)&&b.charAt(0)!="<")throw B("selectors not implemented");return new Q(b)}if(F(b)){var a=ca.createElement("div");a.innerHTML="<div>&#160;</div>"+b;a.removeChild(a.firstChild);bb(this,a.childNodes);this.remove()}else bb(this,b)}function cb(b){return b.cloneNode(!0)}function sa(b){sb(b);for(var a=0,b=b.childNodes||[];a<b.length;a++)sa(b[a])}function tb(b,a,c){var d=$(b,"events");$(b,"handle")&&(t(a)?m(d,function(a,c){db(b,c,a);delete d[c]}):t(c)?(db(b,a,d[a]),delete d[a]):Ua(d[a],c))}function sb(b){var a=
   15.23 -b[Aa],c=Ba[a];c&&(c.handle&&(c.events.$destroy&&c.handle({},"$destroy"),tb(b)),delete Ba[a],b[Aa]=p)}function $(b,a,c){var d=b[Aa],d=Ba[d||-1];if(v(c))d||(b[Aa]=d=++oc,d=Ba[d]={}),d[a]=c;else return d&&d[a]}function ub(b,a,c){var d=$(b,"data"),e=v(c),g=!e&&v(a),i=g&&!L(a);!d&&!i&&$(b,"data",d={});if(e)d[a]=c;else if(g)if(i)return d&&d[a];else x(d,a);else return d}function Ca(b,a){return(" "+b.className+" ").replace(/[\n\t]/g," ").indexOf(" "+a+" ")>-1}function vb(b,a){a&&m(a.split(" "),function(a){b.className=
   15.24 -R((" "+b.className+" ").replace(/[\n\t]/g," ").replace(" "+R(a)+" "," "))})}function wb(b,a){a&&m(a.split(" "),function(a){if(!Ca(b,a))b.className=R(b.className+" "+R(a))})}function bb(b,a){if(a)for(var a=!a.nodeName&&v(a.length)&&!oa(a)?a:[a],c=0;c<a.length;c++)b.push(a[c])}function xb(b,a){return Da(b,"$"+(a||"ngController")+"Controller")}function Da(b,a,c){b=u(b);for(b[0].nodeType==9&&(b=b.find("html"));b.length;){if(c=b.data(a))return c;b=b.parent()}}function yb(b,a){var c=Ea[a.toLowerCase()];
   15.25 -return c&&zb[b.nodeName]&&c}function pc(b,a){var c=function(c,e){if(!c.preventDefault)c.preventDefault=function(){c.returnValue=!1};if(!c.stopPropagation)c.stopPropagation=function(){c.cancelBubble=!0};if(!c.target)c.target=c.srcElement||ca;if(t(c.defaultPrevented)){var g=c.preventDefault;c.preventDefault=function(){c.defaultPrevented=!0;g.call(c)};c.defaultPrevented=!1}c.isDefaultPrevented=function(){return c.defaultPrevented};m(a[e||c.type],function(a){a.call(b,c)});aa<=8?(c.preventDefault=null,
   15.26 -c.stopPropagation=null,c.isDefaultPrevented=null):(delete c.preventDefault,delete c.stopPropagation,delete c.isDefaultPrevented)};c.elem=b;return c}function ga(b){var a=typeof b,c;if(a=="object"&&b!==null)if(typeof(c=b.$$hashKey)=="function")c=b.$$hashKey();else{if(c===p)c=b.$$hashKey=xa()}else c=b;return a+":"+c}function Fa(b){m(b,this.put,this)}function eb(){}function Ab(b){var a,c;if(typeof b=="function"){if(!(a=b.$inject))a=[],c=b.toString().replace(qc,""),c=c.match(rc),m(c[1].split(sc),function(b){b.replace(tc,
   15.27 -function(b,c,d){a.push(d)})}),b.$inject=a}else J(b)?(c=b.length-1,ra(b[c],"fn"),a=b.slice(0,c)):ra(b,"fn",!0);return a}function qb(b){function a(a){return function(b,c){if(L(b))m(b,mb(a));else return a(b,c)}}function c(a,b){N(b)&&(b=l.instantiate(b));if(!b.$get)throw B("Provider "+a+" must define $get factory method.");return j[a+f]=b}function d(a,b){return c(a,{$get:b})}function e(a){var b=[];m(a,function(a){if(!k.get(a))if(k.put(a,!0),F(a)){var c=ta(a);b=b.concat(e(c.requires)).concat(c._runBlocks);
   15.28 -try{for(var d=c._invokeQueue,c=0,f=d.length;c<f;c++){var h=d[c],g=h[0]=="$injector"?l:l.get(h[0]);g[h[1]].apply(g,h[2])}}catch(n){throw n.message&&(n.message+=" from "+a),n;}}else if(N(a))try{b.push(l.invoke(a))}catch(i){throw i.message&&(i.message+=" from "+a),i;}else if(J(a))try{b.push(l.invoke(a))}catch(j){throw j.message&&(j.message+=" from "+String(a[a.length-1])),j;}else ra(a,"module")});return b}function g(a,b){function c(d){if(typeof d!=="string")throw B("Service name expected");if(a.hasOwnProperty(d)){if(a[d]===
   15.29 -i)throw B("Circular dependency: "+h.join(" <- "));return a[d]}else try{return h.unshift(d),a[d]=i,a[d]=b(d)}finally{h.shift()}}function d(a,b,e){var f=[],k=Ab(a),g,n,i;n=0;for(g=k.length;n<g;n++)i=k[n],f.push(e&&e.hasOwnProperty(i)?e[i]:c(i,h));a.$inject||(a=a[g]);switch(b?-1:f.length){case 0:return a();case 1:return a(f[0]);case 2:return a(f[0],f[1]);case 3:return a(f[0],f[1],f[2]);case 4:return a(f[0],f[1],f[2],f[3]);case 5:return a(f[0],f[1],f[2],f[3],f[4]);case 6:return a(f[0],f[1],f[2],f[3],
   15.30 -f[4],f[5]);case 7:return a(f[0],f[1],f[2],f[3],f[4],f[5],f[6]);case 8:return a(f[0],f[1],f[2],f[3],f[4],f[5],f[6],f[7]);case 9:return a(f[0],f[1],f[2],f[3],f[4],f[5],f[6],f[7],f[8]);case 10:return a(f[0],f[1],f[2],f[3],f[4],f[5],f[6],f[7],f[8],f[9]);default:return a.apply(b,f)}}return{invoke:d,instantiate:function(a,b){var c=function(){},e;c.prototype=(J(a)?a[a.length-1]:a).prototype;c=new c;e=d(a,c,b);return L(e)?e:c},get:c,annotate:Ab}}var i={},f="Provider",h=[],k=new Fa,j={$provide:{provider:a(c),
   15.31 -factory:a(d),service:a(function(a,b){return d(a,["$injector",function(a){return a.instantiate(b)}])}),value:a(function(a,b){return d(a,I(b))}),constant:a(function(a,b){j[a]=b;o[a]=b}),decorator:function(a,b){var c=l.get(a+f),d=c.$get;c.$get=function(){var a=r.invoke(d,c);return r.invoke(b,null,{$delegate:a})}}}},l=g(j,function(){throw B("Unknown provider: "+h.join(" <- "));}),o={},r=o.$injector=g(o,function(a){a=l.get(a+f);return r.invoke(a.$get,a)});m(e(b),function(a){r.invoke(a||D)});return r}function uc(){var b=
   15.32 -!0;this.disableAutoScrolling=function(){b=!1};this.$get=["$window","$location","$rootScope",function(a,c,d){function e(a){var b=null;m(a,function(a){!b&&E(a.nodeName)==="a"&&(b=a)});return b}function g(){var b=c.hash(),d;b?(d=i.getElementById(b))?d.scrollIntoView():(d=e(i.getElementsByName(b)))?d.scrollIntoView():b==="top"&&a.scrollTo(0,0):a.scrollTo(0,0)}var i=a.document;b&&d.$watch(function(){return c.hash()},function(){d.$evalAsync(g)});return g}]}function vc(b,a,c,d){function e(a){try{a.apply(null,
   15.33 -ia.call(arguments,1))}finally{if(n--,n===0)for(;w.length;)try{w.pop()()}catch(b){c.error(b)}}}function g(a,b){(function ea(){m(q,function(a){a()});s=b(ea,a)})()}function i(){O!=f.url()&&(O=f.url(),m(A,function(a){a(f.url())}))}var f=this,h=a[0],k=b.location,j=b.history,l=b.setTimeout,o=b.clearTimeout,r={};f.isMock=!1;var n=0,w=[];f.$$completeOutstandingRequest=e;f.$$incOutstandingRequestCount=function(){n++};f.notifyWhenNoOutstandingRequests=function(a){m(q,function(a){a()});n===0?a():w.push(a)};
   15.34 -var q=[],s;f.addPollFn=function(a){t(s)&&g(100,l);q.push(a);return a};var O=k.href,C=a.find("base");f.url=function(a,b){if(a){if(O!=a)return O=a,d.history?b?j.replaceState(null,"",a):(j.pushState(null,"",a),C.attr("href",C.attr("href"))):b?k.replace(a):k.href=a,f}else return k.href.replace(/%27/g,"'")};var A=[],K=!1;f.onUrlChange=function(a){K||(d.history&&u(b).bind("popstate",i),d.hashchange?u(b).bind("hashchange",i):f.addPollFn(i),K=!0);A.push(a);return a};f.baseHref=function(){var a=C.attr("href");
   15.35 -return a?a.replace(/^https?\:\/\/[^\/]*/,""):a};var W={},y="",M=f.baseHref();f.cookies=function(a,b){var d,e,f,k;if(a)if(b===p)h.cookie=escape(a)+"=;path="+M+";expires=Thu, 01 Jan 1970 00:00:00 GMT";else{if(F(b))d=(h.cookie=escape(a)+"="+escape(b)+";path="+M).length+1,d>4096&&c.warn("Cookie '"+a+"' possibly not set or overflowed because it was too large ("+d+" > 4096 bytes)!"),W.length>20&&c.warn("Cookie '"+a+"' possibly not set or overflowed because too many cookies were already set ("+W.length+
   15.36 -" > 20 )")}else{if(h.cookie!==y){y=h.cookie;d=y.split("; ");W={};for(f=0;f<d.length;f++)e=d[f],k=e.indexOf("="),k>0&&(W[unescape(e.substring(0,k))]=unescape(e.substring(k+1)))}return W}};f.defer=function(a,b){var c;n++;c=l(function(){delete r[c];e(a)},b||0);r[c]=!0;return c};f.defer.cancel=function(a){return r[a]?(delete r[a],o(a),e(D),!0):!1}}function wc(){this.$get=["$window","$log","$sniffer","$document",function(b,a,c,d){return new vc(b,d,a,c)}]}function xc(){this.$get=function(){function b(b,
   15.37 -d){function e(a){if(a!=l){if(o){if(o==a)o=a.n}else o=a;g(a.n,a.p);g(a,l);l=a;l.n=null}}function g(a,b){if(a!=b){if(a)a.p=b;if(b)b.n=a}}if(b in a)throw B("cacheId "+b+" taken");var i=0,f=x({},d,{id:b}),h={},k=d&&d.capacity||Number.MAX_VALUE,j={},l=null,o=null;return a[b]={put:function(a,b){var c=j[a]||(j[a]={key:a});e(c);t(b)||(a in h||i++,h[a]=b,i>k&&this.remove(o.key))},get:function(a){var b=j[a];if(b)return e(b),h[a]},remove:function(a){var b=j[a];if(b){if(b==l)l=b.p;if(b==o)o=b.n;g(b.n,b.p);delete j[a];
   15.38 -delete h[a];i--}},removeAll:function(){h={};i=0;j={};l=o=null},destroy:function(){j=f=h=null;delete a[b]},info:function(){return x({},f,{size:i})}}}var a={};b.info=function(){var b={};m(a,function(a,e){b[e]=a.info()});return b};b.get=function(b){return a[b]};return b}}function yc(){this.$get=["$cacheFactory",function(b){return b("templates")}]}function Bb(b){var a={},c="Directive",d=/^\s*directive\:\s*([\d\w\-_]+)\s+(.*)$/,e=/(([\d\w\-_]+)(?:\:([^;]+))?;?)/,g="Template must have exactly one root element. was: ";
   15.39 -this.directive=function f(d,e){F(d)?(qa(e,"directive"),a.hasOwnProperty(d)||(a[d]=[],b.factory(d+c,["$injector","$exceptionHandler",function(b,c){var e=[];m(a[d],function(a){try{var f=b.invoke(a);if(N(f))f={compile:I(f)};else if(!f.compile&&f.link)f.compile=I(f.link);f.priority=f.priority||0;f.name=f.name||d;f.require=f.require||f.controller&&f.name;f.restrict=f.restrict||"A";e.push(f)}catch(k){c(k)}});return e}])),a[d].push(e)):m(d,mb(f));return this};this.$get=["$injector","$interpolate","$exceptionHandler",
   15.40 -"$http","$templateCache","$parse","$controller","$rootScope",function(b,h,k,j,l,o,r,n){function w(a,b,c){a instanceof u||(a=u(a));m(a,function(b,c){b.nodeType==3&&(a[c]=u(b).wrap("<span></span>").parent()[0])});var d=s(a,b,a,c);return function(b,c){qa(b,"scope");var e=c?ua.clone.call(a):a;e.data("$scope",b);q(e,"ng-scope");c&&c(e,b);d&&d(b,e,e);return e}}function q(a,b){try{a.addClass(b)}catch(c){}}function s(a,b,c,d){function e(a,c,d,k){for(var g,h,j,n,o,l=0,r=0,q=f.length;l<q;r++)j=c[r],g=f[l++],
   15.41 -h=f[l++],g?(g.scope?(n=a.$new(L(g.scope)),u(j).data("$scope",n)):n=a,(o=g.transclude)||!k&&b?g(h,n,j,d,function(b){return function(c){var d=a.$new();return b(d,c).bind("$destroy",Va(d,d.$destroy))}}(o||b)):g(h,n,j,p,k)):h&&h(a,j.childNodes,p,k)}for(var f=[],k,g,h,j=0;j<a.length;j++)g=new ea,k=O(a[j],[],g,d),g=(k=k.length?C(k,a[j],g,b,c):null)&&k.terminal||!a[j].childNodes.length?null:s(a[j].childNodes,k?k.transclude:b),f.push(k),f.push(g),h=h||k||g;return h?e:null}function O(a,b,c,f){var k=c.$attr,
   15.42 -g;switch(a.nodeType){case 1:A(b,fa(Cb(a).toLowerCase()),"E",f);var h,j,n;g=a.attributes;for(var o=0,l=g&&g.length;o<l;o++)if(h=g[o],h.specified)j=h.name,n=fa(j.toLowerCase()),k[n]=j,c[n]=h=R(aa&&j=="href"?decodeURIComponent(a.getAttribute(j,2)):h.value),yb(a,n)&&(c[n]=!0),X(a,b,h,n),A(b,n,"A",f);a=a.className;if(F(a)&&a!=="")for(;g=e.exec(a);)n=fa(g[2]),A(b,n,"C",f)&&(c[n]=R(g[3])),a=a.substr(g.index+g[0].length);break;case 3:H(b,a.nodeValue);break;case 8:try{if(g=d.exec(a.nodeValue))n=fa(g[1]),A(b,
   15.43 -n,"M",f)&&(c[n]=R(g[2]))}catch(r){}}b.sort(y);return b}function C(a,b,c,d,e){function f(a,b){if(a)a.require=z.require,l.push(a);if(b)b.require=z.require,ba.push(b)}function h(a,b){var c,d="data",e=!1;if(F(a)){for(;(c=a.charAt(0))=="^"||c=="?";)a=a.substr(1),c=="^"&&(d="inheritedData"),e=e||c=="?";c=b[d]("$"+a+"Controller");if(!c&&!e)throw B("No controller: "+a);}else J(a)&&(c=[],m(a,function(a){c.push(h(a,b))}));return c}function j(a,d,e,f,g){var n,q,w,K,s;n=b===e?c:hc(c,new ea(u(e),c.$attr));q=n.$$element;
   15.44 -if(C){var zc=/^\s*([@=&])\s*(\w*)\s*$/,O=d.$parent||d;m(C.scope,function(a,b){var c=a.match(zc)||[],e=c[2]||b,f,g,k;switch(c[1]){case "@":n.$observe(e,function(a){d[b]=a});n.$$observers[e].$$scope=O;break;case "=":g=o(n[e]);k=g.assign||function(){f=d[b]=g(O);throw B(Db+n[e]+" (directive: "+C.name+")");};f=d[b]=g(O);d.$watch(function(){var a=g(O);a!==d[b]&&(a!==f?f=d[b]=a:k(O,a=f=d[b]));return a});break;case "&":g=o(n[e]);d[b]=function(a){return g(O,a)};break;default:throw B("Invalid isolate scope definition for directive "+
   15.45 -C.name+": "+a);}})}t&&m(t,function(a){var b={$scope:d,$element:q,$attrs:n,$transclude:g};s=a.controller;s=="@"&&(s=n[a.name]);q.data("$"+a.name+"Controller",r(s,b))});f=0;for(w=l.length;f<w;f++)try{K=l[f],K(d,q,n,K.require&&h(K.require,q))}catch(y){k(y,pa(q))}a&&a(d,e.childNodes,p,g);f=0;for(w=ba.length;f<w;f++)try{K=ba[f],K(d,q,n,K.require&&h(K.require,q))}catch(Ha){k(Ha,pa(q))}}for(var n=-Number.MAX_VALUE,l=[],ba=[],s=null,C=null,A=null,y=c.$$element=u(b),z,H,X,D,v=d,t,x,Y,E=0,G=a.length;E<G;E++){z=
   15.46 -a[E];X=p;if(n>z.priority)break;if(Y=z.scope)M("isolated scope",C,z,y),L(Y)&&(q(y,"ng-isolate-scope"),C=z),q(y,"ng-scope"),s=s||z;H=z.name;if(Y=z.controller)t=t||{},M("'"+H+"' controller",t[H],z,y),t[H]=z;if(Y=z.transclude)M("transclusion",D,z,y),D=z,n=z.priority,Y=="element"?(X=u(b),y=c.$$element=u("<\!-- "+H+": "+c[H]+" --\>"),b=y[0],Ga(e,u(X[0]),b),v=w(X,d,n)):(X=u(cb(b)).contents(),y.html(""),v=w(X,d));if(Y=z.template)if(M("template",A,z,y),A=z,Y=Ha(Y),z.replace){X=u("<div>"+R(Y)+"</div>").contents();
   15.47 -b=X[0];if(X.length!=1||b.nodeType!==1)throw new B(g+Y);Ga(e,y,b);H={$attr:{}};a=a.concat(O(b,a.splice(E+1,a.length-(E+1)),H));K(c,H);G=a.length}else y.html(Y);if(z.templateUrl)M("template",A,z,y),A=z,j=W(a.splice(E,a.length-E),j,y,c,e,z.replace,v),G=a.length;else if(z.compile)try{x=z.compile(y,c,v),N(x)?f(null,x):x&&f(x.pre,x.post)}catch(I){k(I,pa(y))}if(z.terminal)j.terminal=!0,n=Math.max(n,z.priority)}j.scope=s&&s.scope;j.transclude=D&&v;return j}function A(d,e,g,h){var j=!1;if(a.hasOwnProperty(e))for(var n,
   15.48 -e=b.get(e+c),o=0,l=e.length;o<l;o++)try{if(n=e[o],(h===p||h>n.priority)&&n.restrict.indexOf(g)!=-1)d.push(n),j=!0}catch(r){k(r)}return j}function K(a,b){var c=b.$attr,d=a.$attr,e=a.$$element;m(a,function(d,e){e.charAt(0)!="$"&&(b[e]&&(d+=(e==="style"?";":" ")+b[e]),a.$set(e,d,!0,c[e]))});m(b,function(b,f){f=="class"?(q(e,b),a["class"]=(a["class"]?a["class"]+" ":"")+b):f=="style"?e.attr("style",e.attr("style")+";"+b):f.charAt(0)!="$"&&!a.hasOwnProperty(f)&&(a[f]=b,d[f]=c[f])})}function W(a,b,c,d,e,
   15.49 -f,k){var h=[],n,o,r=c[0],q=a.shift(),w=x({},q,{controller:null,templateUrl:null,transclude:null,scope:null});c.html("");j.get(q.templateUrl,{cache:l}).success(function(j){var l,q,j=Ha(j);if(f){q=u("<div>"+R(j)+"</div>").contents();l=q[0];if(q.length!=1||l.nodeType!==1)throw new B(g+j);j={$attr:{}};Ga(e,c,l);O(l,a,j);K(d,j)}else l=r,c.html(j);a.unshift(w);n=C(a,c,d,k);for(o=s(c.contents(),k);h.length;){var ba=h.pop(),j=h.pop();q=h.pop();var y=h.pop(),m=l;q!==r&&(m=cb(l),Ga(j,u(q),m));n(function(){b(o,
   15.50 -y,m,e,ba)},y,m,e,ba)}h=null}).error(function(a,b,c,d){throw B("Failed to load template: "+d.url);});return function(a,c,d,e,f){h?(h.push(c),h.push(d),h.push(e),h.push(f)):n(function(){b(o,c,d,e,f)},c,d,e,f)}}function y(a,b){return b.priority-a.priority}function M(a,b,c,d){if(b)throw B("Multiple directives ["+b.name+", "+c.name+"] asking for "+a+" on: "+pa(d));}function H(a,b){var c=h(b,!0);c&&a.push({priority:0,compile:I(function(a,b){var d=b.parent(),e=d.data("$binding")||[];e.push(c);q(d.data("$binding",
   15.51 -e),"ng-binding");a.$watch(c,function(a){b[0].nodeValue=a})})})}function X(a,b,c,d){var e=h(c,!0);e&&b.push({priority:100,compile:I(function(a,b,c){b=c.$$observers||(c.$$observers={});d==="class"&&(e=h(c[d],!0));c[d]=p;(b[d]||(b[d]=[])).$$inter=!0;(c.$$observers&&c.$$observers[d].$$scope||a).$watch(e,function(a){c.$set(d,a)})})})}function Ga(a,b,c){var d=b[0],e=d.parentNode,f,g;if(a){f=0;for(g=a.length;f<g;f++)if(a[f]==d){a[f]=c;break}}e&&e.replaceChild(c,d);c[u.expando]=d[u.expando];b[0]=c}var ea=
   15.52 -function(a,b){this.$$element=a;this.$attr=b||{}};ea.prototype={$normalize:fa,$set:function(a,b,c,d){var e=yb(this.$$element[0],a),f=this.$$observers;e&&(this.$$element.prop(a,b),d=e);this[a]=b;d?this.$attr[a]=d:(d=this.$attr[a])||(this.$attr[a]=d=$a(a,"-"));c!==!1&&(b===null||b===p?this.$$element.removeAttr(d):this.$$element.attr(d,b));f&&m(f[a],function(a){try{a(b)}catch(c){k(c)}})},$observe:function(a,b){var c=this,d=c.$$observers||(c.$$observers={}),e=d[a]||(d[a]=[]);e.push(b);n.$evalAsync(function(){e.$$inter||
   15.53 -b(c[a])});return b}};var D=h.startSymbol(),ba=h.endSymbol(),Ha=D=="{{"||ba=="}}"?ma:function(a){return a.replace(/\{\{/g,D).replace(/}}/g,ba)};return w}]}function fa(b){return rb(b.replace(Ac,""))}function Bc(){var b={};this.register=function(a,c){L(a)?x(b,a):b[a]=c};this.$get=["$injector","$window",function(a,c){return function(d,e){if(F(d)){var g=d,d=b.hasOwnProperty(g)?b[g]:fb(e.$scope,g,!0)||fb(c,g,!0);ra(d,g,!0)}return a.instantiate(d,e)}}]}function Cc(){this.$get=["$window",function(b){return u(b.document)}]}
   15.54 -function Dc(){this.$get=["$log",function(b){return function(a,c){b.error.apply(b,arguments)}}]}function Ec(){var b="{{",a="}}";this.startSymbol=function(a){return a?(b=a,this):b};this.endSymbol=function(b){return b?(a=b,this):a};this.$get=["$parse",function(c){function d(d,f){for(var h,k,j=0,l=[],o=d.length,r=!1,n=[];j<o;)(h=d.indexOf(b,j))!=-1&&(k=d.indexOf(a,h+e))!=-1?(j!=h&&l.push(d.substring(j,h)),l.push(j=c(r=d.substring(h+e,k))),j.exp=r,j=k+g,r=!0):(j!=o&&l.push(d.substring(j)),j=o);if(!(o=
   15.55 -l.length))l.push(""),o=1;if(!f||r)return n.length=o,j=function(a){for(var b=0,c=o,d;b<c;b++){if(typeof(d=l[b])=="function")d=d(a),d==null||d==p?d="":typeof d!="string"&&(d=da(d));n[b]=d}return n.join("")},j.exp=d,j.parts=l,j}var e=b.length,g=a.length;d.startSymbol=function(){return b};d.endSymbol=function(){return a};return d}]}function Eb(b){for(var b=b.split("/"),a=b.length;a--;)b[a]=Za(b[a]);return b.join("/")}function va(b,a){var c=Fb.exec(b),c={protocol:c[1],host:c[3],port:G(c[5])||Gb[c[1]]||
   15.56 -null,path:c[6]||"/",search:c[8],hash:c[10]};if(a)a.$$protocol=c.protocol,a.$$host=c.host,a.$$port=c.port;return c}function ka(b,a,c){return b+"://"+a+(c==Gb[b]?"":":"+c)}function Fc(b,a,c){var d=va(b);return decodeURIComponent(d.path)!=a||t(d.hash)||d.hash.indexOf(c)!==0?b:ka(d.protocol,d.host,d.port)+a.substr(0,a.lastIndexOf("/"))+d.hash.substr(c.length)}function Gc(b,a,c){var d=va(b);if(decodeURIComponent(d.path)==a)return b;else{var e=d.search&&"?"+d.search||"",g=d.hash&&"#"+d.hash||"",i=a.substr(0,
   15.57 -a.lastIndexOf("/")),f=d.path.substr(i.length);if(d.path.indexOf(i)!==0)throw B('Invalid url "'+b+'", missing path prefix "'+i+'" !');return ka(d.protocol,d.host,d.port)+a+"#"+c+f+e+g}}function gb(b,a,c){a=a||"";this.$$parse=function(b){var c=va(b,this);if(c.path.indexOf(a)!==0)throw B('Invalid url "'+b+'", missing path prefix "'+a+'" !');this.$$path=decodeURIComponent(c.path.substr(a.length));this.$$search=Xa(c.search);this.$$hash=c.hash&&decodeURIComponent(c.hash)||"";this.$$compose()};this.$$compose=
   15.58 -function(){var b=ob(this.$$search),c=this.$$hash?"#"+Za(this.$$hash):"";this.$$url=Eb(this.$$path)+(b?"?"+b:"")+c;this.$$absUrl=ka(this.$$protocol,this.$$host,this.$$port)+a+this.$$url};this.$$rewriteAppUrl=function(a){if(a.indexOf(c)==0)return a};this.$$parse(b)}function Ia(b,a,c){var d;this.$$parse=function(b){var c=va(b,this);if(c.hash&&c.hash.indexOf(a)!==0)throw B('Invalid url "'+b+'", missing hash prefix "'+a+'" !');d=c.path+(c.search?"?"+c.search:"");c=Hc.exec((c.hash||"").substr(a.length));
   15.59 -this.$$path=c[1]?(c[1].charAt(0)=="/"?"":"/")+decodeURIComponent(c[1]):"";this.$$search=Xa(c[3]);this.$$hash=c[5]&&decodeURIComponent(c[5])||"";this.$$compose()};this.$$compose=function(){var b=ob(this.$$search),c=this.$$hash?"#"+Za(this.$$hash):"";this.$$url=Eb(this.$$path)+(b?"?"+b:"")+c;this.$$absUrl=ka(this.$$protocol,this.$$host,this.$$port)+d+(this.$$url?"#"+a+this.$$url:"")};this.$$rewriteAppUrl=function(a){if(a.indexOf(c)==0)return a};this.$$parse(b)}function Hb(b,a,c,d){Ia.apply(this,arguments);
   15.60 -this.$$rewriteAppUrl=function(b){if(b.indexOf(c)==0)return c+d+"#"+a+b.substr(c.length)}}function Ja(b){return function(){return this[b]}}function Ib(b,a){return function(c){if(t(c))return this[b];this[b]=a(c);this.$$compose();return this}}function Ic(){var b="",a=!1;this.hashPrefix=function(a){return v(a)?(b=a,this):b};this.html5Mode=function(b){return v(b)?(a=b,this):a};this.$get=["$rootScope","$browser","$sniffer","$rootElement",function(c,d,e,g){function i(a){c.$broadcast("$locationChangeSuccess",
   15.61 -f.absUrl(),a)}var f,h,k,j=d.url(),l=va(j);a?(h=d.baseHref()||"/",k=h.substr(0,h.lastIndexOf("/")),l=ka(l.protocol,l.host,l.port)+k+"/",f=e.history?new gb(Fc(j,h,b),k,l):new Hb(Gc(j,h,b),b,l,h.substr(k.length+1))):(l=ka(l.protocol,l.host,l.port)+(l.path||"")+(l.search?"?"+l.search:"")+"#"+b+"/",f=new Ia(j,b,l));g.bind("click",function(a){if(!a.ctrlKey&&!(a.metaKey||a.which==2)){for(var b=u(a.target);E(b[0].nodeName)!=="a";)if(b[0]===g[0]||!(b=b.parent())[0])return;var d=b.prop("href"),e=f.$$rewriteAppUrl(d);
   15.62 -d&&!b.attr("target")&&e&&(f.$$parse(e),c.$apply(),a.preventDefault(),U.angular["ff-684208-preventDefault"]=!0)}});f.absUrl()!=j&&d.url(f.absUrl(),!0);d.onUrlChange(function(a){f.absUrl()!=a&&(c.$evalAsync(function(){var b=f.absUrl();f.$$parse(a);i(b)}),c.$$phase||c.$digest())});var o=0;c.$watch(function(){var a=d.url(),b=f.$$replace;if(!o||a!=f.absUrl())o++,c.$evalAsync(function(){c.$broadcast("$locationChangeStart",f.absUrl(),a).defaultPrevented?f.$$parse(a):(d.url(f.absUrl(),b),i(a))});f.$$replace=
   15.63 -!1;return o});return f}]}function Jc(){this.$get=["$window",function(b){function a(a){a instanceof B&&(a.stack?a=a.message&&a.stack.indexOf(a.message)===-1?"Error: "+a.message+"\n"+a.stack:a.stack:a.sourceURL&&(a=a.message+"\n"+a.sourceURL+":"+a.line));return a}function c(c){var e=b.console||{},g=e[c]||e.log||D;return g.apply?function(){var b=[];m(arguments,function(c){b.push(a(c))});return g.apply(e,b)}:function(a,b){g(a,b)}}return{log:c("log"),warn:c("warn"),info:c("info"),error:c("error")}}]}function Kc(b,
   15.64 -a){function c(a){return a.indexOf(q)!=-1}function d(){return n+1<b.length?b.charAt(n+1):!1}function e(a){return"0"<=a&&a<="9"}function g(a){return a==" "||a=="\r"||a=="\t"||a=="\n"||a=="\u000b"||a=="\u00a0"}function i(a){return"a"<=a&&a<="z"||"A"<=a&&a<="Z"||"_"==a||a=="$"}function f(a){return a=="-"||a=="+"||e(a)}function h(a,c,d){d=d||n;throw B("Lexer Error: "+a+" at column"+(v(c)?"s "+c+"-"+n+" ["+b.substring(c,d)+"]":" "+d)+" in expression ["+b+"].");}function k(){for(var a="",c=n;n<b.length;){var k=
   15.65 -E(b.charAt(n));if(k=="."||e(k))a+=k;else{var g=d();if(k=="e"&&f(g))a+=k;else if(f(k)&&g&&e(g)&&a.charAt(a.length-1)=="e")a+=k;else if(f(k)&&(!g||!e(g))&&a.charAt(a.length-1)=="e")h("Invalid exponent");else break}n++}a*=1;o.push({index:c,text:a,json:!0,fn:function(){return a}})}function j(){for(var c="",d=n,f,k,h;n<b.length;){var j=b.charAt(n);if(j=="."||i(j)||e(j))j=="."&&(f=n),c+=j;else break;n++}if(f)for(k=n;k<b.length;){j=b.charAt(k);if(j=="("){h=c.substr(f-d+1);c=c.substr(0,f-d);n=k;break}if(g(j))k++;
   15.66 -else break}d={index:d,text:c};if(Ka.hasOwnProperty(c))d.fn=d.json=Ka[c];else{var l=Jb(c,a);d.fn=x(function(a,b){return l(a,b)},{assign:function(a,b){return Kb(a,c,b)}})}o.push(d);h&&(o.push({index:f,text:".",json:!1}),o.push({index:f+1,text:h,json:!1}))}function l(a){var c=n;n++;for(var d="",e=a,f=!1;n<b.length;){var k=b.charAt(n);e+=k;if(f)k=="u"?(k=b.substring(n+1,n+5),k.match(/[\da-f]{4}/i)||h("Invalid unicode escape [\\u"+k+"]"),n+=4,d+=String.fromCharCode(parseInt(k,16))):(f=Lc[k],d+=f?f:k),
   15.67 -f=!1;else if(k=="\\")f=!0;else if(k==a){n++;o.push({index:c,text:e,string:d,json:!0,fn:function(){return d}});return}else d+=k;n++}h("Unterminated quote",c)}for(var o=[],r,n=0,w=[],q,s=":";n<b.length;){q=b.charAt(n);if(c("\"'"))l(q);else if(e(q)||c(".")&&e(d()))k();else if(i(q)){if(j(),"{,".indexOf(s)!=-1&&w[0]=="{"&&(r=o[o.length-1]))r.json=r.text.indexOf(".")==-1}else if(c("(){}[].,;:"))o.push({index:n,text:q,json:":[,".indexOf(s)!=-1&&c("{[")||c("}]:,")}),c("{[")&&w.unshift(q),c("}]")&&w.shift(),
   15.68 -n++;else if(g(q)){n++;continue}else{var m=q+d(),C=Ka[q],A=Ka[m];A?(o.push({index:n,text:m,fn:A}),n+=2):C?(o.push({index:n,text:q,fn:C,json:"[,:".indexOf(s)!=-1&&c("+-")}),n+=1):h("Unexpected next character ",n,n+1)}s=q}return o}function Mc(b,a,c,d){function e(a,c){throw B("Syntax Error: Token '"+c.text+"' "+a+" at column "+(c.index+1)+" of the expression ["+b+"] starting at ["+b.substring(c.index)+"].");}function g(){if(M.length===0)throw B("Unexpected end of expression: "+b);return M[0]}function i(a,
   15.69 -b,c,d){if(M.length>0){var e=M[0],f=e.text;if(f==a||f==b||f==c||f==d||!a&&!b&&!c&&!d)return e}return!1}function f(b,c,d,f){return(b=i(b,c,d,f))?(a&&!b.json&&e("is not valid json",b),M.shift(),b):!1}function h(a){f(a)||e("is unexpected, expecting ["+a+"]",i())}function k(a,b){return function(c,d){return a(c,d,b)}}function j(a,b,c){return function(d,e){return b(d,e,a,c)}}function l(){for(var a=[];;)if(M.length>0&&!i("}",")",";","]")&&a.push(v()),!f(";"))return a.length==1?a[0]:function(b,c){for(var d,
   15.70 -e=0;e<a.length;e++){var f=a[e];f&&(d=f(b,c))}return d}}function o(){for(var a=f(),b=c(a.text),d=[];;)if(a=f(":"))d.push(H());else{var e=function(a,c,e){for(var e=[e],f=0;f<d.length;f++)e.push(d[f](a,c));return b.apply(a,e)};return function(){return e}}}function r(){for(var a=n(),b;;)if(b=f("||"))a=j(a,b.fn,n());else return a}function n(){var a=w(),b;if(b=f("&&"))a=j(a,b.fn,n());return a}function w(){var a=q(),b;if(b=f("==","!="))a=j(a,b.fn,w());return a}function q(){var a;a=s();for(var b;b=f("+",
   15.71 -"-");)a=j(a,b.fn,s());if(b=f("<",">","<=",">="))a=j(a,b.fn,q());return a}function s(){for(var a=m(),b;b=f("*","/","%");)a=j(a,b.fn,m());return a}function m(){var a;return f("+")?C():(a=f("-"))?j(W,a.fn,m()):(a=f("!"))?k(a.fn,m()):C()}function C(){var a;if(f("("))a=v(),h(")");else if(f("["))a=A();else if(f("{"))a=K();else{var b=f();(a=b.fn)||e("not a primary expression",b)}for(var c;b=f("(","[",".");)b.text==="("?(a=u(a,c),c=null):b.text==="["?(c=a,a=ea(a)):b.text==="."?(c=a,a=t(a)):e("IMPOSSIBLE");
   15.72 -return a}function A(){var a=[];if(g().text!="]"){do a.push(H());while(f(","))}h("]");return function(b,c){for(var d=[],e=0;e<a.length;e++)d.push(a[e](b,c));return d}}function K(){var a=[];if(g().text!="}"){do{var b=f(),b=b.string||b.text;h(":");var c=H();a.push({key:b,value:c})}while(f(","))}h("}");return function(b,c){for(var d={},e=0;e<a.length;e++){var f=a[e],k=f.value(b,c);d[f.key]=k}return d}}var W=I(0),y,M=Kc(b,d),H=function(){var a=r(),c,d;return(d=f("="))?(a.assign||e("implies assignment but ["+
   15.73 -b.substring(0,d.index)+"] can not be assigned to",d),c=r(),function(b,d){return a.assign(b,c(b,d),d)}):a},u=function(a,b){var c=[];if(g().text!=")"){do c.push(H());while(f(","))}h(")");return function(d,e){for(var f=[],k=b?b(d,e):d,h=0;h<c.length;h++)f.push(c[h](d,e));h=a(d,e)||D;return h.apply?h.apply(k,f):h(f[0],f[1],f[2],f[3],f[4])}},t=function(a){var b=f().text,c=Jb(b,d);return x(function(b,d){return c(a(b,d),d)},{assign:function(c,d,e){return Kb(a(c,e),b,d)}})},ea=function(a){var b=H();h("]");
   15.74 -return x(function(c,d){var e=a(c,d),f=b(c,d),k;if(!e)return p;if((e=e[f])&&e.then){k=e;if(!("$$v"in e))k.$$v=p,k.then(function(a){k.$$v=a});e=e.$$v}return e},{assign:function(c,d,e){return a(c,e)[b(c,e)]=d}})},v=function(){for(var a=H(),b;;)if(b=f("|"))a=j(a,b.fn,o());else return a};a?(H=r,u=t=ea=v=function(){e("is not valid json",{text:b,index:0})},y=C()):y=l();M.length!==0&&e("is an unexpected token",M[0]);return y}function Kb(b,a,c){for(var a=a.split("."),d=0;a.length>1;d++){var e=a.shift(),g=
   15.75 -b[e];g||(g={},b[e]=g);b=g}return b[a.shift()]=c}function fb(b,a,c){if(!a)return b;for(var a=a.split("."),d,e=b,g=a.length,i=0;i<g;i++)d=a[i],b&&(b=(e=b)[d]);return!c&&N(b)?Va(e,b):b}function Lb(b,a,c,d,e){return function(g,i){var f=i&&i.hasOwnProperty(b)?i:g,h;if(f===null||f===p)return f;if((f=f[b])&&f.then){if(!("$$v"in f))h=f,h.$$v=p,h.then(function(a){h.$$v=a});f=f.$$v}if(!a||f===null||f===p)return f;if((f=f[a])&&f.then){if(!("$$v"in f))h=f,h.$$v=p,h.then(function(a){h.$$v=a});f=f.$$v}if(!c||f===
   15.76 -null||f===p)return f;if((f=f[c])&&f.then){if(!("$$v"in f))h=f,h.$$v=p,h.then(function(a){h.$$v=a});f=f.$$v}if(!d||f===null||f===p)return f;if((f=f[d])&&f.then){if(!("$$v"in f))h=f,h.$$v=p,h.then(function(a){h.$$v=a});f=f.$$v}if(!e||f===null||f===p)return f;if((f=f[e])&&f.then){if(!("$$v"in f))h=f,h.$$v=p,h.then(function(a){h.$$v=a});f=f.$$v}return f}}function Jb(b,a){if(hb.hasOwnProperty(b))return hb[b];var c=b.split("."),d=c.length,e;if(a)e=d<6?Lb(c[0],c[1],c[2],c[3],c[4]):function(a,b){var e=0,
   15.77 -k;do k=Lb(c[e++],c[e++],c[e++],c[e++],c[e++])(a,b),b=p,a=k;while(e<d);return k};else{var g="var l, fn, p;\n";m(c,function(a,b){g+="if(s === null || s === undefined) return s;\nl=s;\ns="+(b?"s":'((k&&k.hasOwnProperty("'+a+'"))?k:s)')+'["'+a+'"];\nif (s && s.then) {\n if (!("$$v" in s)) {\n p=s;\n p.$$v = undefined;\n p.then(function(v) {p.$$v=v;});\n}\n s=s.$$v\n}\n'});g+="return s;";e=Function("s","k",g);e.toString=function(){return g}}return hb[b]=e}function Nc(){var b={};this.$get=["$filter","$sniffer",
   15.78 -function(a,c){return function(d){switch(typeof d){case "string":return b.hasOwnProperty(d)?b[d]:b[d]=Mc(d,!1,a,c.csp);case "function":return d;default:return D}}}]}function Oc(){this.$get=["$rootScope","$exceptionHandler",function(b,a){return Pc(function(a){b.$evalAsync(a)},a)}]}function Pc(b,a){function c(a){return a}function d(a){return i(a)}var e=function(){var f=[],h,k;return k={resolve:function(a){if(f){var c=f;f=p;h=g(a);c.length&&b(function(){for(var a,b=0,d=c.length;b<d;b++)a=c[b],h.then(a[0],
   15.79 -a[1])})}},reject:function(a){k.resolve(i(a))},promise:{then:function(b,k){var g=e(),i=function(d){try{g.resolve((b||c)(d))}catch(e){a(e),g.reject(e)}},n=function(b){try{g.resolve((k||d)(b))}catch(c){a(c),g.reject(c)}};f?f.push([i,n]):h.then(i,n);return g.promise}}}},g=function(a){return a&&a.then?a:{then:function(c){var d=e();b(function(){d.resolve(c(a))});return d.promise}}},i=function(a){return{then:function(c,k){var g=e();b(function(){g.resolve((k||d)(a))});return g.promise}}};return{defer:e,reject:i,
   15.80 -when:function(f,h,k){var j=e(),l,o=function(b){try{return(h||c)(b)}catch(d){return a(d),i(d)}},r=function(b){try{return(k||d)(b)}catch(c){return a(c),i(c)}};b(function(){g(f).then(function(a){l||(l=!0,j.resolve(g(a).then(o,r)))},function(a){l||(l=!0,j.resolve(r(a)))})});return j.promise},all:function(a){var b=e(),c=a.length,d=[];c?m(a,function(a,e){g(a).then(function(a){e in d||(d[e]=a,--c||b.resolve(d))},function(a){e in d||b.reject(a)})}):b.resolve(d);return b.promise}}}function Qc(){var b={};this.when=
   15.81 -function(a,c){b[a]=x({reloadOnSearch:!0},c);if(a){var d=a[a.length-1]=="/"?a.substr(0,a.length-1):a+"/";b[d]={redirectTo:a}}return this};this.otherwise=function(a){this.when(null,a);return this};this.$get=["$rootScope","$location","$routeParams","$q","$injector","$http","$templateCache",function(a,c,d,e,g,i,f){function h(){var b=k(),h=r.current;if(b&&h&&b.$route===h.$route&&ha(b.pathParams,h.pathParams)&&!b.reloadOnSearch&&!o)h.params=b.params,V(h.params,d),a.$broadcast("$routeUpdate",h);else if(b||
   15.82 -h)o=!1,a.$broadcast("$routeChangeStart",b,h),(r.current=b)&&b.redirectTo&&(F(b.redirectTo)?c.path(j(b.redirectTo,b.params)).search(b.params).replace():c.url(b.redirectTo(b.pathParams,c.path(),c.search())).replace()),e.when(b).then(function(){if(b){var a=[],c=[],d;m(b.resolve||{},function(b,d){a.push(d);c.push(F(b)?g.get(b):g.invoke(b))});if(!v(d=b.template))if(v(d=b.templateUrl))d=i.get(d,{cache:f}).then(function(a){return a.data});v(d)&&(a.push("$template"),c.push(d));return e.all(c).then(function(b){var c=
   15.83 -{};m(b,function(b,d){c[a[d]]=b});return c})}}).then(function(c){if(b==r.current){if(b)b.locals=c,V(b.params,d);a.$broadcast("$routeChangeSuccess",b,h)}},function(c){b==r.current&&a.$broadcast("$routeChangeError",b,h,c)})}function k(){var a,d;m(b,function(b,e){if(!d&&(a=l(c.path(),e)))d=ya(b,{params:x({},c.search(),a),pathParams:a}),d.$route=b});return d||b[null]&&ya(b[null],{params:{},pathParams:{}})}function j(a,b){var c=[];m((a||"").split(":"),function(a,d){if(d==0)c.push(a);else{var e=a.match(/(\w+)(.*)/),
   15.84 -f=e[1];c.push(b[f]);c.push(e[2]||"");delete b[f]}});return c.join("")}var l=function(a,b){var c="^"+b.replace(/([\.\\\(\)\^\$])/g,"\\$1")+"$",d=[],e={};m(b.split(/\W/),function(a){if(a){var b=RegExp(":"+a+"([\\W])");c.match(b)&&(c=c.replace(b,"([^\\/]*)$1"),d.push(a))}});var f=a.match(RegExp(c));f&&m(d,function(a,b){e[a]=f[b+1]});return f?e:null},o=!1,r={routes:b,reload:function(){o=!0;a.$evalAsync(h)}};a.$on("$locationChangeSuccess",h);return r}]}function Rc(){this.$get=I({})}function Sc(){var b=
   15.85 -10;this.digestTtl=function(a){arguments.length&&(b=a);return b};this.$get=["$injector","$exceptionHandler","$parse",function(a,c,d){function e(){this.$id=xa();this.$$phase=this.$parent=this.$$watchers=this.$$nextSibling=this.$$prevSibling=this.$$childHead=this.$$childTail=null;this["this"]=this.$root=this;this.$$asyncQueue=[];this.$$listeners={}}function g(a){if(h.$$phase)throw B(h.$$phase+" already in progress");h.$$phase=a}function i(a,b){var c=d(a);ra(c,b);return c}function f(){}e.prototype={$new:function(a){if(N(a))throw B("API-CHANGE: Use $controller to instantiate controllers.");
   15.86 -a?(a=new e,a.$root=this.$root):(a=function(){},a.prototype=this,a=new a,a.$id=xa());a["this"]=a;a.$$listeners={};a.$parent=this;a.$$asyncQueue=[];a.$$watchers=a.$$nextSibling=a.$$childHead=a.$$childTail=null;a.$$prevSibling=this.$$childTail;this.$$childHead?this.$$childTail=this.$$childTail.$$nextSibling=a:this.$$childHead=this.$$childTail=a;return a},$watch:function(a,b,c){var d=i(a,"watch"),e=this.$$watchers,g={fn:b,last:f,get:d,exp:a,eq:!!c};if(!N(b)){var h=i(b||D,"listener");g.fn=function(a,b,
   15.87 -c){h(c)}}if(!e)e=this.$$watchers=[];e.unshift(g);return function(){Ua(e,g)}},$digest:function(){var a,d,e,i,r,n,m,q=b,s,p=[],C,A;g("$digest");do{m=!1;s=this;do{for(r=s.$$asyncQueue;r.length;)try{s.$eval(r.shift())}catch(K){c(K)}if(i=s.$$watchers)for(n=i.length;n--;)try{if(a=i[n],(d=a.get(s))!==(e=a.last)&&!(a.eq?ha(d,e):typeof d=="number"&&typeof e=="number"&&isNaN(d)&&isNaN(e)))m=!0,a.last=a.eq?V(d):d,a.fn(d,e===f?d:e,s),q<5&&(C=4-q,p[C]||(p[C]=[]),A=N(a.exp)?"fn: "+(a.exp.name||a.exp.toString()):
   15.88 -a.exp,A+="; newVal: "+da(d)+"; oldVal: "+da(e),p[C].push(A))}catch(W){c(W)}if(!(i=s.$$childHead||s!==this&&s.$$nextSibling))for(;s!==this&&!(i=s.$$nextSibling);)s=s.$parent}while(s=i);if(m&&!q--)throw h.$$phase=null,B(b+" $digest() iterations reached. Aborting!\nWatchers fired in the last 5 iterations: "+da(p));}while(m||r.length);h.$$phase=null},$destroy:function(){if(h!=this){var a=this.$parent;this.$broadcast("$destroy");if(a.$$childHead==this)a.$$childHead=this.$$nextSibling;if(a.$$childTail==
   15.89 -this)a.$$childTail=this.$$prevSibling;if(this.$$prevSibling)this.$$prevSibling.$$nextSibling=this.$$nextSibling;if(this.$$nextSibling)this.$$nextSibling.$$prevSibling=this.$$prevSibling;this.$parent=this.$$nextSibling=this.$$prevSibling=this.$$childHead=this.$$childTail=null}},$eval:function(a,b){return d(a)(this,b)},$evalAsync:function(a){this.$$asyncQueue.push(a)},$apply:function(a){try{return g("$apply"),this.$eval(a)}catch(b){c(b)}finally{h.$$phase=null;try{h.$digest()}catch(d){throw c(d),d;}}},
   15.90 -$on:function(a,b){var c=this.$$listeners[a];c||(this.$$listeners[a]=c=[]);c.push(b);return function(){c[za(c,b)]=null}},$emit:function(a,b){var d=[],e,f=this,g=!1,h={name:a,targetScope:f,stopPropagation:function(){g=!0},preventDefault:function(){h.defaultPrevented=!0},defaultPrevented:!1},i=[h].concat(ia.call(arguments,1)),m,p;do{e=f.$$listeners[a]||d;h.currentScope=f;m=0;for(p=e.length;m<p;m++)if(e[m])try{if(e[m].apply(null,i),g)return h}catch(C){c(C)}else e.splice(m,1),m--,p--;f=f.$parent}while(f);
   15.91 -return h},$broadcast:function(a,b){var d=this,e=this,f={name:a,targetScope:this,preventDefault:function(){f.defaultPrevented=!0},defaultPrevented:!1},g=[f].concat(ia.call(arguments,1)),h,i;do{d=e;f.currentScope=d;e=d.$$listeners[a]||[];h=0;for(i=e.length;h<i;h++)if(e[h])try{e[h].apply(null,g)}catch(m){c(m)}else e.splice(h,1),h--,i--;if(!(e=d.$$childHead||d!==this&&d.$$nextSibling))for(;d!==this&&!(e=d.$$nextSibling);)d=d.$parent}while(d=e);return f}};var h=new e;return h}]}function Tc(){this.$get=
   15.92 -["$window",function(b){var a={},c=G((/android (\d+)/.exec(E(b.navigator.userAgent))||[])[1]);return{history:!(!b.history||!b.history.pushState||c<4),hashchange:"onhashchange"in b&&(!b.document.documentMode||b.document.documentMode>7),hasEvent:function(c){if(c=="input"&&aa==9)return!1;if(t(a[c])){var e=b.document.createElement("div");a[c]="on"+c in e}return a[c]},csp:!1}}]}function Uc(){this.$get=I(U)}function Mb(b){var a={},c,d,e;if(!b)return a;m(b.split("\n"),function(b){e=b.indexOf(":");c=E(R(b.substr(0,
   15.93 -e)));d=R(b.substr(e+1));c&&(a[c]?a[c]+=", "+d:a[c]=d)});return a}function Nb(b){var a=L(b)?b:p;return function(c){a||(a=Mb(b));return c?a[E(c)]||null:a}}function Ob(b,a,c){if(N(c))return c(b,a);m(c,function(c){b=c(b,a)});return b}function Vc(){var b=/^\s*(\[|\{[^\{])/,a=/[\}\]]\s*$/,c=/^\)\]\}',?\n/,d=this.defaults={transformResponse:[function(d){F(d)&&(d=d.replace(c,""),b.test(d)&&a.test(d)&&(d=nb(d,!0)));return d}],transformRequest:[function(a){return L(a)&&Sa.apply(a)!=="[object File]"?da(a):a}],
   15.94 -headers:{common:{Accept:"application/json, text/plain, */*","X-Requested-With":"XMLHttpRequest"},post:{"Content-Type":"application/json;charset=utf-8"},put:{"Content-Type":"application/json;charset=utf-8"}}},e=this.responseInterceptors=[];this.$get=["$httpBackend","$browser","$cacheFactory","$rootScope","$q","$injector",function(a,b,c,h,k,j){function l(a){function c(a){var b=x({},a,{data:Ob(a.data,a.headers,f)});return 200<=a.status&&a.status<300?b:k.reject(b)}a.method=la(a.method);var e=a.transformRequest||
   15.95 -d.transformRequest,f=a.transformResponse||d.transformResponse,h=d.headers,h=x({"X-XSRF-TOKEN":b.cookies()["XSRF-TOKEN"]},h.common,h[E(a.method)],a.headers),e=Ob(a.data,Nb(h),e),g;t(a.data)&&delete h["Content-Type"];g=o(a,e,h);g=g.then(c,c);m(w,function(a){g=a(g)});g.success=function(b){g.then(function(c){b(c.data,c.status,c.headers,a)});return g};g.error=function(b){g.then(null,function(c){b(c.data,c.status,c.headers,a)});return g};return g}function o(b,c,d){function e(a,b,c){m&&(200<=a&&a<300?m.put(w,
   15.96 -[a,b,Mb(c)]):m.remove(w));f(b,a,c);h.$apply()}function f(a,c,d){c=Math.max(c,0);(200<=c&&c<300?j.resolve:j.reject)({data:a,status:c,headers:Nb(d),config:b})}function i(){var a=za(l.pendingRequests,b);a!==-1&&l.pendingRequests.splice(a,1)}var j=k.defer(),o=j.promise,m,p,w=r(b.url,b.params);l.pendingRequests.push(b);o.then(i,i);b.cache&&b.method=="GET"&&(m=L(b.cache)?b.cache:n);if(m)if(p=m.get(w))if(p.then)return p.then(i,i),p;else J(p)?f(p[1],p[0],V(p[2])):f(p,200,{});else m.put(w,o);p||a(b.method,
   15.97 -w,c,e,d,b.timeout,b.withCredentials);return o}function r(a,b){if(!b)return a;var c=[];ec(b,function(a,b){a==null||a==p||(L(a)&&(a=da(a)),c.push(encodeURIComponent(b)+"="+encodeURIComponent(a)))});return a+(a.indexOf("?")==-1?"?":"&")+c.join("&")}var n=c("$http"),w=[];m(e,function(a){w.push(F(a)?j.get(a):j.invoke(a))});l.pendingRequests=[];(function(a){m(arguments,function(a){l[a]=function(b,c){return l(x(c||{},{method:a,url:b}))}})})("get","delete","head","jsonp");(function(a){m(arguments,function(a){l[a]=
   15.98 -function(b,c,d){return l(x(d||{},{method:a,url:b,data:c}))}})})("post","put");l.defaults=d;return l}]}function Wc(){this.$get=["$browser","$window","$document",function(b,a,c){return Xc(b,Yc,b.defer,a.angular.callbacks,c[0],a.location.protocol.replace(":",""))}]}function Xc(b,a,c,d,e,g){function i(a,b){var c=e.createElement("script"),d=function(){e.body.removeChild(c);b&&b()};c.type="text/javascript";c.src=a;aa?c.onreadystatechange=function(){/loaded|complete/.test(c.readyState)&&d()}:c.onload=c.onerror=
   15.99 -d;e.body.appendChild(c)}return function(e,h,k,j,l,o,r){function n(a,c,d,e){c=(h.match(Fb)||["",g])[1]=="file"?d?200:404:c;a(c==1223?204:c,d,e);b.$$completeOutstandingRequest(D)}b.$$incOutstandingRequestCount();h=h||b.url();if(E(e)=="jsonp"){var p="_"+(d.counter++).toString(36);d[p]=function(a){d[p].data=a};i(h.replace("JSON_CALLBACK","angular.callbacks."+p),function(){d[p].data?n(j,200,d[p].data):n(j,-2);delete d[p]})}else{var q=new a;q.open(e,h,!0);m(l,function(a,b){a&&q.setRequestHeader(b,a)});
  15.100 -var s;q.onreadystatechange=function(){q.readyState==4&&n(j,s||q.status,q.responseText,q.getAllResponseHeaders())};if(r)q.withCredentials=!0;q.send(k||"");o>0&&c(function(){s=-1;q.abort()},o)}}}function Zc(){this.$get=function(){return{id:"en-us",NUMBER_FORMATS:{DECIMAL_SEP:".",GROUP_SEP:",",PATTERNS:[{minInt:1,minFrac:0,maxFrac:3,posPre:"",posSuf:"",negPre:"-",negSuf:"",gSize:3,lgSize:3},{minInt:1,minFrac:2,maxFrac:2,posPre:"\u00a4",posSuf:"",negPre:"(\u00a4",negSuf:")",gSize:3,lgSize:3}],CURRENCY_SYM:"$"},
  15.101 -DATETIME_FORMATS:{MONTH:"January,February,March,April,May,June,July,August,September,October,November,December".split(","),SHORTMONTH:"Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec".split(","),DAY:"Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday".split(","),SHORTDAY:"Sun,Mon,Tue,Wed,Thu,Fri,Sat".split(","),AMPMS:["AM","PM"],medium:"MMM d, y h:mm:ss a","short":"M/d/yy h:mm a",fullDate:"EEEE, MMMM d, y",longDate:"MMMM d, y",mediumDate:"MMM d, y",shortDate:"M/d/yy",mediumTime:"h:mm:ss a",
  15.102 -shortTime:"h:mm a"},pluralCat:function(b){return b===1?"one":"other"}}}}function $c(){this.$get=["$rootScope","$browser","$q","$exceptionHandler",function(b,a,c,d){function e(e,f,h){var k=c.defer(),j=k.promise,l=v(h)&&!h,f=a.defer(function(){try{k.resolve(e())}catch(a){k.reject(a),d(a)}l||b.$apply()},f),h=function(){delete g[j.$$timeoutId]};j.$$timeoutId=f;g[f]=k;j.then(h,h);return j}var g={};e.cancel=function(b){return b&&b.$$timeoutId in g?(g[b.$$timeoutId].reject("canceled"),a.defer.cancel(b.$$timeoutId)):
  15.103 -!1};return e}]}function Pb(b){function a(a,e){return b.factory(a+c,e)}var c="Filter";this.register=a;this.$get=["$injector",function(a){return function(b){return a.get(b+c)}}];a("currency",Qb);a("date",Rb);a("filter",ad);a("json",bd);a("limitTo",cd);a("lowercase",dd);a("number",Sb);a("orderBy",Tb);a("uppercase",ed)}function ad(){return function(b,a){if(!(b instanceof Array))return b;var c=[];c.check=function(a){for(var b=0;b<c.length;b++)if(!c[b](a))return!1;return!0};var d=function(a,b){if(b.charAt(0)===
  15.104 -"!")return!d(a,b.substr(1));switch(typeof a){case "boolean":case "number":case "string":return(""+a).toLowerCase().indexOf(b)>-1;case "object":for(var c in a)if(c.charAt(0)!=="$"&&d(a[c],b))return!0;return!1;case "array":for(c=0;c<a.length;c++)if(d(a[c],b))return!0;return!1;default:return!1}};switch(typeof a){case "boolean":case "number":case "string":a={$:a};case "object":for(var e in a)e=="$"?function(){var b=(""+a[e]).toLowerCase();b&&c.push(function(a){return d(a,b)})}():function(){var b=e,f=
  15.105 -(""+a[e]).toLowerCase();f&&c.push(function(a){return d(fb(a,b),f)})}();break;case "function":c.push(a);break;default:return b}for(var g=[],i=0;i<b.length;i++){var f=b[i];c.check(f)&&g.push(f)}return g}}function Qb(b){var a=b.NUMBER_FORMATS;return function(b,d){if(t(d))d=a.CURRENCY_SYM;return Ub(b,a.PATTERNS[1],a.GROUP_SEP,a.DECIMAL_SEP,2).replace(/\u00A4/g,d)}}function Sb(b){var a=b.NUMBER_FORMATS;return function(b,d){return Ub(b,a.PATTERNS[0],a.GROUP_SEP,a.DECIMAL_SEP,d)}}function Ub(b,a,c,d,e){if(isNaN(b)||
  15.106 -!isFinite(b))return"";var g=b<0,b=Math.abs(b),i=b+"",f="",h=[],k=!1;if(i.indexOf("e")!==-1){var j=i.match(/([\d\.]+)e(-?)(\d+)/);j&&j[2]=="-"&&j[3]>e+1?i="0":(f=i,k=!0)}if(!k){i=(i.split(Vb)[1]||"").length;t(e)&&(e=Math.min(Math.max(a.minFrac,i),a.maxFrac));var i=Math.pow(10,e),b=Math.round(b*i)/i,b=(""+b).split(Vb),i=b[0],b=b[1]||"",k=0,j=a.lgSize,l=a.gSize;if(i.length>=j+l)for(var k=i.length-j,o=0;o<k;o++)(k-o)%l===0&&o!==0&&(f+=c),f+=i.charAt(o);for(o=k;o<i.length;o++)(i.length-o)%j===0&&o!==0&&
  15.107 -(f+=c),f+=i.charAt(o);for(;b.length<e;)b+="0";e&&(f+=d+b.substr(0,e))}h.push(g?a.negPre:a.posPre);h.push(f);h.push(g?a.negSuf:a.posSuf);return h.join("")}function ib(b,a,c){var d="";b<0&&(d="-",b=-b);for(b=""+b;b.length<a;)b="0"+b;c&&(b=b.substr(b.length-a));return d+b}function P(b,a,c,d){return function(e){e=e["get"+b]();if(c>0||e>-c)e+=c;e===0&&c==-12&&(e=12);return ib(e,a,d)}}function La(b,a){return function(c,d){var e=c["get"+b](),g=la(a?"SHORT"+b:b);return d[g][e]}}function Rb(b){function a(a){var b;
  15.108 -if(b=a.match(c)){var a=new Date(0),g=0,i=0;b[9]&&(g=G(b[9]+b[10]),i=G(b[9]+b[11]));a.setUTCFullYear(G(b[1]),G(b[2])-1,G(b[3]));a.setUTCHours(G(b[4]||0)-g,G(b[5]||0)-i,G(b[6]||0),G(b[7]||0))}return a}var c=/^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;return function(c,e){var g="",i=[],f,h,e=e||"mediumDate",e=b.DATETIME_FORMATS[e]||e;F(c)&&(c=fd.test(c)?G(c):a(c));wa(c)&&(c=new Date(c));if(!na(c))return c;for(;e;)(h=gd.exec(e))?(i=i.concat(ia.call(h,
  15.109 -1)),e=i.pop()):(i.push(e),e=null);m(i,function(a){f=hd[a];g+=f?f(c,b.DATETIME_FORMATS):a.replace(/(^'|'$)/g,"").replace(/''/g,"'")});return g}}function bd(){return function(b){return da(b,!0)}}function cd(){return function(b,a){if(!(b instanceof Array))return b;var a=G(a),c=[],d,e;if(!b||!(b instanceof Array))return c;a>b.length?a=b.length:a<-b.length&&(a=-b.length);a>0?(d=0,e=a):(d=b.length+a,e=b.length);for(;d<e;d++)c.push(b[d]);return c}}function Tb(b){return function(a,c,d){function e(a,b){return Wa(b)?
  15.110 -function(b,c){return a(c,b)}:a}if(!(a instanceof Array))return a;if(!c)return a;for(var c=J(c)?c:[c],c=Ta(c,function(a){var c=!1,d=a||ma;if(F(a)){if(a.charAt(0)=="+"||a.charAt(0)=="-")c=a.charAt(0)=="-",a=a.substring(1);d=b(a)}return e(function(a,b){var c;c=d(a);var e=d(b),f=typeof c,g=typeof e;f==g?(f=="string"&&(c=c.toLowerCase()),f=="string"&&(e=e.toLowerCase()),c=c===e?0:c<e?-1:1):c=f<g?-1:1;return c},c)}),g=[],i=0;i<a.length;i++)g.push(a[i]);return g.sort(e(function(a,b){for(var d=0;d<c.length;d++){var e=
  15.111 -c[d](a,b);if(e!==0)return e}return 0},d))}}function S(b){N(b)&&(b={link:b});b.restrict=b.restrict||"AC";return I(b)}function Wb(b,a){function c(a,c){c=c?"-"+$a(c,"-"):"";b.removeClass((a?Ma:Na)+c).addClass((a?Na:Ma)+c)}var d=this,e=b.parent().controller("form")||Oa,g=0,i=d.$error={};d.$name=a.name;d.$dirty=!1;d.$pristine=!0;d.$valid=!0;d.$invalid=!1;e.$addControl(d);b.addClass(Pa);c(!0);d.$addControl=function(a){a.$name&&!d.hasOwnProperty(a.$name)&&(d[a.$name]=a)};d.$removeControl=function(a){a.$name&&
  15.112 -d[a.$name]===a&&delete d[a.$name];m(i,function(b,c){d.$setValidity(c,!0,a)})};d.$setValidity=function(a,b,k){var j=i[a];if(b){if(j&&(Ua(j,k),!j.length)){g--;if(!g)c(b),d.$valid=!0,d.$invalid=!1;i[a]=!1;c(!0,a);e.$setValidity(a,!0,d)}}else{g||c(b);if(j){if(za(j,k)!=-1)return}else i[a]=j=[],g++,c(!1,a),e.$setValidity(a,!1,d);j.push(k);d.$valid=!1;d.$invalid=!0}};d.$setDirty=function(){b.removeClass(Pa).addClass(Xb);d.$dirty=!0;d.$pristine=!1;e.$setDirty()}}function T(b){return t(b)||b===""||b===null||
  15.113 -b!==b}function Qa(b,a,c,d,e,g){var i=function(){var c=R(a.val());d.$viewValue!==c&&b.$apply(function(){d.$setViewValue(c)})};if(e.hasEvent("input"))a.bind("input",i);else{var f;a.bind("keydown",function(a){a=a.keyCode;a===91||15<a&&a<19||37<=a&&a<=40||f||(f=g.defer(function(){i();f=null}))});a.bind("change",i)}d.$render=function(){a.val(T(d.$viewValue)?"":d.$viewValue)};var h=c.ngPattern,k=function(a,b){return T(b)||a.test(b)?(d.$setValidity("pattern",!0),b):(d.$setValidity("pattern",!1),p)};h&&(h.match(/^\/(.*)\/$/)?
  15.114 -(h=RegExp(h.substr(1,h.length-2)),e=function(a){return k(h,a)}):e=function(a){var c=b.$eval(h);if(!c||!c.test)throw new B("Expected "+h+" to be a RegExp but was "+c);return k(c,a)},d.$formatters.push(e),d.$parsers.push(e));if(c.ngMinlength){var j=G(c.ngMinlength),e=function(a){return!T(a)&&a.length<j?(d.$setValidity("minlength",!1),p):(d.$setValidity("minlength",!0),a)};d.$parsers.push(e);d.$formatters.push(e)}if(c.ngMaxlength){var l=G(c.ngMaxlength),c=function(a){return!T(a)&&a.length>l?(d.$setValidity("maxlength",
  15.115 -!1),p):(d.$setValidity("maxlength",!0),a)};d.$parsers.push(c);d.$formatters.push(c)}}function jb(b,a){b="ngClass"+b;return S(function(c,d,e){function g(b,d){if(a===!0||c.$index%2===a)d&&b!==d&&i(d),f(b)}function i(a){L(a)&&!J(a)&&(a=Ta(a,function(a,b){if(a)return b}));d.removeClass(J(a)?a.join(" "):a)}function f(a){L(a)&&!J(a)&&(a=Ta(a,function(a,b){if(a)return b}));a&&d.addClass(J(a)?a.join(" "):a)}c.$watch(e[b],g,!0);e.$observe("class",function(){var a=c.$eval(e[b]);g(a,a)});b!=="ngClass"&&c.$watch("$index",
  15.116 -function(d,g){var j=d%2;j!==g%2&&(j==a?f(c.$eval(e[b])):i(c.$eval(e[b])))})})}var E=function(b){return F(b)?b.toLowerCase():b},la=function(b){return F(b)?b.toUpperCase():b},B=U.Error,aa=G((/msie (\d+)/.exec(E(navigator.userAgent))||[])[1]),u,ja,ia=[].slice,Ra=[].push,Sa=Object.prototype.toString,Yb=U.angular||(U.angular={}),ta,Cb,Z=["0","0","0"];D.$inject=[];ma.$inject=[];Cb=aa<9?function(b){b=b.nodeName?b:b[0];return b.scopeName&&b.scopeName!="HTML"?la(b.scopeName+":"+b.nodeName):b.nodeName}:function(b){return b.nodeName?
  15.117 -b.nodeName:b[0].nodeName};var kc=/[A-Z]/g,id={full:"1.0.3",major:1,minor:0,dot:3,codeName:"bouncy-thunder"},Ba=Q.cache={},Aa=Q.expando="ng-"+(new Date).getTime(),oc=1,Zb=U.document.addEventListener?function(b,a,c){b.addEventListener(a,c,!1)}:function(b,a,c){b.attachEvent("on"+a,c)},db=U.document.removeEventListener?function(b,a,c){b.removeEventListener(a,c,!1)}:function(b,a,c){b.detachEvent("on"+a,c)},mc=/([\:\-\_]+(.))/g,nc=/^moz([A-Z])/,ua=Q.prototype={ready:function(b){function a(){c||(c=!0,b())}
  15.118 -var c=!1;this.bind("DOMContentLoaded",a);Q(U).bind("load",a)},toString:function(){var b=[];m(this,function(a){b.push(""+a)});return"["+b.join(", ")+"]"},eq:function(b){return b>=0?u(this[b]):u(this[this.length+b])},length:0,push:Ra,sort:[].sort,splice:[].splice},Ea={};m("multiple,selected,checked,disabled,readOnly,required".split(","),function(b){Ea[E(b)]=b});var zb={};m("input,select,option,textarea,button,form".split(","),function(b){zb[la(b)]=!0});m({data:ub,inheritedData:Da,scope:function(b){return Da(b,
  15.119 -"$scope")},controller:xb,injector:function(b){return Da(b,"$injector")},removeAttr:function(b,a){b.removeAttribute(a)},hasClass:Ca,css:function(b,a,c){a=rb(a);if(v(c))b.style[a]=c;else{var d;aa<=8&&(d=b.currentStyle&&b.currentStyle[a],d===""&&(d="auto"));d=d||b.style[a];aa<=8&&(d=d===""?p:d);return d}},attr:function(b,a,c){var d=E(a);if(Ea[d])if(v(c))c?(b[a]=!0,b.setAttribute(a,d)):(b[a]=!1,b.removeAttribute(d));else return b[a]||(b.attributes.getNamedItem(a)||D).specified?d:p;else if(v(c))b.setAttribute(a,
  15.120 -c);else if(b.getAttribute)return b=b.getAttribute(a,2),b===null?p:b},prop:function(b,a,c){if(v(c))b[a]=c;else return b[a]},text:x(aa<9?function(b,a){if(b.nodeType==1){if(t(a))return b.innerText;b.innerText=a}else{if(t(a))return b.nodeValue;b.nodeValue=a}}:function(b,a){if(t(a))return b.textContent;b.textContent=a},{$dv:""}),val:function(b,a){if(t(a))return b.value;b.value=a},html:function(b,a){if(t(a))return b.innerHTML;for(var c=0,d=b.childNodes;c<d.length;c++)sa(d[c]);b.innerHTML=a}},function(b,
  15.121 -a){Q.prototype[a]=function(a,d){var e,g;if((b.length==2&&b!==Ca&&b!==xb?a:d)===p)if(L(a)){for(e=0;e<this.length;e++)if(b===ub)b(this[e],a);else for(g in a)b(this[e],g,a[g]);return this}else{if(this.length)return b(this[0],a,d)}else{for(e=0;e<this.length;e++)b(this[e],a,d);return this}return b.$dv}});m({removeData:sb,dealoc:sa,bind:function a(c,d,e){var g=$(c,"events"),i=$(c,"handle");g||$(c,"events",g={});i||$(c,"handle",i=pc(c,g));m(d.split(" "),function(d){var h=g[d];if(!h){if(d=="mouseenter"||
  15.122 -d=="mouseleave"){var k=0;g.mouseenter=[];g.mouseleave=[];a(c,"mouseover",function(a){k++;k==1&&i(a,"mouseenter")});a(c,"mouseout",function(a){k--;k==0&&i(a,"mouseleave")})}else Zb(c,d,i),g[d]=[];h=g[d]}h.push(e)})},unbind:tb,replaceWith:function(a,c){var d,e=a.parentNode;sa(a);m(new Q(c),function(c){d?e.insertBefore(c,d.nextSibling):e.replaceChild(c,a);d=c})},children:function(a){var c=[];m(a.childNodes,function(a){a.nodeName!="#text"&&c.push(a)});return c},contents:function(a){return a.childNodes},
  15.123 -append:function(a,c){m(new Q(c),function(c){a.nodeType===1&&a.appendChild(c)})},prepend:function(a,c){if(a.nodeType===1){var d=a.firstChild;m(new Q(c),function(c){d?a.insertBefore(c,d):(a.appendChild(c),d=c)})}},wrap:function(a,c){var c=u(c)[0],d=a.parentNode;d&&d.replaceChild(c,a);c.appendChild(a)},remove:function(a){sa(a);var c=a.parentNode;c&&c.removeChild(a)},after:function(a,c){var d=a,e=a.parentNode;m(new Q(c),function(a){e.insertBefore(a,d.nextSibling);d=a})},addClass:wb,removeClass:vb,toggleClass:function(a,
  15.124 -c,d){t(d)&&(d=!Ca(a,c));(d?wb:vb)(a,c)},parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},next:function(a){return a.nextSibling},find:function(a,c){return a.getElementsByTagName(c)},clone:cb,triggerHandler:function(a,c){var d=($(a,"events")||{})[c];m(d,function(c){c.call(a,null)})}},function(a,c){Q.prototype[c]=function(c,e){for(var g,i=0;i<this.length;i++)g==p?(g=a(this[i],c,e),g!==p&&(g=u(g))):bb(g,a(this[i],c,e));return g==p?this:g}});Fa.prototype={put:function(a,c){this[ga(a)]=
  15.125 -c},get:function(a){return this[ga(a)]},remove:function(a){var c=this[a=ga(a)];delete this[a];return c}};eb.prototype={push:function(a,c){var d=this[a=ga(a)];d?d.push(c):this[a]=[c]},shift:function(a){var c=this[a=ga(a)];if(c)return c.length==1?(delete this[a],c[0]):c.shift()},peek:function(a){if(a=this[ga(a)])return a[0]}};var rc=/^function\s*[^\(]*\(\s*([^\)]*)\)/m,sc=/,/,tc=/^\s*(_?)(\S+?)\1\s*$/,qc=/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg,Db="Non-assignable model expression: ";Bb.$inject=["$provide"];
  15.126 -var Ac=/^(x[\:\-_]|data[\:\-_])/i,Fb=/^([^:]+):\/\/(\w+:{0,1}\w*@)?([\w\.-]*)(:([0-9]+))?(\/[^\?#]*)?(\?([^#]*))?(#(.*))?$/,$b=/^([^\?#]*)?(\?([^#]*))?(#(.*))?$/,Hc=$b,Gb={http:80,https:443,ftp:21};gb.prototype={$$replace:!1,absUrl:Ja("$$absUrl"),url:function(a,c){if(t(a))return this.$$url;var d=$b.exec(a);d[1]&&this.path(decodeURIComponent(d[1]));if(d[2]||d[1])this.search(d[3]||"");this.hash(d[5]||"",c);return this},protocol:Ja("$$protocol"),host:Ja("$$host"),port:Ja("$$port"),path:Ib("$$path",function(a){return a.charAt(0)==
  15.127 -"/"?a:"/"+a}),search:function(a,c){if(t(a))return this.$$search;v(c)?c===null?delete this.$$search[a]:this.$$search[a]=c:this.$$search=F(a)?Xa(a):a;this.$$compose();return this},hash:Ib("$$hash",ma),replace:function(){this.$$replace=!0;return this}};Ia.prototype=ya(gb.prototype);Hb.prototype=ya(Ia.prototype);var Ka={"null":function(){return null},"true":function(){return!0},"false":function(){return!1},undefined:D,"+":function(a,c,d,e){d=d(a,c);e=e(a,c);return v(d)?v(e)?d+e:d:v(e)?e:p},"-":function(a,
  15.128 -c,d,e){d=d(a,c);e=e(a,c);return(v(d)?d:0)-(v(e)?e:0)},"*":function(a,c,d,e){return d(a,c)*e(a,c)},"/":function(a,c,d,e){return d(a,c)/e(a,c)},"%":function(a,c,d,e){return d(a,c)%e(a,c)},"^":function(a,c,d,e){return d(a,c)^e(a,c)},"=":D,"==":function(a,c,d,e){return d(a,c)==e(a,c)},"!=":function(a,c,d,e){return d(a,c)!=e(a,c)},"<":function(a,c,d,e){return d(a,c)<e(a,c)},">":function(a,c,d,e){return d(a,c)>e(a,c)},"<=":function(a,c,d,e){return d(a,c)<=e(a,c)},">=":function(a,c,d,e){return d(a,c)>=e(a,
  15.129 -c)},"&&":function(a,c,d,e){return d(a,c)&&e(a,c)},"||":function(a,c,d,e){return d(a,c)||e(a,c)},"&":function(a,c,d,e){return d(a,c)&e(a,c)},"|":function(a,c,d,e){return e(a,c)(a,c,d(a,c))},"!":function(a,c,d){return!d(a,c)}},Lc={n:"\n",f:"\u000c",r:"\r",t:"\t",v:"\u000b","'":"'",'"':'"'},hb={},Yc=U.XMLHttpRequest||function(){try{return new ActiveXObject("Msxml2.XMLHTTP.6.0")}catch(a){}try{return new ActiveXObject("Msxml2.XMLHTTP.3.0")}catch(c){}try{return new ActiveXObject("Msxml2.XMLHTTP")}catch(d){}throw new B("This browser does not support XMLHttpRequest.");
  15.130 -};Pb.$inject=["$provide"];Qb.$inject=["$locale"];Sb.$inject=["$locale"];var Vb=".",hd={yyyy:P("FullYear",4),yy:P("FullYear",2,0,!0),y:P("FullYear",1),MMMM:La("Month"),MMM:La("Month",!0),MM:P("Month",2,1),M:P("Month",1,1),dd:P("Date",2),d:P("Date",1),HH:P("Hours",2),H:P("Hours",1),hh:P("Hours",2,-12),h:P("Hours",1,-12),mm:P("Minutes",2),m:P("Minutes",1),ss:P("Seconds",2),s:P("Seconds",1),EEEE:La("Day"),EEE:La("Day",!0),a:function(a,c){return a.getHours()<12?c.AMPMS[0]:c.AMPMS[1]},Z:function(a){a=a.getTimezoneOffset();
  15.131 -return ib(a/60,2)+ib(Math.abs(a%60),2)}},gd=/((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z))(.*)/,fd=/^\d+$/;Rb.$inject=["$locale"];var dd=I(E),ed=I(la);Tb.$inject=["$parse"];var jd=I({restrict:"E",compile:function(a,c){c.href||c.$set("href","");return function(a,c){c.bind("click",function(a){if(!c.attr("href"))return a.preventDefault(),!1})}}}),kb={};m(Ea,function(a,c){var d=fa("ng-"+c);kb[d]=function(){return{priority:100,compile:function(){return function(a,g,i){a.$watch(i[d],
  15.132 -function(a){i.$set(c,!!a)})}}}}});m(["src","href"],function(a){var c=fa("ng-"+a);kb[c]=function(){return{priority:99,link:function(d,e,g){g.$observe(c,function(c){c&&(g.$set(a,c),aa&&e.prop(a,c))})}}}});var Oa={$addControl:D,$removeControl:D,$setValidity:D,$setDirty:D};Wb.$inject=["$element","$attrs","$scope"];var Ra=function(a){return["$timeout",function(c){var d={name:"form",restrict:"E",controller:Wb,compile:function(){return{pre:function(a,d,i,f){if(!i.action){var h=function(a){a.preventDefault?
  15.133 -a.preventDefault():a.returnValue=!1};Zb(d[0],"submit",h);d.bind("$destroy",function(){c(function(){db(d[0],"submit",h)},0,!1)})}var k=d.parent().controller("form"),j=i.name||i.ngForm;j&&(a[j]=f);k&&d.bind("$destroy",function(){k.$removeControl(f);j&&(a[j]=p);x(f,Oa)})}}}};return a?x(V(d),{restrict:"EAC"}):d}]},kd=Ra(),ld=Ra(!0),md=/^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/,nd=/^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$/,od=/^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/,
  15.134 -ac={text:Qa,number:function(a,c,d,e,g,i){Qa(a,c,d,e,g,i);e.$parsers.push(function(a){var c=T(a);return c||od.test(a)?(e.$setValidity("number",!0),a===""?null:c?a:parseFloat(a)):(e.$setValidity("number",!1),p)});e.$formatters.push(function(a){return T(a)?"":""+a});if(d.min){var f=parseFloat(d.min),a=function(a){return!T(a)&&a<f?(e.$setValidity("min",!1),p):(e.$setValidity("min",!0),a)};e.$parsers.push(a);e.$formatters.push(a)}if(d.max){var h=parseFloat(d.max),d=function(a){return!T(a)&&a>h?(e.$setValidity("max",
  15.135 -!1),p):(e.$setValidity("max",!0),a)};e.$parsers.push(d);e.$formatters.push(d)}e.$formatters.push(function(a){return T(a)||wa(a)?(e.$setValidity("number",!0),a):(e.$setValidity("number",!1),p)})},url:function(a,c,d,e,g,i){Qa(a,c,d,e,g,i);a=function(a){return T(a)||md.test(a)?(e.$setValidity("url",!0),a):(e.$setValidity("url",!1),p)};e.$formatters.push(a);e.$parsers.push(a)},email:function(a,c,d,e,g,i){Qa(a,c,d,e,g,i);a=function(a){return T(a)||nd.test(a)?(e.$setValidity("email",!0),a):(e.$setValidity("email",
  15.136 -!1),p)};e.$formatters.push(a);e.$parsers.push(a)},radio:function(a,c,d,e){t(d.name)&&c.attr("name",xa());c.bind("click",function(){c[0].checked&&a.$apply(function(){e.$setViewValue(d.value)})});e.$render=function(){c[0].checked=d.value==e.$viewValue};d.$observe("value",e.$render)},checkbox:function(a,c,d,e){var g=d.ngTrueValue,i=d.ngFalseValue;F(g)||(g=!0);F(i)||(i=!1);c.bind("click",function(){a.$apply(function(){e.$setViewValue(c[0].checked)})});e.$render=function(){c[0].checked=e.$viewValue};e.$formatters.push(function(a){return a===
  15.137 -g});e.$parsers.push(function(a){return a?g:i})},hidden:D,button:D,submit:D,reset:D},bc=["$browser","$sniffer",function(a,c){return{restrict:"E",require:"?ngModel",link:function(d,e,g,i){i&&(ac[E(g.type)]||ac.text)(d,e,g,i,c,a)}}}],Na="ng-valid",Ma="ng-invalid",Pa="ng-pristine",Xb="ng-dirty",pd=["$scope","$exceptionHandler","$attrs","$element","$parse",function(a,c,d,e,g){function i(a,c){c=c?"-"+$a(c,"-"):"";e.removeClass((a?Ma:Na)+c).addClass((a?Na:Ma)+c)}this.$modelValue=this.$viewValue=Number.NaN;
  15.138 -this.$parsers=[];this.$formatters=[];this.$viewChangeListeners=[];this.$pristine=!0;this.$dirty=!1;this.$valid=!0;this.$invalid=!1;this.$name=d.name;var f=g(d.ngModel),h=f.assign;if(!h)throw B(Db+d.ngModel+" ("+pa(e)+")");this.$render=D;var k=e.inheritedData("$formController")||Oa,j=0,l=this.$error={};e.addClass(Pa);i(!0);this.$setValidity=function(a,c){if(l[a]!==!c){if(c){if(l[a]&&j--,!j)i(!0),this.$valid=!0,this.$invalid=!1}else i(!1),this.$invalid=!0,this.$valid=!1,j++;l[a]=!c;i(c,a);k.$setValidity(a,
  15.139 -c,this)}};this.$setViewValue=function(d){this.$viewValue=d;if(this.$pristine)this.$dirty=!0,this.$pristine=!1,e.removeClass(Pa).addClass(Xb),k.$setDirty();m(this.$parsers,function(a){d=a(d)});if(this.$modelValue!==d)this.$modelValue=d,h(a,d),m(this.$viewChangeListeners,function(a){try{a()}catch(d){c(d)}})};var o=this;a.$watch(function(){var c=f(a);if(o.$modelValue!==c){var d=o.$formatters,e=d.length;for(o.$modelValue=c;e--;)c=d[e](c);if(o.$viewValue!==c)o.$viewValue=c,o.$render()}})}],qd=function(){return{require:["ngModel",
  15.140 -"^?form"],controller:pd,link:function(a,c,d,e){var g=e[0],i=e[1]||Oa;i.$addControl(g);c.bind("$destroy",function(){i.$removeControl(g)})}}},rd=I({require:"ngModel",link:function(a,c,d,e){e.$viewChangeListeners.push(function(){a.$eval(d.ngChange)})}}),cc=function(){return{require:"?ngModel",link:function(a,c,d,e){if(e){d.required=!0;var g=function(a){if(d.required&&(T(a)||a===!1))e.$setValidity("required",!1);else return e.$setValidity("required",!0),a};e.$formatters.push(g);e.$parsers.unshift(g);
  15.141 -d.$observe("required",function(){g(e.$viewValue)})}}}},sd=function(){return{require:"ngModel",link:function(a,c,d,e){var g=(a=/\/(.*)\//.exec(d.ngList))&&RegExp(a[1])||d.ngList||",";e.$parsers.push(function(a){var c=[];a&&m(a.split(g),function(a){a&&c.push(R(a))});return c});e.$formatters.push(function(a){return J(a)?a.join(", "):p})}}},td=/^(true|false|\d+)$/,ud=function(){return{priority:100,compile:function(a,c){return td.test(c.ngValue)?function(a,c,g){g.$set("value",a.$eval(g.ngValue))}:function(a,
  15.142 -c,g){a.$watch(g.ngValue,function(a){g.$set("value",a,!1)})}}}},vd=S(function(a,c,d){c.addClass("ng-binding").data("$binding",d.ngBind);a.$watch(d.ngBind,function(a){c.text(a==p?"":a)})}),wd=["$interpolate",function(a){return function(c,d,e){c=a(d.attr(e.$attr.ngBindTemplate));d.addClass("ng-binding").data("$binding",c);e.$observe("ngBindTemplate",function(a){d.text(a)})}}],xd=[function(){return function(a,c,d){c.addClass("ng-binding").data("$binding",d.ngBindHtmlUnsafe);a.$watch(d.ngBindHtmlUnsafe,
  15.143 -function(a){c.html(a||"")})}}],yd=jb("",!0),zd=jb("Odd",0),Ad=jb("Even",1),Bd=S({compile:function(a,c){c.$set("ngCloak",p);a.removeClass("ng-cloak")}}),Cd=[function(){return{scope:!0,controller:"@"}}],Dd=["$sniffer",function(a){return{priority:1E3,compile:function(){a.csp=!0}}}],dc={};m("click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave".split(" "),function(a){var c=fa("ng-"+a);dc[c]=["$parse",function(d){return function(e,g,i){var f=d(i[c]);g.bind(E(a),function(a){e.$apply(function(){f(e,
  15.144 -{$event:a})})})}}]});var Ed=S(function(a,c,d){c.bind("submit",function(){a.$apply(d.ngSubmit)})}),Fd=["$http","$templateCache","$anchorScroll","$compile",function(a,c,d,e){return{restrict:"ECA",terminal:!0,compile:function(g,i){var f=i.ngInclude||i.src,h=i.onload||"",k=i.autoscroll;return function(g,i){var o=0,m,n=function(){m&&(m.$destroy(),m=null);i.html("")};g.$watch(f,function(f){var p=++o;f?a.get(f,{cache:c}).success(function(a){p===o&&(m&&m.$destroy(),m=g.$new(),i.html(a),e(i.contents())(m),
  15.145 -v(k)&&(!k||g.$eval(k))&&d(),m.$emit("$includeContentLoaded"),g.$eval(h))}).error(function(){p===o&&n()}):n()})}}}}],Gd=S({compile:function(){return{pre:function(a,c,d){a.$eval(d.ngInit)}}}}),Hd=S({terminal:!0,priority:1E3}),Id=["$locale","$interpolate",function(a,c){var d=/{}/g;return{restrict:"EA",link:function(e,g,i){var f=i.count,h=g.attr(i.$attr.when),k=i.offset||0,j=e.$eval(h),l={},o=c.startSymbol(),r=c.endSymbol();m(j,function(a,e){l[e]=c(a.replace(d,o+f+"-"+k+r))});e.$watch(function(){var c=
  15.146 -parseFloat(e.$eval(f));return isNaN(c)?"":(j[c]||(c=a.pluralCat(c-k)),l[c](e,g,!0))},function(a){g.text(a)})}}}],Jd=S({transclude:"element",priority:1E3,terminal:!0,compile:function(a,c,d){return function(a,c,i){var f=i.ngRepeat,i=f.match(/^\s*(.+)\s+in\s+(.*)\s*$/),h,k,j;if(!i)throw B("Expected ngRepeat in form of '_item_ in _collection_' but got '"+f+"'.");f=i[1];h=i[2];i=f.match(/^(?:([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\))$/);if(!i)throw B("'item' in 'item in collection' should be identifier or (key, value) but got '"+
  15.147 -f+"'.");k=i[3]||i[1];j=i[2];var l=new eb;a.$watch(function(a){var e,f,i=a.$eval(h),m=gc(i,!0),p,u=new eb,C,A,v,t,y=c;if(J(i))v=i||[];else{v=[];for(C in i)i.hasOwnProperty(C)&&C.charAt(0)!="$"&&v.push(C);v.sort()}e=0;for(f=v.length;e<f;e++){C=i===v?e:v[e];A=i[C];if(t=l.shift(A)){p=t.scope;u.push(A,t);if(e!==t.index)t.index=e,y.after(t.element);y=t.element}else p=a.$new();p[k]=A;j&&(p[j]=C);p.$index=e;p.$first=e===0;p.$last=e===m-1;p.$middle=!(p.$first||p.$last);t||d(p,function(a){y.after(a);t={scope:p,
  15.148 -element:y=a,index:e};u.push(A,t)})}for(C in l)if(l.hasOwnProperty(C))for(v=l[C];v.length;)A=v.pop(),A.element.remove(),A.scope.$destroy();l=u})}}}),Kd=S(function(a,c,d){a.$watch(d.ngShow,function(a){c.css("display",Wa(a)?"":"none")})}),Ld=S(function(a,c,d){a.$watch(d.ngHide,function(a){c.css("display",Wa(a)?"none":"")})}),Md=S(function(a,c,d){a.$watch(d.ngStyle,function(a,d){d&&a!==d&&m(d,function(a,d){c.css(d,"")});a&&c.css(a)},!0)}),Nd=I({restrict:"EA",compile:function(a,c){var d=c.ngSwitch||c.on,
  15.149 -e={};a.data("ng-switch",e);return function(a,i){var f,h,k;a.$watch(d,function(d){h&&(k.$destroy(),h.remove(),h=k=null);if(f=e["!"+d]||e["?"])a.$eval(c.change),k=a.$new(),f(k,function(a){h=a;i.append(a)})})}}}),Od=S({transclude:"element",priority:500,compile:function(a,c,d){a=a.inheritedData("ng-switch");qa(a);a["!"+c.ngSwitchWhen]=d}}),Pd=S({transclude:"element",priority:500,compile:function(a,c,d){a=a.inheritedData("ng-switch");qa(a);a["?"]=d}}),Qd=S({controller:["$transclude","$element",function(a,
  15.150 -c){a(function(a){c.append(a)})}]}),Rd=["$http","$templateCache","$route","$anchorScroll","$compile","$controller",function(a,c,d,e,g,i){return{restrict:"ECA",terminal:!0,link:function(a,c,k){function j(){var j=d.current&&d.current.locals,k=j&&j.$template;if(k){c.html(k);l&&(l.$destroy(),l=null);var k=g(c.contents()),p=d.current;l=p.scope=a.$new();if(p.controller)j.$scope=l,j=i(p.controller,j),c.contents().data("$ngControllerController",j);k(l);l.$emit("$viewContentLoaded");l.$eval(m);e()}else c.html(""),
  15.151 -l&&(l.$destroy(),l=null)}var l,m=k.onload||"";a.$on("$routeChangeSuccess",j);j()}}}],Sd=["$templateCache",function(a){return{restrict:"E",terminal:!0,compile:function(c,d){d.type=="text/ng-template"&&a.put(d.id,c[0].text)}}}],Td=I({terminal:!0}),Ud=["$compile","$parse",function(a,c){var d=/^\s*(.*?)(?:\s+as\s+(.*?))?(?:\s+group\s+by\s+(.*))?\s+for\s+(?:([\$\w][\$\w\d]*)|(?:\(\s*([\$\w][\$\w\d]*)\s*,\s*([\$\w][\$\w\d]*)\s*\)))\s+in\s+(.*)$/,e={$setViewValue:D};return{restrict:"E",require:["select",
  15.152 -"?ngModel"],controller:["$element","$scope","$attrs",function(a,c,d){var h=this,k={},j=e,l;h.databound=d.ngModel;h.init=function(a,c,d){j=a;l=d};h.addOption=function(c){k[c]=!0;j.$viewValue==c&&(a.val(c),l.parent()&&l.remove())};h.removeOption=function(a){this.hasOption(a)&&(delete k[a],j.$viewValue==a&&this.renderUnknownOption(a))};h.renderUnknownOption=function(c){c="? "+ga(c)+" ?";l.val(c);a.prepend(l);a.val(c);l.prop("selected",!0)};h.hasOption=function(a){return k.hasOwnProperty(a)};c.$on("$destroy",
  15.153 -function(){h.renderUnknownOption=D})}],link:function(e,i,f,h){function k(a,c,d,e){d.$render=function(){var a=d.$viewValue;e.hasOption(a)?(A.parent()&&A.remove(),c.val(a),a===""&&s.prop("selected",!0)):t(a)&&s?c.val(""):e.renderUnknownOption(a)};c.bind("change",function(){a.$apply(function(){A.parent()&&A.remove();d.$setViewValue(c.val())})})}function j(a,c,d){var e;d.$render=function(){var a=new Fa(d.$viewValue);m(c.children(),function(c){c.selected=v(a.get(c.value))})};a.$watch(function(){ha(e,d.$viewValue)||
  15.154 -(e=V(d.$viewValue),d.$render())});c.bind("change",function(){a.$apply(function(){var a=[];m(c.children(),function(c){c.selected&&a.push(c.value)});d.$setViewValue(a)})})}function l(e,f,g){function h(){var a={"":[]},c=[""],d,i,s,t,u;s=g.$modelValue;t=r(e)||[];var y=l?lb(t):t,A,w,x;w={};u=!1;var z,B;if(n)u=new Fa(s);else if(s===null||q)a[""].push({selected:s===null,id:"",label:""}),u=!0;for(x=0;A=y.length,x<A;x++){w[k]=t[l?w[l]=y[x]:x];d=m(e,w)||"";if(!(i=a[d]))i=a[d]=[],c.push(d);n?d=u.remove(o(e,
  15.155 -w))!=p:(d=s===o(e,w),u=u||d);z=j(e,w);z=z===p?"":z;i.push({id:l?y[x]:x,label:z,selected:d})}!n&&!u&&a[""].unshift({id:"?",label:"",selected:!0});w=0;for(y=c.length;w<y;w++){d=c[w];i=a[d];if(v.length<=w)s={element:C.clone().attr("label",d),label:i.label},t=[s],v.push(t),f.append(s.element);else if(t=v[w],s=t[0],s.label!=d)s.element.attr("label",s.label=d);z=null;x=0;for(A=i.length;x<A;x++)if(d=i[x],u=t[x+1]){z=u.element;if(u.label!==d.label)z.text(u.label=d.label);if(u.id!==d.id)z.val(u.id=d.id);if(u.element.selected!==
  15.156 -d.selected)z.prop("selected",u.selected=d.selected)}else d.id===""&&q?B=q:(B=D.clone()).val(d.id).attr("selected",d.selected).text(d.label),t.push({element:B,label:d.label,id:d.id,selected:d.selected}),z?z.after(B):s.element.append(B),z=B;for(x++;t.length>x;)t.pop().element.remove()}for(;v.length>w;)v.pop()[0].element.remove()}var i;if(!(i=w.match(d)))throw B("Expected ngOptions in form of '_select_ (as _label_)? for (_key_,)?_value_ in _collection_' but got '"+w+"'.");var j=c(i[2]||i[1]),k=i[4]||
  15.157 -i[6],l=i[5],m=c(i[3]||""),o=c(i[2]?i[1]:k),r=c(i[7]),v=[[{element:f,label:""}]];q&&(a(q)(e),q.removeClass("ng-scope"),q.remove());f.html("");f.bind("change",function(){e.$apply(function(){var a,c=r(e)||[],d={},h,i,j,m,q,s;if(n){i=[];m=0;for(s=v.length;m<s;m++){a=v[m];j=1;for(q=a.length;j<q;j++)if((h=a[j].element)[0].selected)h=h.val(),l&&(d[l]=h),d[k]=c[h],i.push(o(e,d))}}else h=f.val(),h=="?"?i=p:h==""?i=null:(d[k]=c[h],l&&(d[l]=h),i=o(e,d));g.$setViewValue(i)})});g.$render=h;e.$watch(h)}if(h[1]){for(var o=
  15.158 -h[0],r=h[1],n=f.multiple,w=f.ngOptions,q=!1,s,D=u(ca.createElement("option")),C=u(ca.createElement("optgroup")),A=D.clone(),h=0,x=i.children(),E=x.length;h<E;h++)if(x[h].value==""){s=q=x.eq(h);break}o.init(r,q,A);if(n&&(f.required||f.ngRequired)){var y=function(a){r.$setValidity("required",!f.required||a&&a.length);return a};r.$parsers.push(y);r.$formatters.unshift(y);f.$observe("required",function(){y(r.$viewValue)})}w?l(e,i,r):n?j(e,i,r):k(e,i,r,o)}}}}],Vd=["$interpolate",function(a){var c={addOption:D,
  15.159 -removeOption:D};return{restrict:"E",priority:100,compile:function(d,e){if(t(e.value)){var g=a(d.text(),!0);g||e.$set("value",d.text())}return function(a,d,e){var k=d.parent(),j=k.data("$selectController")||k.parent().data("$selectController");j&&j.databound?d.prop("selected",!1):j=c;g?a.$watch(g,function(a,c){e.$set("value",a);a!==c&&j.removeOption(c);j.addOption(a)}):j.addOption(e.value);d.bind("$destroy",function(){j.removeOption(e.value)})}}}}],Wd=I({restrict:"E",terminal:!0});(ja=U.jQuery)?(u=
  15.160 -ja,x(ja.fn,{scope:ua.scope,controller:ua.controller,injector:ua.injector,inheritedData:ua.inheritedData}),ab("remove",!0),ab("empty"),ab("html")):u=Q;Yb.element=u;(function(a){x(a,{bootstrap:pb,copy:V,extend:x,equals:ha,element:u,forEach:m,injector:qb,noop:D,bind:Va,toJson:da,fromJson:nb,identity:ma,isUndefined:t,isDefined:v,isString:F,isFunction:N,isObject:L,isNumber:wa,isElement:fc,isArray:J,version:id,isDate:na,lowercase:E,uppercase:la,callbacks:{counter:0}});ta=lc(U);try{ta("ngLocale")}catch(c){ta("ngLocale",
  15.161 -[]).provider("$locale",Zc)}ta("ng",["ngLocale"],["$provide",function(a){a.provider("$compile",Bb).directive({a:jd,input:bc,textarea:bc,form:kd,script:Sd,select:Ud,style:Wd,option:Vd,ngBind:vd,ngBindHtmlUnsafe:xd,ngBindTemplate:wd,ngClass:yd,ngClassEven:Ad,ngClassOdd:zd,ngCsp:Dd,ngCloak:Bd,ngController:Cd,ngForm:ld,ngHide:Ld,ngInclude:Fd,ngInit:Gd,ngNonBindable:Hd,ngPluralize:Id,ngRepeat:Jd,ngShow:Kd,ngSubmit:Ed,ngStyle:Md,ngSwitch:Nd,ngSwitchWhen:Od,ngSwitchDefault:Pd,ngOptions:Td,ngView:Rd,ngTransclude:Qd,
  15.162 -ngModel:qd,ngList:sd,ngChange:rd,required:cc,ngRequired:cc,ngValue:ud}).directive(kb).directive(dc);a.provider({$anchorScroll:uc,$browser:wc,$cacheFactory:xc,$controller:Bc,$document:Cc,$exceptionHandler:Dc,$filter:Pb,$interpolate:Ec,$http:Vc,$httpBackend:Wc,$location:Ic,$log:Jc,$parse:Nc,$route:Qc,$routeParams:Rc,$rootScope:Sc,$q:Oc,$sniffer:Tc,$templateCache:yc,$timeout:$c,$window:Uc})}])})(Yb);u(ca).ready(function(){jc(ca,pb)})})(window,document);angular.element(document).find("head").append('<style type="text/css">@charset "UTF-8";[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak{display:none;}ng\\:form{display:block;}</style>');
    16.1 --- a/dew/src/main/resources/org/apidesign/bck2brwsr/dew/js/app.js	Tue Feb 11 10:48:24 2014 +0100
    16.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.3 @@ -1,224 +0,0 @@
    16.4 -// 'use strict';
    16.5 -
    16.6 -// Declare app level module which depends on filters, and services
    16.7 -angular.module('bck2brwsr', []).
    16.8 -  directive('uiCodemirror', ['$timeout', function($timeout) {
    16.9 -        'use strict';
   16.10 -
   16.11 -        var events = ["cursorActivity", "viewportChange", "gutterClick", "focus", "blur", "scroll", "update"];
   16.12 -        return {
   16.13 -            restrict: 'A',
   16.14 -            require: 'ngModel',
   16.15 -            link: function(scope, elm, attrs, ngModel) {
   16.16 -                var options, opts, onChange, deferCodeMirror, codeMirror, timeoutId, val;
   16.17 -
   16.18 -                if (elm[0].type !== 'textarea') {
   16.19 -                    throw new Error('uiCodemirror3 can only be applied to a textarea element');
   16.20 -                }
   16.21 -
   16.22 -                options = /* uiConfig.codemirror  || */ {};
   16.23 -                opts = angular.extend({}, options, scope.$eval(attrs.uiCodemirror));
   16.24 -
   16.25 -                onChange = function(instance, changeObj) {                    
   16.26 -                    val = instance.getValue();
   16.27 -                    $timeout.cancel(timeoutId);
   16.28 -                    timeoutId = $timeout(function() {
   16.29 -                        ngModel.$setViewValue(val);                        
   16.30 -                      }, 500);                    
   16.31 -                };
   16.32 -                
   16.33 -                deferCodeMirror = function() {
   16.34 -                    codeMirror = CodeMirror.fromTextArea(elm[0], opts);
   16.35 -                    elm[0].codeMirror = codeMirror;
   16.36 -                    // codeMirror.on("change", onChange(opts.onChange));
   16.37 -                    codeMirror.on("change", onChange);
   16.38 -
   16.39 -                    for (var i = 0, n = events.length, aEvent; i < n; ++i) {
   16.40 -                        aEvent = opts["on" + events[i].charAt(0).toUpperCase() + events[i].slice(1)];
   16.41 -                        if (aEvent === void 0)
   16.42 -                            continue;
   16.43 -                        if (typeof aEvent !== "function")
   16.44 -                            continue;
   16.45 -                                                
   16.46 -                        var bound = _.bind( aEvent, scope );
   16.47 -                        
   16.48 -                        codeMirror.on(events[i], bound);
   16.49 -                    }
   16.50 -
   16.51 -                    // CodeMirror expects a string, so make sure it gets one.
   16.52 -                    // This does not change the model.
   16.53 -                    ngModel.$formatters.push(function(value) {
   16.54 -                        if (angular.isUndefined(value) || value === null) {
   16.55 -                            return '';
   16.56 -                        }
   16.57 -                        else if (angular.isObject(value) || angular.isArray(value)) {
   16.58 -                            throw new Error('ui-codemirror cannot use an object or an array as a model');
   16.59 -                        }
   16.60 -                        return value;
   16.61 -                    });
   16.62 -
   16.63 -                    // Override the ngModelController $render method, which is what gets called when the model is updated.
   16.64 -                    // This takes care of the synchronizing the codeMirror element with the underlying model, in the case that it is changed by something else.
   16.65 -                    ngModel.$render = function() {
   16.66 -                        codeMirror.setValue(ngModel.$viewValue);
   16.67 -                    };
   16.68 -
   16.69 -                };
   16.70 -
   16.71 -                $timeout(deferCodeMirror);
   16.72 -
   16.73 -            }
   16.74 -        };
   16.75 -}]);
   16.76 -
   16.77 -function DevCtrl( $scope, $http ) {
   16.78 -    var templateHtml = 
   16.79 -"<html><body>\n" +
   16.80 -"  <input data-bind=\"value: value, valueUpdate: 'afterkeydown'\" \n" +
   16.81 -"     value=\"0\" type=\"number\">\n" +
   16.82 -"  </input>\n" +
   16.83 -"  * <span data-bind=\"text: value\">0</span> \n" +
   16.84 -"  = <span data-bind=\"text: powerValue\">0</span>\n" +
   16.85 -"  <br/>\n" +
   16.86 -"  <button id='dupl'>Duplicate!</button>\n" +
   16.87 -"  <button id=\"clear\">Clear!</button>" +
   16.88 -" <hr/>\n" +
   16.89 -"\n" +
   16.90 -"\n" +
   16.91 -"\n" +
   16.92 -"\n" +
   16.93 -"\n" +
   16.94 -"\n" +
   16.95 -"\n" +
   16.96 -"\n" +
   16.97 -"\n" +
   16.98 -"\n" +
   16.99 -"\n" +
  16.100 -"\n" +
  16.101 -"\n" +
  16.102 -"\n" +
  16.103 -"\n" +
  16.104 -"\n" +
  16.105 -"\n" +
  16.106 -"\n" +
  16.107 -"\n" +
  16.108 -"\n" +
  16.109 -" <script src=\"/bck2brwsr.js\"></script>\n" +
  16.110 -" <script type=\"text/javascript\">\n" +
  16.111 -"   function ldCls(res) {\n" +
  16.112 -"     var request = new XMLHttpRequest();\n" +
  16.113 -"     request.open('GET', '/classes/' + res, false);\n" +
  16.114 -"     request.send();\n" +
  16.115 -"     var arr = eval('(' + request.responseText + ')');\n" +
  16.116 -"     return arr;\n" +
  16.117 -"   }\n" +
  16.118 -"   var vm = bck2brwsr(ldCls);\n" +
  16.119 -"   vm.loadClass('${fqn}');\n" +
  16.120 -" </script>\n" +
  16.121 -"</body></html>";
  16.122 -    var templateJava = 
  16.123 -"package bck2brwsr.demo;\n" +
  16.124 -"import org.apidesign.bck2brwsr.htmlpage.api.*;\n" +
  16.125 -"import static org.apidesign.bck2brwsr.htmlpage.api.OnEvent.*;\n" +
  16.126 -"\n" +
  16.127 -"@Page(xhtml=\"index.html\", className=\"Index\", properties={\n" +
  16.128 -"  @Property(name=\"value\", type=int.class)\n" +
  16.129 -"})\n" +
  16.130 -"class YourFirstHTML5PageInRealLanguage {\n" +
  16.131 -"  static { new Index().applyBindings(); }\n" +
  16.132 -"  @On(event=CLICK, id=\"dupl\") static void duplicateValue(Index m) {\n" +
  16.133 -"    m.setValue(m.getValue() * 2);\n" +
  16.134 -"  }\n" +
  16.135 -"  @On(event=CLICK, id=\"clear\") static void zeroTheValue(Index m) {\n" +
  16.136 -"     m.setValue(0);;\n" +
  16.137 -"  }\n" +
  16.138 -"  @ComputedProperty static int powerValue(int value) {\n" +
  16.139 -"    return value * value;\n" +
  16.140 -"  }\n" +
  16.141 -"}";
  16.142 -
  16.143 -    
  16.144 -    $scope.makeMarker = function( editor, line ) {
  16.145 -        var marker = document.createElement("div");
  16.146 -        marker.innerHTML = " ";
  16.147 -        marker.className = "issue";
  16.148 -        
  16.149 -        var info = editor.lineInfo(line);
  16.150 -        editor.setGutterMarker(line, "issues", info.markers ? null : marker);
  16.151 -        
  16.152 -        return marker;
  16.153 -    };
  16.154 -    
  16.155 -    
  16.156 -    // Returns a function, that, as long as it continues to be invoked, will not
  16.157 -    // be triggered. The function will be called after it stops being called for
  16.158 -    // N milliseconds. If `immediate` is passed, trigger the function on the
  16.159 -    // leading edge, instead of the trailing.
  16.160 -    $scope.debounce = function(func, wait, immediate) {
  16.161 -      var timeout, result;
  16.162 -      return function() {
  16.163 -        var context = this, args = arguments;
  16.164 -        var later = function() {
  16.165 -          timeout = null;
  16.166 -          if (!immediate) result = func.apply(context, args);
  16.167 -        };
  16.168 -        var callNow = immediate && !timeout;
  16.169 -        clearTimeout(timeout);
  16.170 -        timeout = setTimeout(later, wait);
  16.171 -        if (callNow) result = func.apply(context, args);
  16.172 -        return result;
  16.173 -      };
  16.174 -    };
  16.175 -    
  16.176 -    $scope.reload = function() {
  16.177 -        $scope.errors = null;
  16.178 -        var frame = document.getElementById("result");        
  16.179 -        frame.src = "result.html";
  16.180 -        frame.contentDocument.location.reload(true);
  16.181 -        frame.contentWindow.location.reload();
  16.182 -        document.getElementById("editorJava").codeMirror.clearGutter("issues");   
  16.183 -    };
  16.184 -    
  16.185 -    $scope.fail = function( data ) {
  16.186 -        $scope.errors = eval( data );
  16.187 -        var editor = document.getElementById("editorJava").codeMirror;   
  16.188 -        editor.clearGutter( "issues" );
  16.189 -        
  16.190 -        for( var i = 0; i < $scope.errors.length; i ++ ) {
  16.191 -            $scope.makeMarker( editor, $scope.errors[i].line - 1 );
  16.192 -        }
  16.193 -        
  16.194 -    };
  16.195 -    
  16.196 -    $scope.post = function() {
  16.197 -        return $http({url: ".",
  16.198 -            method: "POST",
  16.199 -            //headers: this.headers,
  16.200 -            data: { html : $scope.html, java : $scope.java} 
  16.201 -        }).success( $scope.reload ).error( $scope.fail );
  16.202 -    };
  16.203 -    
  16.204 -    $scope.errorClass = function( kind ) {
  16.205 -        switch( kind ) {
  16.206 -            case "ERROR" :
  16.207 -                return "error";
  16.208 -            default :         
  16.209 -                return "warning";   
  16.210 -        }
  16.211 -    };
  16.212 -    
  16.213 -    $scope.gotoError = function( line, col ) {
  16.214 -        var editor = document.getElementById("editorJava").codeMirror;   
  16.215 -        editor.setCursor({ line: line - 1, ch : col - 1 });
  16.216 -        editor.focus();
  16.217 -    };
  16.218 -    
  16.219 -    $scope.tab = "html";
  16.220 -    $scope.html= templateHtml;  
  16.221 -    $scope.java = templateJava;  
  16.222 -    
  16.223 -    $scope.$watch( "html", $scope.debounce( $scope.post, 2000 ) );
  16.224 -    $scope.$watch( "java", $scope.debounce( $scope.post, 2000 ) );
  16.225 -    $scope.post();
  16.226 -    
  16.227 -}
    17.1 --- a/dew/src/main/resources/org/apidesign/bck2brwsr/dew/js/codemirror/codemirror.css	Tue Feb 11 10:48:24 2014 +0100
    17.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.3 @@ -1,239 +0,0 @@
    17.4 -/* BASICS */
    17.5 -
    17.6 -.CodeMirror {
    17.7 -  /* Set height, width, borders, and global font properties here */
    17.8 -  font-family: monospace;
    17.9 -  height: 300px;
   17.10 -}
   17.11 -.CodeMirror-scroll {
   17.12 -  /* Set scrolling behaviour here */
   17.13 -  overflow: auto;
   17.14 -}
   17.15 -
   17.16 -/* PADDING */
   17.17 -
   17.18 -.CodeMirror-lines {
   17.19 -  padding: 4px 0; /* Vertical padding around content */
   17.20 -}
   17.21 -.CodeMirror pre {
   17.22 -  padding: 0 4px; /* Horizontal padding of content */
   17.23 -}
   17.24 -
   17.25 -.CodeMirror-scrollbar-filler {
   17.26 -  background-color: white; /* The little square between H and V scrollbars */
   17.27 -}
   17.28 -
   17.29 -/* GUTTER */
   17.30 -
   17.31 -.CodeMirror-gutters {
   17.32 -  border-right: 1px solid #ddd;
   17.33 -  background-color: #f7f7f7;
   17.34 -}
   17.35 -.CodeMirror-linenumbers {}
   17.36 -.CodeMirror-linenumber {
   17.37 -  padding: 0 3px 0 5px;
   17.38 -  min-width: 20px;
   17.39 -  text-align: right;
   17.40 -  color: #999;
   17.41 -}
   17.42 -
   17.43 -/* CURSOR */
   17.44 -
   17.45 -.CodeMirror pre.CodeMirror-cursor {
   17.46 -  border-left: 1px solid black;
   17.47 -}
   17.48 -/* Shown when moving in bi-directional text */
   17.49 -.CodeMirror pre.CodeMirror-secondarycursor {
   17.50 -  border-left: 1px solid silver;
   17.51 -}
   17.52 -.cm-keymap-fat-cursor pre.CodeMirror-cursor {
   17.53 -  width: auto;
   17.54 -  border: 0;
   17.55 -  background: transparent;
   17.56 -  background: rgba(0, 200, 0, .4);
   17.57 -  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#6600c800, endColorstr=#4c00c800);
   17.58 -}
   17.59 -/* Kludge to turn off filter in ie9+, which also accepts rgba */
   17.60 -.cm-keymap-fat-cursor pre.CodeMirror-cursor:not(#nonsense_id) {
   17.61 -  filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
   17.62 -}
   17.63 -/* Can style cursor different in overwrite (non-insert) mode */
   17.64 -.CodeMirror pre.CodeMirror-cursor.CodeMirror-overwrite {}
   17.65 -
   17.66 -/* DEFAULT THEME */
   17.67 -
   17.68 -.cm-s-default .cm-keyword {color: #708;}
   17.69 -.cm-s-default .cm-atom {color: #219;}
   17.70 -.cm-s-default .cm-number {color: #164;}
   17.71 -.cm-s-default .cm-def {color: #00f;}
   17.72 -.cm-s-default .cm-variable {color: black;}
   17.73 -.cm-s-default .cm-variable-2 {color: #05a;}
   17.74 -.cm-s-default .cm-variable-3 {color: #085;}
   17.75 -.cm-s-default .cm-property {color: black;}
   17.76 -.cm-s-default .cm-operator {color: black;}
   17.77 -.cm-s-default .cm-comment {color: #a50;}
   17.78 -.cm-s-default .cm-string {color: #a11;}
   17.79 -.cm-s-default .cm-string-2 {color: #f50;}
   17.80 -.cm-s-default .cm-meta {color: #555;}
   17.81 -.cm-s-default .cm-error {color: #f00;}
   17.82 -.cm-s-default .cm-qualifier {color: #555;}
   17.83 -.cm-s-default .cm-builtin {color: #30a;}
   17.84 -.cm-s-default .cm-bracket {color: #997;}
   17.85 -.cm-s-default .cm-tag {color: #170;}
   17.86 -.cm-s-default .cm-attribute {color: #00c;}
   17.87 -.cm-s-default .cm-header {color: blue;}
   17.88 -.cm-s-default .cm-quote {color: #090;}
   17.89 -.cm-s-default .cm-hr {color: #999;}
   17.90 -.cm-s-default .cm-link {color: #00c;}
   17.91 -
   17.92 -.cm-negative {color: #d44;}
   17.93 -.cm-positive {color: #292;}
   17.94 -.cm-header, .cm-strong {font-weight: bold;}
   17.95 -.cm-em {font-style: italic;}
   17.96 -.cm-emstrong {font-style: italic; font-weight: bold;}
   17.97 -.cm-link {text-decoration: underline;}
   17.98 -
   17.99 -.cm-invalidchar {color: #f00;}
  17.100 -
  17.101 -div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;}
  17.102 -div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
  17.103 -
  17.104 -/* STOP */
  17.105 -
  17.106 -/* The rest of this file contains styles related to the mechanics of
  17.107 -   the editor. You probably shouldn't touch them. */
  17.108 -
  17.109 -.CodeMirror {
  17.110 -  line-height: 1;
  17.111 -  position: relative;
  17.112 -  overflow: hidden;
  17.113 -}
  17.114 -
  17.115 -.CodeMirror-scroll {
  17.116 -  /* 30px is the magic margin used to hide the element's real scrollbars */
  17.117 -  /* See overflow: hidden in .CodeMirror, and the paddings in .CodeMirror-sizer */
  17.118 -  margin-bottom: -30px; margin-right: -30px;
  17.119 -  padding-bottom: 30px; padding-right: 30px;
  17.120 -  height: 100%;
  17.121 -  outline: none; /* Prevent dragging from highlighting the element */
  17.122 -  position: relative;
  17.123 -}
  17.124 -.CodeMirror-sizer {
  17.125 -  position: relative;
  17.126 -}
  17.127 -
  17.128 -/* The fake, visible scrollbars. Used to force redraw during scrolling
  17.129 -   before actuall scrolling happens, thus preventing shaking and
  17.130 -   flickering artifacts. */
  17.131 -.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler {
  17.132 -  position: absolute;
  17.133 -  z-index: 6;
  17.134 -  display: none;
  17.135 -}
  17.136 -.CodeMirror-vscrollbar {
  17.137 -  right: 0; top: 0;
  17.138 -  overflow-x: hidden;
  17.139 -  overflow-y: scroll;
  17.140 -}
  17.141 -.CodeMirror-hscrollbar {
  17.142 -  bottom: 0; left: 0;
  17.143 -  overflow-y: hidden;
  17.144 -  overflow-x: scroll;
  17.145 -}
  17.146 -.CodeMirror-scrollbar-filler {
  17.147 -  right: 0; bottom: 0;
  17.148 -  z-index: 6;
  17.149 -}
  17.150 -
  17.151 -.CodeMirror-gutters {
  17.152 -  position: absolute; left: 0; top: 0;
  17.153 -  height: 100%;
  17.154 -  z-index: 3;
  17.155 -}
  17.156 -.CodeMirror-gutter {
  17.157 -  height: 100%;
  17.158 -  display: inline-block;
  17.159 -  /* Hack to make IE7 behave */
  17.160 -  *zoom:1;
  17.161 -  *display:inline;
  17.162 -}
  17.163 -.CodeMirror-gutter-elt {
  17.164 -  position: absolute;
  17.165 -  cursor: default;
  17.166 -  z-index: 4;
  17.167 -}
  17.168 -
  17.169 -.CodeMirror-lines {
  17.170 -  cursor: text;
  17.171 -}
  17.172 -.CodeMirror pre {
  17.173 -  /* Reset some styles that the rest of the page might have set */
  17.174 -  -moz-border-radius: 0; -webkit-border-radius: 0; -o-border-radius: 0; border-radius: 0;
  17.175 -  border-width: 0;
  17.176 -  background: transparent;
  17.177 -  font-family: inherit;
  17.178 -  font-size: inherit;
  17.179 -  margin: 0;
  17.180 -  white-space: pre;
  17.181 -  word-wrap: normal;
  17.182 -  line-height: inherit;
  17.183 -  color: inherit;
  17.184 -  z-index: 2;
  17.185 -  position: relative;
  17.186 -  overflow: visible;
  17.187 -}
  17.188 -.CodeMirror-wrap pre {
  17.189 -  word-wrap: break-word;
  17.190 -  white-space: pre-wrap;
  17.191 -  word-break: normal;
  17.192 -}
  17.193 -.CodeMirror-linebackground {
  17.194 -  position: absolute;
  17.195 -  left: 0; right: 0; top: 0; bottom: 0;
  17.196 -  z-index: 0;
  17.197 -}
  17.198 -
  17.199 -.CodeMirror-linewidget {
  17.200 -  position: relative;
  17.201 -  z-index: 2;
  17.202 -}
  17.203 -
  17.204 -.CodeMirror-wrap .CodeMirror-scroll {
  17.205 -  overflow-x: hidden;
  17.206 -}
  17.207 -
  17.208 -.CodeMirror-measure {
  17.209 -  position: absolute;
  17.210 -  width: 100%; height: 0px;
  17.211 -  overflow: hidden;
  17.212 -  visibility: hidden;
  17.213 -}
  17.214 -.CodeMirror-measure pre { position: static; }
  17.215 -
  17.216 -.CodeMirror pre.CodeMirror-cursor {
  17.217 -  position: absolute;
  17.218 -  visibility: hidden;
  17.219 -  border-right: none;
  17.220 -  width: 0;
  17.221 -}
  17.222 -.CodeMirror-focused pre.CodeMirror-cursor {
  17.223 -  visibility: visible;
  17.224 -}
  17.225 -
  17.226 -.CodeMirror-selected { background: #d9d9d9; }
  17.227 -.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
  17.228 -
  17.229 -.CodeMirror-searching {
  17.230 -  background: #ffa;
  17.231 -  background: rgba(255, 255, 0, .4);
  17.232 -}
  17.233 -
  17.234 -/* IE7 hack to prevent it from returning funny offsetTops on the spans */
  17.235 -.CodeMirror span { *vertical-align: text-bottom; }
  17.236 -
  17.237 -@media print {
  17.238 -  /* Hide the cursor when printing */
  17.239 -  .CodeMirror pre.CodeMirror-cursor {
  17.240 -    visibility: hidden;
  17.241 -  }
  17.242 -}
    18.1 --- a/dew/src/main/resources/org/apidesign/bck2brwsr/dew/js/codemirror/codemirror.js	Tue Feb 11 10:48:24 2014 +0100
    18.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.3 @@ -1,4553 +0,0 @@
    18.4 -// CodeMirror version 3.0
    18.5 -//
    18.6 -// CodeMirror is the only global var we claim
    18.7 -window.CodeMirror = (function() {
    18.8 -  "use strict";
    18.9 -
   18.10 -  // BROWSER SNIFFING
   18.11 -
   18.12 -  // Crude, but necessary to handle a number of hard-to-feature-detect
   18.13 -  // bugs and behavior differences.
   18.14 -  var gecko = /gecko\/\d/i.test(navigator.userAgent);
   18.15 -  var ie = /MSIE \d/.test(navigator.userAgent);
   18.16 -  var ie_lt8 = /MSIE [1-7]\b/.test(navigator.userAgent);
   18.17 -  var ie_lt9 = /MSIE [1-8]\b/.test(navigator.userAgent);
   18.18 -  var webkit = /WebKit\//.test(navigator.userAgent);
   18.19 -  var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(navigator.userAgent);
   18.20 -  var chrome = /Chrome\//.test(navigator.userAgent);
   18.21 -  var opera = /Opera\//.test(navigator.userAgent);
   18.22 -  var safari = /Apple Computer/.test(navigator.vendor);
   18.23 -  var khtml = /KHTML\//.test(navigator.userAgent);
   18.24 -  var mac_geLion = /Mac OS X 1\d\D([7-9]|\d\d)\D/.test(navigator.userAgent);
   18.25 -  var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(navigator.userAgent);
   18.26 -  var phantom = /PhantomJS/.test(navigator.userAgent);
   18.27 -
   18.28 -  var ios = /AppleWebKit/.test(navigator.userAgent) && /Mobile\/\w+/.test(navigator.userAgent);
   18.29 -  // This is woefully incomplete. Suggestions for alternative methods welcome.
   18.30 -  var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|IEMobile/i.test(navigator.userAgent);
   18.31 -  var mac = ios || /Mac/.test(navigator.platform);
   18.32 -
   18.33 -  // Optimize some code when these features are not used
   18.34 -  var sawReadOnlySpans = false, sawCollapsedSpans = false;
   18.35 -
   18.36 -  // CONSTRUCTOR
   18.37 -
   18.38 -  function CodeMirror(place, options) {
   18.39 -    if (!(this instanceof CodeMirror)) return new CodeMirror(place, options);
   18.40 -    
   18.41 -    this.options = options = options || {};
   18.42 -    // Determine effective options based on given values and defaults.
   18.43 -    for (var opt in defaults) if (!options.hasOwnProperty(opt) && defaults.hasOwnProperty(opt))
   18.44 -      options[opt] = defaults[opt];
   18.45 -    setGuttersForLineNumbers(options);
   18.46 -
   18.47 -    var display = this.display = makeDisplay(place);
   18.48 -    display.wrapper.CodeMirror = this;
   18.49 -    updateGutters(this);
   18.50 -    if (options.autofocus && !mobile) focusInput(this);
   18.51 -
   18.52 -    this.view = makeView(new BranchChunk([new LeafChunk([makeLine("", null, textHeight(display))])]));
   18.53 -    this.nextOpId = 0;
   18.54 -    loadMode(this);
   18.55 -    themeChanged(this);
   18.56 -    if (options.lineWrapping)
   18.57 -      this.display.wrapper.className += " CodeMirror-wrap";
   18.58 -
   18.59 -    // Initialize the content.
   18.60 -    this.setValue(options.value || "");
   18.61 -    // Override magic textarea content restore that IE sometimes does
   18.62 -    // on our hidden textarea on reload
   18.63 -    if (ie) setTimeout(bind(resetInput, this, true), 20);
   18.64 -    this.view.history = makeHistory();
   18.65 -
   18.66 -    registerEventHandlers(this);
   18.67 -    // IE throws unspecified error in certain cases, when
   18.68 -    // trying to access activeElement before onload
   18.69 -    var hasFocus; try { hasFocus = (document.activeElement == display.input); } catch(e) { }
   18.70 -    if (hasFocus || (options.autofocus && !mobile)) setTimeout(bind(onFocus, this), 20);
   18.71 -    else onBlur(this);
   18.72 -
   18.73 -    operation(this, function() {
   18.74 -      for (var opt in optionHandlers)
   18.75 -        if (optionHandlers.propertyIsEnumerable(opt))
   18.76 -          optionHandlers[opt](this, options[opt], Init);
   18.77 -      for (var i = 0; i < initHooks.length; ++i) initHooks[i](this);
   18.78 -    })();
   18.79 -  }
   18.80 -
   18.81 -  // DISPLAY CONSTRUCTOR
   18.82 -
   18.83 -  function makeDisplay(place) {
   18.84 -    var d = {};
   18.85 -    var input = d.input = elt("textarea", null, null, "position: absolute; padding: 0; width: 1px; height: 1em; outline: none;");
   18.86 -    input.setAttribute("wrap", "off"); input.setAttribute("autocorrect", "off"); input.setAttribute("autocapitalize", "off");
   18.87 -    // Wraps and hides input textarea
   18.88 -    d.inputDiv = elt("div", [input], null, "overflow: hidden; position: relative; width: 3px; height: 0px;");
   18.89 -    // The actual fake scrollbars.
   18.90 -    d.scrollbarH = elt("div", [elt("div", null, null, "height: 1px")], "CodeMirror-hscrollbar");
   18.91 -    d.scrollbarV = elt("div", [elt("div", null, null, "width: 1px")], "CodeMirror-vscrollbar");
   18.92 -    d.scrollbarFiller = elt("div", null, "CodeMirror-scrollbar-filler");
   18.93 -    // DIVs containing the selection and the actual code
   18.94 -    d.lineDiv = elt("div");
   18.95 -    d.selectionDiv = elt("div", null, null, "position: relative; z-index: 1");
   18.96 -    // Blinky cursor, and element used to ensure cursor fits at the end of a line
   18.97 -    d.cursor = elt("pre", "\u00a0", "CodeMirror-cursor");
   18.98 -    // Secondary cursor, shown when on a 'jump' in bi-directional text
   18.99 -    d.otherCursor = elt("pre", "\u00a0", "CodeMirror-cursor CodeMirror-secondarycursor");
  18.100 -    // Used to measure text size
  18.101 -    d.measure = elt("div", null, "CodeMirror-measure");
  18.102 -    // Wraps everything that needs to exist inside the vertically-padded coordinate system
  18.103 -    d.lineSpace = elt("div", [d.measure, d.selectionDiv, d.lineDiv, d.cursor, d.otherCursor],
  18.104 -                         null, "position: relative; outline: none");
  18.105 -    // Moved around its parent to cover visible view
  18.106 -    d.mover = elt("div", [elt("div", [d.lineSpace], "CodeMirror-lines")], null, "position: relative");
  18.107 -    // Set to the height of the text, causes scrolling
  18.108 -    d.sizer = elt("div", [d.mover], "CodeMirror-sizer");
  18.109 -    // D is needed because behavior of elts with overflow: auto and padding is inconsistent across browsers
  18.110 -    d.heightForcer = elt("div", "\u00a0", null, "position: absolute; height: " + scrollerCutOff + "px");
  18.111 -    // Will contain the gutters, if any
  18.112 -    d.gutters = elt("div", null, "CodeMirror-gutters");
  18.113 -    d.lineGutter = null;
  18.114 -    // Helper element to properly size the gutter backgrounds
  18.115 -    var scrollerInner = elt("div", [d.sizer, d.heightForcer, d.gutters], null, "position: relative; min-height: 100%");
  18.116 -    // Provides scrolling
  18.117 -    d.scroller = elt("div", [scrollerInner], "CodeMirror-scroll");
  18.118 -    d.scroller.setAttribute("tabIndex", "-1");
  18.119 -    // The element in which the editor lives.
  18.120 -    d.wrapper = elt("div", [d.inputDiv, d.scrollbarH, d.scrollbarV,
  18.121 -                            d.scrollbarFiller, d.scroller], "CodeMirror");
  18.122 -    // Work around IE7 z-index bug
  18.123 -    if (ie_lt8) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0; }
  18.124 -    if (place.appendChild) place.appendChild(d.wrapper); else place(d.wrapper);
  18.125 -
  18.126 -    // Needed to hide big blue blinking cursor on Mobile Safari
  18.127 -    if (ios) input.style.width = "0px";
  18.128 -    if (!webkit) d.scroller.draggable = true;
  18.129 -    // Needed to handle Tab key in KHTML
  18.130 -    if (khtml) { d.inputDiv.style.height = "1px"; d.inputDiv.style.position = "absolute"; }
  18.131 -    // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).
  18.132 -    else if (ie_lt8) d.scrollbarH.style.minWidth = d.scrollbarV.style.minWidth = "18px";
  18.133 -
  18.134 -    // Current visible range (may be bigger than the view window).
  18.135 -    d.viewOffset = d.showingFrom = d.showingTo = d.lastSizeC = 0;
  18.136 -
  18.137 -    // Used to only resize the line number gutter when necessary (when
  18.138 -    // the amount of lines crosses a boundary that makes its width change)
  18.139 -    d.lineNumWidth = d.lineNumInnerWidth = d.lineNumChars = null;
  18.140 -    // See readInput and resetInput
  18.141 -    d.prevInput = "";
  18.142 -    // Set to true when a non-horizontal-scrolling widget is added. As
  18.143 -    // an optimization, widget aligning is skipped when d is false.
  18.144 -    d.alignWidgets = false;
  18.145 -    // Flag that indicates whether we currently expect input to appear
  18.146 -    // (after some event like 'keypress' or 'input') and are polling
  18.147 -    // intensively.
  18.148 -    d.pollingFast = false;
  18.149 -    // Self-resetting timeout for the poller
  18.150 -    d.poll = new Delayed();
  18.151 -    // True when a drag from the editor is active
  18.152 -    d.draggingText = false;
  18.153 -
  18.154 -    d.cachedCharWidth = d.cachedTextHeight = null;
  18.155 -    d.measureLineCache = [];
  18.156 -    d.measureLineCachePos = 0;
  18.157 -
  18.158 -    // Tracks when resetInput has punted to just putting a short
  18.159 -    // string instead of the (large) selection.
  18.160 -    d.inaccurateSelection = false;
  18.161 -
  18.162 -    // Used to adjust overwrite behaviour when a paste has been
  18.163 -    // detected
  18.164 -    d.pasteIncoming = false;
  18.165 -
  18.166 -    return d;
  18.167 -  }
  18.168 -
  18.169 -  // VIEW CONSTRUCTOR
  18.170 -
  18.171 -  function makeView(doc) {
  18.172 -    var selPos = {line: 0, ch: 0};
  18.173 -    return {
  18.174 -      doc: doc,
  18.175 -      // frontier is the point up to which the content has been parsed,
  18.176 -      frontier: 0, highlight: new Delayed(),
  18.177 -      sel: {from: selPos, to: selPos, head: selPos, anchor: selPos, shift: false, extend: false},
  18.178 -      scrollTop: 0, scrollLeft: 0,
  18.179 -      overwrite: false, focused: false,
  18.180 -      // Tracks the maximum line length so that
  18.181 -      // the horizontal scrollbar can be kept
  18.182 -      // static when scrolling.
  18.183 -      maxLine: getLine(doc, 0),
  18.184 -      maxLineLength: 0,
  18.185 -      maxLineChanged: false,
  18.186 -      suppressEdits: false,
  18.187 -      goalColumn: null,
  18.188 -      cantEdit: false,
  18.189 -      keyMaps: []
  18.190 -    };
  18.191 -  }
  18.192 -
  18.193 -  // STATE UPDATES
  18.194 -
  18.195 -  // Used to get the editor into a consistent state again when options change.
  18.196 -
  18.197 -  function loadMode(cm) {
  18.198 -    var doc = cm.view.doc;
  18.199 -    cm.view.mode = CodeMirror.getMode(cm.options, cm.options.mode);
  18.200 -    doc.iter(0, doc.size, function(line) { line.stateAfter = null; });
  18.201 -    cm.view.frontier = 0;
  18.202 -    startWorker(cm, 100);
  18.203 -  }
  18.204 -
  18.205 -  function wrappingChanged(cm) {
  18.206 -    var doc = cm.view.doc, th = textHeight(cm.display);
  18.207 -    if (cm.options.lineWrapping) {
  18.208 -      cm.display.wrapper.className += " CodeMirror-wrap";
  18.209 -      var perLine = cm.display.scroller.clientWidth / charWidth(cm.display) - 3;
  18.210 -      doc.iter(0, doc.size, function(line) {
  18.211 -        if (line.height == 0) return;
  18.212 -        var guess = Math.ceil(line.text.length / perLine) || 1;
  18.213 -        if (guess != 1) updateLineHeight(line, guess * th);
  18.214 -      });
  18.215 -      cm.display.sizer.style.minWidth = "";
  18.216 -    } else {
  18.217 -      cm.display.wrapper.className = cm.display.wrapper.className.replace(" CodeMirror-wrap", "");
  18.218 -      computeMaxLength(cm.view);
  18.219 -      doc.iter(0, doc.size, function(line) {
  18.220 -        if (line.height != 0) updateLineHeight(line, th);
  18.221 -      });
  18.222 -    }
  18.223 -    regChange(cm, 0, doc.size);
  18.224 -    clearCaches(cm);
  18.225 -    setTimeout(function(){updateScrollbars(cm.display, cm.view.doc.height);}, 100);
  18.226 -  }
  18.227 -
  18.228 -  function keyMapChanged(cm) {
  18.229 -    var style = keyMap[cm.options.keyMap].style;
  18.230 -    cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-keymap-\S+/g, "") +
  18.231 -      (style ? " cm-keymap-" + style : "");
  18.232 -  }
  18.233 -
  18.234 -  function themeChanged(cm) {
  18.235 -    cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-s-\S+/g, "") +
  18.236 -      cm.options.theme.replace(/(^|\s)\s*/g, " cm-s-");
  18.237 -    clearCaches(cm);
  18.238 -  }
  18.239 -
  18.240 -  function guttersChanged(cm) {
  18.241 -    updateGutters(cm);
  18.242 -    updateDisplay(cm, true);
  18.243 -  }
  18.244 -
  18.245 -  function updateGutters(cm) {
  18.246 -    var gutters = cm.display.gutters, specs = cm.options.gutters;
  18.247 -    removeChildren(gutters);
  18.248 -    for (var i = 0; i < specs.length; ++i) {
  18.249 -      var gutterClass = specs[i];
  18.250 -      var gElt = gutters.appendChild(elt("div", null, "CodeMirror-gutter " + gutterClass));
  18.251 -      if (gutterClass == "CodeMirror-linenumbers") {
  18.252 -        cm.display.lineGutter = gElt;
  18.253 -        gElt.style.width = (cm.display.lineNumWidth || 1) + "px";
  18.254 -      }
  18.255 -    }
  18.256 -    gutters.style.display = i ? "" : "none";
  18.257 -  }
  18.258 -
  18.259 -  function lineLength(doc, line) {
  18.260 -    if (line.height == 0) return 0;
  18.261 -    var len = line.text.length, merged, cur = line;
  18.262 -    while (merged = collapsedSpanAtStart(cur)) {
  18.263 -      var found = merged.find();
  18.264 -      cur = getLine(doc, found.from.line);
  18.265 -      len += found.from.ch - found.to.ch;
  18.266 -    }
  18.267 -    cur = line;
  18.268 -    while (merged = collapsedSpanAtEnd(cur)) {
  18.269 -      var found = merged.find();
  18.270 -      len -= cur.text.length - found.from.ch;
  18.271 -      cur = getLine(doc, found.to.line);
  18.272 -      len += cur.text.length - found.to.ch;
  18.273 -    }
  18.274 -    return len;
  18.275 -  }
  18.276 -
  18.277 -  function computeMaxLength(view) {
  18.278 -    view.maxLine = getLine(view.doc, 0);
  18.279 -    view.maxLineLength = lineLength(view.doc, view.maxLine);
  18.280 -    view.maxLineChanged = true;
  18.281 -    view.doc.iter(1, view.doc.size, function(line) {
  18.282 -      var len = lineLength(view.doc, line);
  18.283 -      if (len > view.maxLineLength) {
  18.284 -        view.maxLineLength = len;
  18.285 -        view.maxLine = line;
  18.286 -      }
  18.287 -    });
  18.288 -  }
  18.289 -
  18.290 -  // Make sure the gutters options contains the element
  18.291 -  // "CodeMirror-linenumbers" when the lineNumbers option is true.
  18.292 -  function setGuttersForLineNumbers(options) {
  18.293 -    var found = false;
  18.294 -    for (var i = 0; i < options.gutters.length; ++i) {
  18.295 -      if (options.gutters[i] == "CodeMirror-linenumbers") {
  18.296 -        if (options.lineNumbers) found = true;
  18.297 -        else options.gutters.splice(i--, 1);
  18.298 -      }
  18.299 -    }
  18.300 -    if (!found && options.lineNumbers)
  18.301 -      options.gutters.push("CodeMirror-linenumbers");
  18.302 -  }
  18.303 -
  18.304 -  // SCROLLBARS
  18.305 -
  18.306 -  // Re-synchronize the fake scrollbars with the actual size of the
  18.307 -  // content. Optionally force a scrollTop.
  18.308 -  function updateScrollbars(d /* display */, docHeight) {
  18.309 -    var totalHeight = docHeight + 2 * paddingTop(d);
  18.310 -    d.sizer.style.minHeight = d.heightForcer.style.top = totalHeight + "px";
  18.311 -    var scrollHeight = Math.max(totalHeight, d.scroller.scrollHeight);
  18.312 -    var needsH = d.scroller.scrollWidth > d.scroller.clientWidth;
  18.313 -    var needsV = scrollHeight > d.scroller.clientHeight;
  18.314 -    if (needsV) {
  18.315 -      d.scrollbarV.style.display = "block";
  18.316 -      d.scrollbarV.style.bottom = needsH ? scrollbarWidth(d.measure) + "px" : "0";
  18.317 -      d.scrollbarV.firstChild.style.height = 
  18.318 -        (scrollHeight - d.scroller.clientHeight + d.scrollbarV.clientHeight) + "px";
  18.319 -    } else d.scrollbarV.style.display = "";
  18.320 -    if (needsH) {
  18.321 -      d.scrollbarH.style.display = "block";
  18.322 -      d.scrollbarH.style.right = needsV ? scrollbarWidth(d.measure) + "px" : "0";
  18.323 -      d.scrollbarH.firstChild.style.width =
  18.324 -        (d.scroller.scrollWidth - d.scroller.clientWidth + d.scrollbarH.clientWidth) + "px";
  18.325 -    } else d.scrollbarH.style.display = "";
  18.326 -    if (needsH && needsV) {
  18.327 -      d.scrollbarFiller.style.display = "block";
  18.328 -      d.scrollbarFiller.style.height = d.scrollbarFiller.style.width = scrollbarWidth(d.measure) + "px";
  18.329 -    } else d.scrollbarFiller.style.display = "";
  18.330 -
  18.331 -    if (mac_geLion && scrollbarWidth(d.measure) === 0)
  18.332 -      d.scrollbarV.style.minWidth = d.scrollbarH.style.minHeight = mac_geMountainLion ? "18px" : "12px";
  18.333 -  }
  18.334 -
  18.335 -  function visibleLines(display, doc, viewPort) {
  18.336 -    var top = display.scroller.scrollTop, height = display.wrapper.clientHeight;
  18.337 -    if (typeof viewPort == "number") top = viewPort;
  18.338 -    else if (viewPort) {top = viewPort.top; height = viewPort.bottom - viewPort.top;}
  18.339 -    top = Math.floor(top - paddingTop(display));
  18.340 -    var bottom = Math.ceil(top + height);
  18.341 -    return {from: lineAtHeight(doc, top), to: lineAtHeight(doc, bottom)};
  18.342 -  }
  18.343 -
  18.344 -  // LINE NUMBERS
  18.345 -
  18.346 -  function alignHorizontally(cm) {
  18.347 -    var display = cm.display;
  18.348 -    if (!display.alignWidgets && !display.gutters.firstChild) return;
  18.349 -    var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.view.scrollLeft;
  18.350 -    var gutterW = display.gutters.offsetWidth, l = comp + "px";
  18.351 -    for (var n = display.lineDiv.firstChild; n; n = n.nextSibling) if (n.alignable) {
  18.352 -      for (var i = 0, a = n.alignable; i < a.length; ++i) a[i].style.left = l;
  18.353 -    }
  18.354 -    display.gutters.style.left = (comp + gutterW) + "px";
  18.355 -  }
  18.356 -
  18.357 -  function maybeUpdateLineNumberWidth(cm) {
  18.358 -    if (!cm.options.lineNumbers) return false;
  18.359 -    var doc = cm.view.doc, last = lineNumberFor(cm.options, doc.size - 1), display = cm.display;
  18.360 -    if (last.length != display.lineNumChars) {
  18.361 -      var test = display.measure.appendChild(elt("div", [elt("div", last)],
  18.362 -                                                 "CodeMirror-linenumber CodeMirror-gutter-elt"));
  18.363 -      var innerW = test.firstChild.offsetWidth, padding = test.offsetWidth - innerW;
  18.364 -      display.lineGutter.style.width = "";
  18.365 -      display.lineNumInnerWidth = Math.max(innerW, display.lineGutter.offsetWidth - padding);
  18.366 -      display.lineNumWidth = display.lineNumInnerWidth + padding;
  18.367 -      display.lineNumChars = display.lineNumInnerWidth ? last.length : -1;
  18.368 -      display.lineGutter.style.width = display.lineNumWidth + "px";
  18.369 -      return true;
  18.370 -    }
  18.371 -    return false;
  18.372 -  }
  18.373 -
  18.374 -  function lineNumberFor(options, i) {
  18.375 -    return String(options.lineNumberFormatter(i + options.firstLineNumber));
  18.376 -  }
  18.377 -  function compensateForHScroll(display) {
  18.378 -    return display.scroller.getBoundingClientRect().left - display.sizer.getBoundingClientRect().left;
  18.379 -  }
  18.380 -
  18.381 -  // DISPLAY DRAWING
  18.382 -
  18.383 -  function updateDisplay(cm, changes, viewPort) {
  18.384 -    var oldFrom = cm.display.showingFrom, oldTo = cm.display.showingTo;
  18.385 -    var updated = updateDisplayInner(cm, changes, viewPort);
  18.386 -    if (updated) {
  18.387 -      signalLater(cm, cm, "update", cm);
  18.388 -      if (cm.display.showingFrom != oldFrom || cm.display.showingTo != oldTo)
  18.389 -        signalLater(cm, cm, "viewportChange", cm, cm.display.showingFrom, cm.display.showingTo);
  18.390 -    }
  18.391 -    updateSelection(cm);
  18.392 -    updateScrollbars(cm.display, cm.view.doc.height);
  18.393 -
  18.394 -    return updated;
  18.395 -  }
  18.396 -
  18.397 -  // Uses a set of changes plus the current scroll position to
  18.398 -  // determine which DOM updates have to be made, and makes the
  18.399 -  // updates.
  18.400 -  function updateDisplayInner(cm, changes, viewPort) {
  18.401 -    var display = cm.display, doc = cm.view.doc;
  18.402 -    if (!display.wrapper.clientWidth) {
  18.403 -      display.showingFrom = display.showingTo = display.viewOffset = 0;
  18.404 -      return;
  18.405 -    }
  18.406 -
  18.407 -    // Compute the new visible window
  18.408 -    // If scrollTop is specified, use that to determine which lines
  18.409 -    // to render instead of the current scrollbar position.
  18.410 -    var visible = visibleLines(display, doc, viewPort);
  18.411 -    // Bail out if the visible area is already rendered and nothing changed.
  18.412 -    if (changes !== true && changes.length == 0 &&
  18.413 -        visible.from > display.showingFrom && visible.to < display.showingTo)
  18.414 -      return;
  18.415 -
  18.416 -    if (changes && maybeUpdateLineNumberWidth(cm))
  18.417 -      changes = true;
  18.418 -    display.sizer.style.marginLeft = display.scrollbarH.style.left = display.gutters.offsetWidth + "px";
  18.419 -
  18.420 -    // When merged lines are present, the line that needs to be
  18.421 -    // redrawn might not be the one that was changed.
  18.422 -    if (changes !== true && sawCollapsedSpans)
  18.423 -      for (var i = 0; i < changes.length; ++i) {
  18.424 -        var ch = changes[i], merged;
  18.425 -        while (merged = collapsedSpanAtStart(getLine(doc, ch.from))) {
  18.426 -          var from = merged.find().from.line;
  18.427 -          if (ch.diff) ch.diff -= ch.from - from;
  18.428 -          ch.from = from;
  18.429 -        }
  18.430 -      }
  18.431 -
  18.432 -    // Used to determine which lines need their line numbers updated
  18.433 -    var positionsChangedFrom = changes === true ? 0 : Infinity;
  18.434 -    if (cm.options.lineNumbers && changes && changes !== true)
  18.435 -      for (var i = 0; i < changes.length; ++i)
  18.436 -        if (changes[i].diff) { positionsChangedFrom = changes[i].from; break; }
  18.437 -
  18.438 -    var from = Math.max(visible.from - cm.options.viewportMargin, 0);
  18.439 -    var to = Math.min(doc.size, visible.to + cm.options.viewportMargin);
  18.440 -    if (display.showingFrom < from && from - display.showingFrom < 20) from = display.showingFrom;
  18.441 -    if (display.showingTo > to && display.showingTo - to < 20) to = Math.min(doc.size, display.showingTo);
  18.442 -    if (sawCollapsedSpans) {
  18.443 -      from = lineNo(visualLine(doc, getLine(doc, from)));
  18.444 -      while (to < doc.size && lineIsHidden(getLine(doc, to))) ++to;
  18.445 -    }
  18.446 -
  18.447 -    // Create a range of theoretically intact lines, and punch holes
  18.448 -    // in that using the change info.
  18.449 -    var intact = changes === true ? [] :
  18.450 -      computeIntact([{from: display.showingFrom, to: display.showingTo}], changes);
  18.451 -    // Clip off the parts that won't be visible
  18.452 -    var intactLines = 0;
  18.453 -    for (var i = 0; i < intact.length; ++i) {
  18.454 -      var range = intact[i];
  18.455 -      if (range.from < from) range.from = from;
  18.456 -      if (range.to > to) range.to = to;
  18.457 -      if (range.from >= range.to) intact.splice(i--, 1);
  18.458 -      else intactLines += range.to - range.from;
  18.459 -    }
  18.460 -    if (intactLines == to - from && from == display.showingFrom && to == display.showingTo)
  18.461 -      return;
  18.462 -    intact.sort(function(a, b) {return a.from - b.from;});
  18.463 -
  18.464 -    if (intactLines < (to - from) * .7) display.lineDiv.style.display = "none";
  18.465 -    patchDisplay(cm, from, to, intact, positionsChangedFrom);
  18.466 -    display.lineDiv.style.display = "";
  18.467 -
  18.468 -    var different = from != display.showingFrom || to != display.showingTo ||
  18.469 -      display.lastSizeC != display.wrapper.clientHeight;
  18.470 -    // This is just a bogus formula that detects when the editor is
  18.471 -    // resized or the font size changes.
  18.472 -    if (different) display.lastSizeC = display.wrapper.clientHeight;
  18.473 -    display.showingFrom = from; display.showingTo = to;
  18.474 -    startWorker(cm, 100);
  18.475 -
  18.476 -    var prevBottom = display.lineDiv.offsetTop;
  18.477 -    for (var node = display.lineDiv.firstChild, height; node; node = node.nextSibling) if (node.lineObj) {
  18.478 -      if (ie_lt8) {
  18.479 -        var bot = node.offsetTop + node.offsetHeight;
  18.480 -        height = bot - prevBottom;
  18.481 -        prevBottom = bot;
  18.482 -      } else {
  18.483 -        var box = node.getBoundingClientRect();
  18.484 -        height = box.bottom - box.top;
  18.485 -      }
  18.486 -      var diff = node.lineObj.height - height;
  18.487 -      if (height < 2) height = textHeight(display);
  18.488 -      if (diff > .001 || diff < -.001)
  18.489 -        updateLineHeight(node.lineObj, height);
  18.490 -    }
  18.491 -    display.viewOffset = heightAtLine(cm, getLine(doc, from));
  18.492 -    // Position the mover div to align with the current virtual scroll position
  18.493 -    display.mover.style.top = display.viewOffset + "px";
  18.494 -    return true;
  18.495 -  }
  18.496 -
  18.497 -  function computeIntact(intact, changes) {
  18.498 -    for (var i = 0, l = changes.length || 0; i < l; ++i) {
  18.499 -      var change = changes[i], intact2 = [], diff = change.diff || 0;
  18.500 -      for (var j = 0, l2 = intact.length; j < l2; ++j) {
  18.501 -        var range = intact[j];
  18.502 -        if (change.to <= range.from && change.diff) {
  18.503 -          intact2.push({from: range.from + diff, to: range.to + diff});
  18.504 -        } else if (change.to <= range.from || change.from >= range.to) {
  18.505 -          intact2.push(range);
  18.506 -        } else {
  18.507 -          if (change.from > range.from)
  18.508 -            intact2.push({from: range.from, to: change.from});
  18.509 -          if (change.to < range.to)
  18.510 -            intact2.push({from: change.to + diff, to: range.to + diff});
  18.511 -        }
  18.512 -      }
  18.513 -      intact = intact2;
  18.514 -    }
  18.515 -    return intact;
  18.516 -  }
  18.517 -
  18.518 -  function getDimensions(cm) {
  18.519 -    var d = cm.display, left = {}, width = {};
  18.520 -    for (var n = d.gutters.firstChild, i = 0; n; n = n.nextSibling, ++i) {
  18.521 -      left[cm.options.gutters[i]] = n.offsetLeft;
  18.522 -      width[cm.options.gutters[i]] = n.offsetWidth;
  18.523 -    }
  18.524 -    return {fixedPos: compensateForHScroll(d),
  18.525 -            gutterTotalWidth: d.gutters.offsetWidth,
  18.526 -            gutterLeft: left,
  18.527 -            gutterWidth: width,
  18.528 -            wrapperWidth: d.wrapper.clientWidth};
  18.529 -  }
  18.530 -
  18.531 -  function patchDisplay(cm, from, to, intact, updateNumbersFrom) {
  18.532 -    var dims = getDimensions(cm);
  18.533 -    var display = cm.display, lineNumbers = cm.options.lineNumbers;
  18.534 -    // IE does bad things to nodes when .innerHTML = "" is used on a parent
  18.535 -    // we still need widgets and markers intact to add back to the new content later
  18.536 -    if (!intact.length && !ie && (!webkit || !cm.display.currentWheelTarget))
  18.537 -      removeChildren(display.lineDiv);
  18.538 -    var container = display.lineDiv, cur = container.firstChild;
  18.539 -
  18.540 -    function rm(node) {
  18.541 -      var next = node.nextSibling;
  18.542 -      if (webkit && mac && cm.display.currentWheelTarget == node) {
  18.543 -        node.style.display = "none";
  18.544 -        node.lineObj = null;
  18.545 -      } else {
  18.546 -        container.removeChild(node);
  18.547 -      }
  18.548 -      return next;
  18.549 -    }
  18.550 -
  18.551 -    var nextIntact = intact.shift(), lineNo = from;
  18.552 -    cm.view.doc.iter(from, to, function(line) {
  18.553 -      if (nextIntact && nextIntact.to == lineNo) nextIntact = intact.shift();
  18.554 -      if (lineIsHidden(line)) {
  18.555 -        if (line.height != 0) updateLineHeight(line, 0);
  18.556 -      } else if (nextIntact && nextIntact.from <= lineNo && nextIntact.to > lineNo) {
  18.557 -        // This line is intact. Skip to the actual node. Update its
  18.558 -        // line number if needed.
  18.559 -        while (cur.lineObj != line) cur = rm(cur);
  18.560 -        if (lineNumbers && updateNumbersFrom <= lineNo && cur.lineNumber)
  18.561 -          setTextContent(cur.lineNumber, lineNumberFor(cm.options, lineNo));
  18.562 -        cur = cur.nextSibling;
  18.563 -      } else {
  18.564 -        // This line needs to be generated.
  18.565 -        var lineNode = buildLineElement(cm, line, lineNo, dims);
  18.566 -        container.insertBefore(lineNode, cur);
  18.567 -        lineNode.lineObj = line;
  18.568 -      }
  18.569 -      ++lineNo;
  18.570 -    });
  18.571 -    while (cur) cur = rm(cur);
  18.572 -  }
  18.573 -
  18.574 -  function buildLineElement(cm, line, lineNo, dims) {
  18.575 -    var lineElement = lineContent(cm, line);
  18.576 -    var markers = line.gutterMarkers, display = cm.display;
  18.577 -
  18.578 -    if (!cm.options.lineNumbers && !markers && !line.bgClass && !line.wrapClass &&
  18.579 -        (!line.widgets || !line.widgets.length)) return lineElement;
  18.580 -
  18.581 -    // Lines with gutter elements or a background class need
  18.582 -    // to be wrapped again, and have the extra elements added
  18.583 -    // to the wrapper div
  18.584 -
  18.585 -    var wrap = elt("div", null, line.wrapClass, "position: relative");
  18.586 -    if (cm.options.lineNumbers || markers) {
  18.587 -      var gutterWrap = wrap.appendChild(elt("div", null, null, "position: absolute; left: " +
  18.588 -                                            dims.fixedPos + "px"));
  18.589 -      wrap.alignable = [gutterWrap];
  18.590 -      if (cm.options.lineNumbers && (!markers || !markers["CodeMirror-linenumbers"]))
  18.591 -        wrap.lineNumber = gutterWrap.appendChild(
  18.592 -          elt("div", lineNumberFor(cm.options, lineNo),
  18.593 -              "CodeMirror-linenumber CodeMirror-gutter-elt",
  18.594 -              "left: " + dims.gutterLeft["CodeMirror-linenumbers"] + "px; width: "
  18.595 -              + display.lineNumInnerWidth + "px"));
  18.596 -      if (markers)
  18.597 -        for (var k = 0; k < cm.options.gutters.length; ++k) {
  18.598 -          var id = cm.options.gutters[k], found = markers.hasOwnProperty(id) && markers[id];
  18.599 -          if (found)
  18.600 -            gutterWrap.appendChild(elt("div", [found], "CodeMirror-gutter-elt", "left: " +
  18.601 -                                       dims.gutterLeft[id] + "px; width: " + dims.gutterWidth[id] + "px"));
  18.602 -        }
  18.603 -    }
  18.604 -    // Kludge to make sure the styled element lies behind the selection (by z-index)
  18.605 -    if (line.bgClass)
  18.606 -      wrap.appendChild(elt("div", "\u00a0", line.bgClass + " CodeMirror-linebackground"));
  18.607 -    wrap.appendChild(lineElement);
  18.608 -    if (line.widgets)
  18.609 -      for (var i = 0, ws = line.widgets; i < ws.length; ++i) {
  18.610 -        var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget");
  18.611 -        node.widget = widget;
  18.612 -        if (widget.noHScroll) {
  18.613 -          (wrap.alignable || (wrap.alignable = [])).push(node);
  18.614 -          var width = dims.wrapperWidth;
  18.615 -          node.style.left = dims.fixedPos + "px";
  18.616 -          if (!widget.coverGutter) {
  18.617 -            width -= dims.gutterTotalWidth;
  18.618 -            node.style.paddingLeft = dims.gutterTotalWidth + "px";
  18.619 -          }
  18.620 -          node.style.width = width + "px";
  18.621 -        }
  18.622 -        if (widget.coverGutter) {
  18.623 -          node.style.zIndex = 5;
  18.624 -          node.style.position = "relative";
  18.625 -          if (!widget.noHScroll) node.style.marginLeft = -dims.gutterTotalWidth + "px";
  18.626 -        }
  18.627 -        if (widget.above)
  18.628 -          wrap.insertBefore(node, cm.options.lineNumbers && line.height != 0 ? gutterWrap : lineElement);
  18.629 -        else
  18.630 -          wrap.appendChild(node);
  18.631 -      }
  18.632 -
  18.633 -    if (ie_lt8) wrap.style.zIndex = 2;
  18.634 -    return wrap;
  18.635 -  }
  18.636 -
  18.637 -  // SELECTION / CURSOR
  18.638 -
  18.639 -  function updateSelection(cm) {
  18.640 -    var display = cm.display;
  18.641 -    var collapsed = posEq(cm.view.sel.from, cm.view.sel.to);
  18.642 -    if (collapsed || cm.options.showCursorWhenSelecting)
  18.643 -      updateSelectionCursor(cm);
  18.644 -    else
  18.645 -      display.cursor.style.display = display.otherCursor.style.display = "none";
  18.646 -    if (!collapsed)
  18.647 -      updateSelectionRange(cm);
  18.648 -    else
  18.649 -      display.selectionDiv.style.display = "none";
  18.650 -
  18.651 -    // Move the hidden textarea near the cursor to prevent scrolling artifacts
  18.652 -    var headPos = cursorCoords(cm, cm.view.sel.head, "div");
  18.653 -    var wrapOff = display.wrapper.getBoundingClientRect(), lineOff = display.lineDiv.getBoundingClientRect();
  18.654 -    display.inputDiv.style.top = Math.max(0, Math.min(display.wrapper.clientHeight - 10,
  18.655 -                                                      headPos.top + lineOff.top - wrapOff.top)) + "px";
  18.656 -    display.inputDiv.style.left = Math.max(0, Math.min(display.wrapper.clientWidth - 10,
  18.657 -                                                       headPos.left + lineOff.left - wrapOff.left)) + "px";
  18.658 -  }
  18.659 -
  18.660 -  // No selection, plain cursor
  18.661 -  function updateSelectionCursor(cm) {
  18.662 -    var display = cm.display, pos = cursorCoords(cm, cm.view.sel.head, "div");
  18.663 -    display.cursor.style.left = pos.left + "px";
  18.664 -    display.cursor.style.top = pos.top + "px";
  18.665 -    display.cursor.style.height = Math.max(0, pos.bottom - pos.top) * cm.options.cursorHeight + "px";
  18.666 -    display.cursor.style.display = "";
  18.667 -
  18.668 -    if (pos.other) {
  18.669 -      display.otherCursor.style.display = "";
  18.670 -      display.otherCursor.style.left = pos.other.left + "px";
  18.671 -      display.otherCursor.style.top = pos.other.top + "px";
  18.672 -      display.otherCursor.style.height = (pos.other.bottom - pos.other.top) * .85 + "px";
  18.673 -    } else { display.otherCursor.style.display = "none"; }
  18.674 -  }
  18.675 -
  18.676 -  // Highlight selection
  18.677 -  function updateSelectionRange(cm) {
  18.678 -    var display = cm.display, doc = cm.view.doc, sel = cm.view.sel;
  18.679 -    var fragment = document.createDocumentFragment();
  18.680 -    var clientWidth = display.lineSpace.offsetWidth, pl = paddingLeft(cm.display);
  18.681 -
  18.682 -    function add(left, top, width, bottom) {
  18.683 -      if (top < 0) top = 0;
  18.684 -      fragment.appendChild(elt("div", null, "CodeMirror-selected", "position: absolute; left: " + left +
  18.685 -                               "px; top: " + top + "px; width: " + (width == null ? clientWidth - left : width) +
  18.686 -                               "px; height: " + (bottom - top) + "px"));
  18.687 -    }
  18.688 -
  18.689 -    function drawForLine(line, fromArg, toArg, retTop) {
  18.690 -      var lineObj = getLine(doc, line);
  18.691 -      var lineLen = lineObj.text.length, rVal = retTop ? Infinity : -Infinity;
  18.692 -      function coords(ch) {
  18.693 -        return charCoords(cm, {line: line, ch: ch}, "div", lineObj);
  18.694 -      }
  18.695 -
  18.696 -      iterateBidiSections(getOrder(lineObj), fromArg || 0, toArg == null ? lineLen : toArg, function(from, to, dir) {
  18.697 -        var leftPos = coords(dir == "rtl" ? to - 1 : from);
  18.698 -        var rightPos = coords(dir == "rtl" ? from : to - 1);
  18.699 -        var left = leftPos.left, right = rightPos.right;
  18.700 -        if (rightPos.top - leftPos.top > 3) { // Different lines, draw top part
  18.701 -          add(left, leftPos.top, null, leftPos.bottom);
  18.702 -          left = pl;
  18.703 -          if (leftPos.bottom < rightPos.top) add(left, leftPos.bottom, null, rightPos.top);
  18.704 -        }
  18.705 -        if (toArg == null && to == lineLen) right = clientWidth;
  18.706 -        if (fromArg == null && from == 0) left = pl;
  18.707 -        rVal = retTop ? Math.min(rightPos.top, rVal) : Math.max(rightPos.bottom, rVal);
  18.708 -        if (left < pl + 1) left = pl;
  18.709 -        add(left, rightPos.top, right - left, rightPos.bottom);
  18.710 -      });
  18.711 -      return rVal;
  18.712 -    }
  18.713 -
  18.714 -    if (sel.from.line == sel.to.line) {
  18.715 -      drawForLine(sel.from.line, sel.from.ch, sel.to.ch);
  18.716 -    } else {
  18.717 -      var fromObj = getLine(doc, sel.from.line);
  18.718 -      var cur = fromObj, merged, path = [sel.from.line, sel.from.ch], singleLine;
  18.719 -      while (merged = collapsedSpanAtEnd(cur)) {
  18.720 -        var found = merged.find();
  18.721 -        path.push(found.from.ch, found.to.line, found.to.ch);
  18.722 -        if (found.to.line == sel.to.line) {
  18.723 -          path.push(sel.to.ch);
  18.724 -          singleLine = true;
  18.725 -          break;
  18.726 -        }
  18.727 -        cur = getLine(doc, found.to.line);
  18.728 -      }
  18.729 -
  18.730 -      // This is a single, merged line
  18.731 -      if (singleLine) {
  18.732 -        for (var i = 0; i < path.length; i += 3)
  18.733 -          drawForLine(path[i], path[i+1], path[i+2]);
  18.734 -      } else {
  18.735 -        var middleTop, middleBot, toObj = getLine(doc, sel.to.line);
  18.736 -        if (sel.from.ch)
  18.737 -          // Draw the first line of selection.
  18.738 -          middleTop = drawForLine(sel.from.line, sel.from.ch, null, false);
  18.739 -        else
  18.740 -          // Simply include it in the middle block.
  18.741 -          middleTop = heightAtLine(cm, fromObj) - display.viewOffset;
  18.742 -
  18.743 -        if (!sel.to.ch)
  18.744 -          middleBot = heightAtLine(cm, toObj) - display.viewOffset;
  18.745 -        else
  18.746 -          middleBot = drawForLine(sel.to.line, collapsedSpanAtStart(toObj) ? null : 0, sel.to.ch, true);
  18.747 -
  18.748 -        if (middleTop < middleBot) add(pl, middleTop, null, middleBot);
  18.749 -      }
  18.750 -    }
  18.751 -
  18.752 -    removeChildrenAndAdd(display.selectionDiv, fragment);
  18.753 -    display.selectionDiv.style.display = "";
  18.754 -  }
  18.755 -
  18.756 -  // Cursor-blinking
  18.757 -  function restartBlink(cm) {
  18.758 -    var display = cm.display;
  18.759 -    clearInterval(display.blinker);
  18.760 -    var on = true;
  18.761 -    display.cursor.style.visibility = display.otherCursor.style.visibility = "";
  18.762 -    display.blinker = setInterval(function() {
  18.763 -      if (!display.cursor.offsetHeight) return;
  18.764 -      display.cursor.style.visibility = display.otherCursor.style.visibility = (on = !on) ? "" : "hidden";
  18.765 -    }, cm.options.cursorBlinkRate);
  18.766 -  }
  18.767 -
  18.768 -  // HIGHLIGHT WORKER
  18.769 -
  18.770 -  function startWorker(cm, time) {
  18.771 -    if (cm.view.frontier < cm.display.showingTo)
  18.772 -      cm.view.highlight.set(time, bind(highlightWorker, cm));
  18.773 -  }
  18.774 -
  18.775 -  function highlightWorker(cm) {
  18.776 -    var view = cm.view, doc = view.doc;
  18.777 -    if (view.frontier >= cm.display.showingTo) return;
  18.778 -    var end = +new Date + cm.options.workTime;
  18.779 -    var state = copyState(view.mode, getStateBefore(cm, view.frontier));
  18.780 -    var changed = [], prevChange;
  18.781 -    doc.iter(view.frontier, Math.min(doc.size, cm.display.showingTo + 500), function(line) {
  18.782 -      if (view.frontier >= cm.display.showingFrom) { // Visible
  18.783 -        if (highlightLine(cm, line, state) && view.frontier >= cm.display.showingFrom) {
  18.784 -          if (prevChange && prevChange.end == view.frontier) prevChange.end++;
  18.785 -          else changed.push(prevChange = {start: view.frontier, end: view.frontier + 1});
  18.786 -        }
  18.787 -        line.stateAfter = copyState(view.mode, state);
  18.788 -      } else {
  18.789 -        processLine(cm, line, state);
  18.790 -        line.stateAfter = view.frontier % 5 == 0 ? copyState(view.mode, state) : null;
  18.791 -      }
  18.792 -      ++view.frontier;
  18.793 -      if (+new Date > end) {
  18.794 -        startWorker(cm, cm.options.workDelay);
  18.795 -        return true;
  18.796 -      }
  18.797 -    });
  18.798 -    if (changed.length)
  18.799 -      operation(cm, function() {
  18.800 -        for (var i = 0; i < changed.length; ++i)
  18.801 -          regChange(this, changed[i].start, changed[i].end);
  18.802 -      })();
  18.803 -  }
  18.804 -
  18.805 -  // Finds the line to start with when starting a parse. Tries to
  18.806 -  // find a line with a stateAfter, so that it can start with a
  18.807 -  // valid state. If that fails, it returns the line with the
  18.808 -  // smallest indentation, which tends to need the least context to
  18.809 -  // parse correctly.
  18.810 -  function findStartLine(cm, n) {
  18.811 -    var minindent, minline, doc = cm.view.doc;
  18.812 -    for (var search = n, lim = n - 100; search > lim; --search) {
  18.813 -      if (search == 0) return 0;
  18.814 -      var line = getLine(doc, search-1);
  18.815 -      if (line.stateAfter) return search;
  18.816 -      var indented = countColumn(line.text, null, cm.options.tabSize);
  18.817 -      if (minline == null || minindent > indented) {
  18.818 -        minline = search - 1;
  18.819 -        minindent = indented;
  18.820 -      }
  18.821 -    }
  18.822 -    return minline;
  18.823 -  }
  18.824 -
  18.825 -  function getStateBefore(cm, n) {
  18.826 -    var view = cm.view;
  18.827 -    var pos = findStartLine(cm, n), state = pos && getLine(view.doc, pos-1).stateAfter;
  18.828 -    if (!state) state = startState(view.mode);
  18.829 -    else state = copyState(view.mode, state);
  18.830 -    view.doc.iter(pos, n, function(line) {
  18.831 -      processLine(cm, line, state);
  18.832 -      var save = pos == n - 1 || pos % 5 == 0 || pos >= view.showingFrom && pos < view.showingTo;
  18.833 -      line.stateAfter = save ? copyState(view.mode, state) : null;
  18.834 -      ++pos;
  18.835 -    });
  18.836 -    return state;
  18.837 -  }
  18.838 -
  18.839 -  // POSITION MEASUREMENT
  18.840 -  
  18.841 -  function paddingTop(display) {return display.lineSpace.offsetTop;}
  18.842 -  function paddingLeft(display) {
  18.843 -    var e = removeChildrenAndAdd(display.measure, elt("pre")).appendChild(elt("span", "x"));
  18.844 -    return e.offsetLeft;
  18.845 -  }
  18.846 -
  18.847 -  function measureChar(cm, line, ch, data) {
  18.848 -    var data = data || measureLine(cm, line), dir = -1;
  18.849 -    for (var pos = ch;; pos += dir) {
  18.850 -      var r = data[pos];
  18.851 -      if (r) break;
  18.852 -      if (dir < 0 && pos == 0) dir = 1;
  18.853 -    }
  18.854 -    return {left: pos < ch ? r.right : r.left,
  18.855 -            right: pos > ch ? r.left : r.right,
  18.856 -            top: r.top, bottom: r.bottom};
  18.857 -  }
  18.858 -
  18.859 -  function measureLine(cm, line) {
  18.860 -    // First look in the cache
  18.861 -    var display = cm.display, cache = cm.display.measureLineCache;
  18.862 -    for (var i = 0; i < cache.length; ++i) {
  18.863 -      var memo = cache[i];
  18.864 -      if (memo.text == line.text && memo.markedSpans == line.markedSpans &&
  18.865 -          display.scroller.clientWidth == memo.width)
  18.866 -        return memo.measure;
  18.867 -    }
  18.868 -    
  18.869 -    var measure = measureLineInner(cm, line);
  18.870 -    // Store result in the cache
  18.871 -    var memo = {text: line.text, width: display.scroller.clientWidth,
  18.872 -                markedSpans: line.markedSpans, measure: measure};
  18.873 -    if (cache.length == 16) cache[++display.measureLineCachePos % 16] = memo;
  18.874 -    else cache.push(memo);
  18.875 -    return measure;
  18.876 -  }
  18.877 -
  18.878 -  function measureLineInner(cm, line) {
  18.879 -    var display = cm.display, measure = emptyArray(line.text.length);
  18.880 -    var pre = lineContent(cm, line, measure);
  18.881 -
  18.882 -    // IE does not cache element positions of inline elements between
  18.883 -    // calls to getBoundingClientRect. This makes the loop below,
  18.884 -    // which gathers the positions of all the characters on the line,
  18.885 -    // do an amount of layout work quadratic to the number of
  18.886 -    // characters. When line wrapping is off, we try to improve things
  18.887 -    // by first subdividing the line into a bunch of inline blocks, so
  18.888 -    // that IE can reuse most of the layout information from caches
  18.889 -    // for those blocks. This does interfere with line wrapping, so it
  18.890 -    // doesn't work when wrapping is on, but in that case the
  18.891 -    // situation is slightly better, since IE does cache line-wrapping
  18.892 -    // information and only recomputes per-line.
  18.893 -    if (ie && !ie_lt8 && !cm.options.lineWrapping && pre.childNodes.length > 100) {
  18.894 -      var fragment = document.createDocumentFragment();
  18.895 -      var chunk = 10, n = pre.childNodes.length;
  18.896 -      for (var i = 0, chunks = Math.ceil(n / chunk); i < chunks; ++i) {
  18.897 -        var wrap = elt("div", null, null, "display: inline-block");
  18.898 -        for (var j = 0; j < chunk && n; ++j) {
  18.899 -          wrap.appendChild(pre.firstChild);
  18.900 -          --n;
  18.901 -        }
  18.902 -        fragment.appendChild(wrap);
  18.903 -      }
  18.904 -      pre.appendChild(fragment);
  18.905 -    }
  18.906 -
  18.907 -    removeChildrenAndAdd(display.measure, pre);
  18.908 -
  18.909 -    var outer = display.lineDiv.getBoundingClientRect();
  18.910 -    var vranges = [], data = emptyArray(line.text.length), maxBot = pre.offsetHeight;
  18.911 -    for (var i = 0, cur; i < measure.length; ++i) if (cur = measure[i]) {
  18.912 -      var size = cur.getBoundingClientRect();
  18.913 -      var top = Math.max(0, size.top - outer.top), bot = Math.min(size.bottom - outer.top, maxBot);
  18.914 -      for (var j = 0; j < vranges.length; j += 2) {
  18.915 -        var rtop = vranges[j], rbot = vranges[j+1];
  18.916 -        if (rtop > bot || rbot < top) continue;
  18.917 -        if (rtop <= top && rbot >= bot ||
  18.918 -            top <= rtop && bot >= rbot ||
  18.919 -            Math.min(bot, rbot) - Math.max(top, rtop) >= (bot - top) >> 1) {
  18.920 -          vranges[j] = Math.min(top, rtop);
  18.921 -          vranges[j+1] = Math.max(bot, rbot);
  18.922 -          break;
  18.923 -        }
  18.924 -      }
  18.925 -      if (j == vranges.length) vranges.push(top, bot);
  18.926 -      data[i] = {left: size.left - outer.left, right: size.right - outer.left, top: j};
  18.927 -    }
  18.928 -    for (var i = 0, cur; i < data.length; ++i) if (cur = data[i]) {
  18.929 -      var vr = cur.top;
  18.930 -      cur.top = vranges[vr]; cur.bottom = vranges[vr+1];
  18.931 -    }
  18.932 -    return data;
  18.933 -  }
  18.934 -
  18.935 -  function clearCaches(cm) {
  18.936 -    cm.display.measureLineCache.length = cm.display.measureLineCachePos = 0;
  18.937 -    cm.display.cachedCharWidth = cm.display.cachedTextHeight = null;
  18.938 -    cm.view.maxLineChanged = true;
  18.939 -  }
  18.940 -
  18.941 -  // Context is one of "line", "div" (display.lineDiv), "local"/null (editor), or "page"
  18.942 -  function intoCoordSystem(cm, lineObj, rect, context) {
  18.943 -    if (lineObj.widgets) for (var i = 0; i < lineObj.widgets.length; ++i) if (lineObj.widgets[i].above) {
  18.944 -      var size = lineObj.widgets[i].node.offsetHeight;
  18.945 -      rect.top += size; rect.bottom += size;
  18.946 -    }
  18.947 -    if (context == "line") return rect;
  18.948 -    if (!context) context = "local";
  18.949 -    var yOff = heightAtLine(cm, lineObj);
  18.950 -    if (context != "local") yOff -= cm.display.viewOffset;
  18.951 -    if (context == "page") {
  18.952 -      var lOff = cm.display.lineSpace.getBoundingClientRect();
  18.953 -      yOff += lOff.top + (window.pageYOffset || (document.documentElement || document.body).scrollTop);
  18.954 -      var xOff = lOff.left + (window.pageXOffset || (document.documentElement || document.body).scrollLeft);
  18.955 -      rect.left += xOff; rect.right += xOff;
  18.956 -    }
  18.957 -    rect.top += yOff; rect.bottom += yOff;
  18.958 -    return rect;
  18.959 -  }
  18.960 -
  18.961 -  function charCoords(cm, pos, context, lineObj) {
  18.962 -    if (!lineObj) lineObj = getLine(cm.view.doc, pos.line);
  18.963 -    return intoCoordSystem(cm, lineObj, measureChar(cm, lineObj, pos.ch), context);
  18.964 -  }
  18.965 -
  18.966 -  function cursorCoords(cm, pos, context, lineObj, measurement) {
  18.967 -    lineObj = lineObj || getLine(cm.view.doc, pos.line);
  18.968 -    if (!measurement) measurement = measureLine(cm, lineObj);
  18.969 -    function get(ch, right) {
  18.970 -      var m = measureChar(cm, lineObj, ch, measurement);
  18.971 -      if (right) m.left = m.right; else m.right = m.left;
  18.972 -      return intoCoordSystem(cm, lineObj, m, context);
  18.973 -    }
  18.974 -    var order = getOrder(lineObj), ch = pos.ch;
  18.975 -    if (!order) return get(ch);
  18.976 -    var main, other, linedir = order[0].level;
  18.977 -    for (var i = 0; i < order.length; ++i) {
  18.978 -      var part = order[i], rtl = part.level % 2, nb, here;
  18.979 -      if (part.from < ch && part.to > ch) return get(ch, rtl);
  18.980 -      var left = rtl ? part.to : part.from, right = rtl ? part.from : part.to;
  18.981 -      if (left == ch) {
  18.982 -        // Opera and IE return bogus offsets and widths for edges
  18.983 -        // where the direction flips, but only for the side with the
  18.984 -        // lower level. So we try to use the side with the higher
  18.985 -        // level.
  18.986 -        if (i && part.level < (nb = order[i-1]).level) here = get(nb.level % 2 ? nb.from : nb.to - 1, true);
  18.987 -        else here = get(rtl && part.from != part.to ? ch - 1 : ch);
  18.988 -        if (rtl == linedir) main = here; else other = here;
  18.989 -      } else if (right == ch) {
  18.990 -        var nb = i < order.length - 1 && order[i+1];
  18.991 -        if (!rtl && nb && nb.from == nb.to) continue;
  18.992 -        if (nb && part.level < nb.level) here = get(nb.level % 2 ? nb.to - 1 : nb.from);
  18.993 -        else here = get(rtl ? ch : ch - 1, true);
  18.994 -        if (rtl == linedir) main = here; else other = here;
  18.995 -      }
  18.996 -    }
  18.997 -    if (linedir && !ch) other = get(order[0].to - 1);
  18.998 -    if (!main) return other;
  18.999 -    if (other) main.other = other;
 18.1000 -    return main;
 18.1001 -  }
 18.1002 -
 18.1003 -  // Coords must be lineSpace-local
 18.1004 -  function coordsChar(cm, x, y) {
 18.1005 -    var doc = cm.view.doc;
 18.1006 -    y += cm.display.viewOffset;
 18.1007 -    if (y < 0) return {line: 0, ch: 0, outside: true};
 18.1008 -    var lineNo = lineAtHeight(doc, y);
 18.1009 -    if (lineNo >= doc.size) return {line: doc.size - 1, ch: getLine(doc, doc.size - 1).text.length};
 18.1010 -    if (x < 0) x = 0;
 18.1011 -
 18.1012 -    for (;;) {
 18.1013 -      var lineObj = getLine(doc, lineNo);
 18.1014 -      var found = coordsCharInner(cm, lineObj, lineNo, x, y);
 18.1015 -      var merged = collapsedSpanAtEnd(lineObj);
 18.1016 -      if (merged && found.ch == lineRight(lineObj))
 18.1017 -        lineNo = merged.find().to.line;
 18.1018 -      else
 18.1019 -        return found;
 18.1020 -    }
 18.1021 -  }
 18.1022 -
 18.1023 -  function coordsCharInner(cm, lineObj, lineNo, x, y) {
 18.1024 -    var innerOff = y - heightAtLine(cm, lineObj);
 18.1025 -    var wrongLine = false, cWidth = cm.display.wrapper.clientWidth;
 18.1026 -    var measurement = measureLine(cm, lineObj);
 18.1027 -
 18.1028 -    function getX(ch) {
 18.1029 -      var sp = cursorCoords(cm, {line: lineNo, ch: ch}, "line",
 18.1030 -                            lineObj, measurement);
 18.1031 -      wrongLine = true;
 18.1032 -      if (innerOff > sp.bottom) return Math.max(0, sp.left - cWidth);
 18.1033 -      else if (innerOff < sp.top) return sp.left + cWidth;
 18.1034 -      else wrongLine = false;
 18.1035 -      return sp.left;
 18.1036 -    }
 18.1037 -
 18.1038 -    var bidi = getOrder(lineObj), dist = lineObj.text.length;
 18.1039 -    var from = lineLeft(lineObj), to = lineRight(lineObj);
 18.1040 -    var fromX = paddingLeft(cm.display), toX = getX(to);
 18.1041 -
 18.1042 -    if (x > toX) return {line: lineNo, ch: to, outside: wrongLine};
 18.1043 -    // Do a binary search between these bounds.
 18.1044 -    for (;;) {
 18.1045 -      if (bidi ? to == from || to == moveVisually(lineObj, from, 1) : to - from <= 1) {
 18.1046 -        var after = x - fromX < toX - x, ch = after ? from : to;
 18.1047 -        while (isExtendingChar.test(lineObj.text.charAt(ch))) ++ch;
 18.1048 -        return {line: lineNo, ch: ch, after: after, outside: wrongLine};
 18.1049 -      }
 18.1050 -      var step = Math.ceil(dist / 2), middle = from + step;
 18.1051 -      if (bidi) {
 18.1052 -        middle = from;
 18.1053 -        for (var i = 0; i < step; ++i) middle = moveVisually(lineObj, middle, 1);
 18.1054 -      }
 18.1055 -      var middleX = getX(middle);
 18.1056 -      if (middleX > x) {to = middle; toX = middleX; if (wrongLine) toX += 1000; dist -= step;}
 18.1057 -      else {from = middle; fromX = middleX; dist = step;}
 18.1058 -    }
 18.1059 -  }
 18.1060 -
 18.1061 -  var measureText;
 18.1062 -  function textHeight(display) {
 18.1063 -    if (display.cachedTextHeight != null) return display.cachedTextHeight;
 18.1064 -    if (measureText == null) {
 18.1065 -      measureText = elt("pre");
 18.1066 -      // Measure a bunch of lines, for browsers that compute
 18.1067 -      // fractional heights.
 18.1068 -      for (var i = 0; i < 49; ++i) {
 18.1069 -        measureText.appendChild(document.createTextNode("x"));
 18.1070 -        measureText.appendChild(elt("br"));
 18.1071 -      }
 18.1072 -      measureText.appendChild(document.createTextNode("x"));
 18.1073 -    }
 18.1074 -    removeChildrenAndAdd(display.measure, measureText);
 18.1075 -    var height = measureText.offsetHeight / 50;
 18.1076 -    if (height > 3) display.cachedTextHeight = height;
 18.1077 -    removeChildren(display.measure);
 18.1078 -    return height || 1;
 18.1079 -  }
 18.1080 -
 18.1081 -  function charWidth(display) {
 18.1082 -    if (display.cachedCharWidth != null) return display.cachedCharWidth;
 18.1083 -    var anchor = elt("span", "x");
 18.1084 -    var pre = elt("pre", [anchor]);
 18.1085 -    removeChildrenAndAdd(display.measure, pre);
 18.1086 -    var width = anchor.offsetWidth;
 18.1087 -    if (width > 2) display.cachedCharWidth = width;
 18.1088 -    return width || 10;
 18.1089 -  }
 18.1090 -
 18.1091 -  // OPERATIONS
 18.1092 -
 18.1093 -  // Operations are used to wrap changes in such a way that each
 18.1094 -  // change won't have to update the cursor and display (which would
 18.1095 -  // be awkward, slow, and error-prone), but instead updates are
 18.1096 -  // batched and then all combined and executed at once.
 18.1097 -
 18.1098 -  function startOperation(cm) {
 18.1099 -    if (cm.curOp) ++cm.curOp.depth;
 18.1100 -    else cm.curOp = {
 18.1101 -      // Nested operations delay update until the outermost one
 18.1102 -      // finishes.
 18.1103 -      depth: 1,
 18.1104 -      // An array of ranges of lines that have to be updated. See
 18.1105 -      // updateDisplay.
 18.1106 -      changes: [],
 18.1107 -      delayedCallbacks: [],
 18.1108 -      updateInput: null,
 18.1109 -      userSelChange: null,
 18.1110 -      textChanged: null,
 18.1111 -      selectionChanged: false,
 18.1112 -      updateMaxLine: false,
 18.1113 -      id: ++cm.nextOpId
 18.1114 -    };
 18.1115 -  }
 18.1116 -
 18.1117 -  function endOperation(cm) {
 18.1118 -    var op = cm.curOp;
 18.1119 -    if (--op.depth) return;
 18.1120 -    cm.curOp = null;
 18.1121 -    var view = cm.view, display = cm.display;
 18.1122 -    if (op.updateMaxLine) computeMaxLength(view);
 18.1123 -    if (view.maxLineChanged && !cm.options.lineWrapping) {
 18.1124 -      var width = measureChar(cm, view.maxLine, view.maxLine.text.length).right;
 18.1125 -      display.sizer.style.minWidth = (width + 3 + scrollerCutOff) + "px";
 18.1126 -      view.maxLineChanged = false;
 18.1127 -    }
 18.1128 -    var newScrollPos, updated;
 18.1129 -    if (op.selectionChanged) {
 18.1130 -      var coords = cursorCoords(cm, view.sel.head);
 18.1131 -      newScrollPos = calculateScrollPos(cm, coords.left, coords.top, coords.left, coords.bottom);
 18.1132 -    }
 18.1133 -    if (op.changes.length || newScrollPos && newScrollPos.scrollTop != null)
 18.1134 -      updated = updateDisplay(cm, op.changes, newScrollPos && newScrollPos.scrollTop);
 18.1135 -    if (!updated && op.selectionChanged) updateSelection(cm);
 18.1136 -    if (newScrollPos) scrollCursorIntoView(cm);
 18.1137 -    if (op.selectionChanged) restartBlink(cm);
 18.1138 -
 18.1139 -    if (view.focused && op.updateInput)
 18.1140 -      resetInput(cm, op.userSelChange);
 18.1141 -
 18.1142 -    if (op.textChanged)
 18.1143 -      signal(cm, "change", cm, op.textChanged);
 18.1144 -    if (op.selectionChanged) signal(cm, "cursorActivity", cm);
 18.1145 -    for (var i = 0; i < op.delayedCallbacks.length; ++i) op.delayedCallbacks[i](cm);
 18.1146 -  }
 18.1147 -
 18.1148 -  // Wraps a function in an operation. Returns the wrapped function.
 18.1149 -  function operation(cm1, f) {
 18.1150 -    return function() {
 18.1151 -      var cm = cm1 || this;
 18.1152 -      startOperation(cm);
 18.1153 -      try {var result = f.apply(cm, arguments);}
 18.1154 -      finally {endOperation(cm);}
 18.1155 -      return result;
 18.1156 -    };
 18.1157 -  }
 18.1158 -
 18.1159 -  function regChange(cm, from, to, lendiff) {
 18.1160 -    cm.curOp.changes.push({from: from, to: to, diff: lendiff});
 18.1161 -  }
 18.1162 -
 18.1163 -  // INPUT HANDLING
 18.1164 -
 18.1165 -  function slowPoll(cm) {
 18.1166 -    if (cm.view.pollingFast) return;
 18.1167 -    cm.display.poll.set(cm.options.pollInterval, function() {
 18.1168 -      readInput(cm);
 18.1169 -      if (cm.view.focused) slowPoll(cm);
 18.1170 -    });
 18.1171 -  }
 18.1172 -
 18.1173 -  function fastPoll(cm) {
 18.1174 -    var missed = false;
 18.1175 -    cm.display.pollingFast = true;
 18.1176 -    function p() {
 18.1177 -      var changed = readInput(cm);
 18.1178 -      if (!changed && !missed) {missed = true; cm.display.poll.set(60, p);}
 18.1179 -      else {cm.display.pollingFast = false; slowPoll(cm);}
 18.1180 -    }
 18.1181 -    cm.display.poll.set(20, p);
 18.1182 -  }
 18.1183 -
 18.1184 -  // prevInput is a hack to work with IME. If we reset the textarea
 18.1185 -  // on every change, that breaks IME. So we look for changes
 18.1186 -  // compared to the previous content instead. (Modern browsers have
 18.1187 -  // events that indicate IME taking place, but these are not widely
 18.1188 -  // supported or compatible enough yet to rely on.)
 18.1189 -  function readInput(cm) {
 18.1190 -    var input = cm.display.input, prevInput = cm.display.prevInput, view = cm.view, sel = view.sel;
 18.1191 -    if (!view.focused || hasSelection(input) || isReadOnly(cm)) return false;
 18.1192 -    var text = input.value;
 18.1193 -    if (text == prevInput && posEq(sel.from, sel.to)) return false;
 18.1194 -    startOperation(cm);
 18.1195 -    view.sel.shift = false;
 18.1196 -    var same = 0, l = Math.min(prevInput.length, text.length);
 18.1197 -    while (same < l && prevInput[same] == text[same]) ++same;
 18.1198 -    var from = sel.from, to = sel.to;
 18.1199 -    if (same < prevInput.length)
 18.1200 -      from = {line: from.line, ch: from.ch - (prevInput.length - same)};
 18.1201 -    else if (view.overwrite && posEq(from, to) && !cm.display.pasteIncoming)
 18.1202 -      to = {line: to.line, ch: Math.min(getLine(cm.view.doc, to.line).text.length, to.ch + (text.length - same))};
 18.1203 -    var updateInput = cm.curOp.updateInput;
 18.1204 -    updateDoc(cm, from, to, splitLines(text.slice(same)), "end",
 18.1205 -              cm.display.pasteIncoming ? "paste" : "input", {from: from, to: to});
 18.1206 -    cm.curOp.updateInput = updateInput;
 18.1207 -    if (text.length > 1000) input.value = cm.display.prevInput = "";
 18.1208 -    else cm.display.prevInput = text;
 18.1209 -    endOperation(cm);
 18.1210 -    cm.display.pasteIncoming = false;
 18.1211 -    return true;
 18.1212 -  }
 18.1213 -
 18.1214 -  function resetInput(cm, user) {
 18.1215 -    var view = cm.view, minimal, selected;
 18.1216 -    if (!posEq(view.sel.from, view.sel.to)) {
 18.1217 -      cm.display.prevInput = "";
 18.1218 -      minimal = hasCopyEvent &&
 18.1219 -        (view.sel.to.line - view.sel.from.line > 100 || (selected = cm.getSelection()).length > 1000);
 18.1220 -      if (minimal) cm.display.input.value = "-";
 18.1221 -      else cm.display.input.value = selected || cm.getSelection();
 18.1222 -      if (view.focused) selectInput(cm.display.input);
 18.1223 -    } else if (user) cm.display.prevInput = cm.display.input.value = "";
 18.1224 -    cm.display.inaccurateSelection = minimal;
 18.1225 -  }
 18.1226 -
 18.1227 -  function focusInput(cm) {
 18.1228 -    if (cm.options.readOnly != "nocursor" && (ie || document.activeElement != cm.display.input))
 18.1229 -      cm.display.input.focus();
 18.1230 -  }
 18.1231 -
 18.1232 -  function isReadOnly(cm) {
 18.1233 -    return cm.options.readOnly || cm.view.cantEdit;
 18.1234 -  }
 18.1235 -
 18.1236 -  // EVENT HANDLERS
 18.1237 -
 18.1238 -  function registerEventHandlers(cm) {
 18.1239 -    var d = cm.display;
 18.1240 -    on(d.scroller, "mousedown", operation(cm, onMouseDown));
 18.1241 -    on(d.scroller, "dblclick", operation(cm, e_preventDefault));
 18.1242 -    on(d.lineSpace, "selectstart", function(e) {
 18.1243 -      if (!mouseEventInWidget(d, e)) e_preventDefault(e);
 18.1244 -    });
 18.1245 -    // Gecko browsers fire contextmenu *after* opening the menu, at
 18.1246 -    // which point we can't mess with it anymore. Context menu is
 18.1247 -    // handled in onMouseDown for Gecko.
 18.1248 -    if (!gecko) on(d.scroller, "contextmenu", function(e) {onContextMenu(cm, e);});
 18.1249 -
 18.1250 -    on(d.scroller, "scroll", function() {
 18.1251 -      setScrollTop(cm, d.scroller.scrollTop);
 18.1252 -      setScrollLeft(cm, d.scroller.scrollLeft, true);
 18.1253 -      signal(cm, "scroll", cm);
 18.1254 -    });
 18.1255 -    on(d.scrollbarV, "scroll", function() {
 18.1256 -      setScrollTop(cm, d.scrollbarV.scrollTop);
 18.1257 -    });
 18.1258 -    on(d.scrollbarH, "scroll", function() {
 18.1259 -      setScrollLeft(cm, d.scrollbarH.scrollLeft);
 18.1260 -    });
 18.1261 -
 18.1262 -    on(d.scroller, "mousewheel", function(e){onScrollWheel(cm, e);});
 18.1263 -    on(d.scroller, "DOMMouseScroll", function(e){onScrollWheel(cm, e);});
 18.1264 -
 18.1265 -    function reFocus() { if (cm.view.focused) setTimeout(bind(focusInput, cm), 0); }
 18.1266 -    on(d.scrollbarH, "mousedown", reFocus);
 18.1267 -    on(d.scrollbarV, "mousedown", reFocus);
 18.1268 -    // Prevent wrapper from ever scrolling
 18.1269 -    on(d.wrapper, "scroll", function() { d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; });
 18.1270 -    on(window, "resize", function resizeHandler() {
 18.1271 -      // Might be a text scaling operation, clear size caches.
 18.1272 -      d.cachedCharWidth = d.cachedTextHeight = null;
 18.1273 -      clearCaches(cm);
 18.1274 -      if (d.wrapper.parentNode) updateDisplay(cm, true);
 18.1275 -      else off(window, "resize", resizeHandler);
 18.1276 -    });
 18.1277 -
 18.1278 -    on(d.input, "keyup", operation(cm, function(e) {
 18.1279 -      if (cm.options.onKeyEvent && cm.options.onKeyEvent(cm, addStop(e))) return;
 18.1280 -      if (e_prop(e, "keyCode") == 16) cm.view.sel.shift = false;
 18.1281 -    }));
 18.1282 -    on(d.input, "input", bind(fastPoll, cm));
 18.1283 -    on(d.input, "keydown", operation(cm, onKeyDown));
 18.1284 -    on(d.input, "keypress", operation(cm, onKeyPress));
 18.1285 -    on(d.input, "focus", bind(onFocus, cm));
 18.1286 -    on(d.input, "blur", bind(onBlur, cm));
 18.1287 -
 18.1288 -    function drag_(e) {
 18.1289 -      if (cm.options.onDragEvent && cm.options.onDragEvent(cm, addStop(e))) return;
 18.1290 -      e_stop(e);
 18.1291 -    }
 18.1292 -    if (cm.options.dragDrop) {
 18.1293 -      on(d.scroller, "dragstart", function(e){onDragStart(cm, e);});
 18.1294 -      on(d.scroller, "dragenter", drag_);
 18.1295 -      on(d.scroller, "dragover", drag_);
 18.1296 -      on(d.scroller, "drop", operation(cm, onDrop));
 18.1297 -    }
 18.1298 -    on(d.scroller, "paste", function(){focusInput(cm); fastPoll(cm);});
 18.1299 -    on(d.input, "paste", function() {
 18.1300 -      d.pasteIncoming = true;
 18.1301 -      fastPoll(cm);
 18.1302 -    });
 18.1303 -
 18.1304 -    function prepareCopy() {
 18.1305 -      if (d.inaccurateSelection) {
 18.1306 -        d.prevInput = "";
 18.1307 -        d.inaccurateSelection = false;
 18.1308 -        d.input.value = cm.getSelection();
 18.1309 -        selectInput(d.input);
 18.1310 -      }
 18.1311 -    }
 18.1312 -    on(d.input, "cut", prepareCopy);
 18.1313 -    on(d.input, "copy", prepareCopy);
 18.1314 -
 18.1315 -    // Needed to handle Tab key in KHTML
 18.1316 -    if (khtml) on(d.sizer, "mouseup", function() {
 18.1317 -        if (document.activeElement == d.input) d.input.blur();
 18.1318 -        focusInput(cm);
 18.1319 -    });
 18.1320 -  }
 18.1321 -
 18.1322 -  function mouseEventInWidget(display, e) {
 18.1323 -    for (var n = e_target(e); n != display.wrapper; n = n.parentNode)
 18.1324 -      if (/\bCodeMirror-(?:line)?widget\b/.test(n.className) ||
 18.1325 -          n.parentNode == display.sizer && n != display.mover) return true;
 18.1326 -  }
 18.1327 -
 18.1328 -  function posFromMouse(cm, e, liberal) {
 18.1329 -    var display = cm.display;
 18.1330 -    if (!liberal) {
 18.1331 -      var target = e_target(e);
 18.1332 -      if (target == display.scrollbarH || target == display.scrollbarH.firstChild ||
 18.1333 -          target == display.scrollbarV || target == display.scrollbarV.firstChild ||
 18.1334 -          target == display.scrollbarFiller) return null;
 18.1335 -    }
 18.1336 -    var x, y, space = display.lineSpace.getBoundingClientRect();
 18.1337 -    // Fails unpredictably on IE[67] when mouse is dragged around quickly.
 18.1338 -    try { x = e.clientX; y = e.clientY; } catch (e) { return null; }
 18.1339 -    return coordsChar(cm, x - space.left, y - space.top);
 18.1340 -  }
 18.1341 -
 18.1342 -  var lastClick, lastDoubleClick;
 18.1343 -  function onMouseDown(e) {
 18.1344 -    var cm = this, display = cm.display, view = cm.view, sel = view.sel, doc = view.doc;
 18.1345 -    sel.shift = e_prop(e, "shiftKey");
 18.1346 -
 18.1347 -    if (mouseEventInWidget(display, e)) {
 18.1348 -      if (!webkit) {
 18.1349 -        display.scroller.draggable = false;
 18.1350 -        setTimeout(function(){display.scroller.draggable = true;}, 100);
 18.1351 -      }
 18.1352 -      return;
 18.1353 -    }
 18.1354 -    if (clickInGutter(cm, e)) return;
 18.1355 -    var start = posFromMouse(cm, e);
 18.1356 -
 18.1357 -    switch (e_button(e)) {
 18.1358 -    case 3:
 18.1359 -      if (gecko) onContextMenu.call(cm, cm, e);
 18.1360 -      return;
 18.1361 -    case 2:
 18.1362 -      if (start) extendSelection(cm, start);
 18.1363 -      setTimeout(bind(focusInput, cm), 20);
 18.1364 -      e_preventDefault(e);
 18.1365 -      return;
 18.1366 -    }
 18.1367 -    // For button 1, if it was clicked inside the editor
 18.1368 -    // (posFromMouse returning non-null), we have to adjust the
 18.1369 -    // selection.
 18.1370 -    if (!start) {if (e_target(e) == display.scroller) e_preventDefault(e); return;}
 18.1371 -
 18.1372 -    if (!view.focused) onFocus(cm);
 18.1373 -
 18.1374 -    var now = +new Date, type = "single";
 18.1375 -    if (lastDoubleClick && lastDoubleClick.time > now - 400 && posEq(lastDoubleClick.pos, start)) {
 18.1376 -      type = "triple";
 18.1377 -      e_preventDefault(e);
 18.1378 -      setTimeout(bind(focusInput, cm), 20);
 18.1379 -      selectLine(cm, start.line);
 18.1380 -    } else if (lastClick && lastClick.time > now - 400 && posEq(lastClick.pos, start)) {
 18.1381 -      type = "double";
 18.1382 -      lastDoubleClick = {time: now, pos: start};
 18.1383 -      e_preventDefault(e);
 18.1384 -      var word = findWordAt(getLine(doc, start.line).text, start);
 18.1385 -      extendSelection(cm, word.from, word.to);
 18.1386 -    } else { lastClick = {time: now, pos: start}; }
 18.1387 -
 18.1388 -    var last = start;
 18.1389 -    if (cm.options.dragDrop && dragAndDrop && !isReadOnly(cm) && !posEq(sel.from, sel.to) &&
 18.1390 -        !posLess(start, sel.from) && !posLess(sel.to, start) && type == "single") {
 18.1391 -      var dragEnd = operation(cm, function(e2) {
 18.1392 -        if (webkit) display.scroller.draggable = false;
 18.1393 -        view.draggingText = false;
 18.1394 -        off(document, "mouseup", dragEnd);
 18.1395 -        off(display.scroller, "drop", dragEnd);
 18.1396 -        if (Math.abs(e.clientX - e2.clientX) + Math.abs(e.clientY - e2.clientY) < 10) {
 18.1397 -          e_preventDefault(e2);
 18.1398 -          extendSelection(cm, start);
 18.1399 -          focusInput(cm);
 18.1400 -        }
 18.1401 -      });
 18.1402 -      // Let the drag handler handle this.
 18.1403 -      if (webkit) display.scroller.draggable = true;
 18.1404 -      view.draggingText = dragEnd;
 18.1405 -      // IE's approach to draggable
 18.1406 -      if (display.scroller.dragDrop) display.scroller.dragDrop();
 18.1407 -      on(document, "mouseup", dragEnd);
 18.1408 -      on(display.scroller, "drop", dragEnd);
 18.1409 -      return;
 18.1410 -    }
 18.1411 -    e_preventDefault(e);
 18.1412 -    if (type == "single") extendSelection(cm, clipPos(doc, start));
 18.1413 -
 18.1414 -    var startstart = sel.from, startend = sel.to;
 18.1415 -
 18.1416 -    function doSelect(cur) {
 18.1417 -      if (type == "single") {
 18.1418 -        extendSelection(cm, clipPos(doc, start), cur);
 18.1419 -        return;
 18.1420 -      }
 18.1421 -
 18.1422 -      startstart = clipPos(doc, startstart);
 18.1423 -      startend = clipPos(doc, startend);
 18.1424 -      if (type == "double") {
 18.1425 -        var word = findWordAt(getLine(doc, cur.line).text, cur);
 18.1426 -        if (posLess(cur, startstart)) extendSelection(cm, word.from, startend);
 18.1427 -        else extendSelection(cm, startstart, word.to);
 18.1428 -      } else if (type == "triple") {
 18.1429 -        if (posLess(cur, startstart)) extendSelection(cm, startend, clipPos(doc, {line: cur.line, ch: 0}));
 18.1430 -        else extendSelection(cm, startstart, clipPos(doc, {line: cur.line + 1, ch: 0}));
 18.1431 -      }
 18.1432 -    }
 18.1433 -
 18.1434 -    var editorSize = display.wrapper.getBoundingClientRect();
 18.1435 -    // Used to ensure timeout re-tries don't fire when another extend
 18.1436 -    // happened in the meantime (clearTimeout isn't reliable -- at
 18.1437 -    // least on Chrome, the timeouts still happen even when cleared,
 18.1438 -    // if the clear happens after their scheduled firing time).
 18.1439 -    var counter = 0;
 18.1440 -
 18.1441 -    function extend(e) {
 18.1442 -      var curCount = ++counter;
 18.1443 -      var cur = posFromMouse(cm, e, true);
 18.1444 -      if (!cur) return;
 18.1445 -      if (!posEq(cur, last)) {
 18.1446 -        if (!view.focused) onFocus(cm);
 18.1447 -        last = cur;
 18.1448 -        doSelect(cur);
 18.1449 -        var visible = visibleLines(display, doc);
 18.1450 -        if (cur.line >= visible.to || cur.line < visible.from)
 18.1451 -          setTimeout(operation(cm, function(){if (counter == curCount) extend(e);}), 150);
 18.1452 -      } else {
 18.1453 -        var outside = e.clientY < editorSize.top ? -20 : e.clientY > editorSize.bottom ? 20 : 0;
 18.1454 -        if (outside) setTimeout(operation(cm, function() {
 18.1455 -          if (counter != curCount) return;
 18.1456 -          display.scroller.scrollTop += outside;
 18.1457 -          extend(e);
 18.1458 -        }), 50);
 18.1459 -      }
 18.1460 -    }
 18.1461 -
 18.1462 -    function done(e) {
 18.1463 -      counter = Infinity;
 18.1464 -      var cur = posFromMouse(cm, e);
 18.1465 -      if (cur) doSelect(cur);
 18.1466 -      e_preventDefault(e);
 18.1467 -      focusInput(cm);
 18.1468 -      off(document, "mousemove", move);
 18.1469 -      off(document, "mouseup", up);
 18.1470 -    }
 18.1471 -
 18.1472 -    var move = operation(cm, function(e) {
 18.1473 -      if (!ie && !e_button(e)) done(e);
 18.1474 -      else extend(e);
 18.1475 -    });
 18.1476 -    var up = operation(cm, done);
 18.1477 -    on(document, "mousemove", move);
 18.1478 -    on(document, "mouseup", up);
 18.1479 -  }
 18.1480 -
 18.1481 -  function onDrop(e) {
 18.1482 -    var cm = this;
 18.1483 -    if (cm.options.onDragEvent && cm.options.onDragEvent(cm, addStop(e))) return;
 18.1484 -    e_preventDefault(e);
 18.1485 -    var pos = posFromMouse(cm, e, true), files = e.dataTransfer.files;
 18.1486 -    if (!pos || isReadOnly(cm)) return;
 18.1487 -    if (files && files.length && window.FileReader && window.File) {
 18.1488 -      var n = files.length, text = Array(n), read = 0;
 18.1489 -      var loadFile = function(file, i) {
 18.1490 -        var reader = new FileReader;
 18.1491 -        reader.onload = function() {
 18.1492 -          text[i] = reader.result;
 18.1493 -          if (++read == n) {
 18.1494 -            pos = clipPos(cm.view.doc, pos);
 18.1495 -            operation(cm, function() {
 18.1496 -              var end = replaceRange(cm, text.join(""), pos, pos, "paste");
 18.1497 -              setSelection(cm, pos, end);
 18.1498 -            })();
 18.1499 -          }
 18.1500 -        };
 18.1501 -        reader.readAsText(file);
 18.1502 -      };
 18.1503 -      for (var i = 0; i < n; ++i) loadFile(files[i], i);
 18.1504 -    } else {
 18.1505 -      // Don't do a replace if the drop happened inside of the selected text.
 18.1506 -      if (cm.view.draggingText && !(posLess(pos, cm.view.sel.from) || posLess(cm.view.sel.to, pos))) {
 18.1507 -        cm.view.draggingText(e);
 18.1508 -        if (ie) setTimeout(bind(focusInput, cm), 50);
 18.1509 -        return;
 18.1510 -      }
 18.1511 -      try {
 18.1512 -        var text = e.dataTransfer.getData("Text");
 18.1513 -        if (text) {
 18.1514 -          var curFrom = cm.view.sel.from, curTo = cm.view.sel.to;
 18.1515 -          setSelection(cm, pos, pos);
 18.1516 -          if (cm.view.draggingText) replaceRange(cm, "", curFrom, curTo, "paste");
 18.1517 -          cm.replaceSelection(text, null, "paste");
 18.1518 -          focusInput(cm);
 18.1519 -          onFocus(cm);
 18.1520 -        }
 18.1521 -      }
 18.1522 -      catch(e){}
 18.1523 -    }
 18.1524 -  }
 18.1525 -
 18.1526 -  function clickInGutter(cm, e) {
 18.1527 -    var display = cm.display;
 18.1528 -    try { var mX = e.clientX, mY = e.clientY; }
 18.1529 -    catch(e) { return false; }
 18.1530 -
 18.1531 -    if (mX >= Math.floor(display.gutters.getBoundingClientRect().right)) return false;
 18.1532 -    e_preventDefault(e);
 18.1533 -    if (!hasHandler(cm, "gutterClick")) return true;
 18.1534 -
 18.1535 -    var lineBox = display.lineDiv.getBoundingClientRect();
 18.1536 -    if (mY > lineBox.bottom) return true;
 18.1537 -    mY -= lineBox.top - display.viewOffset;
 18.1538 -
 18.1539 -    for (var i = 0; i < cm.options.gutters.length; ++i) {
 18.1540 -      var g = display.gutters.childNodes[i];
 18.1541 -      if (g && g.getBoundingClientRect().right >= mX) {
 18.1542 -        var line = lineAtHeight(cm.view.doc, mY);
 18.1543 -        var gutter = cm.options.gutters[i];
 18.1544 -        signalLater(cm, cm, "gutterClick", cm, line, gutter, e);
 18.1545 -        break;
 18.1546 -      }
 18.1547 -    }
 18.1548 -    return true;
 18.1549 -  }
 18.1550 -
 18.1551 -  function onDragStart(cm, e) {
 18.1552 -    var txt = cm.getSelection();
 18.1553 -    e.dataTransfer.setData("Text", txt);
 18.1554 -
 18.1555 -    // Use dummy image instead of default browsers image.
 18.1556 -    // Recent Safari (~6.0.2) have a tendency to segfault when this happens, so we don't do it there.
 18.1557 -    if (e.dataTransfer.setDragImage && !safari)
 18.1558 -      e.dataTransfer.setDragImage(elt('img'), 0, 0);
 18.1559 -  }
 18.1560 -
 18.1561 -  function setScrollTop(cm, val) {
 18.1562 -    if (Math.abs(cm.view.scrollTop - val) < 2) return;
 18.1563 -    cm.view.scrollTop = val;
 18.1564 -    if (!gecko) updateDisplay(cm, [], val);
 18.1565 -    if (cm.display.scroller.scrollTop != val) cm.display.scroller.scrollTop = val;
 18.1566 -    if (cm.display.scrollbarV.scrollTop != val) cm.display.scrollbarV.scrollTop = val;
 18.1567 -    if (gecko) updateDisplay(cm, []);
 18.1568 -  }
 18.1569 -  function setScrollLeft(cm, val, isScroller) {
 18.1570 -    if (isScroller ? val == cm.view.scrollLeft : Math.abs(cm.view.scrollLeft - val) < 2) return;
 18.1571 -    cm.view.scrollLeft = val;
 18.1572 -    alignHorizontally(cm);
 18.1573 -    if (cm.display.scroller.scrollLeft != val) cm.display.scroller.scrollLeft = val;
 18.1574 -    if (cm.display.scrollbarH.scrollLeft != val) cm.display.scrollbarH.scrollLeft = val;
 18.1575 -  }
 18.1576 -
 18.1577 -  // Since the delta values reported on mouse wheel events are
 18.1578 -  // unstandardized between browsers and even browser versions, and
 18.1579 -  // generally horribly unpredictable, this code starts by measuring
 18.1580 -  // the scroll effect that the first few mouse wheel events have,
 18.1581 -  // and, from that, detects the way it can convert deltas to pixel
 18.1582 -  // offsets afterwards.
 18.1583 -  //
 18.1584 -  // The reason we want to know the amount a wheel event will scroll
 18.1585 -  // is that it gives us a chance to update the display before the
 18.1586 -  // actual scrolling happens, reducing flickering.
 18.1587 -
 18.1588 -  var wheelSamples = 0, wheelDX, wheelDY, wheelStartX, wheelStartY, wheelPixelsPerUnit = null;
 18.1589 -  // Fill in a browser-detected starting value on browsers where we
 18.1590 -  // know one. These don't have to be accurate -- the result of them
 18.1591 -  // being wrong would just be a slight flicker on the first wheel
 18.1592 -  // scroll (if it is large enough).
 18.1593 -  if (ie) wheelPixelsPerUnit = -.53;
 18.1594 -  else if (gecko) wheelPixelsPerUnit = 15;
 18.1595 -  else if (chrome) wheelPixelsPerUnit = -.7;
 18.1596 -  else if (safari) wheelPixelsPerUnit = -1/3;
 18.1597 -
 18.1598 -  function onScrollWheel(cm, e) {
 18.1599 -    var dx = e.wheelDeltaX, dy = e.wheelDeltaY;
 18.1600 -    if (dx == null && e.detail && e.axis == e.HORIZONTAL_AXIS) dx = e.detail;
 18.1601 -    if (dy == null && e.detail && e.axis == e.VERTICAL_AXIS) dy = e.detail;
 18.1602 -    else if (dy == null) dy = e.wheelDelta;
 18.1603 -
 18.1604 -    // Webkit browsers on OS X abort momentum scrolls when the target
 18.1605 -    // of the scroll event is removed from the scrollable element.
 18.1606 -    // This hack (see related code in patchDisplay) makes sure the
 18.1607 -    // element is kept around.
 18.1608 -    if (dy && mac && webkit) {
 18.1609 -      for (var cur = e.target; cur != scroll; cur = cur.parentNode) {
 18.1610 -        if (cur.lineObj) {
 18.1611 -          cm.display.currentWheelTarget = cur;
 18.1612 -          break;
 18.1613 -        }
 18.1614 -      }
 18.1615 -    }
 18.1616 -
 18.1617 -    var scroll = cm.display.scroller;
 18.1618 -    // On some browsers, horizontal scrolling will cause redraws to
 18.1619 -    // happen before the gutter has been realigned, causing it to
 18.1620 -    // wriggle around in a most unseemly way. When we have an
 18.1621 -    // estimated pixels/delta value, we just handle horizontal
 18.1622 -    // scrolling entirely here. It'll be slightly off from native, but
 18.1623 -    // better than glitching out.
 18.1624 -    if (dx && !gecko && !opera && wheelPixelsPerUnit != null) {
 18.1625 -      if (dy)
 18.1626 -        setScrollTop(cm, Math.max(0, Math.min(scroll.scrollTop + dy * wheelPixelsPerUnit, scroll.scrollHeight - scroll.clientHeight)));
 18.1627 -      setScrollLeft(cm, Math.max(0, Math.min(scroll.scrollLeft + dx * wheelPixelsPerUnit, scroll.scrollWidth - scroll.clientWidth)));
 18.1628 -      e_preventDefault(e);
 18.1629 -      wheelStartX = null; // Abort measurement, if in progress
 18.1630 -      return;
 18.1631 -    }
 18.1632 -
 18.1633 -    if (dy && wheelPixelsPerUnit != null) {
 18.1634 -      var pixels = dy * wheelPixelsPerUnit;
 18.1635 -      var top = cm.view.scrollTop, bot = top + cm.display.wrapper.clientHeight;
 18.1636 -      if (pixels < 0) top = Math.max(0, top + pixels - 50);
 18.1637 -      else bot = Math.min(cm.view.doc.height, bot + pixels + 50);
 18.1638 -      updateDisplay(cm, [], {top: top, bottom: bot});
 18.1639 -    }
 18.1640 -
 18.1641 -    if (wheelSamples < 20) {
 18.1642 -      if (wheelStartX == null) {
 18.1643 -        wheelStartX = scroll.scrollLeft; wheelStartY = scroll.scrollTop;
 18.1644 -        wheelDX = dx; wheelDY = dy;
 18.1645 -        setTimeout(function() {
 18.1646 -          if (wheelStartX == null) return;
 18.1647 -          var movedX = scroll.scrollLeft - wheelStartX;
 18.1648 -          var movedY = scroll.scrollTop - wheelStartY;
 18.1649 -          var sample = (movedY && wheelDY && movedY / wheelDY) ||
 18.1650 -            (movedX && wheelDX && movedX / wheelDX);
 18.1651 -          wheelStartX = wheelStartY = null;
 18.1652 -          if (!sample) return;
 18.1653 -          wheelPixelsPerUnit = (wheelPixelsPerUnit * wheelSamples + sample) / (wheelSamples + 1);
 18.1654 -          ++wheelSamples;
 18.1655 -        }, 200);
 18.1656 -      } else {
 18.1657 -        wheelDX += dx; wheelDY += dy;
 18.1658 -      }
 18.1659 -    }
 18.1660 -  }
 18.1661 -
 18.1662 -  function doHandleBinding(cm, bound, dropShift) {
 18.1663 -    if (typeof bound == "string") {
 18.1664 -      bound = commands[bound];
 18.1665 -      if (!bound) return false;
 18.1666 -    }
 18.1667 -    // Ensure previous input has been read, so that the handler sees a
 18.1668 -    // consistent view of the document
 18.1669 -    if (cm.display.pollingFast && readInput(cm)) cm.display.pollingFast = false;
 18.1670 -    var view = cm.view, prevShift = view.sel.shift;
 18.1671 -    try {
 18.1672 -      if (isReadOnly(cm)) view.suppressEdits = true;
 18.1673 -      if (dropShift) view.sel.shift = false;
 18.1674 -      bound(cm);
 18.1675 -    } catch(e) {
 18.1676 -      if (e != Pass) throw e;
 18.1677 -      return false;
 18.1678 -    } finally {
 18.1679 -      view.sel.shift = prevShift;
 18.1680 -      view.suppressEdits = false;
 18.1681 -    }
 18.1682 -    return true;
 18.1683 -  }
 18.1684 -
 18.1685 -  function allKeyMaps(cm) {
 18.1686 -    var maps = cm.view.keyMaps.slice(0);
 18.1687 -    maps.push(cm.options.keyMap);
 18.1688 -    if (cm.options.extraKeys) maps.unshift(cm.options.extraKeys);
 18.1689 -    return maps;
 18.1690 -  }
 18.1691 -
 18.1692 -  var maybeTransition;
 18.1693 -  function handleKeyBinding(cm, e) {
 18.1694 -    // Handle auto keymap transitions
 18.1695 -    var startMap = getKeyMap(cm.options.keyMap), next = startMap.auto;
 18.1696 -    clearTimeout(maybeTransition);
 18.1697 -    if (next && !isModifierKey(e)) maybeTransition = setTimeout(function() {
 18.1698 -      if (getKeyMap(cm.options.keyMap) == startMap)
 18.1699 -        cm.options.keyMap = (next.call ? next.call(null, cm) : next);
 18.1700 -    }, 50);
 18.1701 -
 18.1702 -    var name = keyNames[e_prop(e, "keyCode")], handled = false;
 18.1703 -    var flipCtrlCmd = mac && (opera || qtwebkit);
 18.1704 -    if (name == null || e.altGraphKey) return false;
 18.1705 -    if (e_prop(e, "altKey")) name = "Alt-" + name;
 18.1706 -    if (e_prop(e, flipCtrlCmd ? "metaKey" : "ctrlKey")) name = "Ctrl-" + name;
 18.1707 -    if (e_prop(e, flipCtrlCmd ? "ctrlKey" : "metaKey")) name = "Cmd-" + name;
 18.1708 -
 18.1709 -    var stopped = false;
 18.1710 -    function stop() { stopped = true; }
 18.1711 -    var keymaps = allKeyMaps(cm);
 18.1712 -
 18.1713 -    if (e_prop(e, "shiftKey")) {
 18.1714 -      handled = lookupKey("Shift-" + name, keymaps,
 18.1715 -                          function(b) {return doHandleBinding(cm, b, true);}, stop)
 18.1716 -        || lookupKey(name, keymaps, function(b) {
 18.1717 -          if (typeof b == "string" && /^go[A-Z]/.test(b)) return doHandleBinding(cm, b);
 18.1718 -        }, stop);
 18.1719 -    } else {
 18.1720 -      handled = lookupKey(name, keymaps,
 18.1721 -                          function(b) { return doHandleBinding(cm, b); }, stop);
 18.1722 -    }
 18.1723 -    if (stopped) handled = false;
 18.1724 -    if (handled) {
 18.1725 -      e_preventDefault(e);
 18.1726 -      restartBlink(cm);
 18.1727 -      if (ie_lt9) { e.oldKeyCode = e.keyCode; e.keyCode = 0; }
 18.1728 -    }
 18.1729 -    return handled;
 18.1730 -  }
 18.1731 -
 18.1732 -  function handleCharBinding(cm, e, ch) {
 18.1733 -    var handled = lookupKey("'" + ch + "'", allKeyMaps(cm),
 18.1734 -                            function(b) { return doHandleBinding(cm, b, true); });
 18.1735 -    if (handled) {
 18.1736 -      e_preventDefault(e);
 18.1737 -      restartBlink(cm);
 18.1738 -    }
 18.1739 -    return handled;
 18.1740 -  }
 18.1741 -
 18.1742 -  var lastStoppedKey = null;
 18.1743 -  function onKeyDown(e) {
 18.1744 -    var cm = this;
 18.1745 -    if (!cm.view.focused) onFocus(cm);
 18.1746 -    if (ie && e.keyCode == 27) { e.returnValue = false; }
 18.1747 -    if (cm.options.onKeyEvent && cm.options.onKeyEvent(cm, addStop(e))) return;
 18.1748 -    var code = e_prop(e, "keyCode");
 18.1749 -    // IE does strange things with escape.
 18.1750 -    cm.view.sel.shift = code == 16 || e_prop(e, "shiftKey");
 18.1751 -    // First give onKeyEvent option a chance to handle this.
 18.1752 -    var handled = handleKeyBinding(cm, e);
 18.1753 -    if (opera) {
 18.1754 -      lastStoppedKey = handled ? code : null;
 18.1755 -      // Opera has no cut event... we try to at least catch the key combo
 18.1756 -      if (!handled && code == 88 && !hasCopyEvent && e_prop(e, mac ? "metaKey" : "ctrlKey"))
 18.1757 -        cm.replaceSelection("");
 18.1758 -    }
 18.1759 -  }
 18.1760 -
 18.1761 -  function onKeyPress(e) {
 18.1762 -    var cm = this;
 18.1763 -    if (cm.options.onKeyEvent && cm.options.onKeyEvent(cm, addStop(e))) return;
 18.1764 -    var keyCode = e_prop(e, "keyCode"), charCode = e_prop(e, "charCode");
 18.1765 -    if (opera && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return;}
 18.1766 -    if (((opera && (!e.which || e.which < 10)) || khtml) && handleKeyBinding(cm, e)) return;
 18.1767 -    var ch = String.fromCharCode(charCode == null ? keyCode : charCode);
 18.1768 -    if (this.options.electricChars && this.view.mode.electricChars &&
 18.1769 -        this.options.smartIndent && !isReadOnly(this) &&
 18.1770 -        this.view.mode.electricChars.indexOf(ch) > -1)
 18.1771 -      setTimeout(operation(cm, function() {indentLine(cm, cm.view.sel.to.line, "smart");}), 75);
 18.1772 -    if (handleCharBinding(cm, e, ch)) return;
 18.1773 -    fastPoll(cm);
 18.1774 -  }
 18.1775 -
 18.1776 -  function onFocus(cm) {
 18.1777 -    if (cm.options.readOnly == "nocursor") return;
 18.1778 -    if (!cm.view.focused) {
 18.1779 -      signal(cm, "focus", cm);
 18.1780 -      cm.view.focused = true;
 18.1781 -      if (cm.display.scroller.className.search(/\bCodeMirror-focused\b/) == -1)
 18.1782 -        cm.display.scroller.className += " CodeMirror-focused";
 18.1783 -      resetInput(cm, true);
 18.1784 -    }
 18.1785 -    slowPoll(cm);
 18.1786 -    restartBlink(cm);
 18.1787 -  }
 18.1788 -  function onBlur(cm) {
 18.1789 -    if (cm.view.focused) {
 18.1790 -      signal(cm, "blur", cm);
 18.1791 -      cm.view.focused = false;
 18.1792 -      cm.display.scroller.className = cm.display.scroller.className.replace(" CodeMirror-focused", "");
 18.1793 -    }
 18.1794 -    clearInterval(cm.display.blinker);
 18.1795 -    setTimeout(function() {if (!cm.view.focused) cm.view.sel.shift = false;}, 150);
 18.1796 -  }
 18.1797 -
 18.1798 -  var detectingSelectAll;
 18.1799 -  function onContextMenu(cm, e) {
 18.1800 -    var display = cm.display, sel = cm.view.sel;
 18.1801 -    var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop;
 18.1802 -    if (!pos || opera) return; // Opera is difficult.
 18.1803 -    if (posEq(sel.from, sel.to) || posLess(pos, sel.from) || !posLess(pos, sel.to))
 18.1804 -      operation(cm, setSelection)(cm, pos, pos);
 18.1805 -
 18.1806 -    var oldCSS = display.input.style.cssText;
 18.1807 -    display.inputDiv.style.position = "absolute";
 18.1808 -    display.input.style.cssText = "position: fixed; width: 30px; height: 30px; top: " + (e.clientY - 5) +
 18.1809 -      "px; left: " + (e.clientX - 5) + "px; z-index: 1000; background: white; outline: none;" +
 18.1810 -      "border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);";
 18.1811 -    focusInput(cm);
 18.1812 -    resetInput(cm, true);
 18.1813 -    // Adds "Select all" to context menu in FF
 18.1814 -    if (posEq(sel.from, sel.to)) display.input.value = display.prevInput = " ";
 18.1815 -
 18.1816 -    function rehide() {
 18.1817 -      display.inputDiv.style.position = "relative";
 18.1818 -      display.input.style.cssText = oldCSS;
 18.1819 -      if (ie_lt9) display.scrollbarV.scrollTop = display.scroller.scrollTop = scrollPos;
 18.1820 -      slowPoll(cm);
 18.1821 -
 18.1822 -      // Try to detect the user choosing select-all 
 18.1823 -      if (display.input.selectionStart != null) {
 18.1824 -        clearTimeout(detectingSelectAll);
 18.1825 -        var extval = display.input.value = " " + (posEq(sel.from, sel.to) ? "" : display.input.value), i = 0;
 18.1826 -        display.prevInput = " ";
 18.1827 -        display.input.selectionStart = 1; display.input.selectionEnd = extval.length;
 18.1828 -        detectingSelectAll = setTimeout(function poll(){
 18.1829 -          if (display.prevInput == " " && display.input.selectionStart == 0)
 18.1830 -            operation(cm, commands.selectAll)(cm);
 18.1831 -          else if (i++ < 10) detectingSelectAll = setTimeout(poll, 500);
 18.1832 -          else resetInput(cm);
 18.1833 -        }, 200);
 18.1834 -      }
 18.1835 -    }
 18.1836 -
 18.1837 -    if (gecko) {
 18.1838 -      e_stop(e);
 18.1839 -      on(window, "mouseup", function mouseup() {
 18.1840 -        off(window, "mouseup", mouseup);
 18.1841 -        setTimeout(rehide, 20);
 18.1842 -      });
 18.1843 -    } else {
 18.1844 -      setTimeout(rehide, 50);
 18.1845 -    }
 18.1846 -  }
 18.1847 -
 18.1848 -  // UPDATING
 18.1849 -
 18.1850 -  // Replace the range from from to to by the strings in newText.
 18.1851 -  // Afterwards, set the selection to selFrom, selTo.
 18.1852 -  function updateDoc(cm, from, to, newText, selUpdate, origin) {
 18.1853 -    // Possibly split or suppress the update based on the presence
 18.1854 -    // of read-only spans in its range.
 18.1855 -    var split = sawReadOnlySpans &&
 18.1856 -      removeReadOnlyRanges(cm.view.doc, from, to);
 18.1857 -    if (split) {
 18.1858 -      for (var i = split.length - 1; i >= 1; --i)
 18.1859 -        updateDocInner(cm, split[i].from, split[i].to, [""], origin);
 18.1860 -      if (split.length)
 18.1861 -        return updateDocInner(cm, split[0].from, split[0].to, newText, selUpdate, origin);
 18.1862 -    } else {
 18.1863 -      return updateDocInner(cm, from, to, newText, selUpdate, origin);
 18.1864 -    }
 18.1865 -  }
 18.1866 -
 18.1867 -  function updateDocInner(cm, from, to, newText, selUpdate, origin) {
 18.1868 -    if (cm.view.suppressEdits) return;
 18.1869 -
 18.1870 -    var view = cm.view, doc = view.doc, old = [];
 18.1871 -    doc.iter(from.line, to.line + 1, function(line) {
 18.1872 -      old.push(newHL(line.text, line.markedSpans));
 18.1873 -    });
 18.1874 -    var startSelFrom = view.sel.from, startSelTo = view.sel.to;
 18.1875 -    var lines = updateMarkedSpans(hlSpans(old[0]), hlSpans(lst(old)), from.ch, to.ch, newText);
 18.1876 -    var retval = updateDocNoUndo(cm, from, to, lines, selUpdate, origin);
 18.1877 -    if (view.history) addChange(cm, from.line, newText.length, old, origin,
 18.1878 -                                startSelFrom, startSelTo, view.sel.from, view.sel.to);
 18.1879 -    return retval;
 18.1880 -  }
 18.1881 -
 18.1882 -  function unredoHelper(cm, type) {
 18.1883 -    var doc = cm.view.doc, hist = cm.view.history;
 18.1884 -    var set = (type == "undo" ? hist.done : hist.undone).pop();
 18.1885 -    if (!set) return;
 18.1886 -    var anti = {events: [], fromBefore: set.fromAfter, toBefore: set.toAfter,
 18.1887 -                fromAfter: set.fromBefore, toAfter: set.toBefore};
 18.1888 -    for (var i = set.events.length - 1; i >= 0; i -= 1) {
 18.1889 -      hist.dirtyCounter += type == "undo" ? -1 : 1;
 18.1890 -      var change = set.events[i];
 18.1891 -      var replaced = [], end = change.start + change.added;
 18.1892 -      doc.iter(change.start, end, function(line) { replaced.push(newHL(line.text, line.markedSpans)); });
 18.1893 -      anti.events.push({start: change.start, added: change.old.length, old: replaced});
 18.1894 -      var selPos = i ? null : {from: set.fromBefore, to: set.toBefore};
 18.1895 -      updateDocNoUndo(cm, {line: change.start, ch: 0}, {line: end - 1, ch: getLine(doc, end-1).text.length},
 18.1896 -                      change.old, selPos, type);
 18.1897 -    }
 18.1898 -    (type == "undo" ? hist.undone : hist.done).push(anti);
 18.1899 -  }
 18.1900 -
 18.1901 -  function updateDocNoUndo(cm, from, to, lines, selUpdate, origin) {
 18.1902 -    var view = cm.view, doc = view.doc, display = cm.display;
 18.1903 -    if (view.suppressEdits) return;
 18.1904 -
 18.1905 -    var nlines = to.line - from.line, firstLine = getLine(doc, from.line), lastLine = getLine(doc, to.line);
 18.1906 -    var recomputeMaxLength = false, checkWidthStart = from.line;
 18.1907 -    if (!cm.options.lineWrapping) {
 18.1908 -      checkWidthStart = lineNo(visualLine(doc, firstLine));
 18.1909 -      doc.iter(checkWidthStart, to.line + 1, function(line) {
 18.1910 -        if (lineLength(doc, line) == view.maxLineLength) {
 18.1911 -          recomputeMaxLength = true;
 18.1912 -          return true;
 18.1913 -        }
 18.1914 -      });
 18.1915 -    }
 18.1916 -
 18.1917 -    var lastHL = lst(lines), th = textHeight(display);
 18.1918 -
 18.1919 -    // First adjust the line structure
 18.1920 -    if (from.ch == 0 && to.ch == 0 && hlText(lastHL) == "") {
 18.1921 -      // This is a whole-line replace. Treated specially to make
 18.1922 -      // sure line objects move the way they are supposed to.
 18.1923 -      var added = [];
 18.1924 -      for (var i = 0, e = lines.length - 1; i < e; ++i)
 18.1925 -        added.push(makeLine(hlText(lines[i]), hlSpans(lines[i]), th));
 18.1926 -      updateLine(cm, lastLine, lastLine.text, hlSpans(lastHL));
 18.1927 -      if (nlines) doc.remove(from.line, nlines, cm);
 18.1928 -      if (added.length) doc.insert(from.line, added);
 18.1929 -    } else if (firstLine == lastLine) {
 18.1930 -      if (lines.length == 1) {
 18.1931 -        updateLine(cm, firstLine, firstLine.text.slice(0, from.ch) + hlText(lines[0]) +
 18.1932 -                   firstLine.text.slice(to.ch), hlSpans(lines[0]));
 18.1933 -      } else {
 18.1934 -        for (var added = [], i = 1, e = lines.length - 1; i < e; ++i)
 18.1935 -          added.push(makeLine(hlText(lines[i]), hlSpans(lines[i]), th));
 18.1936 -        added.push(makeLine(hlText(lastHL) + firstLine.text.slice(to.ch), hlSpans(lastHL), th));
 18.1937 -        updateLine(cm, firstLine, firstLine.text.slice(0, from.ch) + hlText(lines[0]), hlSpans(lines[0]));
 18.1938 -        doc.insert(from.line + 1, added);
 18.1939 -      }
 18.1940 -    } else if (lines.length == 1) {
 18.1941 -      updateLine(cm, firstLine, firstLine.text.slice(0, from.ch) + hlText(lines[0]) +
 18.1942 -                 lastLine.text.slice(to.ch), hlSpans(lines[0]));
 18.1943 -      doc.remove(from.line + 1, nlines, cm);
 18.1944 -    } else {
 18.1945 -      var added = [];
 18.1946 -      updateLine(cm, firstLine, firstLine.text.slice(0, from.ch) + hlText(lines[0]), hlSpans(lines[0]));
 18.1947 -      updateLine(cm, lastLine, hlText(lastHL) + lastLine.text.slice(to.ch), hlSpans(lastHL));
 18.1948 -      for (var i = 1, e = lines.length - 1; i < e; ++i)
 18.1949 -        added.push(makeLine(hlText(lines[i]), hlSpans(lines[i]), th));
 18.1950 -      if (nlines > 1) doc.remove(from.line + 1, nlines - 1, cm);
 18.1951 -      doc.insert(from.line + 1, added);
 18.1952 -    }
 18.1953 -
 18.1954 -    if (cm.options.lineWrapping) {
 18.1955 -      var perLine = Math.max(5, display.scroller.clientWidth / charWidth(display) - 3);
 18.1956 -      doc.iter(from.line, from.line + lines.length, function(line) {
 18.1957 -        if (line.height == 0) return;
 18.1958 -        var guess = (Math.ceil(line.text.length / perLine) || 1) * th;
 18.1959 -        if (guess != line.height) updateLineHeight(line, guess);
 18.1960 -      });
 18.1961 -    } else {
 18.1962 -      doc.iter(checkWidthStart, from.line + lines.length, function(line) {
 18.1963 -        var len = lineLength(doc, line);
 18.1964 -        if (len > view.maxLineLength) {
 18.1965 -          view.maxLine = line;
 18.1966 -          view.maxLineLength = len;
 18.1967 -          view.maxLineChanged = true;
 18.1968 -          recomputeMaxLength = false;
 18.1969 -        }
 18.1970 -      });
 18.1971 -      if (recomputeMaxLength) cm.curOp.updateMaxLine = true;
 18.1972 -    }
 18.1973 -
 18.1974 -    // Adjust frontier, schedule worker
 18.1975 -    view.frontier = Math.min(view.frontier, from.line);
 18.1976 -    startWorker(cm, 400);
 18.1977 -
 18.1978 -    var lendiff = lines.length - nlines - 1;
 18.1979 -    // Remember that these lines changed, for updating the display
 18.1980 -    regChange(cm, from.line, to.line + 1, lendiff);
 18.1981 -    if (hasHandler(cm, "change")) {
 18.1982 -      // Normalize lines to contain only strings, since that's what
 18.1983 -      // the change event handler expects
 18.1984 -      for (var i = 0; i < lines.length; ++i)
 18.1985 -        if (typeof lines[i] != "string") lines[i] = lines[i].text;
 18.1986 -      var changeObj = {from: from, to: to, text: lines, origin: origin};
 18.1987 -      if (cm.curOp.textChanged) {
 18.1988 -        for (var cur = cm.curOp.textChanged; cur.next; cur = cur.next) {}
 18.1989 -        cur.next = changeObj;
 18.1990 -      } else cm.curOp.textChanged = changeObj;
 18.1991 -    }
 18.1992 -
 18.1993 -    // Update the selection
 18.1994 -    var newSelFrom, newSelTo, end = {line: from.line + lines.length - 1,
 18.1995 -                                     ch: hlText(lastHL).length  + (lines.length == 1 ? from.ch : 0)};
 18.1996 -    if (selUpdate && typeof selUpdate != "string") {
 18.1997 -      if (selUpdate.from) { newSelFrom = selUpdate.from; newSelTo = selUpdate.to; }
 18.1998 -      else newSelFrom = newSelTo = selUpdate;
 18.1999 -    } else if (selUpdate == "end") {
 18.2000 -      newSelFrom = newSelTo = end;
 18.2001 -    } else if (selUpdate == "start") {
 18.2002 -      newSelFrom = newSelTo = from;
 18.2003 -    } else if (selUpdate == "around") {
 18.2004 -      newSelFrom = from; newSelTo = end;
 18.2005 -    } else {
 18.2006 -      var adjustPos = function(pos) {
 18.2007 -        if (posLess(pos, from)) return pos;
 18.2008 -        if (!posLess(to, pos)) return end;
 18.2009 -        var line = pos.line + lendiff;
 18.2010 -        var ch = pos.ch;
 18.2011 -        if (pos.line == to.line)
 18.2012 -          ch += hlText(lastHL).length - (to.ch - (to.line == from.line ? from.ch : 0));
 18.2013 -        return {line: line, ch: ch};
 18.2014 -      };
 18.2015 -      newSelFrom = adjustPos(view.sel.from);
 18.2016 -      newSelTo = adjustPos(view.sel.to);
 18.2017 -    }
 18.2018 -    setSelection(cm, newSelFrom, newSelTo, null, true);
 18.2019 -    return end;
 18.2020 -  }
 18.2021 -
 18.2022 -  function replaceRange(cm, code, from, to, origin) {
 18.2023 -    if (!to) to = from;
 18.2024 -    if (posLess(to, from)) { var tmp = to; to = from; from = tmp; }
 18.2025 -    return updateDoc(cm, from, to, splitLines(code), null, origin);
 18.2026 -  }
 18.2027 -
 18.2028 -  // SELECTION
 18.2029 -
 18.2030 -  function posEq(a, b) {return a.line == b.line && a.ch == b.ch;}
 18.2031 -  function posLess(a, b) {return a.line < b.line || (a.line == b.line && a.ch < b.ch);}
 18.2032 -  function copyPos(x) {return {line: x.line, ch: x.ch};}
 18.2033 -
 18.2034 -  function clipLine(doc, n) {return Math.max(0, Math.min(n, doc.size-1));}
 18.2035 -  function clipPos(doc, pos) {
 18.2036 -    if (pos.line < 0) return {line: 0, ch: 0};
 18.2037 -    if (pos.line >= doc.size) return {line: doc.size-1, ch: getLine(doc, doc.size-1).text.length};
 18.2038 -    var ch = pos.ch, linelen = getLine(doc, pos.line).text.length;
 18.2039 -    if (ch == null || ch > linelen) return {line: pos.line, ch: linelen};
 18.2040 -    else if (ch < 0) return {line: pos.line, ch: 0};
 18.2041 -    else return pos;
 18.2042 -  }
 18.2043 -  function isLine(doc, l) {return l >= 0 && l < doc.size;}
 18.2044 -
 18.2045 -  // If shift is held, this will move the selection anchor. Otherwise,
 18.2046 -  // it'll set the whole selection.
 18.2047 -  function extendSelection(cm, pos, other, bias) {
 18.2048 -    var sel = cm.view.sel;
 18.2049 -    if (sel.shift || sel.extend) {
 18.2050 -      var anchor = sel.anchor;
 18.2051 -      if (other) {
 18.2052 -        var posBefore = posLess(pos, anchor);
 18.2053 -        if (posBefore != posLess(other, anchor)) {
 18.2054 -          anchor = pos;
 18.2055 -          pos = other;
 18.2056 -        } else if (posBefore != posLess(pos, other)) {
 18.2057 -          pos = other;
 18.2058 -        }
 18.2059 -      }
 18.2060 -      setSelection(cm, anchor, pos, bias);
 18.2061 -    } else {
 18.2062 -      setSelection(cm, pos, other || pos, bias);
 18.2063 -    }
 18.2064 -    cm.curOp.userSelChange = true;
 18.2065 -  }
 18.2066 -
 18.2067 -  // Update the selection. Last two args are only used by
 18.2068 -  // updateDoc, since they have to be expressed in the line
 18.2069 -  // numbers before the update.
 18.2070 -  function setSelection(cm, anchor, head, bias, checkAtomic) {
 18.2071 -    cm.view.goalColumn = null;
 18.2072 -    var sel = cm.view.sel;
 18.2073 -    // Skip over atomic spans.
 18.2074 -    if (checkAtomic || !posEq(anchor, sel.anchor))
 18.2075 -      anchor = skipAtomic(cm, anchor, bias, checkAtomic != "push");
 18.2076 -    if (checkAtomic || !posEq(head, sel.head))
 18.2077 -      head = skipAtomic(cm, head, bias, checkAtomic != "push");
 18.2078 -
 18.2079 -    if (posEq(sel.anchor, anchor) && posEq(sel.head, head)) return;
 18.2080 -
 18.2081 -    sel.anchor = anchor; sel.head = head;
 18.2082 -    var inv = posLess(head, anchor);
 18.2083 -    sel.from = inv ? head : anchor;
 18.2084 -    sel.to = inv ? anchor : head;
 18.2085 -
 18.2086 -    cm.curOp.updateInput = true;
 18.2087 -    cm.curOp.selectionChanged = true;
 18.2088 -  }
 18.2089 -
 18.2090 -  function reCheckSelection(cm) {
 18.2091 -    setSelection(cm, cm.view.sel.from, cm.view.sel.to, null, "push");
 18.2092 -  }
 18.2093 -
 18.2094 -  function skipAtomic(cm, pos, bias, mayClear) {
 18.2095 -    var doc = cm.view.doc, flipped = false, curPos = pos;
 18.2096 -    var dir = bias || 1;
 18.2097 -    cm.view.cantEdit = false;
 18.2098 -    search: for (;;) {
 18.2099 -      var line = getLine(doc, curPos.line), toClear;
 18.2100 -      if (line.markedSpans) {
 18.2101 -        for (var i = 0; i < line.markedSpans.length; ++i) {
 18.2102 -          var sp = line.markedSpans[i], m = sp.marker;
 18.2103 -          if ((sp.from == null || (m.inclusiveLeft ? sp.from <= curPos.ch : sp.from < curPos.ch)) &&
 18.2104 -              (sp.to == null || (m.inclusiveRight ? sp.to >= curPos.ch : sp.to > curPos.ch))) {
 18.2105 -            if (mayClear && m.clearOnEnter) {
 18.2106 -              (toClear || (toClear = [])).push(m);
 18.2107 -              continue;
 18.2108 -            } else if (!m.atomic) continue;
 18.2109 -            var newPos = m.find()[dir < 0 ? "from" : "to"];
 18.2110 -            if (posEq(newPos, curPos)) {
 18.2111 -              newPos.ch += dir;
 18.2112 -              if (newPos.ch < 0) {
 18.2113 -                if (newPos.line) newPos = clipPos(doc, {line: newPos.line - 1});
 18.2114 -                else newPos = null;
 18.2115 -              } else if (newPos.ch > line.text.length) {
 18.2116 -                if (newPos.line < doc.size - 1) newPos = {line: newPos.line + 1, ch: 0};
 18.2117 -                else newPos = null;
 18.2118 -              }
 18.2119 -              if (!newPos) {
 18.2120 -                if (flipped) {
 18.2121 -                  // Driven in a corner -- no valid cursor position found at all
 18.2122 -                  // -- try again *with* clearing, if we didn't already
 18.2123 -                  if (!mayClear) return skipAtomic(cm, pos, bias, true);
 18.2124 -                  // Otherwise, turn off editing until further notice, and return the start of the doc
 18.2125 -                  cm.view.cantEdit = true;
 18.2126 -                  return {line: 0, ch: 0};
 18.2127 -                }
 18.2128 -                flipped = true; newPos = pos; dir = -dir;
 18.2129 -              }
 18.2130 -            }
 18.2131 -            curPos = newPos;
 18.2132 -            continue search;
 18.2133 -          }
 18.2134 -        }
 18.2135 -        if (toClear) for (var i = 0; i < toClear.length; ++i) toClear[i].clear();
 18.2136 -      }
 18.2137 -      return curPos;
 18.2138 -    }
 18.2139 -  }
 18.2140 -
 18.2141 -  // SCROLLING
 18.2142 -
 18.2143 -  function scrollCursorIntoView(cm) {
 18.2144 -    var view = cm.view;
 18.2145 -    var coords = scrollPosIntoView(cm, view.sel.head);
 18.2146 -    if (!view.focused) return;
 18.2147 -    var display = cm.display, box = display.sizer.getBoundingClientRect(), doScroll = null;
 18.2148 -    if (coords.top + box.top < 0) doScroll = true;
 18.2149 -    else if (coords.bottom + box.top > (window.innerHeight || document.documentElement.clientHeight)) doScroll = false;
 18.2150 -    if (doScroll != null && !phantom) {
 18.2151 -      var hidden = display.cursor.style.display == "none";
 18.2152 -      if (hidden) {
 18.2153 -        display.cursor.style.display = "";
 18.2154 -        display.cursor.style.left = coords.left + "px";
 18.2155 -        display.cursor.style.top = (coords.top - display.viewOffset) + "px";
 18.2156 -      }
 18.2157 -      display.cursor.scrollIntoView(doScroll);
 18.2158 -      if (hidden) display.cursor.style.display = "none";
 18.2159 -    }
 18.2160 -  }
 18.2161 -
 18.2162 -  function scrollPosIntoView(cm, pos) {
 18.2163 -    for (;;) {
 18.2164 -      var changed = false, coords = cursorCoords(cm, pos);
 18.2165 -      var scrollPos = calculateScrollPos(cm, coords.left, coords.top, coords.left, coords.bottom);
 18.2166 -      var startTop = cm.view.scrollTop, startLeft = cm.view.scrollLeft;
 18.2167 -      if (scrollPos.scrollTop != null) {
 18.2168 -        setScrollTop(cm, scrollPos.scrollTop);
 18.2169 -        if (Math.abs(cm.view.scrollTop - startTop) > 1) changed = true;
 18.2170 -      }
 18.2171 -      if (scrollPos.scrollLeft != null) {
 18.2172 -        setScrollLeft(cm, scrollPos.scrollLeft);
 18.2173 -        if (Math.abs(cm.view.scrollLeft - startLeft) > 1) changed = true;
 18.2174 -      }
 18.2175 -      if (!changed) return coords;
 18.2176 -    }
 18.2177 -  }
 18.2178 -
 18.2179 -  function scrollIntoView(cm, x1, y1, x2, y2) {
 18.2180 -    var scrollPos = calculateScrollPos(cm, x1, y1, x2, y2);
 18.2181 -    if (scrollPos.scrollTop != null) setScrollTop(cm, scrollPos.scrollTop);
 18.2182 -    if (scrollPos.scrollLeft != null) setScrollLeft(cm, scrollPos.scrollLeft);
 18.2183 -  }
 18.2184 -
 18.2185 -  function calculateScrollPos(cm, x1, y1, x2, y2) {
 18.2186 -    var display = cm.display, pt = paddingTop(display);
 18.2187 -    y1 += pt; y2 += pt;
 18.2188 -    var screen = display.scroller.clientHeight - scrollerCutOff, screentop = display.scroller.scrollTop, result = {};
 18.2189 -    var docBottom = cm.view.doc.height + 2 * pt;
 18.2190 -    var atTop = y1 < pt + 10, atBottom = y2 + pt > docBottom - 10;
 18.2191 -    if (y1 < screentop) result.scrollTop = atTop ? 0 : Math.max(0, y1);
 18.2192 -    else if (y2 > screentop + screen) result.scrollTop = (atBottom ? docBottom : y2) - screen;
 18.2193 -
 18.2194 -    var screenw = display.scroller.clientWidth - scrollerCutOff, screenleft = display.scroller.scrollLeft;
 18.2195 -    x1 += display.gutters.offsetWidth; x2 += display.gutters.offsetWidth;
 18.2196 -    var gutterw = display.gutters.offsetWidth;
 18.2197 -    var atLeft = x1 < gutterw + 10;
 18.2198 -    if (x1 < screenleft + gutterw || atLeft) {
 18.2199 -      if (atLeft) x1 = 0;
 18.2200 -      result.scrollLeft = Math.max(0, x1 - 10 - gutterw);
 18.2201 -    } else if (x2 > screenw + screenleft - 3) {
 18.2202 -      result.scrollLeft = x2 + 10 - screenw;
 18.2203 -    }
 18.2204 -    return result;
 18.2205 -  }
 18.2206 -
 18.2207 -  // API UTILITIES
 18.2208 -
 18.2209 -  function indentLine(cm, n, how, aggressive) {
 18.2210 -    var doc = cm.view.doc;
 18.2211 -    if (!how) how = "add";
 18.2212 -    if (how == "smart") {
 18.2213 -      if (!cm.view.mode.indent) how = "prev";
 18.2214 -      else var state = getStateBefore(cm, n);
 18.2215 -    }
 18.2216 -
 18.2217 -    var tabSize = cm.options.tabSize;
 18.2218 -    var line = getLine(doc, n), curSpace = countColumn(line.text, null, tabSize);
 18.2219 -    var curSpaceString = line.text.match(/^\s*/)[0], indentation;
 18.2220 -    if (how == "smart") {
 18.2221 -      indentation = cm.view.mode.indent(state, line.text.slice(curSpaceString.length), line.text);
 18.2222 -      if (indentation == Pass) {
 18.2223 -        if (!aggressive) return;
 18.2224 -        how = "prev";
 18.2225 -      }
 18.2226 -    }
 18.2227 -    if (how == "prev") {
 18.2228 -      if (n) indentation = countColumn(getLine(doc, n-1).text, null, tabSize);
 18.2229 -      else indentation = 0;
 18.2230 -    }
 18.2231 -    else if (how == "add") indentation = curSpace + cm.options.indentUnit;
 18.2232 -    else if (how == "subtract") indentation = curSpace - cm.options.indentUnit;
 18.2233 -    indentation = Math.max(0, indentation);
 18.2234 -
 18.2235 -    var indentString = "", pos = 0;
 18.2236 -    if (cm.options.indentWithTabs)
 18.2237 -      for (var i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += "\t";}
 18.2238 -    if (pos < indentation) indentString += spaceStr(indentation - pos);
 18.2239 -
 18.2240 -    if (indentString != curSpaceString)
 18.2241 -      replaceRange(cm, indentString, {line: n, ch: 0}, {line: n, ch: curSpaceString.length}, "input");
 18.2242 -    line.stateAfter = null;
 18.2243 -  }
 18.2244 -
 18.2245 -  function changeLine(cm, handle, op) {
 18.2246 -    var no = handle, line = handle, doc = cm.view.doc;
 18.2247 -    if (typeof handle == "number") line = getLine(doc, clipLine(doc, handle));
 18.2248 -    else no = lineNo(handle);
 18.2249 -    if (no == null) return null;
 18.2250 -    if (op(line, no)) regChange(cm, no, no + 1);
 18.2251 -    else return null;
 18.2252 -    return line;
 18.2253 -  }
 18.2254 -
 18.2255 -  function findPosH(cm, dir, unit, visually) {
 18.2256 -    var doc = cm.view.doc, end = cm.view.sel.head, line = end.line, ch = end.ch;
 18.2257 -    var lineObj = getLine(doc, line);
 18.2258 -    function findNextLine() {
 18.2259 -      var l = line + dir;
 18.2260 -      if (l < 0 || l == doc.size) return false;
 18.2261 -      line = l;
 18.2262 -      return lineObj = getLine(doc, l);
 18.2263 -    }
 18.2264 -    function moveOnce(boundToLine) {
 18.2265 -      var next = (visually ? moveVisually : moveLogically)(lineObj, ch, dir, true);
 18.2266 -      if (next == null) {
 18.2267 -        if (!boundToLine && findNextLine()) {
 18.2268 -          if (visually) ch = (dir < 0 ? lineRight : lineLeft)(lineObj);
 18.2269 -          else ch = dir < 0 ? lineObj.text.length : 0;
 18.2270 -        } else return false;
 18.2271 -      } else ch = next;
 18.2272 -      return true;
 18.2273 -    }
 18.2274 -    if (unit == "char") moveOnce();
 18.2275 -    else if (unit == "column") moveOnce(true);
 18.2276 -    else if (unit == "word") {
 18.2277 -      var sawWord = false;
 18.2278 -      for (;;) {
 18.2279 -        if (dir < 0) if (!moveOnce()) break;
 18.2280 -        if (isWordChar(lineObj.text.charAt(ch))) sawWord = true;
 18.2281 -        else if (sawWord) {if (dir < 0) {dir = 1; moveOnce();} break;}
 18.2282 -        if (dir > 0) if (!moveOnce()) break;
 18.2283 -      }
 18.2284 -    }
 18.2285 -    return skipAtomic(cm, {line: line, ch: ch}, dir, true);
 18.2286 -  }
 18.2287 -
 18.2288 -  function findWordAt(line, pos) {
 18.2289 -    var start = pos.ch, end = pos.ch;
 18.2290 -    if (line) {
 18.2291 -      if (pos.after === false || end == line.length) --start; else ++end;
 18.2292 -      var startChar = line.charAt(start);
 18.2293 -      var check = isWordChar(startChar) ? isWordChar :
 18.2294 -        /\s/.test(startChar) ? function(ch) {return /\s/.test(ch);} :
 18.2295 -      function(ch) {return !/\s/.test(ch) && !isWordChar(ch);};
 18.2296 -      while (start > 0 && check(line.charAt(start - 1))) --start;
 18.2297 -      while (end < line.length && check(line.charAt(end))) ++end;
 18.2298 -    }
 18.2299 -    return {from: {line: pos.line, ch: start}, to: {line: pos.line, ch: end}};
 18.2300 -  }
 18.2301 -
 18.2302 -  function selectLine(cm, line) {
 18.2303 -    extendSelection(cm, {line: line, ch: 0}, clipPos(cm.view.doc, {line: line + 1, ch: 0}));
 18.2304 -  }
 18.2305 -
 18.2306 -  // PROTOTYPE
 18.2307 -
 18.2308 -  // The publicly visible API. Note that operation(null, f) means
 18.2309 -  // 'wrap f in an operation, performed on its `this` parameter'
 18.2310 -
 18.2311 -  CodeMirror.prototype = {
 18.2312 -    getValue: function(lineSep) {
 18.2313 -      var text = [], doc = this.view.doc;
 18.2314 -      doc.iter(0, doc.size, function(line) { text.push(line.text); });
 18.2315 -      return text.join(lineSep || "\n");
 18.2316 -    },
 18.2317 -
 18.2318 -    setValue: operation(null, function(code) {
 18.2319 -      var doc = this.view.doc, top = {line: 0, ch: 0}, lastLen = getLine(doc, doc.size-1).text.length;
 18.2320 -      updateDocInner(this, top, {line: doc.size - 1, ch: lastLen}, splitLines(code), top, top, "setValue");
 18.2321 -    }),
 18.2322 -
 18.2323 -    getSelection: function(lineSep) { return this.getRange(this.view.sel.from, this.view.sel.to, lineSep); },
 18.2324 -
 18.2325 -    replaceSelection: operation(null, function(code, collapse, origin) {
 18.2326 -      var sel = this.view.sel;
 18.2327 -      updateDoc(this, sel.from, sel.to, splitLines(code), collapse || "around", origin);
 18.2328 -    }),
 18.2329 -
 18.2330 -    focus: function(){window.focus(); focusInput(this); onFocus(this); fastPoll(this);},
 18.2331 -
 18.2332 -    setOption: function(option, value) {
 18.2333 -      var options = this.options, old = options[option];
 18.2334 -      if (options[option] == value && option != "mode") return;
 18.2335 -      options[option] = value;
 18.2336 -      if (optionHandlers.hasOwnProperty(option))
 18.2337 -        operation(this, optionHandlers[option])(this, value, old);
 18.2338 -    },
 18.2339 -
 18.2340 -    getOption: function(option) {return this.options[option];},
 18.2341 -
 18.2342 -    getMode: function() {return this.view.mode;},
 18.2343 -
 18.2344 -    addKeyMap: function(map) {
 18.2345 -      this.view.keyMaps.push(map);
 18.2346 -    },
 18.2347 -
 18.2348 -    removeKeyMap: function(map) {
 18.2349 -      var maps = this.view.keyMaps;
 18.2350 -      for (var i = 0; i < maps.length; ++i)
 18.2351 -        if ((typeof map == "string" ? maps[i].name : maps[i]) == map) {
 18.2352 -          maps.splice(i, 1);
 18.2353 -          return true;
 18.2354 -        }
 18.2355 -    },
 18.2356 -
 18.2357 -    undo: operation(null, function() {unredoHelper(this, "undo");}),
 18.2358 -    redo: operation(null, function() {unredoHelper(this, "redo");}),
 18.2359 -
 18.2360 -    indentLine: operation(null, function(n, dir, aggressive) {
 18.2361 -      if (typeof dir != "string") {
 18.2362 -        if (dir == null) dir = this.options.smartIndent ? "smart" : "prev";
 18.2363 -        else dir = dir ? "add" : "subtract";
 18.2364 -      }
 18.2365 -      if (isLine(this.view.doc, n)) indentLine(this, n, dir, aggressive);
 18.2366 -    }),
 18.2367 -
 18.2368 -    indentSelection: operation(null, function(how) {
 18.2369 -      var sel = this.view.sel;
 18.2370 -      if (posEq(sel.from, sel.to)) return indentLine(this, sel.from.line, how);
 18.2371 -      var e = sel.to.line - (sel.to.ch ? 0 : 1);
 18.2372 -      for (var i = sel.from.line; i <= e; ++i) indentLine(this, i, how);
 18.2373 -    }),
 18.2374 -
 18.2375 -    historySize: function() {
 18.2376 -      var hist = this.view.history;
 18.2377 -      return {undo: hist.done.length, redo: hist.undone.length};
 18.2378 -    },
 18.2379 -
 18.2380 -    clearHistory: function() {this.view.history = makeHistory();},
 18.2381 -
 18.2382 -    markClean: function() {
 18.2383 -      this.view.history.dirtyCounter = 0;
 18.2384 -      this.view.history.lastOp = this.view.history.lastOrigin = null;
 18.2385 -    },
 18.2386 -
 18.2387 -    isClean: function () {return this.view.history.dirtyCounter == 0;},
 18.2388 -      
 18.2389 -    getHistory: function() {
 18.2390 -      var hist = this.view.history;
 18.2391 -      function cp(arr) {
 18.2392 -        for (var i = 0, nw = [], nwelt; i < arr.length; ++i) {
 18.2393 -          var set = arr[i];
 18.2394 -          nw.push({events: nwelt = [], fromBefore: set.fromBefore, toBefore: set.toBefore,
 18.2395 -                   fromAfter: set.fromAfter, toAfter: set.toAfter});
 18.2396 -          for (var j = 0, elt = set.events; j < elt.length; ++j) {
 18.2397 -            var old = [], cur = elt[j];
 18.2398 -            nwelt.push({start: cur.start, added: cur.added, old: old});
 18.2399 -            for (var k = 0; k < cur.old.length; ++k) old.push(hlText(cur.old[k]));
 18.2400 -          }
 18.2401 -        }
 18.2402 -        return nw;
 18.2403 -      }
 18.2404 -      return {done: cp(hist.done), undone: cp(hist.undone)};
 18.2405 -    },
 18.2406 -
 18.2407 -    setHistory: function(histData) {
 18.2408 -      var hist = this.view.history = makeHistory();
 18.2409 -      hist.done = histData.done;
 18.2410 -      hist.undone = histData.undone;
 18.2411 -    },
 18.2412 -
 18.2413 -    // Fetch the parser token for a given character. Useful for hacks
 18.2414 -    // that want to inspect the mode state (say, for completion).
 18.2415 -    getTokenAt: function(pos) {
 18.2416 -      var doc = this.view.doc;
 18.2417 -      pos = clipPos(doc, pos);
 18.2418 -      var state = getStateBefore(this, pos.line), mode = this.view.mode;
 18.2419 -      var line = getLine(doc, pos.line);
 18.2420 -      var stream = new StringStream(line.text, this.options.tabSize);
 18.2421 -      while (stream.pos < pos.ch && !stream.eol()) {
 18.2422 -        stream.start = stream.pos;
 18.2423 -        var style = mode.token(stream, state);
 18.2424 -      }
 18.2425 -      return {start: stream.start,
 18.2426 -              end: stream.pos,
 18.2427 -              string: stream.current(),
 18.2428 -              className: style || null, // Deprecated, use 'type' instead
 18.2429 -              type: style || null,
 18.2430 -              state: state};
 18.2431 -    },
 18.2432 -
 18.2433 -    getStateAfter: function(line) {
 18.2434 -      var doc = this.view.doc;
 18.2435 -      line = clipLine(doc, line == null ? doc.size - 1: line);
 18.2436 -      return getStateBefore(this, line + 1);
 18.2437 -    },
 18.2438 -
 18.2439 -    cursorCoords: function(start, mode) {
 18.2440 -      var pos, sel = this.view.sel;
 18.2441 -      if (start == null) pos = sel.head;
 18.2442 -      else if (typeof start == "object") pos = clipPos(this.view.doc, start);
 18.2443 -      else pos = start ? sel.from : sel.to;
 18.2444 -      return cursorCoords(this, pos, mode || "page");
 18.2445 -    },
 18.2446 -
 18.2447 -    charCoords: function(pos, mode) {
 18.2448 -      return charCoords(this, clipPos(this.view.doc, pos), mode || "page");
 18.2449 -    },
 18.2450 -
 18.2451 -    coordsChar: function(coords) {
 18.2452 -      var off = this.display.lineSpace.getBoundingClientRect();
 18.2453 -      return coordsChar(this, coords.left - off.left, coords.top - off.top);
 18.2454 -    },
 18.2455 -
 18.2456 -    defaultTextHeight: function() { return textHeight(this.display); },
 18.2457 -
 18.2458 -    markText: operation(null, function(from, to, options) {
 18.2459 -      return markText(this, clipPos(this.view.doc, from), clipPos(this.view.doc, to),
 18.2460 -                      options, "range");
 18.2461 -    }),
 18.2462 -
 18.2463 -    setBookmark: operation(null, function(pos, widget) {
 18.2464 -      pos = clipPos(this.view.doc, pos);
 18.2465 -      return markText(this, pos, pos, widget ? {replacedWith: widget} : {}, "bookmark");
 18.2466 -    }),
 18.2467 -
 18.2468 -    findMarksAt: function(pos) {
 18.2469 -      var doc = this.view.doc;
 18.2470 -      pos = clipPos(doc, pos);
 18.2471 -      var markers = [], spans = getLine(doc, pos.line).markedSpans;
 18.2472 -      if (spans) for (var i = 0; i < spans.length; ++i) {
 18.2473 -        var span = spans[i];
 18.2474 -        if ((span.from == null || span.from <= pos.ch) &&
 18.2475 -            (span.to == null || span.to >= pos.ch))
 18.2476 -          markers.push(span.marker);
 18.2477 -      }
 18.2478 -      return markers;
 18.2479 -    },
 18.2480 -
 18.2481 -    setGutterMarker: operation(null, function(line, gutterID, value) {
 18.2482 -      return changeLine(this, line, function(line) {
 18.2483 -        var markers = line.gutterMarkers || (line.gutterMarkers = {});
 18.2484 -        markers[gutterID] = value;
 18.2485 -        if (!value && isEmpty(markers)) line.gutterMarkers = null;
 18.2486 -        return true;
 18.2487 -      });
 18.2488 -    }),
 18.2489 -
 18.2490 -    clearGutter: operation(null, function(gutterID) {
 18.2491 -      var i = 0, cm = this, doc = cm.view.doc;
 18.2492 -      doc.iter(0, doc.size, function(line) {
 18.2493 -        if (line.gutterMarkers && line.gutterMarkers[gutterID]) {
 18.2494 -          line.gutterMarkers[gutterID] = null;
 18.2495 -          regChange(cm, i, i + 1);
 18.2496 -          if (isEmpty(line.gutterMarkers)) line.gutterMarkers = null;
 18.2497 -        }
 18.2498 -        ++i;
 18.2499 -      });
 18.2500 -    }),
 18.2501 -
 18.2502 -    addLineClass: operation(null, function(handle, where, cls) {
 18.2503 -      return changeLine(this, handle, function(line) {
 18.2504 -        var prop = where == "text" ? "textClass" : where == "background" ? "bgClass" : "wrapClass";
 18.2505 -        if (!line[prop]) line[prop] = cls;
 18.2506 -        else if (new RegExp("\\b" + cls + "\\b").test(line[prop])) return false;
 18.2507 -        else line[prop] += " " + cls;
 18.2508 -        return true;
 18.2509 -      });
 18.2510 -    }),
 18.2511 -
 18.2512 -    removeLineClass: operation(null, function(handle, where, cls) {
 18.2513 -      return changeLine(this, handle, function(line) {
 18.2514 -        var prop = where == "text" ? "textClass" : where == "background" ? "bgClass" : "wrapClass";
 18.2515 -        var cur = line[prop];
 18.2516 -        if (!cur) return false;
 18.2517 -        else if (cls == null) line[prop] = null;
 18.2518 -        else {
 18.2519 -          var upd = cur.replace(new RegExp("^" + cls + "\\b\\s*|\\s*\\b" + cls + "\\b"), "");
 18.2520 -          if (upd == cur) return false;
 18.2521 -          line[prop] = upd || null;
 18.2522 -        }
 18.2523 -        return true;
 18.2524 -      });
 18.2525 -    }),
 18.2526 -
 18.2527 -    addLineWidget: operation(null, function(handle, node, options) {
 18.2528 -      var widget = options || {};
 18.2529 -      widget.node = node;
 18.2530 -      if (widget.noHScroll) this.display.alignWidgets = true;
 18.2531 -      changeLine(this, handle, function(line) {
 18.2532 -        (line.widgets || (line.widgets = [])).push(widget);
 18.2533 -        widget.line = line;
 18.2534 -        return true;
 18.2535 -      });
 18.2536 -      return widget;
 18.2537 -    }),
 18.2538 -
 18.2539 -    removeLineWidget: operation(null, function(widget) {
 18.2540 -      var ws = widget.line.widgets, no = lineNo(widget.line);
 18.2541 -      if (no == null) return;
 18.2542 -      for (var i = 0; i < ws.length; ++i) if (ws[i] == widget) ws.splice(i--, 1);
 18.2543 -      regChange(this, no, no + 1);
 18.2544 -    }),
 18.2545 -
 18.2546 -    lineInfo: function(line) {
 18.2547 -      if (typeof line == "number") {
 18.2548 -        if (!isLine(this.view.doc, line)) return null;
 18.2549 -        var n = line;
 18.2550 -        line = getLine(this.view.doc, line);
 18.2551 -        if (!line) return null;
 18.2552 -      } else {
 18.2553 -        var n = lineNo(line);
 18.2554 -        if (n == null) return null;
 18.2555 -      }
 18.2556 -      return {line: n, handle: line, text: line.text, gutterMarkers: line.gutterMarkers,
 18.2557 -              textClass: line.textClass, bgClass: line.bgClass, wrapClass: line.wrapClass,
 18.2558 -              widgets: line.widgets};
 18.2559 -    },
 18.2560 -
 18.2561 -    getViewport: function() { return {from: this.display.showingFrom, to: this.display.showingTo};},
 18.2562 -
 18.2563 -    addWidget: function(pos, node, scroll, vert, horiz) {
 18.2564 -      var display = this.display;
 18.2565 -      pos = cursorCoords(this, clipPos(this.view.doc, pos));
 18.2566 -      var top = pos.top, left = pos.left;
 18.2567 -      node.style.position = "absolute";
 18.2568 -      display.sizer.appendChild(node);
 18.2569 -      if (vert == "over") top = pos.top;
 18.2570 -      else if (vert == "near") {
 18.2571 -        var vspace = Math.max(display.wrapper.clientHeight, this.view.doc.height),
 18.2572 -        hspace = Math.max(display.sizer.clientWidth, display.lineSpace.clientWidth);
 18.2573 -        if (pos.bottom + node.offsetHeight > vspace && pos.top > node.offsetHeight)
 18.2574 -          top = pos.top - node.offsetHeight;
 18.2575 -        if (left + node.offsetWidth > hspace)
 18.2576 -          left = hspace - node.offsetWidth;
 18.2577 -      }
 18.2578 -      node.style.top = (top + paddingTop(display)) + "px";
 18.2579 -      node.style.left = node.style.right = "";
 18.2580 -      if (horiz == "right") {
 18.2581 -        left = display.sizer.clientWidth - node.offsetWidth;
 18.2582 -        node.style.right = "0px";
 18.2583 -      } else {
 18.2584 -        if (horiz == "left") left = 0;
 18.2585 -        else if (horiz == "middle") left = (display.sizer.clientWidth - node.offsetWidth) / 2;
 18.2586 -        node.style.left = left + "px";
 18.2587 -      }
 18.2588 -      if (scroll)
 18.2589 -        scrollIntoView(this, left, top, left + node.offsetWidth, top + node.offsetHeight);
 18.2590 -    },
 18.2591 -
 18.2592 -    lineCount: function() {return this.view.doc.size;},
 18.2593 -
 18.2594 -    clipPos: function(pos) {return clipPos(this.view.doc, pos);},
 18.2595 -
 18.2596 -    getCursor: function(start) {
 18.2597 -      var sel = this.view.sel, pos;
 18.2598 -      if (start == null || start == "head") pos = sel.head;
 18.2599 -      else if (start == "anchor") pos = sel.anchor;
 18.2600 -      else if (start == "end" || start === false) pos = sel.to;
 18.2601 -      else pos = sel.from;
 18.2602 -      return copyPos(pos);
 18.2603 -    },
 18.2604 -
 18.2605 -    somethingSelected: function() {return !posEq(this.view.sel.from, this.view.sel.to);},
 18.2606 -
 18.2607 -    setCursor: operation(null, function(line, ch, extend) {
 18.2608 -      var pos = clipPos(this.view.doc, typeof line == "number" ? {line: line, ch: ch || 0} : line);
 18.2609 -      if (extend) extendSelection(this, pos);
 18.2610 -      else setSelection(this, pos, pos);
 18.2611 -    }),
 18.2612 -
 18.2613 -    setSelection: operation(null, function(anchor, head) {
 18.2614 -      var doc = this.view.doc;
 18.2615 -      setSelection(this, clipPos(doc, anchor), clipPos(doc, head || anchor));
 18.2616 -    }),
 18.2617 -
 18.2618 -    extendSelection: operation(null, function(from, to) {
 18.2619 -      var doc = this.view.doc;
 18.2620 -      extendSelection(this, clipPos(doc, from), to && clipPos(doc, to));
 18.2621 -    }),
 18.2622 -
 18.2623 -    setExtending: function(val) {this.view.sel.extend = val;},
 18.2624 -
 18.2625 -    getLine: function(line) {var l = this.getLineHandle(line); return l && l.text;},
 18.2626 -
 18.2627 -    getLineHandle: function(line) {
 18.2628 -      var doc = this.view.doc;
 18.2629 -      if (isLine(doc, line)) return getLine(doc, line);
 18.2630 -    },
 18.2631 -
 18.2632 -    getLineNumber: function(line) {return lineNo(line);},
 18.2633 -
 18.2634 -    setLine: operation(null, function(line, text) {
 18.2635 -      if (isLine(this.view.doc, line))
 18.2636 -        replaceRange(this, text, {line: line, ch: 0}, {line: line, ch: getLine(this.view.doc, line).text.length});
 18.2637 -    }),
 18.2638 -
 18.2639 -    removeLine: operation(null, function(line) {
 18.2640 -      if (isLine(this.view.doc, line))
 18.2641 -        replaceRange(this, "", {line: line, ch: 0}, clipPos(this.view.doc, {line: line+1, ch: 0}));
 18.2642 -    }),
 18.2643 -
 18.2644 -    replaceRange: operation(null, function(code, from, to) {
 18.2645 -      var doc = this.view.doc;
 18.2646 -      from = clipPos(doc, from);
 18.2647 -      to = to ? clipPos(doc, to) : from;
 18.2648 -      return replaceRange(this, code, from, to);
 18.2649 -    }),
 18.2650 -
 18.2651 -    getRange: function(from, to, lineSep) {
 18.2652 -      var doc = this.view.doc;
 18.2653 -      from = clipPos(doc, from); to = clipPos(doc, to);
 18.2654 -      var l1 = from.line, l2 = to.line;
 18.2655 -      if (l1 == l2) return getLine(doc, l1).text.slice(from.ch, to.ch);
 18.2656 -      var code = [getLine(doc, l1).text.slice(from.ch)];
 18.2657 -      doc.iter(l1 + 1, l2, function(line) { code.push(line.text); });
 18.2658 -      code.push(getLine(doc, l2).text.slice(0, to.ch));
 18.2659 -      return code.join(lineSep || "\n");
 18.2660 -    },
 18.2661 -
 18.2662 -    triggerOnKeyDown: operation(null, onKeyDown),
 18.2663 -
 18.2664 -    execCommand: function(cmd) {return commands[cmd](this);},
 18.2665 -
 18.2666 -    // Stuff used by commands, probably not much use to outside code.
 18.2667 -    moveH: operation(null, function(dir, unit) {
 18.2668 -      var sel = this.view.sel, pos = dir < 0 ? sel.from : sel.to;
 18.2669 -      if (sel.shift || sel.extend || posEq(sel.from, sel.to)) pos = findPosH(this, dir, unit, true);
 18.2670 -      extendSelection(this, pos, pos, dir);
 18.2671 -    }),
 18.2672 -
 18.2673 -    deleteH: operation(null, function(dir, unit) {
 18.2674 -      var sel = this.view.sel;
 18.2675 -      if (!posEq(sel.from, sel.to)) replaceRange(this, "", sel.from, sel.to, "delete");
 18.2676 -      else replaceRange(this, "", sel.from, findPosH(this, dir, unit, false), "delete");
 18.2677 -      this.curOp.userSelChange = true;
 18.2678 -    }),
 18.2679 -
 18.2680 -    moveV: operation(null, function(dir, unit) {
 18.2681 -      var view = this.view, doc = view.doc, display = this.display;
 18.2682 -      var cur = view.sel.head, pos = cursorCoords(this, cur, "div");
 18.2683 -      var x = pos.left, y;
 18.2684 -      if (view.goalColumn != null) x = view.goalColumn;
 18.2685 -      if (unit == "page") {
 18.2686 -        var pageSize = Math.min(display.wrapper.clientHeight, window.innerHeight || document.documentElement.clientHeight);
 18.2687 -        y = pos.top + dir * pageSize;
 18.2688 -      } else if (unit == "line") {
 18.2689 -        y = dir > 0 ? pos.bottom + 3 : pos.top - 3;
 18.2690 -      }
 18.2691 -      do {
 18.2692 -        var target = coordsChar(this, x, y);
 18.2693 -        y += dir * 5;
 18.2694 -      } while (target.outside && (dir < 0 ? y > 0 : y < doc.height));
 18.2695 -
 18.2696 -      if (unit == "page") display.scrollbarV.scrollTop += charCoords(this, target, "div").top - pos.top;
 18.2697 -      extendSelection(this, target, target, dir);
 18.2698 -      view.goalColumn = x;
 18.2699 -    }),
 18.2700 -
 18.2701 -    toggleOverwrite: function() {
 18.2702 -      if (this.view.overwrite = !this.view.overwrite)
 18.2703 -        this.display.cursor.className += " CodeMirror-overwrite";
 18.2704 -      else
 18.2705 -        this.display.cursor.className = this.display.cursor.className.replace(" CodeMirror-overwrite", "");
 18.2706 -    },
 18.2707 -
 18.2708 -    posFromIndex: function(off) {
 18.2709 -      var lineNo = 0, ch, doc = this.view.doc;
 18.2710 -      doc.iter(0, doc.size, function(line) {
 18.2711 -        var sz = line.text.length + 1;
 18.2712 -        if (sz > off) { ch = off; return true; }
 18.2713 -        off -= sz;
 18.2714 -        ++lineNo;
 18.2715 -      });
 18.2716 -      return clipPos(doc, {line: lineNo, ch: ch});
 18.2717 -    },
 18.2718 -    indexFromPos: function (coords) {
 18.2719 -      if (coords.line < 0 || coords.ch < 0) return 0;
 18.2720 -      var index = coords.ch;
 18.2721 -      this.view.doc.iter(0, coords.line, function (line) {
 18.2722 -        index += line.text.length + 1;
 18.2723 -      });
 18.2724 -      return index;
 18.2725 -    },
 18.2726 -
 18.2727 -    scrollTo: function(x, y) {
 18.2728 -      if (x != null) this.display.scrollbarH.scrollLeft = this.display.scroller.scrollLeft = x;
 18.2729 -      if (y != null) this.display.scrollbarV.scrollTop = this.display.scroller.scrollTop = y;
 18.2730 -      updateDisplay(this, []);
 18.2731 -    },
 18.2732 -    getScrollInfo: function() {
 18.2733 -      var scroller = this.display.scroller, co = scrollerCutOff;
 18.2734 -      return {left: scroller.scrollLeft, top: scroller.scrollTop,
 18.2735 -              height: scroller.scrollHeight - co, width: scroller.scrollWidth - co,
 18.2736 -              clientHeight: scroller.clientHeight - co, clientWidth: scroller.clientWidth - co};
 18.2737 -    },
 18.2738 -
 18.2739 -    scrollIntoView: function(pos) {
 18.2740 -      if (typeof pos == "number") pos = {line: pos, ch: 0};
 18.2741 -      pos = pos ? clipPos(this.view.doc, pos) : this.view.sel.head;
 18.2742 -      scrollPosIntoView(this, pos);
 18.2743 -    },
 18.2744 -
 18.2745 -    setSize: function(width, height) {
 18.2746 -      function interpret(val) {
 18.2747 -        return typeof val == "number" || /^\d+$/.test(String(val)) ? val + "px" : val;
 18.2748 -      }
 18.2749 -      if (width != null) this.display.wrapper.style.width = interpret(width);
 18.2750 -      if (height != null) this.display.wrapper.style.height = interpret(height);
 18.2751 -      this.refresh();
 18.2752 -    },
 18.2753 -
 18.2754 -    on: function(type, f) {on(this, type, f);},
 18.2755 -    off: function(type, f) {off(this, type, f);},
 18.2756 -
 18.2757 -    operation: function(f){return operation(this, f)();},
 18.2758 -
 18.2759 -    refresh: function() {
 18.2760 -      clearCaches(this);
 18.2761 -      if (this.display.scroller.scrollHeight > this.view.scrollTop)
 18.2762 -        this.display.scrollbarV.scrollTop = this.display.scroller.scrollTop = this.view.scrollTop;
 18.2763 -      updateDisplay(this, true);
 18.2764 -    },
 18.2765 -
 18.2766 -    getInputField: function(){return this.display.input;},
 18.2767 -    getWrapperElement: function(){return this.display.wrapper;},
 18.2768 -    getScrollerElement: function(){return this.display.scroller;},
 18.2769 -    getGutterElement: function(){return this.display.gutters;}
 18.2770 -  };
 18.2771 -
 18.2772 -  // OPTION DEFAULTS
 18.2773 -
 18.2774 -  var optionHandlers = CodeMirror.optionHandlers = {};
 18.2775 -
 18.2776 -  // The default configuration options.
 18.2777 -  var defaults = CodeMirror.defaults = {};
 18.2778 -
 18.2779 -  function option(name, deflt, handle, notOnInit) {
 18.2780 -    CodeMirror.defaults[name] = deflt;
 18.2781 -    if (handle) optionHandlers[name] =
 18.2782 -      notOnInit ? function(cm, val, old) {if (old != Init) handle(cm, val, old);} : handle;
 18.2783 -  }
 18.2784 -
 18.2785 -  var Init = CodeMirror.Init = {toString: function(){return "CodeMirror.Init";}};
 18.2786 -
 18.2787 -  // These two are, on init, called from the constructor because they
 18.2788 -  // have to be initialized before the editor can start at all.
 18.2789 -  option("value", "", function(cm, val) {cm.setValue(val);}, true);
 18.2790 -  option("mode", null, loadMode, true);
 18.2791 -
 18.2792 -  option("indentUnit", 2, loadMode, true);
 18.2793 -  option("indentWithTabs", false);
 18.2794 -  option("smartIndent", true);
 18.2795 -  option("tabSize", 4, function(cm) {
 18.2796 -    loadMode(cm);
 18.2797 -    clearCaches(cm);
 18.2798 -    updateDisplay(cm, true);
 18.2799 -  }, true);
 18.2800 -  option("electricChars", true);
 18.2801 -
 18.2802 -  option("theme", "default", function(cm) {
 18.2803 -    themeChanged(cm);
 18.2804 -    guttersChanged(cm);
 18.2805 -  }, true);
 18.2806 -  option("keyMap", "default", keyMapChanged);
 18.2807 -  option("extraKeys", null);
 18.2808 -
 18.2809 -  option("onKeyEvent", null);
 18.2810 -  option("onDragEvent", null);
 18.2811 -
 18.2812 -  option("lineWrapping", false, wrappingChanged, true);
 18.2813 -  option("gutters", [], function(cm) {
 18.2814 -    setGuttersForLineNumbers(cm.options);
 18.2815 -    guttersChanged(cm);
 18.2816 -  }, true);
 18.2817 -  option("lineNumbers", false, function(cm) {
 18.2818 -    setGuttersForLineNumbers(cm.options);
 18.2819 -    guttersChanged(cm);
 18.2820 -  }, true);
 18.2821 -  option("firstLineNumber", 1, guttersChanged, true);
 18.2822 -  option("lineNumberFormatter", function(integer) {return integer;}, guttersChanged, true);
 18.2823 -  option("showCursorWhenSelecting", false, updateSelection, true);
 18.2824 -  
 18.2825 -  option("readOnly", false, function(cm, val) {
 18.2826 -    if (val == "nocursor") {onBlur(cm); cm.display.input.blur();}
 18.2827 -    else if (!val) resetInput(cm, true);
 18.2828 -  });
 18.2829 -  option("dragDrop", true);
 18.2830 -
 18.2831 -  option("cursorBlinkRate", 530);
 18.2832 -  option("cursorHeight", 1);
 18.2833 -  option("workTime", 100);
 18.2834 -  option("workDelay", 100);
 18.2835 -  option("flattenSpans", true);
 18.2836 -  option("pollInterval", 100);
 18.2837 -  option("undoDepth", 40);
 18.2838 -  option("viewportMargin", 10, function(cm){cm.refresh();}, true);
 18.2839 -
 18.2840 -  option("tabindex", null, function(cm, val) {
 18.2841 -    cm.display.input.tabIndex = val || "";
 18.2842 -  });
 18.2843 -  option("autofocus", null);
 18.2844 -
 18.2845 -  // MODE DEFINITION AND QUERYING
 18.2846 -
 18.2847 -  // Known modes, by name and by MIME
 18.2848 -  var modes = CodeMirror.modes = {}, mimeModes = CodeMirror.mimeModes = {};
 18.2849 -
 18.2850 -  CodeMirror.defineMode = function(name, mode) {
 18.2851 -    if (!CodeMirror.defaults.mode && name != "null") CodeMirror.defaults.mode = name;
 18.2852 -    if (arguments.length > 2) {
 18.2853 -      mode.dependencies = [];
 18.2854 -      for (var i = 2; i < arguments.length; ++i) mode.dependencies.push(arguments[i]);
 18.2855 -    }
 18.2856 -    modes[name] = mode;
 18.2857 -  };
 18.2858 -
 18.2859 -  CodeMirror.defineMIME = function(mime, spec) {
 18.2860 -    mimeModes[mime] = spec;
 18.2861 -  };
 18.2862 -
 18.2863 -  CodeMirror.resolveMode = function(spec) {
 18.2864 -    if (typeof spec == "string" && mimeModes.hasOwnProperty(spec))
 18.2865 -      spec = mimeModes[spec];
 18.2866 -    else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec))
 18.2867 -      return CodeMirror.resolveMode("application/xml");
 18.2868 -    if (typeof spec == "string") return {name: spec};
 18.2869 -    else return spec || {name: "null"};
 18.2870 -  };
 18.2871 -
 18.2872 -  CodeMirror.getMode = function(options, spec) {
 18.2873 -    var spec = CodeMirror.resolveMode(spec);
 18.2874 -    var mfactory = modes[spec.name];
 18.2875 -    if (!mfactory) return CodeMirror.getMode(options, "text/plain");
 18.2876 -    var modeObj = mfactory(options, spec);
 18.2877 -    if (modeExtensions.hasOwnProperty(spec.name)) {
 18.2878 -      var exts = modeExtensions[spec.name];
 18.2879 -      for (var prop in exts) {
 18.2880 -        if (!exts.hasOwnProperty(prop)) continue;
 18.2881 -        if (modeObj.hasOwnProperty(prop)) modeObj["_" + prop] = modeObj[prop];
 18.2882 -        modeObj[prop] = exts[prop];
 18.2883 -      }
 18.2884 -    }
 18.2885 -    modeObj.name = spec.name;
 18.2886 -    return modeObj;
 18.2887 -  };
 18.2888 -
 18.2889 -  CodeMirror.defineMode("null", function() {
 18.2890 -    return {token: function(stream) {stream.skipToEnd();}};
 18.2891 -  });
 18.2892 -  CodeMirror.defineMIME("text/plain", "null");
 18.2893 -
 18.2894 -  var modeExtensions = CodeMirror.modeExtensions = {};
 18.2895 -  CodeMirror.extendMode = function(mode, properties) {
 18.2896 -    var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {});
 18.2897 -    for (var prop in properties) if (properties.hasOwnProperty(prop))
 18.2898 -      exts[prop] = properties[prop];
 18.2899 -  };
 18.2900 -
 18.2901 -  // EXTENSIONS
 18.2902 -
 18.2903 -  CodeMirror.defineExtension = function(name, func) {
 18.2904 -    CodeMirror.prototype[name] = func;
 18.2905 -  };
 18.2906 -
 18.2907 -  CodeMirror.defineOption = option;
 18.2908 -
 18.2909 -  var initHooks = [];
 18.2910 -  CodeMirror.defineInitHook = function(f) {initHooks.push(f);};
 18.2911 -
 18.2912 -  // MODE STATE HANDLING
 18.2913 -
 18.2914 -  // Utility functions for working with state. Exported because modes
 18.2915 -  // sometimes need to do this.
 18.2916 -  function copyState(mode, state) {
 18.2917 -    if (state === true) return state;
 18.2918 -    if (mode.copyState) return mode.copyState(state);
 18.2919 -    var nstate = {};
 18.2920 -    for (var n in state) {
 18.2921 -      var val = state[n];
 18.2922 -      if (val instanceof Array) val = val.concat([]);
 18.2923 -      nstate[n] = val;
 18.2924 -    }
 18.2925 -    return nstate;
 18.2926 -  }
 18.2927 -  CodeMirror.copyState = copyState;
 18.2928 -
 18.2929 -  function startState(mode, a1, a2) {
 18.2930 -    return mode.startState ? mode.startState(a1, a2) : true;
 18.2931 -  }
 18.2932 -  CodeMirror.startState = startState;
 18.2933 -
 18.2934 -  CodeMirror.innerMode = function(mode, state) {
 18.2935 -    while (mode.innerMode) {
 18.2936 -      var info = mode.innerMode(state);
 18.2937 -      state = info.state;
 18.2938 -      mode = info.mode;
 18.2939 -    }
 18.2940 -    return info || {mode: mode, state: state};
 18.2941 -  };
 18.2942 -
 18.2943 -  // STANDARD COMMANDS
 18.2944 -
 18.2945 -  var commands = CodeMirror.commands = {
 18.2946 -    selectAll: function(cm) {cm.setSelection({line: 0, ch: 0}, {line: cm.lineCount() - 1});},
 18.2947 -    killLine: function(cm) {
 18.2948 -      var from = cm.getCursor(true), to = cm.getCursor(false), sel = !posEq(from, to);
 18.2949 -      if (!sel && cm.getLine(from.line).length == from.ch)
 18.2950 -        cm.replaceRange("", from, {line: from.line + 1, ch: 0}, "delete");
 18.2951 -      else cm.replaceRange("", from, sel ? to : {line: from.line}, "delete");
 18.2952 -    },
 18.2953 -    deleteLine: function(cm) {
 18.2954 -      var l = cm.getCursor().line;
 18.2955 -      cm.replaceRange("", {line: l, ch: 0}, {line: l}, "delete");
 18.2956 -    },
 18.2957 -    undo: function(cm) {cm.undo();},
 18.2958 -    redo: function(cm) {cm.redo();},
 18.2959 -    goDocStart: function(cm) {cm.extendSelection({line: 0, ch: 0});},
 18.2960 -    goDocEnd: function(cm) {cm.extendSelection({line: cm.lineCount() - 1});},
 18.2961 -    goLineStart: function(cm) {
 18.2962 -      cm.extendSelection(lineStart(cm, cm.getCursor().line));
 18.2963 -    },
 18.2964 -    goLineStartSmart: function(cm) {
 18.2965 -      var cur = cm.getCursor(), start = lineStart(cm, cur.line);
 18.2966 -      var line = cm.getLineHandle(start.line);
 18.2967 -      var order = getOrder(line);
 18.2968 -      if (!order || order[0].level == 0) {
 18.2969 -        var firstNonWS = Math.max(0, line.text.search(/\S/));
 18.2970 -        var inWS = cur.line == start.line && cur.ch <= firstNonWS && cur.ch;
 18.2971 -        cm.extendSelection({line: start.line, ch: inWS ? 0 : firstNonWS});
 18.2972 -      } else cm.extendSelection(start);
 18.2973 -    },
 18.2974 -    goLineEnd: function(cm) {
 18.2975 -      cm.extendSelection(lineEnd(cm, cm.getCursor().line));
 18.2976 -    },
 18.2977 -    goLineUp: function(cm) {cm.moveV(-1, "line");},
 18.2978 -    goLineDown: function(cm) {cm.moveV(1, "line");},
 18.2979 -    goPageUp: function(cm) {cm.moveV(-1, "page");},
 18.2980 -    goPageDown: function(cm) {cm.moveV(1, "page");},
 18.2981 -    goCharLeft: function(cm) {cm.moveH(-1, "char");},
 18.2982 -    goCharRight: function(cm) {cm.moveH(1, "char");},
 18.2983 -    goColumnLeft: function(cm) {cm.moveH(-1, "column");},
 18.2984 -    goColumnRight: function(cm) {cm.moveH(1, "column");},
 18.2985 -    goWordLeft: function(cm) {cm.moveH(-1, "word");},
 18.2986 -    goWordRight: function(cm) {cm.moveH(1, "word");},
 18.2987 -    delCharBefore: function(cm) {cm.deleteH(-1, "char");},
 18.2988 -    delCharAfter: function(cm) {cm.deleteH(1, "char");},
 18.2989 -    delWordBefore: function(cm) {cm.deleteH(-1, "word");},
 18.2990 -    delWordAfter: function(cm) {cm.deleteH(1, "word");},
 18.2991 -    indentAuto: function(cm) {cm.indentSelection("smart");},
 18.2992 -    indentMore: function(cm) {cm.indentSelection("add");},
 18.2993 -    indentLess: function(cm) {cm.indentSelection("subtract");},
 18.2994 -    insertTab: function(cm) {cm.replaceSelection("\t", "end", "input");},
 18.2995 -    defaultTab: function(cm) {
 18.2996 -      if (cm.somethingSelected()) cm.indentSelection("add");
 18.2997 -      else cm.replaceSelection("\t", "end", "input");
 18.2998 -    },
 18.2999 -    transposeChars: function(cm) {
 18.3000 -      var cur = cm.getCursor(), line = cm.getLine(cur.line);
 18.3001 -      if (cur.ch > 0 && cur.ch < line.length - 1)
 18.3002 -        cm.replaceRange(line.charAt(cur.ch) + line.charAt(cur.ch - 1),
 18.3003 -                        {line: cur.line, ch: cur.ch - 1}, {line: cur.line, ch: cur.ch + 1});
 18.3004 -    },
 18.3005 -    newlineAndIndent: function(cm) {
 18.3006 -      operation(cm, function() {
 18.3007 -        cm.replaceSelection("\n", "end", "input");
 18.3008 -        cm.indentLine(cm.getCursor().line, null, true);
 18.3009 -      })();
 18.3010 -    },
 18.3011 -    toggleOverwrite: function(cm) {cm.toggleOverwrite();}
 18.3012 -  };
 18.3013 -
 18.3014 -  // STANDARD KEYMAPS
 18.3015 -
 18.3016 -  var keyMap = CodeMirror.keyMap = {};
 18.3017 -  keyMap.basic = {
 18.3018 -    "Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown",
 18.3019 -    "End": "goLineEnd", "Home": "goLineStartSmart", "PageUp": "goPageUp", "PageDown": "goPageDown",
 18.3020 -    "Delete": "delCharAfter", "Backspace": "delCharBefore", "Tab": "defaultTab", "Shift-Tab": "indentAuto",
 18.3021 -    "Enter": "newlineAndIndent", "Insert": "toggleOverwrite"
 18.3022 -  };
 18.3023 -  // Note that the save and find-related commands aren't defined by
 18.3024 -  // default. Unknown commands are simply ignored.
 18.3025 -  keyMap.pcDefault = {
 18.3026 -    "Ctrl-A": "selectAll", "Ctrl-D": "deleteLine", "Ctrl-Z": "undo", "Shift-Ctrl-Z": "redo", "Ctrl-Y": "redo",
 18.3027 -    "Ctrl-Home": "goDocStart", "Alt-Up": "goDocStart", "Ctrl-End": "goDocEnd", "Ctrl-Down": "goDocEnd",
 18.3028 -    "Ctrl-Left": "goWordLeft", "Ctrl-Right": "goWordRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd",
 18.3029 -    "Ctrl-Backspace": "delWordBefore", "Ctrl-Delete": "delWordAfter", "Ctrl-S": "save", "Ctrl-F": "find",
 18.3030 -    "Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll",
 18.3031 -    "Ctrl-[": "indentLess", "Ctrl-]": "indentMore",
 18.3032 -    fallthrough: "basic"
 18.3033 -  };
 18.3034 -  keyMap.macDefault = {
 18.3035 -    "Cmd-A": "selectAll", "Cmd-D": "deleteLine", "Cmd-Z": "undo", "Shift-Cmd-Z": "redo", "Cmd-Y": "redo",
 18.3036 -    "Cmd-Up": "goDocStart", "Cmd-End": "goDocEnd", "Cmd-Down": "goDocEnd", "Alt-Left": "goWordLeft",
 18.3037 -    "Alt-Right": "goWordRight", "Cmd-Left": "goLineStart", "Cmd-Right": "goLineEnd", "Alt-Backspace": "delWordBefore",
 18.3038 -    "Ctrl-Alt-Backspace": "delWordAfter", "Alt-Delete": "delWordAfter", "Cmd-S": "save", "Cmd-F": "find",
 18.3039 -    "Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll",
 18.3040 -    "Cmd-[": "indentLess", "Cmd-]": "indentMore",
 18.3041 -    fallthrough: ["basic", "emacsy"]
 18.3042 -  };
 18.3043 -  keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault;
 18.3044 -  keyMap.emacsy = {
 18.3045 -    "Ctrl-F": "goCharRight", "Ctrl-B": "goCharLeft", "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown",
 18.3046 -    "Alt-F": "goWordRight", "Alt-B": "goWordLeft", "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd",
 18.3047 -    "Ctrl-V": "goPageDown", "Shift-Ctrl-V": "goPageUp", "Ctrl-D": "delCharAfter", "Ctrl-H": "delCharBefore",
 18.3048 -    "Alt-D": "delWordAfter", "Alt-Backspace": "delWordBefore", "Ctrl-K": "killLine", "Ctrl-T": "transposeChars"
 18.3049 -  };
 18.3050 -
 18.3051 -  // KEYMAP DISPATCH
 18.3052 -
 18.3053 -  function getKeyMap(val) {
 18.3054 -    if (typeof val == "string") return keyMap[val];
 18.3055 -    else return val;
 18.3056 -  }
 18.3057 -
 18.3058 -  function lookupKey(name, maps, handle, stop) {
 18.3059 -    function lookup(map) {
 18.3060 -      map = getKeyMap(map);
 18.3061 -      var found = map[name];
 18.3062 -      if (found === false) {
 18.3063 -        if (stop) stop();
 18.3064 -        return true;
 18.3065 -      }
 18.3066 -      if (found != null && handle(found)) return true;
 18.3067 -      if (map.nofallthrough) {
 18.3068 -        if (stop) stop();
 18.3069 -        return true;
 18.3070 -      }
 18.3071 -      var fallthrough = map.fallthrough;
 18.3072 -      if (fallthrough == null) return false;
 18.3073 -      if (Object.prototype.toString.call(fallthrough) != "[object Array]")
 18.3074 -        return lookup(fallthrough);
 18.3075 -      for (var i = 0, e = fallthrough.length; i < e; ++i) {
 18.3076 -        if (lookup(fallthrough[i])) return true;
 18.3077 -      }
 18.3078 -      return false;
 18.3079 -    }
 18.3080 -
 18.3081 -    for (var i = 0; i < maps.length; ++i)
 18.3082 -      if (lookup(maps[i])) return true;
 18.3083 -  }
 18.3084 -  function isModifierKey(event) {
 18.3085 -    var name = keyNames[e_prop(event, "keyCode")];
 18.3086 -    return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod";
 18.3087 -  }
 18.3088 -  CodeMirror.isModifierKey = isModifierKey;
 18.3089 -
 18.3090 -  // FROMTEXTAREA
 18.3091 -
 18.3092 -  CodeMirror.fromTextArea = function(textarea, options) {
 18.3093 -    if (!options) options = {};
 18.3094 -    options.value = textarea.value;
 18.3095 -    if (!options.tabindex && textarea.tabindex)
 18.3096 -      options.tabindex = textarea.tabindex;
 18.3097 -    // Set autofocus to true if this textarea is focused, or if it has
 18.3098 -    // autofocus and no other element is focused.
 18.3099 -    if (options.autofocus == null) {
 18.3100 -      var hasFocus = document.body;
 18.3101 -      // doc.activeElement occasionally throws on IE
 18.3102 -      try { hasFocus = document.activeElement; } catch(e) {}
 18.3103 -      options.autofocus = hasFocus == textarea ||
 18.3104 -        textarea.getAttribute("autofocus") != null && hasFocus == document.body;
 18.3105 -    }
 18.3106 -
 18.3107 -    function save() {textarea.value = cm.getValue();}
 18.3108 -    if (textarea.form) {
 18.3109 -      // Deplorable hack to make the submit method do the right thing.
 18.3110 -      on(textarea.form, "submit", save);
 18.3111 -      var form = textarea.form, realSubmit = form.submit;
 18.3112 -      try {
 18.3113 -        form.submit = function wrappedSubmit() {
 18.3114 -          save();
 18.3115 -          form.submit = realSubmit;
 18.3116 -          form.submit();
 18.3117 -          form.submit = wrappedSubmit;
 18.3118 -        };
 18.3119 -      } catch(e) {}
 18.3120 -    }
 18.3121 -
 18.3122 -    textarea.style.display = "none";
 18.3123 -    var cm = CodeMirror(function(node) {
 18.3124 -      textarea.parentNode.insertBefore(node, textarea.nextSibling);
 18.3125 -    }, options);
 18.3126 -    cm.save = save;
 18.3127 -    cm.getTextArea = function() { return textarea; };
 18.3128 -    cm.toTextArea = function() {
 18.3129 -      save();
 18.3130 -      textarea.parentNode.removeChild(cm.getWrapperElement());
 18.3131 -      textarea.style.display = "";
 18.3132 -      if (textarea.form) {
 18.3133 -        off(textarea.form, "submit", save);
 18.3134 -        if (typeof textarea.form.submit == "function")
 18.3135 -          textarea.form.submit = realSubmit;
 18.3136 -      }
 18.3137 -    };
 18.3138 -    return cm;
 18.3139 -  };
 18.3140 -
 18.3141 -  // STRING STREAM
 18.3142 -
 18.3143 -  // Fed to the mode parsers, provides helper functions to make
 18.3144 -  // parsers more succinct.
 18.3145 -
 18.3146 -  // The character stream used by a mode's parser.
 18.3147 -  function StringStream(string, tabSize) {
 18.3148 -    this.pos = this.start = 0;
 18.3149 -    this.string = string;
 18.3150 -    this.tabSize = tabSize || 8;
 18.3151 -  }
 18.3152 -
 18.3153 -  StringStream.prototype = {
 18.3154 -    eol: function() {return this.pos >= this.string.length;},
 18.3155 -    sol: function() {return this.pos == 0;},
 18.3156 -    peek: function() {return this.string.charAt(this.pos) || undefined;},
 18.3157 -    next: function() {
 18.3158 -      if (this.pos < this.string.length)
 18.3159 -        return this.string.charAt(this.pos++);
 18.3160 -    },
 18.3161 -    eat: function(match) {
 18.3162 -      var ch = this.string.charAt(this.pos);
 18.3163 -      if (typeof match == "string") var ok = ch == match;
 18.3164 -      else var ok = ch && (match.test ? match.test(ch) : match(ch));
 18.3165 -      if (ok) {++this.pos; return ch;}
 18.3166 -    },
 18.3167 -    eatWhile: function(match) {
 18.3168 -      var start = this.pos;
 18.3169 -      while (this.eat(match)){}
 18.3170 -      return this.pos > start;
 18.3171 -    },
 18.3172 -    eatSpace: function() {
 18.3173 -      var start = this.pos;
 18.3174 -      while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos;
 18.3175 -      return this.pos > start;
 18.3176 -    },
 18.3177 -    skipToEnd: function() {this.pos = this.string.length;},
 18.3178 -    skipTo: function(ch) {
 18.3179 -      var found = this.string.indexOf(ch, this.pos);
 18.3180 -      if (found > -1) {this.pos = found; return true;}
 18.3181 -    },
 18.3182 -    backUp: function(n) {this.pos -= n;},
 18.3183 -    column: function() {return countColumn(this.string, this.start, this.tabSize);},
 18.3184 -    indentation: function() {return countColumn(this.string, null, this.tabSize);},
 18.3185 -    match: function(pattern, consume, caseInsensitive) {
 18.3186 -      if (typeof pattern == "string") {
 18.3187 -        var cased = function(str) {return caseInsensitive ? str.toLowerCase() : str;};
 18.3188 -        if (cased(this.string).indexOf(cased(pattern), this.pos) == this.pos) {
 18.3189 -          if (consume !== false) this.pos += pattern.length;
 18.3190 -          return true;
 18.3191 -        }
 18.3192 -      } else {
 18.3193 -        var match = this.string.slice(this.pos).match(pattern);
 18.3194 -        if (match && match.index > 0) return null;
 18.3195 -        if (match && consume !== false) this.pos += match[0].length;
 18.3196 -        return match;
 18.3197 -      }
 18.3198 -    },
 18.3199 -    current: function(){return this.string.slice(this.start, this.pos);}
 18.3200 -  };
 18.3201 -  CodeMirror.StringStream = StringStream;
 18.3202 -
 18.3203 -  // TEXTMARKERS
 18.3204 -
 18.3205 -  function TextMarker(cm, type) {
 18.3206 -    this.lines = [];
 18.3207 -    this.type = type;
 18.3208 -    this.cm = cm;
 18.3209 -  }
 18.3210 -
 18.3211 -  TextMarker.prototype.clear = function() {
 18.3212 -    if (this.explicitlyCleared) return;
 18.3213 -    startOperation(this.cm);
 18.3214 -    var min = null, max = null;
 18.3215 -    for (var i = 0; i < this.lines.length; ++i) {
 18.3216 -      var line = this.lines[i];
 18.3217 -      var span = getMarkedSpanFor(line.markedSpans, this);
 18.3218 -      if (span.to != null) max = lineNo(line);
 18.3219 -      line.markedSpans = removeMarkedSpan(line.markedSpans, span);
 18.3220 -      if (span.from != null)
 18.3221 -        min = lineNo(line);
 18.3222 -      else if (this.collapsed && !lineIsHidden(line))
 18.3223 -        updateLineHeight(line, textHeight(this.cm.display));
 18.3224 -    }
 18.3225 -    if (min != null) regChange(this.cm, min, max + 1);
 18.3226 -    this.lines.length = 0;
 18.3227 -    this.explicitlyCleared = true;
 18.3228 -    if (this.collapsed && this.cm.view.cantEdit) {
 18.3229 -      this.cm.view.cantEdit = false;
 18.3230 -      reCheckSelection(this.cm);
 18.3231 -    }
 18.3232 -    endOperation(this.cm);
 18.3233 -    signalLater(this.cm, this, "clear");
 18.3234 -  };
 18.3235 -
 18.3236 -  TextMarker.prototype.find = function() {
 18.3237 -    var from, to;
 18.3238 -    for (var i = 0; i < this.lines.length; ++i) {
 18.3239 -      var line = this.lines[i];
 18.3240 -      var span = getMarkedSpanFor(line.markedSpans, this);
 18.3241 -      if (span.from != null || span.to != null) {
 18.3242 -        var found = lineNo(line);
 18.3243 -        if (span.from != null) from = {line: found, ch: span.from};
 18.3244 -        if (span.to != null) to = {line: found, ch: span.to};
 18.3245 -      }
 18.3246 -    }
 18.3247 -    if (this.type == "bookmark") return from;
 18.3248 -    return from && {from: from, to: to};
 18.3249 -  };
 18.3250 -
 18.3251 -  function markText(cm, from, to, options, type) {
 18.3252 -    var doc = cm.view.doc;
 18.3253 -    var marker = new TextMarker(cm, type);
 18.3254 -    if (type == "range" && !posLess(from, to)) return marker;
 18.3255 -    if (options) for (var opt in options) if (options.hasOwnProperty(opt))
 18.3256 -      marker[opt] = options[opt];
 18.3257 -    if (marker.replacedWith) {
 18.3258 -      marker.collapsed = true;
 18.3259 -      marker.replacedWith = elt("span", [marker.replacedWith], "CodeMirror-widget");
 18.3260 -    }
 18.3261 -    if (marker.collapsed) sawCollapsedSpans = true;
 18.3262 -
 18.3263 -    var curLine = from.line, size = 0, collapsedAtStart, collapsedAtEnd;
 18.3264 -    doc.iter(curLine, to.line + 1, function(line) {
 18.3265 -      var span = {from: null, to: null, marker: marker};
 18.3266 -      size += line.text.length;
 18.3267 -      if (curLine == from.line) {span.from = from.ch; size -= from.ch;}
 18.3268 -      if (curLine == to.line) {span.to = to.ch; size -= line.text.length - to.ch;}
 18.3269 -      if (marker.collapsed) {
 18.3270 -        if (curLine == to.line) collapsedAtEnd = collapsedSpanAt(line, to.ch);
 18.3271 -        if (curLine == from.line) collapsedAtStart = collapsedSpanAt(line, from.ch);
 18.3272 -        else updateLineHeight(line, 0);
 18.3273 -      }
 18.3274 -      addMarkedSpan(line, span);
 18.3275 -      if (marker.collapsed && curLine == from.line && lineIsHidden(line))
 18.3276 -        updateLineHeight(line, 0);
 18.3277 -      ++curLine;
 18.3278 -    });
 18.3279 -
 18.3280 -    if (marker.readOnly) {
 18.3281 -      sawReadOnlySpans = true;
 18.3282 -      if (cm.view.history.done.length || cm.view.history.undone.length)
 18.3283 -        cm.clearHistory();
 18.3284 -    }
 18.3285 -    if (marker.collapsed) {
 18.3286 -      if (collapsedAtStart != collapsedAtEnd)
 18.3287 -        throw new Error("Inserting collapsed marker overlapping an existing one");
 18.3288 -      marker.size = size;
 18.3289 -      marker.atomic = true;
 18.3290 -    }
 18.3291 -    if (marker.className || marker.startStyle || marker.endStyle || marker.collapsed)
 18.3292 -      regChange(cm, from.line, to.line + 1);
 18.3293 -    if (marker.atomic) reCheckSelection(cm);
 18.3294 -    return marker;
 18.3295 -  }
 18.3296 -
 18.3297 -  // TEXTMARKER SPANS
 18.3298 -
 18.3299 -  function getMarkedSpanFor(spans, marker) {
 18.3300 -    if (spans) for (var i = 0; i < spans.length; ++i) {
 18.3301 -      var span = spans[i];
 18.3302 -      if (span.marker == marker) return span;
 18.3303 -    }
 18.3304 -  }
 18.3305 -  function removeMarkedSpan(spans, span) {
 18.3306 -    for (var r, i = 0; i < spans.length; ++i)
 18.3307 -      if (spans[i] != span) (r || (r = [])).push(spans[i]);
 18.3308 -    return r;
 18.3309 -  }
 18.3310 -  function addMarkedSpan(line, span) {
 18.3311 -    line.markedSpans = line.markedSpans ? line.markedSpans.concat([span]) : [span];
 18.3312 -    span.marker.lines.push(line);
 18.3313 -  }
 18.3314 -
 18.3315 -  function markedSpansBefore(old, startCh) {
 18.3316 -    if (old) for (var i = 0, nw; i < old.length; ++i) {
 18.3317 -      var span = old[i], marker = span.marker;
 18.3318 -      var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= startCh : span.from < startCh);
 18.3319 -      if (startsBefore || marker.type == "bookmark" && span.from == startCh) {
 18.3320 -        var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= startCh : span.to > startCh);
 18.3321 -        (nw || (nw = [])).push({from: span.from,
 18.3322 -                                to: endsAfter ? null : span.to,
 18.3323 -                                marker: marker});
 18.3324 -      }
 18.3325 -    }
 18.3326 -    return nw;
 18.3327 -  }
 18.3328 -
 18.3329 -  function markedSpansAfter(old, startCh, endCh) {
 18.3330 -    if (old) for (var i = 0, nw; i < old.length; ++i) {
 18.3331 -      var span = old[i], marker = span.marker;
 18.3332 -      var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh);
 18.3333 -      if (endsAfter || marker.type == "bookmark" && span.from == endCh && span.from != startCh) {
 18.3334 -        var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh);
 18.3335 -        (nw || (nw = [])).push({from: startsBefore ? null : span.from - endCh,
 18.3336 -                                to: span.to == null ? null : span.to - endCh,
 18.3337 -                                marker: marker});
 18.3338 -      }
 18.3339 -    }
 18.3340 -    return nw;
 18.3341 -  }
 18.3342 -
 18.3343 -  function updateMarkedSpans(oldFirst, oldLast, startCh, endCh, newText) {
 18.3344 -    if (!oldFirst && !oldLast) return newText;
 18.3345 -    // Get the spans that 'stick out' on both sides
 18.3346 -    var first = markedSpansBefore(oldFirst, startCh);
 18.3347 -    var last = markedSpansAfter(oldLast, startCh, endCh);
 18.3348 -
 18.3349 -    // Next, merge those two ends
 18.3350 -    var sameLine = newText.length == 1, offset = lst(newText).length + (sameLine ? startCh : 0);
 18.3351 -    if (first) {
 18.3352 -      // Fix up .to properties of first
 18.3353 -      for (var i = 0; i < first.length; ++i) {
 18.3354 -        var span = first[i];
 18.3355 -        if (span.to == null) {
 18.3356 -          var found = getMarkedSpanFor(last, span.marker);
 18.3357 -          if (!found) span.to = startCh;
 18.3358 -          else if (sameLine) span.to = found.to == null ? null : found.to + offset;
 18.3359 -        }
 18.3360 -      }
 18.3361 -    }
 18.3362 -    if (last) {
 18.3363 -      // Fix up .from in last (or move them into first in case of sameLine)
 18.3364 -      for (var i = 0; i < last.length; ++i) {
 18.3365 -        var span = last[i];
 18.3366 -        if (span.to != null) span.to += offset;
 18.3367 -        if (span.from == null) {
 18.3368 -          var found = getMarkedSpanFor(first, span.marker);
 18.3369 -          if (!found) {
 18.3370 -            span.from = offset;
 18.3371 -            if (sameLine) (first || (first = [])).push(span);
 18.3372 -          }
 18.3373 -        } else {
 18.3374 -          span.from += offset;
 18.3375 -          if (sameLine) (first || (first = [])).push(span);
 18.3376 -        }
 18.3377 -      }
 18.3378 -    }
 18.3379 -
 18.3380 -    var newMarkers = [newHL(newText[0], first)];
 18.3381 -    if (!sameLine) {
 18.3382 -      // Fill gap with whole-line-spans
 18.3383 -      var gap = newText.length - 2, gapMarkers;
 18.3384 -      if (gap > 0 && first)
 18.3385 -        for (var i = 0; i < first.length; ++i)
 18.3386 -          if (first[i].to == null)
 18.3387 -            (gapMarkers || (gapMarkers = [])).push({from: null, to: null, marker: first[i].marker});
 18.3388 -      for (var i = 0; i < gap; ++i)
 18.3389 -        newMarkers.push(newHL(newText[i+1], gapMarkers));
 18.3390 -      newMarkers.push(newHL(lst(newText), last));
 18.3391 -    }
 18.3392 -    return newMarkers;
 18.3393 -  }
 18.3394 -
 18.3395 -  function removeReadOnlyRanges(doc, from, to) {
 18.3396 -    var markers = null;
 18.3397 -    doc.iter(from.line, to.line + 1, function(line) {
 18.3398 -      if (line.markedSpans) for (var i = 0; i < line.markedSpans.length; ++i) {
 18.3399 -        var mark = line.markedSpans[i].marker;
 18.3400 -        if (mark.readOnly && (!markers || indexOf(markers, mark) == -1))
 18.3401 -          (markers || (markers = [])).push(mark);
 18.3402 -      }
 18.3403 -    });
 18.3404 -    if (!markers) return null;
 18.3405 -    var parts = [{from: from, to: to}];
 18.3406 -    for (var i = 0; i < markers.length; ++i) {
 18.3407 -      var m = markers[i].find();
 18.3408 -      for (var j = 0; j < parts.length; ++j) {
 18.3409 -        var p = parts[j];
 18.3410 -        if (!posLess(m.from, p.to) || posLess(m.to, p.from)) continue;
 18.3411 -        var newParts = [j, 1];
 18.3412 -        if (posLess(p.from, m.from)) newParts.push({from: p.from, to: m.from});
 18.3413 -        if (posLess(m.to, p.to)) newParts.push({from: m.to, to: p.to});
 18.3414 -        parts.splice.apply(parts, newParts);
 18.3415 -        j += newParts.length - 1;
 18.3416 -      }
 18.3417 -    }
 18.3418 -    return parts;
 18.3419 -  }
 18.3420 -
 18.3421 -  function collapsedSpanAt(line, ch) {
 18.3422 -    var sps = sawCollapsedSpans && line.markedSpans, found;
 18.3423 -    if (sps) for (var sp, i = 0; i < sps.length; ++i) {
 18.3424 -      sp = sps[i];
 18.3425 -      if (!sp.marker.collapsed) continue;
 18.3426 -      if ((sp.from == null || sp.from < ch) &&
 18.3427 -          (sp.to == null || sp.to > ch) &&
 18.3428 -          (!found || found.width < sp.marker.width))
 18.3429 -        found = sp.marker;
 18.3430 -    }
 18.3431 -    return found;
 18.3432 -  }
 18.3433 -  function collapsedSpanAtStart(line) { return collapsedSpanAt(line, -1); }
 18.3434 -  function collapsedSpanAtEnd(line) { return collapsedSpanAt(line, line.text.length + 1); }
 18.3435 -
 18.3436 -  function visualLine(doc, line) {
 18.3437 -    var merged;
 18.3438 -    while (merged = collapsedSpanAtStart(line))
 18.3439 -      line = getLine(doc, merged.find().from.line);
 18.3440 -    return line;
 18.3441 -  }
 18.3442 -
 18.3443 -  function lineIsHidden(line) {
 18.3444 -    var sps = sawCollapsedSpans && line.markedSpans;
 18.3445 -    if (sps) for (var sp, i = 0; i < sps.length; ++i) {
 18.3446 -      sp = sps[i];
 18.3447 -      if (!sp.marker.collapsed) continue;
 18.3448 -      if (sp.from == null) return true;
 18.3449 -      if (sp.from == 0 && sp.marker.inclusiveLeft && lineIsHiddenInner(line, sp))
 18.3450 -        return true;
 18.3451 -    }
 18.3452 -  }
 18.3453 -  window.lineIsHidden = lineIsHidden;
 18.3454 -  function lineIsHiddenInner(line, span) {
 18.3455 -    if (span.to == null || span.marker.inclusiveRight && span.to == line.text.length)
 18.3456 -      return true;
 18.3457 -    for (var sp, i = 0; i < line.markedSpans.length; ++i) {
 18.3458 -      sp = line.markedSpans[i];
 18.3459 -      if (sp.marker.collapsed && sp.from == span.to &&
 18.3460 -          (sp.marker.inclusiveLeft || span.marker.inclusiveRight) &&
 18.3461 -          lineIsHiddenInner(line, sp)) return true;
 18.3462 -    }
 18.3463 -  }
 18.3464 -
 18.3465 -  // hl stands for history-line, a data structure that can be either a
 18.3466 -  // string (line without markers) or a {text, markedSpans} object.
 18.3467 -  function hlText(val) { return typeof val == "string" ? val : val.text; }
 18.3468 -  function hlSpans(val) {
 18.3469 -    if (typeof val == "string") return null;
 18.3470 -    var spans = val.markedSpans, out = null;
 18.3471 -    for (var i = 0; i < spans.length; ++i) {
 18.3472 -      if (spans[i].marker.explicitlyCleared) { if (!out) out = spans.slice(0, i); }
 18.3473 -      else if (out) out.push(spans[i]);
 18.3474 -    }
 18.3475 -    return !out ? spans : out.length ? out : null;
 18.3476 -  }
 18.3477 -  function newHL(text, spans) { return spans ? {text: text, markedSpans: spans} : text; }
 18.3478 -
 18.3479 -  function detachMarkedSpans(line) {
 18.3480 -    var spans = line.markedSpans;
 18.3481 -    if (!spans) return;
 18.3482 -    for (var i = 0; i < spans.length; ++i) {
 18.3483 -      var lines = spans[i].marker.lines;
 18.3484 -      var ix = indexOf(lines, line);
 18.3485 -      lines.splice(ix, 1);
 18.3486 -    }
 18.3487 -    line.markedSpans = null;
 18.3488 -  }
 18.3489 -
 18.3490 -  function attachMarkedSpans(line, spans) {
 18.3491 -    if (!spans) return;
 18.3492 -    for (var i = 0; i < spans.length; ++i)
 18.3493 -      spans[i].marker.lines.push(line);
 18.3494 -    line.markedSpans = spans;
 18.3495 -  }
 18.3496 -
 18.3497 -  // LINE DATA STRUCTURE
 18.3498 -
 18.3499 -  // Line objects. These hold state related to a line, including
 18.3500 -  // highlighting info (the styles array).
 18.3501 -  function makeLine(text, markedSpans, height) {
 18.3502 -    var line = {text: text, height: height};
 18.3503 -    attachMarkedSpans(line, markedSpans);
 18.3504 -    if (lineIsHidden(line)) line.height = 0;
 18.3505 -    return line;
 18.3506 -  }
 18.3507 -
 18.3508 -  function updateLine(cm, line, text, markedSpans) {
 18.3509 -    line.text = text;
 18.3510 -    line.stateAfter = line.styles = null;
 18.3511 -    if (line.order != null) line.order = null;
 18.3512 -    detachMarkedSpans(line);
 18.3513 -    attachMarkedSpans(line, markedSpans);
 18.3514 -    if (lineIsHidden(line)) line.height = 0;
 18.3515 -    else if (!line.height) line.height = textHeight(cm.display);
 18.3516 -    signalLater(cm, line, "change");
 18.3517 -  }
 18.3518 -
 18.3519 -  function cleanUpLine(line) {
 18.3520 -    line.parent = null;
 18.3521 -    detachMarkedSpans(line);
 18.3522 -  }
 18.3523 -
 18.3524 -  // Run the given mode's parser over a line, update the styles
 18.3525 -  // array, which contains alternating fragments of text and CSS
 18.3526 -  // classes.
 18.3527 -  function highlightLine(cm, line, state) {
 18.3528 -    var mode = cm.view.mode, flattenSpans = cm.options.flattenSpans;
 18.3529 -    var changed = !line.styles, pos = 0, curText = "", curStyle = null;
 18.3530 -    var stream = new StringStream(line.text, cm.options.tabSize), st = line.styles || (line.styles = []);
 18.3531 -    if (line.text == "" && mode.blankLine) mode.blankLine(state);
 18.3532 -    while (!stream.eol()) {
 18.3533 -      var style = mode.token(stream, state), substr = stream.current();
 18.3534 -      stream.start = stream.pos;
 18.3535 -      if (!flattenSpans || curStyle != style) {
 18.3536 -        if (curText) {
 18.3537 -          changed = changed || pos >= st.length || curText != st[pos] || curStyle != st[pos+1];
 18.3538 -          st[pos++] = curText; st[pos++] = curStyle;
 18.3539 -        }
 18.3540 -        curText = substr; curStyle = style;
 18.3541 -      } else curText = curText + substr;
 18.3542 -      // Give up when line is ridiculously long
 18.3543 -      if (stream.pos > 5000) break;
 18.3544 -    }
 18.3545 -    if (curText) {
 18.3546 -      changed = changed || pos >= st.length || curText != st[pos] || curStyle != st[pos+1];
 18.3547 -      st[pos++] = curText; st[pos++] = curStyle;
 18.3548 -    }
 18.3549 -    if (stream.pos > 5000) { st[pos++] = line.text.slice(stream.pos); st[pos++] = null; }
 18.3550 -    if (pos != st.length) { st.length = pos; changed = true; }
 18.3551 -    return changed;
 18.3552 -  }
 18.3553 -
 18.3554 -  // Lightweight form of highlight -- proceed over this line and
 18.3555 -  // update state, but don't save a style array.
 18.3556 -  function processLine(cm, line, state) {
 18.3557 -    var mode = cm.view.mode;
 18.3558 -    var stream = new StringStream(line.text, cm.options.tabSize);
 18.3559 -    if (line.text == "" && mode.blankLine) mode.blankLine(state);
 18.3560 -    while (!stream.eol() && stream.pos <= 5000) {
 18.3561 -      mode.token(stream, state);
 18.3562 -      stream.start = stream.pos;
 18.3563 -    }
 18.3564 -  }
 18.3565 -
 18.3566 -  var styleToClassCache = {};
 18.3567 -  function styleToClass(style) {
 18.3568 -    if (!style) return null;
 18.3569 -    return styleToClassCache[style] ||
 18.3570 -      (styleToClassCache[style] = "cm-" + style.replace(/ +/g, " cm-"));
 18.3571 -  }
 18.3572 -
 18.3573 -  function lineContent(cm, realLine, measure) {
 18.3574 -    var merged, line = realLine, lineBefore, sawBefore, simple = true;
 18.3575 -    while (merged = collapsedSpanAtStart(line)) {
 18.3576 -      simple = false;
 18.3577 -      line = getLine(cm.view.doc, merged.find().from.line);
 18.3578 -      if (!lineBefore) lineBefore = line;
 18.3579 -    }
 18.3580 -
 18.3581 -    var builder = {pre: elt("pre"), col: 0, pos: 0, display: !measure,
 18.3582 -                   measure: null, addedOne: false, cm: cm};
 18.3583 -    if (line.textClass) builder.pre.className = line.textClass;
 18.3584 -
 18.3585 -    do {
 18.3586 -      if (!line.styles)
 18.3587 -        highlightLine(cm, line, line.stateAfter = getStateBefore(cm, lineNo(line)));
 18.3588 -      builder.measure = line == realLine && measure;
 18.3589 -      builder.pos = 0;
 18.3590 -      builder.addToken = builder.measure ? buildTokenMeasure : buildToken;
 18.3591 -      if (measure && sawBefore && line != realLine && !builder.addedOne) {
 18.3592 -        measure[0] = builder.pre.appendChild(zeroWidthElement(cm.display.measure));
 18.3593 -        builder.addedOne = true;
 18.3594 -      }
 18.3595 -      var next = insertLineContent(line, builder);
 18.3596 -      sawBefore = line == lineBefore;
 18.3597 -      if (next) {
 18.3598 -        line = getLine(cm.view.doc, next.to.line);
 18.3599 -        simple = false;
 18.3600 -      }
 18.3601 -    } while (next);
 18.3602 -
 18.3603 -    if (measure && !builder.addedOne)
 18.3604 -      measure[0] = builder.pre.appendChild(simple ? elt("span", "\u00a0") : zeroWidthElement(cm.display.measure));
 18.3605 -    if (!builder.pre.firstChild && !lineIsHidden(realLine))
 18.3606 -      builder.pre.appendChild(document.createTextNode("\u00a0"));
 18.3607 -
 18.3608 -    return builder.pre;
 18.3609 -  }
 18.3610 -
 18.3611 -  var tokenSpecialChars = /[\t\u0000-\u0019\u200b\u2028\u2029\uFEFF]/g;
 18.3612 -  function buildToken(builder, text, style, startStyle, endStyle) {
 18.3613 -    if (!text) return;
 18.3614 -    if (!tokenSpecialChars.test(text)) {
 18.3615 -      builder.col += text.length;
 18.3616 -      var content = document.createTextNode(text);
 18.3617 -    } else {
 18.3618 -      var content = document.createDocumentFragment(), pos = 0;
 18.3619 -      while (true) {
 18.3620 -        tokenSpecialChars.lastIndex = pos;
 18.3621 -        var m = tokenSpecialChars.exec(text);
 18.3622 -        var skipped = m ? m.index - pos : text.length - pos;
 18.3623 -        if (skipped) {
 18.3624 -          content.appendChild(document.createTextNode(text.slice(pos, pos + skipped)));
 18.3625 -          builder.col += skipped;
 18.3626 -        }
 18.3627 -        if (!m) break;
 18.3628 -        pos += skipped + 1;
 18.3629 -        if (m[0] == "\t") {
 18.3630 -          var tabSize = builder.cm.options.tabSize, tabWidth = tabSize - builder.col % tabSize;
 18.3631 -          content.appendChild(elt("span", spaceStr(tabWidth), "cm-tab"));
 18.3632 -          builder.col += tabWidth;
 18.3633 -        } else {
 18.3634 -          var token = elt("span", "\u2022", "cm-invalidchar");
 18.3635 -          token.title = "\\u" + m[0].charCodeAt(0).toString(16);
 18.3636 -          content.appendChild(token);
 18.3637 -          builder.col += 1;
 18.3638 -        }
 18.3639 -      }
 18.3640 -    }
 18.3641 -    if (style || startStyle || endStyle || builder.measure) {
 18.3642 -      var fullStyle = style || "";
 18.3643 -      if (startStyle) fullStyle += startStyle;
 18.3644 -      if (endStyle) fullStyle += endStyle;
 18.3645 -      return builder.pre.appendChild(elt("span", [content], fullStyle));
 18.3646 -    }
 18.3647 -    builder.pre.appendChild(content);
 18.3648 -  }
 18.3649 -
 18.3650 -  function buildTokenMeasure(builder, text, style, startStyle, endStyle) {
 18.3651 -    for (var i = 0; i < text.length; ++i) {
 18.3652 -      if (i && i < text.length - 1 &&
 18.3653 -          builder.cm.options.lineWrapping &&
 18.3654 -          spanAffectsWrapping.test(text.slice(i - 1, i + 1)))
 18.3655 -        builder.pre.appendChild(elt("wbr"));
 18.3656 -      builder.measure[builder.pos++] =
 18.3657 -        buildToken(builder, text.charAt(i), style,
 18.3658 -                   i == 0 && startStyle, i == text.length - 1 && endStyle);
 18.3659 -    }
 18.3660 -    if (text.length) builder.addedOne = true;
 18.3661 -  }
 18.3662 -
 18.3663 -  function buildCollapsedSpan(builder, size, widget) {
 18.3664 -    if (widget) {
 18.3665 -      if (!builder.display) widget = widget.cloneNode(true);
 18.3666 -      builder.pre.appendChild(widget);
 18.3667 -      if (builder.measure && size) {
 18.3668 -        builder.measure[builder.pos] = widget;
 18.3669 -        builder.addedOne = true;
 18.3670 -      }
 18.3671 -    }
 18.3672 -    builder.pos += size;
 18.3673 -  }
 18.3674 -
 18.3675 -  // Outputs a number of spans to make up a line, taking highlighting
 18.3676 -  // and marked text into account.
 18.3677 -  function insertLineContent(line, builder) {
 18.3678 -    var st = line.styles, spans = line.markedSpans;
 18.3679 -    if (!spans) {
 18.3680 -      for (var i = 0; i < st.length; i+=2)
 18.3681 -        builder.addToken(builder, st[i], styleToClass(st[i+1]));
 18.3682 -      return;
 18.3683 -    }
 18.3684 -
 18.3685 -    var allText = line.text, len = allText.length;
 18.3686 -    var pos = 0, i = 0, text = "", style;
 18.3687 -    var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, collapsed;
 18.3688 -    for (;;) {
 18.3689 -      if (nextChange == pos) { // Update current marker set
 18.3690 -        spanStyle = spanEndStyle = spanStartStyle = "";
 18.3691 -        collapsed = null; nextChange = Infinity;
 18.3692 -        var foundBookmark = null;
 18.3693 -        for (var j = 0; j < spans.length; ++j) {
 18.3694 -          var sp = spans[j], m = sp.marker;
 18.3695 -          if (sp.from <= pos && (sp.to == null || sp.to > pos)) {
 18.3696 -            if (sp.to != null && nextChange > sp.to) { nextChange = sp.to; spanEndStyle = ""; }
 18.3697 -            if (m.className) spanStyle += " " + m.className;
 18.3698 -            if (m.startStyle && sp.from == pos) spanStartStyle += " " + m.startStyle;
 18.3699 -            if (m.endStyle && sp.to == nextChange) spanEndStyle += " " + m.endStyle;
 18.3700 -            if (m.collapsed && (!collapsed || collapsed.marker.width < m.width))
 18.3701 -              collapsed = sp;
 18.3702 -          } else if (sp.from > pos && nextChange > sp.from) {
 18.3703 -            nextChange = sp.from;
 18.3704 -          }
 18.3705 -          if (m.type == "bookmark" && sp.from == pos && m.replacedWith)
 18.3706 -            foundBookmark = m.replacedWith;
 18.3707 -        }
 18.3708 -        if (collapsed && (collapsed.from || 0) == pos) {
 18.3709 -          buildCollapsedSpan(builder, (collapsed.to == null ? len : collapsed.to) - pos,
 18.3710 -                             collapsed.from != null && collapsed.marker.replacedWith);
 18.3711 -          if (collapsed.to == null) return collapsed.marker.find();
 18.3712 -        }
 18.3713 -        if (foundBookmark && !collapsed) buildCollapsedSpan(builder, 0, foundBookmark);
 18.3714 -      }
 18.3715 -      if (pos >= len) break;
 18.3716 -
 18.3717 -      var upto = Math.min(len, nextChange);
 18.3718 -      while (true) {
 18.3719 -        if (text) {
 18.3720 -          var end = pos + text.length;
 18.3721 -          if (!collapsed) {
 18.3722 -            var tokenText = end > upto ? text.slice(0, upto - pos) : text;
 18.3723 -            builder.addToken(builder, tokenText, style + spanStyle,
 18.3724 -                             spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : "");
 18.3725 -          }
 18.3726 -          if (end >= upto) {text = text.slice(upto - pos); pos = upto; break;}
 18.3727 -          pos = end;
 18.3728 -          spanStartStyle = "";
 18.3729 -        }
 18.3730 -        text = st[i++]; style = styleToClass(st[i++]);
 18.3731 -      }
 18.3732 -    }
 18.3733 -  }
 18.3734 -
 18.3735 -  // DOCUMENT DATA STRUCTURE
 18.3736 -
 18.3737 -  function LeafChunk(lines) {
 18.3738 -    this.lines = lines;
 18.3739 -    this.parent = null;
 18.3740 -    for (var i = 0, e = lines.length, height = 0; i < e; ++i) {
 18.3741 -      lines[i].parent = this;
 18.3742 -      height += lines[i].height;
 18.3743 -    }
 18.3744 -    this.height = height;
 18.3745 -  }
 18.3746 -
 18.3747 -  LeafChunk.prototype = {
 18.3748 -    chunkSize: function() { return this.lines.length; },
 18.3749 -    remove: function(at, n, cm) {
 18.3750 -      for (var i = at, e = at + n; i < e; ++i) {
 18.3751 -        var line = this.lines[i];
 18.3752 -        this.height -= line.height;
 18.3753 -        cleanUpLine(line);
 18.3754 -        signalLater(cm, line, "delete");
 18.3755 -      }
 18.3756 -      this.lines.splice(at, n);
 18.3757 -    },
 18.3758 -    collapse: function(lines) {
 18.3759 -      lines.splice.apply(lines, [lines.length, 0].concat(this.lines));
 18.3760 -    },
 18.3761 -    insertHeight: function(at, lines, height) {
 18.3762 -      this.height += height;
 18.3763 -      this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at));
 18.3764 -      for (var i = 0, e = lines.length; i < e; ++i) lines[i].parent = this;
 18.3765 -    },
 18.3766 -    iterN: function(at, n, op) {
 18.3767 -      for (var e = at + n; at < e; ++at)
 18.3768 -        if (op(this.lines[at])) return true;
 18.3769 -    }
 18.3770 -  };
 18.3771 -
 18.3772 -  function BranchChunk(children) {
 18.3773 -    this.children = children;
 18.3774 -    var size = 0, height = 0;
 18.3775 -    for (var i = 0, e = children.length; i < e; ++i) {
 18.3776 -      var ch = children[i];
 18.3777 -      size += ch.chunkSize(); height += ch.height;
 18.3778 -      ch.parent = this;
 18.3779 -    }
 18.3780 -    this.size = size;
 18.3781 -    this.height = height;
 18.3782 -    this.parent = null;
 18.3783 -  }
 18.3784 -
 18.3785 -  BranchChunk.prototype = {
 18.3786 -    chunkSize: function() { return this.size; },
 18.3787 -    remove: function(at, n, callbacks) {
 18.3788 -      this.size -= n;
 18.3789 -      for (var i = 0; i < this.children.length; ++i) {
 18.3790 -        var child = this.children[i], sz = child.chunkSize();
 18.3791 -        if (at < sz) {
 18.3792 -          var rm = Math.min(n, sz - at), oldHeight = child.height;
 18.3793 -          child.remove(at, rm, callbacks);
 18.3794 -          this.height -= oldHeight - child.height;
 18.3795 -          if (sz == rm) { this.children.splice(i--, 1); child.parent = null; }
 18.3796 -          if ((n -= rm) == 0) break;
 18.3797 -          at = 0;
 18.3798 -        } else at -= sz;
 18.3799 -      }
 18.3800 -      if (this.size - n < 25) {
 18.3801 -        var lines = [];
 18.3802 -        this.collapse(lines);
 18.3803 -        this.children = [new LeafChunk(lines)];
 18.3804 -        this.children[0].parent = this;
 18.3805 -      }
 18.3806 -    },
 18.3807 -    collapse: function(lines) {
 18.3808 -      for (var i = 0, e = this.children.length; i < e; ++i) this.children[i].collapse(lines);
 18.3809 -    },
 18.3810 -    insert: function(at, lines) {
 18.3811 -      var height = 0;
 18.3812 -      for (var i = 0, e = lines.length; i < e; ++i) height += lines[i].height;
 18.3813 -      this.insertHeight(at, lines, height);
 18.3814 -    },
 18.3815 -    insertHeight: function(at, lines, height) {
 18.3816 -      this.size += lines.length;
 18.3817 -      this.height += height;
 18.3818 -      for (var i = 0, e = this.children.length; i < e; ++i) {
 18.3819 -        var child = this.children[i], sz = child.chunkSize();
 18.3820 -        if (at <= sz) {
 18.3821 -          child.insertHeight(at, lines, height);
 18.3822 -          if (child.lines && child.lines.length > 50) {
 18.3823 -            while (child.lines.length > 50) {
 18.3824 -              var spilled = child.lines.splice(child.lines.length - 25, 25);
 18.3825 -              var newleaf = new LeafChunk(spilled);
 18.3826 -              child.height -= newleaf.height;
 18.3827 -              this.children.splice(i + 1, 0, newleaf);
 18.3828 -              newleaf.parent = this;
 18.3829 -            }
 18.3830 -            this.maybeSpill();
 18.3831 -          }
 18.3832 -          break;
 18.3833 -        }
 18.3834 -        at -= sz;
 18.3835 -      }
 18.3836 -    },
 18.3837 -    maybeSpill: function() {
 18.3838 -      if (this.children.length <= 10) return;
 18.3839 -      var me = this;
 18.3840 -      do {
 18.3841 -        var spilled = me.children.splice(me.children.length - 5, 5);
 18.3842 -        var sibling = new BranchChunk(spilled);
 18.3843 -        if (!me.parent) { // Become the parent node
 18.3844 -          var copy = new BranchChunk(me.children);
 18.3845 -          copy.parent = me;
 18.3846 -          me.children = [copy, sibling];
 18.3847 -          me = copy;
 18.3848 -        } else {
 18.3849 -          me.size -= sibling.size;
 18.3850 -          me.height -= sibling.height;
 18.3851 -          var myIndex = indexOf(me.parent.children, me);
 18.3852 -          me.parent.children.splice(myIndex + 1, 0, sibling);
 18.3853 -        }
 18.3854 -        sibling.parent = me.parent;
 18.3855 -      } while (me.children.length > 10);
 18.3856 -      me.parent.maybeSpill();
 18.3857 -    },
 18.3858 -    iter: function(from, to, op) { this.iterN(from, to - from, op); },
 18.3859 -    iterN: function(at, n, op) {
 18.3860 -      for (var i = 0, e = this.children.length; i < e; ++i) {
 18.3861 -        var child = this.children[i], sz = child.chunkSize();
 18.3862 -        if (at < sz) {
 18.3863 -          var used = Math.min(n, sz - at);
 18.3864 -          if (child.iterN(at, used, op)) return true;
 18.3865 -          if ((n -= used) == 0) break;
 18.3866 -          at = 0;
 18.3867 -        } else at -= sz;
 18.3868 -      }
 18.3869 -    }
 18.3870 -  };
 18.3871 -
 18.3872 -  // LINE UTILITIES
 18.3873 -
 18.3874 -  function getLine(chunk, n) {
 18.3875 -    while (!chunk.lines) {
 18.3876 -      for (var i = 0;; ++i) {
 18.3877 -        var child = chunk.children[i], sz = child.chunkSize();
 18.3878 -        if (n < sz) { chunk = child; break; }
 18.3879 -        n -= sz;
 18.3880 -      }
 18.3881 -    }
 18.3882 -    return chunk.lines[n];
 18.3883 -  }
 18.3884 -
 18.3885 -  function updateLineHeight(line, height) {
 18.3886 -    var diff = height - line.height;
 18.3887 -    for (var n = line; n; n = n.parent) n.height += diff;
 18.3888 -  }
 18.3889 -
 18.3890 -  function lineNo(line) {
 18.3891 -    if (line.parent == null) return null;
 18.3892 -    var cur = line.parent, no = indexOf(cur.lines, line);
 18.3893 -    for (var chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) {
 18.3894 -      for (var i = 0;; ++i) {
 18.3895 -        if (chunk.children[i] == cur) break;
 18.3896 -        no += chunk.children[i].chunkSize();
 18.3897 -      }
 18.3898 -    }
 18.3899 -    return no;
 18.3900 -  }
 18.3901 -
 18.3902 -  function lineAtHeight(chunk, h) {
 18.3903 -    var n = 0;
 18.3904 -    outer: do {
 18.3905 -      for (var i = 0, e = chunk.children.length; i < e; ++i) {
 18.3906 -        var child = chunk.children[i], ch = child.height;
 18.3907 -        if (h < ch) { chunk = child; continue outer; }
 18.3908 -        h -= ch;
 18.3909 -        n += child.chunkSize();
 18.3910 -      }
 18.3911 -      return n;
 18.3912 -    } while (!chunk.lines);
 18.3913 -    for (var i = 0, e = chunk.lines.length; i < e; ++i) {
 18.3914 -      var line = chunk.lines[i], lh = line.height;
 18.3915 -      if (h < lh) break;
 18.3916 -      h -= lh;
 18.3917 -    }
 18.3918 -    return n + i;
 18.3919 -  }
 18.3920 -
 18.3921 -  function heightAtLine(cm, lineObj) {
 18.3922 -    lineObj = visualLine(cm.view.doc, lineObj);
 18.3923 -
 18.3924 -    var h = 0, chunk = lineObj.parent;
 18.3925 -    for (var i = 0; i < chunk.lines.length; ++i) {
 18.3926 -      var line = chunk.lines[i];
 18.3927 -      if (line == lineObj) break;
 18.3928 -      else h += line.height;
 18.3929 -    }
 18.3930 -    for (var p = chunk.parent; p; chunk = p, p = chunk.parent) {
 18.3931 -      for (var i = 0; i < p.children.length; ++i) {
 18.3932 -        var cur = p.children[i];
 18.3933 -        if (cur == chunk) break;
 18.3934 -        else h += cur.height;
 18.3935 -      }
 18.3936 -    }
 18.3937 -    return h;
 18.3938 -  }
 18.3939 -
 18.3940 -  function getOrder(line) {
 18.3941 -    var order = line.order;
 18.3942 -    if (order == null) order = line.order = bidiOrdering(line.text);
 18.3943 -    return order;
 18.3944 -  }
 18.3945 -
 18.3946 -  // HISTORY
 18.3947 -
 18.3948 -  function makeHistory() {
 18.3949 -    return {
 18.3950 -      // Arrays of history events. Doing something adds an event to
 18.3951 -      // done and clears undo. Undoing moves events from done to
 18.3952 -      // undone, redoing moves them in the other direction.
 18.3953 -      done: [], undone: [],
 18.3954 -      // Used to track when changes can be merged into a single undo
 18.3955 -      // event
 18.3956 -      lastTime: 0, lastOp: null, lastOrigin: null,
 18.3957 -      // Used by the isClean() method
 18.3958 -      dirtyCounter: 0
 18.3959 -    };
 18.3960 -  }
 18.3961 -
 18.3962 -  function addChange(cm, start, added, old, origin, fromBefore, toBefore, fromAfter, toAfter) {
 18.3963 -    var history = cm.view.history;
 18.3964 -    history.undone.length = 0;
 18.3965 -    var time = +new Date, cur = lst(history.done);
 18.3966 -    
 18.3967 -    if (cur &&
 18.3968 -        (history.lastOp == cm.curOp.id ||
 18.3969 -         history.lastOrigin == origin && (origin == "input" || origin == "delete") &&
 18.3970 -         history.lastTime > time - 600)) {
 18.3971 -      // Merge this change into the last event
 18.3972 -      var last = lst(cur.events);
 18.3973 -      if (last.start > start + old.length || last.start + last.added < start) {
 18.3974 -        // Doesn't intersect with last sub-event, add new sub-event
 18.3975 -        cur.events.push({start: start, added: added, old: old});
 18.3976 -      } else {
 18.3977 -        // Patch up the last sub-event
 18.3978 -        var startBefore = Math.max(0, last.start - start),
 18.3979 -        endAfter = Math.max(0, (start + old.length) - (last.start + last.added));
 18.3980 -        for (var i = startBefore; i > 0; --i) last.old.unshift(old[i - 1]);
 18.3981 -        for (var i = endAfter; i > 0; --i) last.old.push(old[old.length - i]);
 18.3982 -        if (startBefore) last.start = start;
 18.3983 -        last.added += added - (old.length - startBefore - endAfter);
 18.3984 -      }
 18.3985 -      cur.fromAfter = fromAfter; cur.toAfter = toAfter;
 18.3986 -    } else {
 18.3987 -      // Can not be merged, start a new event.
 18.3988 -      cur = {events: [{start: start, added: added, old: old}],
 18.3989 -             fromBefore: fromBefore, toBefore: toBefore, fromAfter: fromAfter, toAfter: toAfter};
 18.3990 -      history.done.push(cur);
 18.3991 -      while (history.done.length > cm.options.undoDepth)
 18.3992 -        history.done.shift();
 18.3993 -      if (history.dirtyCounter < 0)
 18.3994 -          // The user has made a change after undoing past the last clean state. 
 18.3995 -          // We can never get back to a clean state now until markClean() is called.
 18.3996 -          history.dirtyCounter = NaN;
 18.3997 -      else
 18.3998 -        history.dirtyCounter++;
 18.3999 -    }
 18.4000 -    history.lastTime = time;
 18.4001 -    history.lastOp = cm.curOp.id;
 18.4002 -    history.lastOrigin = origin;
 18.4003 -  }
 18.4004 -
 18.4005 -  // EVENT OPERATORS
 18.4006 -
 18.4007 -  function stopMethod() {e_stop(this);}
 18.4008 -  // Ensure an event has a stop method.
 18.4009 -  function addStop(event) {
 18.4010 -    if (!event.stop) event.stop = stopMethod;
 18.4011 -    return event;
 18.4012 -  }
 18.4013 -
 18.4014 -  function e_preventDefault(e) {
 18.4015 -    if (e.preventDefault) e.preventDefault();
 18.4016 -    else e.returnValue = false;
 18.4017 -  }
 18.4018 -  function e_stopPropagation(e) {
 18.4019 -    if (e.stopPropagation) e.stopPropagation();
 18.4020 -    else e.cancelBubble = true;
 18.4021 -  }
 18.4022 -  function e_stop(e) {e_preventDefault(e); e_stopPropagation(e);}
 18.4023 -  CodeMirror.e_stop = e_stop;
 18.4024 -  CodeMirror.e_preventDefault = e_preventDefault;
 18.4025 -  CodeMirror.e_stopPropagation = e_stopPropagation;
 18.4026 -
 18.4027 -  function e_target(e) {return e.target || e.srcElement;}
 18.4028 -  function e_button(e) {
 18.4029 -    var b = e.which;
 18.4030 -    if (b == null) {
 18.4031 -      if (e.button & 1) b = 1;
 18.4032 -      else if (e.button & 2) b = 3;
 18.4033 -      else if (e.button & 4) b = 2;
 18.4034 -    }
 18.4035 -    if (mac && e.ctrlKey && b == 1) b = 3;
 18.4036 -    return b;
 18.4037 -  }
 18.4038 -
 18.4039 -  // Allow 3rd-party code to override event properties by adding an override
 18.4040 -  // object to an event object.
 18.4041 -  function e_prop(e, prop) {
 18.4042 -    var overridden = e.override && e.override.hasOwnProperty(prop);
 18.4043 -    return overridden ? e.override[prop] : e[prop];
 18.4044 -  }
 18.4045 -
 18.4046 -  // EVENT HANDLING
 18.4047 -
 18.4048 -  function on(emitter, type, f) {
 18.4049 -    if (emitter.addEventListener)
 18.4050 -      emitter.addEventListener(type, f, false);
 18.4051 -    else if (emitter.attachEvent)
 18.4052 -      emitter.attachEvent("on" + type, f);
 18.4053 -    else {
 18.4054 -      var map = emitter._handlers || (emitter._handlers = {});
 18.4055 -      var arr = map[type] || (map[type] = []);
 18.4056 -      arr.push(f);
 18.4057 -    }
 18.4058 -  }
 18.4059 -
 18.4060 -  function off(emitter, type, f) {
 18.4061 -    if (emitter.removeEventListener)
 18.4062 -      emitter.removeEventListener(type, f, false);
 18.4063 -    else if (emitter.detachEvent)
 18.4064 -      emitter.detachEvent("on" + type, f);
 18.4065 -    else {
 18.4066 -      var arr = emitter._handlers && emitter._handlers[type];
 18.4067 -      if (!arr) return;
 18.4068 -      for (var i = 0; i < arr.length; ++i)
 18.4069 -        if (arr[i] == f) { arr.splice(i, 1); break; }
 18.4070 -    }
 18.4071 -  }
 18.4072 -
 18.4073 -  function signal(emitter, type /*, values...*/) {
 18.4074 -    var arr = emitter._handlers && emitter._handlers[type];
 18.4075 -    if (!arr) return;
 18.4076 -    var args = Array.prototype.slice.call(arguments, 2);
 18.4077 -    for (var i = 0; i < arr.length; ++i) arr[i].apply(null, args);
 18.4078 -  }
 18.4079 -
 18.4080 -  function signalLater(cm, emitter, type /*, values...*/) {
 18.4081 -    var arr = emitter._handlers && emitter._handlers[type];
 18.4082 -    if (!arr) return;
 18.4083 -    var args = Array.prototype.slice.call(arguments, 3), flist = cm.curOp && cm.curOp.delayedCallbacks;
 18.4084 -    function bnd(f) {return function(){f.apply(null, args);};};
 18.4085 -    for (var i = 0; i < arr.length; ++i)
 18.4086 -      if (flist) flist.push(bnd(arr[i]));
 18.4087 -      else arr[i].apply(null, args);
 18.4088 -  }
 18.4089 -
 18.4090 -  function hasHandler(emitter, type) {
 18.4091 -    var arr = emitter._handlers && emitter._handlers[type];
 18.4092 -    return arr && arr.length > 0;
 18.4093 -  }
 18.4094 -
 18.4095 -  CodeMirror.on = on; CodeMirror.off = off; CodeMirror.signal = signal;
 18.4096 -
 18.4097 -  // MISC UTILITIES
 18.4098 -
 18.4099 -  // Number of pixels added to scroller and sizer to hide scrollbar
 18.4100 -  var scrollerCutOff = 30;
 18.4101 -
 18.4102 -  // Returned or thrown by various protocols to signal 'I'm not
 18.4103 -  // handling this'.
 18.4104 -  var Pass = CodeMirror.Pass = {toString: function(){return "CodeMirror.Pass";}};
 18.4105 -
 18.4106 -  function Delayed() {this.id = null;}
 18.4107 -  Delayed.prototype = {set: function(ms, f) {clearTimeout(this.id); this.id = setTimeout(f, ms);}};
 18.4108 -
 18.4109 -  // Counts the column offset in a string, taking tabs into account.
 18.4110 -  // Used mostly to find indentation.
 18.4111 -  function countColumn(string, end, tabSize) {
 18.4112 -    if (end == null) {
 18.4113 -      end = string.search(/[^\s\u00a0]/);
 18.4114 -      if (end == -1) end = string.length;
 18.4115 -    }
 18.4116 -    for (var i = 0, n = 0; i < end; ++i) {
 18.4117 -      if (string.charAt(i) == "\t") n += tabSize - (n % tabSize);
 18.4118 -      else ++n;
 18.4119 -    }
 18.4120 -    return n;
 18.4121 -  }
 18.4122 -  CodeMirror.countColumn = countColumn;
 18.4123 -
 18.4124 -  var spaceStrs = [""];
 18.4125 -  function spaceStr(n) {
 18.4126 -    while (spaceStrs.length <= n)
 18.4127 -      spaceStrs.push(lst(spaceStrs) + " ");
 18.4128 -    return spaceStrs[n];
 18.4129 -  }
 18.4130 -
 18.4131 -  function lst(arr) { return arr[arr.length-1]; }
 18.4132 -
 18.4133 -  function selectInput(node) {
 18.4134 -    if (ios) { // Mobile Safari apparently has a bug where select() is broken.
 18.4135 -      node.selectionStart = 0;
 18.4136 -      node.selectionEnd = node.value.length;
 18.4137 -    } else node.select();
 18.4138 -  }
 18.4139 -
 18.4140 -  function indexOf(collection, elt) {
 18.4141 -    if (collection.indexOf) return collection.indexOf(elt);
 18.4142 -    for (var i = 0, e = collection.length; i < e; ++i)
 18.4143 -      if (collection[i] == elt) return i;
 18.4144 -    return -1;
 18.4145 -  }
 18.4146 -
 18.4147 -  function emptyArray(size) {
 18.4148 -    for (var a = [], i = 0; i < size; ++i) a.push(undefined);
 18.4149 -    return a;
 18.4150 -  }
 18.4151 -
 18.4152 -  function bind(f) {
 18.4153 -    var args = Array.prototype.slice.call(arguments, 1);
 18.4154 -    return function(){return f.apply(null, args);};
 18.4155 -  }
 18.4156 -
 18.4157 -  var nonASCIISingleCaseWordChar = /[\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc]/;
 18.4158 -  function isWordChar(ch) {
 18.4159 -    return /\w/.test(ch) || ch > "\x80" &&
 18.4160 -      (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch));
 18.4161 -  }
 18.4162 -
 18.4163 -  function isEmpty(obj) {
 18.4164 -    var c = 0;
 18.4165 -    for (var n in obj) if (obj.hasOwnProperty(n) && obj[n]) ++c;
 18.4166 -    return !c;
 18.4167 -  }
 18.4168 -
 18.4169 -  var isExtendingChar = /[\u0300-\u036F\u0483-\u0487\u0488-\u0489\u0591-\u05BD\u05BF\u05C1-\u05C2\u05C4-\u05C5\u05C7\u0610-\u061A\u064B-\u065F\u0670\u06D6-\u06DC\u06DF-\u06E4\u06E7-\u06E8\u06EA-\u06ED\uA66F\uA670-\uA672\uA674-\uA67D\uA69F]/;
 18.4170 -
 18.4171 -  // DOM UTILITIES
 18.4172 -
 18.4173 -  function elt(tag, content, className, style) {
 18.4174 -    var e = document.createElement(tag);
 18.4175 -    if (className) e.className = className;
 18.4176 -    if (style) e.style.cssText = style;
 18.4177 -    if (typeof content == "string") setTextContent(e, content);
 18.4178 -    else if (content) for (var i = 0; i < content.length; ++i) e.appendChild(content[i]);
 18.4179 -    return e;
 18.4180 -  }
 18.4181 -
 18.4182 -  function removeChildren(e) {
 18.4183 -    e.innerHTML = "";
 18.4184 -    return e;
 18.4185 -  }
 18.4186 -
 18.4187 -  function removeChildrenAndAdd(parent, e) {
 18.4188 -    return removeChildren(parent).appendChild(e);
 18.4189 -  }
 18.4190 -
 18.4191 -  function setTextContent(e, str) {
 18.4192 -    if (ie_lt9) {
 18.4193 -      e.innerHTML = "";
 18.4194 -      e.appendChild(document.createTextNode(str));
 18.4195 -    } else e.textContent = str;
 18.4196 -  }
 18.4197 -
 18.4198 -  // FEATURE DETECTION
 18.4199 -
 18.4200 -  // Detect drag-and-drop
 18.4201 -  var dragAndDrop = function() {
 18.4202 -    // There is *some* kind of drag-and-drop support in IE6-8, but I
 18.4203 -    // couldn't get it to work yet.
 18.4204 -    if (ie_lt9) return false;
 18.4205 -    var div = elt('div');
 18.4206 -    return "draggable" in div || "dragDrop" in div;
 18.4207 -  }();
 18.4208 -
 18.4209 -  // For a reason I have yet to figure out, some browsers disallow
 18.4210 -  // word wrapping between certain characters *only* if a new inline
 18.4211 -  // element is started between them. This makes it hard to reliably
 18.4212 -  // measure the position of things, since that requires inserting an
 18.4213 -  // extra span. This terribly fragile set of regexps matches the
 18.4214 -  // character combinations that suffer from this phenomenon on the
 18.4215 -  // various browsers.
 18.4216 -  var spanAffectsWrapping = /^$/; // Won't match any two-character string
 18.4217 -  if (gecko) spanAffectsWrapping = /$'/;
 18.4218 -  else if (safari) spanAffectsWrapping = /\-[^ \-?]|\?[^ !'\"\),.\-\/:;\?\]\}]/;
 18.4219 -  else if (chrome) spanAffectsWrapping = /\-[^ \-\.?]|\?[^ \-\.?\]\}:;!'\"\),\/]|[\.!\"#&%\)*+,:;=>\]|\}~][\(\{\[<]|\$'/;
 18.4220 -
 18.4221 -  var knownScrollbarWidth;
 18.4222 -  function scrollbarWidth(measure) {
 18.4223 -    if (knownScrollbarWidth != null) return knownScrollbarWidth;
 18.4224 -    var test = elt("div", null, null, "width: 50px; height: 50px; overflow-x: scroll");
 18.4225 -    removeChildrenAndAdd(measure, test);
 18.4226 -    if (test.offsetWidth)
 18.4227 -      knownScrollbarWidth = test.offsetHeight - test.clientHeight;
 18.4228 -    return knownScrollbarWidth || 0;
 18.4229 -  }
 18.4230 -
 18.4231 -  var zwspSupported;
 18.4232 -  function zeroWidthElement(measure) {
 18.4233 -    if (zwspSupported == null) {
 18.4234 -      var test = elt("span", "\u200b");
 18.4235 -      removeChildrenAndAdd(measure, elt("span", [test, document.createTextNode("x")]));
 18.4236 -      if (measure.firstChild.offsetHeight != 0)
 18.4237 -        zwspSupported = test.offsetWidth <= 1 && test.offsetHeight > 2 && !ie_lt8;
 18.4238 -    }
 18.4239 -    if (zwspSupported) return elt("span", "\u200b");
 18.4240 -    else return elt("span", "\u00a0", null, "display: inline-block; width: 1px; margin-right: -1px");
 18.4241 -  }
 18.4242 -
 18.4243 -  // See if "".split is the broken IE version, if so, provide an
 18.4244 -  // alternative way to split lines.
 18.4245 -  var splitLines = "\n\nb".split(/\n/).length != 3 ? function(string) {
 18.4246 -    var pos = 0, result = [], l = string.length;
 18.4247 -    while (pos <= l) {
 18.4248 -      var nl = string.indexOf("\n", pos);
 18.4249 -      if (nl == -1) nl = string.length;
 18.4250 -      var line = string.slice(pos, string.charAt(nl - 1) == "\r" ? nl - 1 : nl);
 18.4251 -      var rt = line.indexOf("\r");
 18.4252 -      if (rt != -1) {
 18.4253 -        result.push(line.slice(0, rt));
 18.4254 -        pos += rt + 1;
 18.4255 -      } else {
 18.4256 -        result.push(line);
 18.4257 -        pos = nl + 1;
 18.4258 -      }
 18.4259 -    }
 18.4260 -    return result;
 18.4261 -  } : function(string){return string.split(/\r\n?|\n/);};
 18.4262 -  CodeMirror.splitLines = splitLines;
 18.4263 -
 18.4264 -  var hasSelection = window.getSelection ? function(te) {
 18.4265 -    try { return te.selectionStart != te.selectionEnd; }
 18.4266 -    catch(e) { return false; }
 18.4267 -  } : function(te) {
 18.4268 -    try {var range = te.ownerDocument.selection.createRange();}
 18.4269 -    catch(e) {}
 18.4270 -    if (!range || range.parentElement() != te) return false;
 18.4271 -    return range.compareEndPoints("StartToEnd", range) != 0;
 18.4272 -  };
 18.4273 -
 18.4274 -  var hasCopyEvent = (function() {
 18.4275 -    var e = elt("div");
 18.4276 -    if ("oncopy" in e) return true;
 18.4277 -    e.setAttribute("oncopy", "return;");
 18.4278 -    return typeof e.oncopy == 'function';
 18.4279 -  })();
 18.4280 -
 18.4281 -  // KEY NAMING
 18.4282 -
 18.4283 -  var keyNames = {3: "Enter", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt",
 18.4284 -                  19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End",
 18.4285 -                  36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert",
 18.4286 -                  46: "Delete", 59: ";", 91: "Mod", 92: "Mod", 93: "Mod", 109: "-", 107: "=", 127: "Delete",
 18.4287 -                  186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\",
 18.4288 -                  221: "]", 222: "'", 63276: "PageUp", 63277: "PageDown", 63275: "End", 63273: "Home",
 18.4289 -                  63234: "Left", 63232: "Up", 63235: "Right", 63233: "Down", 63302: "Insert", 63272: "Delete"};
 18.4290 -  CodeMirror.keyNames = keyNames;
 18.4291 -  (function() {
 18.4292 -    // Number keys
 18.4293 -    for (var i = 0; i < 10; i++) keyNames[i + 48] = String(i);
 18.4294 -    // Alphabetic keys
 18.4295 -    for (var i = 65; i <= 90; i++) keyNames[i] = String.fromCharCode(i);
 18.4296 -    // Function keys
 18.4297 -    for (var i = 1; i <= 12; i++) keyNames[i + 111] = keyNames[i + 63235] = "F" + i;
 18.4298 -  })();
 18.4299 -
 18.4300 -  // BIDI HELPERS
 18.4301 -
 18.4302 -  function iterateBidiSections(order, from, to, f) {
 18.4303 -    if (!order) return f(from, to, "ltr");
 18.4304 -    for (var i = 0; i < order.length; ++i) {
 18.4305 -      var part = order[i];
 18.4306 -      if (part.from < to && part.to > from)
 18.4307 -        f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr");
 18.4308 -    }
 18.4309 -  }
 18.4310 -
 18.4311 -  function bidiLeft(part) { return part.level % 2 ? part.to : part.from; }
 18.4312 -  function bidiRight(part) { return part.level % 2 ? part.from : part.to; }
 18.4313 -
 18.4314 -  function lineLeft(line) { var order = getOrder(line); return order ? bidiLeft(order[0]) : 0; }
 18.4315 -  function lineRight(line) {
 18.4316 -    var order = getOrder(line);
 18.4317 -    if (!order) return line.text.length;
 18.4318 -    return bidiRight(lst(order));
 18.4319 -  }
 18.4320 -
 18.4321 -  function lineStart(cm, lineN) {
 18.4322 -    var line = getLine(cm.view.doc, lineN);
 18.4323 -    var visual = visualLine(cm.view.doc, line);
 18.4324 -    if (visual != line) lineN = lineNo(visual);
 18.4325 -    var order = getOrder(visual);
 18.4326 -    var ch = !order ? 0 : order[0].level % 2 ? lineRight(visual) : lineLeft(visual);
 18.4327 -    return {line: lineN, ch: ch};
 18.4328 -  }
 18.4329 -  function lineEnd(cm, lineNo) {
 18.4330 -    var merged, line;
 18.4331 -    while (merged = collapsedSpanAtEnd(line = getLine(cm.view.doc, lineNo)))
 18.4332 -      lineNo = merged.find().to.line;
 18.4333 -    var order = getOrder(line);
 18.4334 -    var ch = !order ? line.text.length : order[0].level % 2 ? lineLeft(line) : lineRight(line);
 18.4335 -    return {line: lineNo, ch: ch};
 18.4336 -  }
 18.4337 -
 18.4338 -  // This is somewhat involved. It is needed in order to move
 18.4339 -  // 'visually' through bi-directional text -- i.e., pressing left
 18.4340 -  // should make the cursor go left, even when in RTL text. The
 18.4341 -  // tricky part is the 'jumps', where RTL and LTR text touch each
 18.4342 -  // other. This often requires the cursor offset to move more than
 18.4343 -  // one unit, in order to visually move one unit.
 18.4344 -  function moveVisually(line, start, dir, byUnit) {
 18.4345 -    var bidi = getOrder(line);
 18.4346 -    if (!bidi) return moveLogically(line, start, dir, byUnit);
 18.4347 -    var moveOneUnit = byUnit ? function(pos, dir) {
 18.4348 -      do pos += dir;
 18.4349 -      while (pos > 0 && isExtendingChar.test(line.text.charAt(pos)));
 18.4350 -      return pos;
 18.4351 -    } : function(pos, dir) { return pos + dir; };
 18.4352 -    var linedir = bidi[0].level;
 18.4353 -    for (var i = 0; i < bidi.length; ++i) {
 18.4354 -      var part = bidi[i], sticky = part.level % 2 == linedir;
 18.4355 -      if ((part.from < start && part.to > start) ||
 18.4356 -          (sticky && (part.from == start || part.to == start))) break;
 18.4357 -    }
 18.4358 -    var target = moveOneUnit(start, part.level % 2 ? -dir : dir);
 18.4359 -
 18.4360 -    while (target != null) {
 18.4361 -      if (part.level % 2 == linedir) {
 18.4362 -        if (target < part.from || target > part.to) {
 18.4363 -          part = bidi[i += dir];
 18.4364 -          target = part && (dir > 0 == part.level % 2 ? moveOneUnit(part.to, -1) : moveOneUnit(part.from, 1));
 18.4365 -        } else break;
 18.4366 -      } else {
 18.4367 -        if (target == bidiLeft(part)) {
 18.4368 -          part = bidi[--i];
 18.4369 -          target = part && bidiRight(part);
 18.4370 -        } else if (target == bidiRight(part)) {
 18.4371 -          part = bidi[++i];
 18.4372 -          target = part && bidiLeft(part);
 18.4373 -        } else break;
 18.4374 -      }
 18.4375 -    }
 18.4376 -
 18.4377 -    return target < 0 || target > line.text.length ? null : target;
 18.4378 -  }
 18.4379 -
 18.4380 -  function moveLogically(line, start, dir, byUnit) {
 18.4381 -    var target = start + dir;
 18.4382 -    if (byUnit) while (target > 0 && isExtendingChar.test(line.text.charAt(target))) target += dir;
 18.4383 -    return target < 0 || target > line.text.length ? null : target;
 18.4384 -  }
 18.4385 -
 18.4386 -  // Bidirectional ordering algorithm
 18.4387 -  // See http://unicode.org/reports/tr9/tr9-13.html for the algorithm
 18.4388 -  // that this (partially) implements.
 18.4389 -
 18.4390 -  // One-char codes used for character types:
 18.4391 -  // L (L):   Left-to-Right
 18.4392 -  // R (R):   Right-to-Left
 18.4393 -  // r (AL):  Right-to-Left Arabic
 18.4394 -  // 1 (EN):  European Number
 18.4395 -  // + (ES):  European Number Separator
 18.4396 -  // % (ET):  European Number Terminator
 18.4397 -  // n (AN):  Arabic Number
 18.4398 -  // , (CS):  Common Number Separator
 18.4399 -  // m (NSM): Non-Spacing Mark
 18.4400 -  // b (BN):  Boundary Neutral
 18.4401 -  // s (B):   Paragraph Separator
 18.4402 -  // t (S):   Segment Separator
 18.4403 -  // w (WS):  Whitespace
 18.4404 -  // N (ON):  Other Neutrals
 18.4405 -
 18.4406 -  // Returns null if characters are ordered as they appear
 18.4407 -  // (left-to-right), or an array of sections ({from, to, level}
 18.4408 -  // objects) in the order in which they occur visually.
 18.4409 -  var bidiOrdering = (function() {
 18.4410 -    // Character types for codepoints 0 to 0xff
 18.4411 -    var lowTypes = "bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLL";
 18.4412 -    // Character types for codepoints 0x600 to 0x6ff
 18.4413 -    var arabicTypes = "rrrrrrrrrrrr,rNNmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmrrrrrrrnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmNmmmmrrrrrrrrrrrrrrrrrr";
 18.4414 -    function charType(code) {
 18.4415 -      if (code <= 0xff) return lowTypes.charAt(code);
 18.4416 -      else if (0x590 <= code && code <= 0x5f4) return "R";
 18.4417 -      else if (0x600 <= code && code <= 0x6ff) return arabicTypes.charAt(code - 0x600);
 18.4418 -      else if (0x700 <= code && code <= 0x8ac) return "r";
 18.4419 -      else return "L";
 18.4420 -    }
 18.4421 -
 18.4422 -    var bidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/;
 18.4423 -    var isNeutral = /[stwN]/, isStrong = /[LRr]/, countsAsLeft = /[Lb1n]/, countsAsNum = /[1n]/;
 18.4424 -
 18.4425 -    return function charOrdering(str) {
 18.4426 -      if (!bidiRE.test(str)) return false;
 18.4427 -      var len = str.length, types = [], startType = null;
 18.4428 -      for (var i = 0, type; i < len; ++i) {
 18.4429 -        types.push(type = charType(str.charCodeAt(i)));
 18.4430 -        if (startType == null) {
 18.4431 -          if (type == "L") startType = "L";
 18.4432 -          else if (type == "R" || type == "r") startType = "R";
 18.4433 -        }
 18.4434 -      }
 18.4435 -      if (startType == null) startType = "L";
 18.4436 -
 18.4437 -      // W1. Examine each non-spacing mark (NSM) in the level run, and
 18.4438 -      // change the type of the NSM to the type of the previous
 18.4439 -      // character. If the NSM is at the start of the level run, it will
 18.4440 -      // get the type of sor.
 18.4441 -      for (var i = 0, prev = startType; i < len; ++i) {
 18.4442 -        var type = types[i];
 18.4443 -        if (type == "m") types[i] = prev;
 18.4444 -        else prev = type;
 18.4445 -      }
 18.4446 -
 18.4447 -      // W2. Search backwards from each instance of a European number
 18.4448 -      // until the first strong type (R, L, AL, or sor) is found. If an
 18.4449 -      // AL is found, change the type of the European number to Arabic
 18.4450 -      // number.
 18.4451 -      // W3. Change all ALs to R.
 18.4452 -      for (var i = 0, cur = startType; i < len; ++i) {
 18.4453 -        var type = types[i];
 18.4454 -        if (type == "1" && cur == "r") types[i] = "n";
 18.4455 -        else if (isStrong.test(type)) { cur = type; if (type == "r") types[i] = "R"; }
 18.4456 -      }
 18.4457 -
 18.4458 -      // W4. A single European separator between two European numbers
 18.4459 -      // changes to a European number. A single common separator between
 18.4460 -      // two numbers of the same type changes to that type.
 18.4461 -      for (var i = 1, prev = types[0]; i < len - 1; ++i) {
 18.4462 -        var type = types[i];
 18.4463 -        if (type == "+" && prev == "1" && types[i+1] == "1") types[i] = "1";
 18.4464 -        else if (type == "," && prev == types[i+1] &&
 18.4465 -                 (prev == "1" || prev == "n")) types[i] = prev;
 18.4466 -        prev = type;
 18.4467 -      }
 18.4468 -
 18.4469 -      // W5. A sequence of European terminators adjacent to European
 18.4470 -      // numbers changes to all European numbers.
 18.4471 -      // W6. Otherwise, separators and terminators change to Other
 18.4472 -      // Neutral.
 18.4473 -      for (var i = 0; i < len; ++i) {
 18.4474 -        var type = types[i];
 18.4475 -        if (type == ",") types[i] = "N";
 18.4476 -        else if (type == "%") {
 18.4477 -          for (var end = i + 1; end < len && types[end] == "%"; ++end) {}
 18.4478 -          var replace = (i && types[i-1] == "!") || (end < len - 1 && types[end] == "1") ? "1" : "N";
 18.4479 -          for (var j = i; j < end; ++j) types[j] = replace;
 18.4480 -          i = end - 1;
 18.4481 -        }
 18.4482 -      }
 18.4483 -
 18.4484 -      // W7. Search backwards from each instance of a European number
 18.4485 -      // until the first strong type (R, L, or sor) is found. If an L is
 18.4486 -      // found, then change the type of the European number to L.
 18.4487 -      for (var i = 0, cur = startType; i < len; ++i) {
 18.4488 -        var type = types[i];
 18.4489 -        if (cur == "L" && type == "1") types[i] = "L";
 18.4490 -        else if (isStrong.test(type)) cur = type;
 18.4491 -      }
 18.4492 -
 18.4493 -      // N1. A sequence of neutrals takes the direction of the
 18.4494 -      // surrounding strong text if the text on both sides has the same
 18.4495 -      // direction. European and Arabic numbers act as if they were R in
 18.4496 -      // terms of their influence on neutrals. Start-of-level-run (sor)
 18.4497 -      // and end-of-level-run (eor) are used at level run boundaries.
 18.4498 -      // N2. Any remaining neutrals take the embedding direction.
 18.4499 -      for (var i = 0; i < len; ++i) {
 18.4500 -        if (isNeutral.test(types[i])) {
 18.4501 -          for (var end = i + 1; end < len && isNeutral.test(types[end]); ++end) {}
 18.4502 -          var before = (i ? types[i-1] : startType) == "L";
 18.4503 -          var after = (end < len - 1 ? types[end] : startType) == "L";
 18.4504 -          var replace = before || after ? "L" : "R";
 18.4505 -          for (var j = i; j < end; ++j) types[j] = replace;
 18.4506 -          i = end - 1;
 18.4507 -        }
 18.4508 -      }
 18.4509 -
 18.4510 -      // Here we depart from the documented algorithm, in order to avoid
 18.4511 -      // building up an actual levels array. Since there are only three
 18.4512 -      // levels (0, 1, 2) in an implementation that doesn't take
 18.4513 -      // explicit embedding into account, we can build up the order on
 18.4514 -      // the fly, without following the level-based algorithm.
 18.4515 -      var order = [], m;
 18.4516 -      for (var i = 0; i < len;) {
 18.4517 -        if (countsAsLeft.test(types[i])) {
 18.4518 -          var start = i;
 18.4519 -          for (++i; i < len && countsAsLeft.test(types[i]); ++i) {}
 18.4520 -          order.push({from: start, to: i, level: 0});
 18.4521 -        } else {
 18.4522 -          var pos = i, at = order.length;
 18.4523 -          for (++i; i < len && types[i] != "L"; ++i) {}
 18.4524 -          for (var j = pos; j < i;) {
 18.4525 -            if (countsAsNum.test(types[j])) {
 18.4526 -              if (pos < j) order.splice(at, 0, {from: pos, to: j, level: 1});
 18.4527 -              var nstart = j;
 18.4528 -              for (++j; j < i && countsAsNum.test(types[j]); ++j) {}
 18.4529 -              order.splice(at, 0, {from: nstart, to: j, level: 2});
 18.4530 -              pos = j;
 18.4531 -            } else ++j;
 18.4532 -          }
 18.4533 -          if (pos < i) order.splice(at, 0, {from: pos, to: i, level: 1});
 18.4534 -        }
 18.4535 -      }
 18.4536 -      if (order[0].level == 1 && (m = str.match(/^\s+/))) {
 18.4537 -        order[0].from = m[0].length;
 18.4538 -        order.unshift({from: 0, to: m[0].length, level: 0});
 18.4539 -      }
 18.4540 -      if (lst(order).level == 1 && (m = str.match(/\s+$/))) {
 18.4541 -        lst(order).to -= m[0].length;
 18.4542 -        order.push({from: len - m[0].length, to: len, level: 0});
 18.4543 -      }
 18.4544 -      if (order[0].level != lst(order).level)
 18.4545 -        order.push({from: len, to: len, level: order[0].level});
 18.4546 -
 18.4547 -      return order;
 18.4548 -    };
 18.4549 -  })();
 18.4550 -
 18.4551 -  // THE END
 18.4552 -
 18.4553 -  CodeMirror.version = "3.0";
 18.4554 -
 18.4555 -  return CodeMirror;
 18.4556 -})();
    19.1 --- a/dew/src/main/resources/org/apidesign/bck2brwsr/dew/js/codemirror/mode/clike.js	Tue Feb 11 10:48:24 2014 +0100
    19.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    19.3 @@ -1,300 +0,0 @@
    19.4 -CodeMirror.defineMode("clike", function(config, parserConfig) {
    19.5 -  var indentUnit = config.indentUnit,
    19.6 -      statementIndentUnit = parserConfig.statementIndentUnit || indentUnit,
    19.7 -      keywords = parserConfig.keywords || {},
    19.8 -      builtin = parserConfig.builtin || {},
    19.9 -      blockKeywords = parserConfig.blockKeywords || {},
   19.10 -      atoms = parserConfig.atoms || {},
   19.11 -      hooks = parserConfig.hooks || {},
   19.12 -      multiLineStrings = parserConfig.multiLineStrings;
   19.13 -  var isOperatorChar = /[+\-*&%=<>!?|\/]/;
   19.14 -
   19.15 -  var curPunc;
   19.16 -
   19.17 -  function tokenBase(stream, state) {
   19.18 -    var ch = stream.next();
   19.19 -    if (hooks[ch]) {
   19.20 -      var result = hooks[ch](stream, state);
   19.21 -      if (result !== false) return result;
   19.22 -    }
   19.23 -    if (ch == '"' || ch == "'") {
   19.24 -      state.tokenize = tokenString(ch);
   19.25 -      return state.tokenize(stream, state);
   19.26 -    }
   19.27 -    if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
   19.28 -      curPunc = ch;
   19.29 -      return null;
   19.30 -    }
   19.31 -    if (/\d/.test(ch)) {
   19.32 -      stream.eatWhile(/[\w\.]/);
   19.33 -      return "number";
   19.34 -    }
   19.35 -    if (ch == "/") {
   19.36 -      if (stream.eat("*")) {
   19.37 -        state.tokenize = tokenComment;
   19.38 -        return tokenComment(stream, state);
   19.39 -      }
   19.40 -      if (stream.eat("/")) {
   19.41 -        stream.skipToEnd();
   19.42 -        return "comment";
   19.43 -      }
   19.44 -    }
   19.45 -    if (isOperatorChar.test(ch)) {
   19.46 -      stream.eatWhile(isOperatorChar);
   19.47 -      return "operator";
   19.48 -    }
   19.49 -    stream.eatWhile(/[\w\$_]/);
   19.50 -    var cur = stream.current();
   19.51 -    if (keywords.propertyIsEnumerable(cur)) {
   19.52 -      if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement";
   19.53 -      return "keyword";
   19.54 -    }
   19.55 -    if (builtin.propertyIsEnumerable(cur)) {
   19.56 -      if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement";
   19.57 -      return "builtin";
   19.58 -    }
   19.59 -    if (atoms.propertyIsEnumerable(cur)) return "atom";
   19.60 -    return "variable";
   19.61 -  }
   19.62 -
   19.63 -  function tokenString(quote) {
   19.64 -    return function(stream, state) {
   19.65 -      var escaped = false, next, end = false;
   19.66 -      while ((next = stream.next()) != null) {
   19.67 -        if (next == quote && !escaped) {end = true; break;}
   19.68 -        escaped = !escaped && next == "\\";
   19.69 -      }
   19.70 -      if (end || !(escaped || multiLineStrings))
   19.71 -        state.tokenize = null;
   19.72 -      return "string";
   19.73 -    };
   19.74 -  }
   19.75 -
   19.76 -  function tokenComment(stream, state) {
   19.77 -    var maybeEnd = false, ch;
   19.78 -    while (ch = stream.next()) {
   19.79 -      if (ch == "/" && maybeEnd) {
   19.80 -        state.tokenize = null;
   19.81 -        break;
   19.82 -      }
   19.83 -      maybeEnd = (ch == "*");
   19.84 -    }
   19.85 -    return "comment";
   19.86 -  }
   19.87 -
   19.88 -  function Context(indented, column, type, align, prev) {
   19.89 -    this.indented = indented;
   19.90 -    this.column = column;
   19.91 -    this.type = type;
   19.92 -    this.align = align;
   19.93 -    this.prev = prev;
   19.94 -  }
   19.95 -  function pushContext(state, col, type) {
   19.96 -    var indent = state.indented;
   19.97 -    if (state.context && state.context.type == "statement")
   19.98 -      indent = state.context.indented;
   19.99 -    return state.context = new Context(indent, col, type, null, state.context);
  19.100 -  }
  19.101 -  function popContext(state) {
  19.102 -    var t = state.context.type;
  19.103 -    if (t == ")" || t == "]" || t == "}")
  19.104 -      state.indented = state.context.indented;
  19.105 -    return state.context = state.context.prev;
  19.106 -  }
  19.107 -
  19.108 -  // Interface
  19.109 -
  19.110 -  return {
  19.111 -    startState: function(basecolumn) {
  19.112 -      return {
  19.113 -        tokenize: null,
  19.114 -        context: new Context((basecolumn || 0) - indentUnit, 0, "top", false),
  19.115 -        indented: 0,
  19.116 -        startOfLine: true
  19.117 -      };
  19.118 -    },
  19.119 -
  19.120 -    token: function(stream, state) {
  19.121 -      var ctx = state.context;
  19.122 -      if (stream.sol()) {
  19.123 -        if (ctx.align == null) ctx.align = false;
  19.124 -        state.indented = stream.indentation();
  19.125 -        state.startOfLine = true;
  19.126 -      }
  19.127 -      if (stream.eatSpace()) return null;
  19.128 -      curPunc = null;
  19.129 -      var style = (state.tokenize || tokenBase)(stream, state);
  19.130 -      if (style == "comment" || style == "meta") return style;
  19.131 -      if (ctx.align == null) ctx.align = true;
  19.132 -
  19.133 -      if ((curPunc == ";" || curPunc == ":" || curPunc == ",") && ctx.type == "statement") popContext(state);
  19.134 -      else if (curPunc == "{") pushContext(state, stream.column(), "}");
  19.135 -      else if (curPunc == "[") pushContext(state, stream.column(), "]");
  19.136 -      else if (curPunc == "(") pushContext(state, stream.column(), ")");
  19.137 -      else if (curPunc == "}") {
  19.138 -        while (ctx.type == "statement") ctx = popContext(state);
  19.139 -        if (ctx.type == "}") ctx = popContext(state);
  19.140 -        while (ctx.type == "statement") ctx = popContext(state);
  19.141 -      }
  19.142 -      else if (curPunc == ctx.type) popContext(state);
  19.143 -      else if (((ctx.type == "}" || ctx.type == "top") && curPunc != ';') || (ctx.type == "statement" && curPunc == "newstatement"))
  19.144 -        pushContext(state, stream.column(), "statement");
  19.145 -      state.startOfLine = false;
  19.146 -      return style;
  19.147 -    },
  19.148 -
  19.149 -    indent: function(state, textAfter) {
  19.150 -      if (state.tokenize != tokenBase && state.tokenize != null) return CodeMirror.Pass;
  19.151 -      var ctx = state.context, firstChar = textAfter && textAfter.charAt(0);
  19.152 -      if (ctx.type == "statement" && firstChar == "}") ctx = ctx.prev;
  19.153 -      var closing = firstChar == ctx.type;
  19.154 -      if (ctx.type == "statement") return ctx.indented + (firstChar == "{" ? 0 : statementIndentUnit);
  19.155 -      else if (ctx.align) return ctx.column + (closing ? 0 : 1);
  19.156 -      else return ctx.indented + (closing ? 0 : indentUnit);
  19.157 -    },
  19.158 -
  19.159 -    electricChars: "{}"
  19.160 -  };
  19.161 -});
  19.162 -
  19.163 -(function() {
  19.164 -  function words(str) {
  19.165 -    var obj = {}, words = str.split(" ");
  19.166 -    for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
  19.167 -    return obj;
  19.168 -  }
  19.169 -  var cKeywords = "auto if break int case long char register continue return default short do sizeof " +
  19.170 -    "double static else struct entry switch extern typedef float union for unsigned " +
  19.171 -    "goto while enum void const signed volatile";
  19.172 -
  19.173 -  function cppHook(stream, state) {
  19.174 -    if (!state.startOfLine) return false;
  19.175 -    for (;;) {
  19.176 -      if (stream.skipTo("\\")) {
  19.177 -        stream.next();
  19.178 -        if (stream.eol()) {
  19.179 -          state.tokenize = cppHook;
  19.180 -          break;
  19.181 -        }
  19.182 -      } else {
  19.183 -        stream.skipToEnd();
  19.184 -        state.tokenize = null;
  19.185 -        break;
  19.186 -      }
  19.187 -    }
  19.188 -    return "meta";
  19.189 -  }
  19.190 -
  19.191 -  // C#-style strings where "" escapes a quote.
  19.192 -  function tokenAtString(stream, state) {
  19.193 -    var next;
  19.194 -    while ((next = stream.next()) != null) {
  19.195 -      if (next == '"' && !stream.eat('"')) {
  19.196 -        state.tokenize = null;
  19.197 -        break;
  19.198 -      }
  19.199 -    }
  19.200 -    return "string";
  19.201 -  }
  19.202 -
  19.203 -  function mimes(ms, mode) {
  19.204 -    for (var i = 0; i < ms.length; ++i) CodeMirror.defineMIME(ms[i], mode);
  19.205 -  }
  19.206 -
  19.207 -  mimes(["text/x-csrc", "text/x-c", "text/x-chdr"], {
  19.208 -    name: "clike",
  19.209 -    keywords: words(cKeywords),
  19.210 -    blockKeywords: words("case do else for if switch while struct"),
  19.211 -    atoms: words("null"),
  19.212 -    hooks: {"#": cppHook}
  19.213 -  });
  19.214 -  mimes(["text/x-c++src", "text/x-c++hdr"], {
  19.215 -    name: "clike",
  19.216 -    keywords: words(cKeywords + " asm dynamic_cast namespace reinterpret_cast try bool explicit new " +
  19.217 -                    "static_cast typeid catch operator template typename class friend private " +
  19.218 -                    "this using const_cast inline public throw virtual delete mutable protected " +
  19.219 -                    "wchar_t"),
  19.220 -    blockKeywords: words("catch class do else finally for if struct switch try while"),
  19.221 -    atoms: words("true false null"),
  19.222 -    hooks: {"#": cppHook}
  19.223 -  });
  19.224 -  CodeMirror.defineMIME("text/x-java", {
  19.225 -    name: "clike",
  19.226 -    keywords: words("abstract assert boolean break byte case catch char class const continue default " + 
  19.227 -                    "do double else enum extends final finally float for goto if implements import " +
  19.228 -                    "instanceof int interface long native new package private protected public " +
  19.229 -                    "return short static strictfp super switch synchronized this throw throws transient " +
  19.230 -                    "try void volatile while"),
  19.231 -    blockKeywords: words("catch class do else finally for if switch try while"),
  19.232 -    atoms: words("true false null"),
  19.233 -    hooks: {
  19.234 -      "@": function(stream) {
  19.235 -        stream.eatWhile(/[\w\$_]/);
  19.236 -        return "meta";
  19.237 -      }
  19.238 -    }
  19.239 -  });
  19.240 -  CodeMirror.defineMIME("text/x-csharp", {
  19.241 -    name: "clike",
  19.242 -    keywords: words("abstract as base break case catch checked class const continue" + 
  19.243 -                    " default delegate do else enum event explicit extern finally fixed for" + 
  19.244 -                    " foreach goto if implicit in interface internal is lock namespace new" + 
  19.245 -                    " operator out override params private protected public readonly ref return sealed" + 
  19.246 -                    " sizeof stackalloc static struct switch this throw try typeof unchecked" + 
  19.247 -                    " unsafe using virtual void volatile while add alias ascending descending dynamic from get" + 
  19.248 -                    " global group into join let orderby partial remove select set value var yield"),
  19.249 -    blockKeywords: words("catch class do else finally for foreach if struct switch try while"),
  19.250 -    builtin: words("Boolean Byte Char DateTime DateTimeOffset Decimal Double" +
  19.251 -                    " Guid Int16 Int32 Int64 Object SByte Single String TimeSpan UInt16 UInt32" +
  19.252 -                    " UInt64 bool byte char decimal double short int long object"  +
  19.253 -                    " sbyte float string ushort uint ulong"),
  19.254 -    atoms: words("true false null"),
  19.255 -    hooks: {
  19.256 -      "@": function(stream, state) {
  19.257 -        if (stream.eat('"')) {
  19.258 -          state.tokenize = tokenAtString;
  19.259 -          return tokenAtString(stream, state);
  19.260 -        }
  19.261 -        stream.eatWhile(/[\w\$_]/);
  19.262 -        return "meta";
  19.263 -      }
  19.264 -    }
  19.265 -  });
  19.266 -  CodeMirror.defineMIME("text/x-scala", {
  19.267 -    name: "clike",
  19.268 -    keywords: words(
  19.269 -      
  19.270 -      /* scala */
  19.271 -      "abstract case catch class def do else extends false final finally for forSome if " +
  19.272 -      "implicit import lazy match new null object override package private protected return " +
  19.273 -      "sealed super this throw trait try trye type val var while with yield _ : = => <- <: " +
  19.274 -      "<% >: # @ " +
  19.275 -                    
  19.276 -      /* package scala */
  19.277 -      "assert assume require print println printf readLine readBoolean readByte readShort " +
  19.278 -      "readChar readInt readLong readFloat readDouble " +
  19.279 -      
  19.280 -      "AnyVal App Application Array BufferedIterator BigDecimal BigInt Char Console Either " +
  19.281 -      "Enumeration Equiv Error Exception Fractional Function IndexedSeq Integral Iterable " +
  19.282 -      "Iterator List Map Numeric Nil NotNull Option Ordered Ordering PartialFunction PartialOrdering " +
  19.283 -      "Product Proxy Range Responder Seq Serializable Set Specializable Stream StringBuilder " +
  19.284 -      "StringContext Symbol Throwable Traversable TraversableOnce Tuple Unit Vector :: #:: " +
  19.285 -      
  19.286 -      /* package java.lang */            
  19.287 -      "Boolean Byte Character CharSequence Class ClassLoader Cloneable Comparable " +
  19.288 -      "Compiler Double Exception Float Integer Long Math Number Object Package Pair Process " +
  19.289 -      "Runtime Runnable SecurityManager Short StackTraceElement StrictMath String " +
  19.290 -      "StringBuffer System Thread ThreadGroup ThreadLocal Throwable Triple Void"
  19.291 -      
  19.292 -      
  19.293 -    ),
  19.294 -    blockKeywords: words("catch class do else finally for forSome if match switch try while"),
  19.295 -    atoms: words("true false null"),
  19.296 -    hooks: {
  19.297 -      "@": function(stream) {
  19.298 -        stream.eatWhile(/[\w\$_]/);
  19.299 -        return "meta";
  19.300 -      }
  19.301 -    }
  19.302 -  });
  19.303 -}());
    20.1 --- a/dew/src/main/resources/org/apidesign/bck2brwsr/dew/js/codemirror/mode/xml.js	Tue Feb 11 10:48:24 2014 +0100
    20.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    20.3 @@ -1,324 +0,0 @@
    20.4 -CodeMirror.defineMode("xml", function(config, parserConfig) {
    20.5 -  var indentUnit = config.indentUnit;
    20.6 -  var Kludges = parserConfig.htmlMode ? {
    20.7 -    autoSelfClosers: {'area': true, 'base': true, 'br': true, 'col': true, 'command': true,
    20.8 -                      'embed': true, 'frame': true, 'hr': true, 'img': true, 'input': true,
    20.9 -                      'keygen': true, 'link': true, 'meta': true, 'param': true, 'source': true,
   20.10 -                      'track': true, 'wbr': true},
   20.11 -    implicitlyClosed: {'dd': true, 'li': true, 'optgroup': true, 'option': true, 'p': true,
   20.12 -                       'rp': true, 'rt': true, 'tbody': true, 'td': true, 'tfoot': true,
   20.13 -                       'th': true, 'tr': true},
   20.14 -    contextGrabbers: {
   20.15 -      'dd': {'dd': true, 'dt': true},
   20.16 -      'dt': {'dd': true, 'dt': true},
   20.17 -      'li': {'li': true},
   20.18 -      'option': {'option': true, 'optgroup': true},
   20.19 -      'optgroup': {'optgroup': true},
   20.20 -      'p': {'address': true, 'article': true, 'aside': true, 'blockquote': true, 'dir': true,
   20.21 -            'div': true, 'dl': true, 'fieldset': true, 'footer': true, 'form': true,
   20.22 -            'h1': true, 'h2': true, 'h3': true, 'h4': true, 'h5': true, 'h6': true,
   20.23 -            'header': true, 'hgroup': true, 'hr': true, 'menu': true, 'nav': true, 'ol': true,
   20.24 -            'p': true, 'pre': true, 'section': true, 'table': true, 'ul': true},
   20.25 -      'rp': {'rp': true, 'rt': true},
   20.26 -      'rt': {'rp': true, 'rt': true},
   20.27 -      'tbody': {'tbody': true, 'tfoot': true},
   20.28 -      'td': {'td': true, 'th': true},
   20.29 -      'tfoot': {'tbody': true},
   20.30 -      'th': {'td': true, 'th': true},
   20.31 -      'thead': {'tbody': true, 'tfoot': true},
   20.32 -      'tr': {'tr': true}
   20.33 -    },
   20.34 -    doNotIndent: {"pre": true},
   20.35 -    allowUnquoted: true,
   20.36 -    allowMissing: true
   20.37 -  } : {
   20.38 -    autoSelfClosers: {},
   20.39 -    implicitlyClosed: {},
   20.40 -    contextGrabbers: {},
   20.41 -    doNotIndent: {},
   20.42 -    allowUnquoted: false,
   20.43 -    allowMissing: false
   20.44 -  };
   20.45 -  var alignCDATA = parserConfig.alignCDATA;
   20.46 -
   20.47 -  // Return variables for tokenizers
   20.48 -  var tagName, type;
   20.49 -
   20.50 -  function inText(stream, state) {
   20.51 -    function chain(parser) {
   20.52 -      state.tokenize = parser;
   20.53 -      return parser(stream, state);
   20.54 -    }
   20.55 -
   20.56 -    var ch = stream.next();
   20.57 -    if (ch == "<") {
   20.58 -      if (stream.eat("!")) {
   20.59 -        if (stream.eat("[")) {
   20.60 -          if (stream.match("CDATA[")) return chain(inBlock("atom", "]]>"));
   20.61 -          else return null;
   20.62 -        }
   20.63 -        else if (stream.match("--")) return chain(inBlock("comment", "-->"));
   20.64 -        else if (stream.match("DOCTYPE", true, true)) {
   20.65 -          stream.eatWhile(/[\w\._\-]/);
   20.66 -          return chain(doctype(1));
   20.67 -        }
   20.68 -        else return null;
   20.69 -      }
   20.70 -      else if (stream.eat("?")) {
   20.71 -        stream.eatWhile(/[\w\._\-]/);
   20.72 -        state.tokenize = inBlock("meta", "?>");
   20.73 -        return "meta";
   20.74 -      }
   20.75 -      else {
   20.76 -        var isClose = stream.eat("/");
   20.77 -        tagName = "";
   20.78 -        var c;
   20.79 -        while ((c = stream.eat(/[^\s\u00a0=<>\"\'\/?]/))) tagName += c;
   20.80 -        if (!tagName) return "error";
   20.81 -        type = isClose ? "closeTag" : "openTag";
   20.82 -        state.tokenize = inTag;
   20.83 -        return "tag";
   20.84 -      }
   20.85 -    }
   20.86 -    else if (ch == "&") {
   20.87 -      var ok;
   20.88 -      if (stream.eat("#")) {
   20.89 -        if (stream.eat("x")) {
   20.90 -          ok = stream.eatWhile(/[a-fA-F\d]/) && stream.eat(";");          
   20.91 -        } else {
   20.92 -          ok = stream.eatWhile(/[\d]/) && stream.eat(";");
   20.93 -        }
   20.94 -      } else {
   20.95 -        ok = stream.eatWhile(/[\w\.\-:]/) && stream.eat(";");
   20.96 -      }
   20.97 -      return ok ? "atom" : "error";
   20.98 -    }
   20.99 -    else {
  20.100 -      stream.eatWhile(/[^&<]/);
  20.101 -      return null;
  20.102 -    }
  20.103 -  }
  20.104 -
  20.105 -  function inTag(stream, state) {
  20.106 -    var ch = stream.next();
  20.107 -    if (ch == ">" || (ch == "/" && stream.eat(">"))) {
  20.108 -      state.tokenize = inText;
  20.109 -      type = ch == ">" ? "endTag" : "selfcloseTag";
  20.110 -      return "tag";
  20.111 -    }
  20.112 -    else if (ch == "=") {
  20.113 -      type = "equals";
  20.114 -      return null;
  20.115 -    }
  20.116 -    else if (/[\'\"]/.test(ch)) {
  20.117 -      state.tokenize = inAttribute(ch);
  20.118 -      return state.tokenize(stream, state);
  20.119 -    }
  20.120 -    else {
  20.121 -      stream.eatWhile(/[^\s\u00a0=<>\"\']/);
  20.122 -      return "word";
  20.123 -    }
  20.124 -  }
  20.125 -
  20.126 -  function inAttribute(quote) {
  20.127 -    return function(stream, state) {
  20.128 -      while (!stream.eol()) {
  20.129 -        if (stream.next() == quote) {
  20.130 -          state.tokenize = inTag;
  20.131 -          break;
  20.132 -        }
  20.133 -      }
  20.134 -      return "string";
  20.135 -    };
  20.136 -  }
  20.137 -
  20.138 -  function inBlock(style, terminator) {
  20.139 -    return function(stream, state) {
  20.140 -      while (!stream.eol()) {
  20.141 -        if (stream.match(terminator)) {
  20.142 -          state.tokenize = inText;
  20.143 -          break;
  20.144 -        }
  20.145 -        stream.next();
  20.146 -      }
  20.147 -      return style;
  20.148 -    };
  20.149 -  }
  20.150 -  function doctype(depth) {
  20.151 -    return function(stream, state) {
  20.152 -      var ch;
  20.153 -      while ((ch = stream.next()) != null) {
  20.154 -        if (ch == "<") {
  20.155 -          state.tokenize = doctype(depth + 1);
  20.156 -          return state.tokenize(stream, state);
  20.157 -        } else if (ch == ">") {
  20.158 -          if (depth == 1) {
  20.159 -            state.tokenize = inText;
  20.160 -            break;
  20.161 -          } else {
  20.162 -            state.tokenize = doctype(depth - 1);
  20.163 -            return state.tokenize(stream, state);
  20.164 -          }
  20.165 -        }
  20.166 -      }
  20.167 -      return "meta";
  20.168 -    };
  20.169 -  }
  20.170 -
  20.171 -  var curState, setStyle;
  20.172 -  function pass() {
  20.173 -    for (var i = arguments.length - 1; i >= 0; i--) curState.cc.push(arguments[i]);
  20.174 -  }
  20.175 -  function cont() {
  20.176 -    pass.apply(null, arguments);
  20.177 -    return true;
  20.178 -  }
  20.179 -
  20.180 -  function pushContext(tagName, startOfLine) {
  20.181 -    var noIndent = Kludges.doNotIndent.hasOwnProperty(tagName) || (curState.context && curState.context.noIndent);
  20.182 -    curState.context = {
  20.183 -      prev: curState.context,
  20.184 -      tagName: tagName,
  20.185 -      indent: curState.indented,
  20.186 -      startOfLine: startOfLine,
  20.187 -      noIndent: noIndent
  20.188 -    };
  20.189 -  }
  20.190 -  function popContext() {
  20.191 -    if (curState.context) curState.context = curState.context.prev;
  20.192 -  }
  20.193 -
  20.194 -  function element(type) {
  20.195 -    if (type == "openTag") {
  20.196 -      curState.tagName = tagName;
  20.197 -      return cont(attributes, endtag(curState.startOfLine));
  20.198 -    } else if (type == "closeTag") {
  20.199 -      var err = false;
  20.200 -      if (curState.context) {
  20.201 -        if (curState.context.tagName != tagName) {
  20.202 -          if (Kludges.implicitlyClosed.hasOwnProperty(curState.context.tagName.toLowerCase())) {
  20.203 -            popContext();
  20.204 -          }
  20.205 -          err = !curState.context || curState.context.tagName != tagName;
  20.206 -        }
  20.207 -      } else {
  20.208 -        err = true;
  20.209 -      }
  20.210 -      if (err) setStyle = "error";
  20.211 -      return cont(endclosetag(err));
  20.212 -    }
  20.213 -    return cont();
  20.214 -  }
  20.215 -  function endtag(startOfLine) {
  20.216 -    return function(type) {
  20.217 -      var tagName = curState.tagName;
  20.218 -      curState.tagName = null;
  20.219 -      if (type == "selfcloseTag" ||
  20.220 -          (type == "endTag" && Kludges.autoSelfClosers.hasOwnProperty(tagName.toLowerCase()))) {
  20.221 -        maybePopContext(tagName.toLowerCase());
  20.222 -        return cont();
  20.223 -      }
  20.224 -      if (type == "endTag") {
  20.225 -        maybePopContext(tagName.toLowerCase());
  20.226 -        pushContext(tagName, startOfLine);
  20.227 -        return cont();
  20.228 -      }
  20.229 -      return cont();
  20.230 -    };
  20.231 -  }
  20.232 -  function endclosetag(err) {
  20.233 -    return function(type) {
  20.234 -      if (err) setStyle = "error";
  20.235 -      if (type == "endTag") { popContext(); return cont(); }
  20.236 -      setStyle = "error";
  20.237 -      return cont(arguments.callee);
  20.238 -    };
  20.239 -  }
  20.240 -  function maybePopContext(nextTagName) {
  20.241 -    var parentTagName;
  20.242 -    while (true) {
  20.243 -      if (!curState.context) {
  20.244 -        return;
  20.245 -      }
  20.246 -      parentTagName = curState.context.tagName.toLowerCase();
  20.247 -      if (!Kludges.contextGrabbers.hasOwnProperty(parentTagName) ||
  20.248 -          !Kludges.contextGrabbers[parentTagName].hasOwnProperty(nextTagName)) {
  20.249 -        return;
  20.250 -      }
  20.251 -      popContext();
  20.252 -    }
  20.253 -  }
  20.254 -
  20.255 -  function attributes(type) {
  20.256 -    if (type == "word") {setStyle = "attribute"; return cont(attribute, attributes);}
  20.257 -    if (type == "endTag" || type == "selfcloseTag") return pass();
  20.258 -    setStyle = "error";
  20.259 -    return cont(attributes);
  20.260 -  }
  20.261 -  function attribute(type) {
  20.262 -    if (type == "equals") return cont(attvalue, attributes);
  20.263 -    if (!Kludges.allowMissing) setStyle = "error";
  20.264 -    else if (type == "word") setStyle = "attribute";
  20.265 -    return (type == "endTag" || type == "selfcloseTag") ? pass() : cont();
  20.266 -  }
  20.267 -  function attvalue(type) {
  20.268 -    if (type == "string") return cont(attvaluemaybe);
  20.269 -    if (type == "word" && Kludges.allowUnquoted) {setStyle = "string"; return cont();}
  20.270 -    setStyle = "error";
  20.271 -    return (type == "endTag" || type == "selfCloseTag") ? pass() : cont();
  20.272 -  }
  20.273 -  function attvaluemaybe(type) {
  20.274 -    if (type == "string") return cont(attvaluemaybe);
  20.275 -    else return pass();
  20.276 -  }
  20.277 -
  20.278 -  return {
  20.279 -    startState: function() {
  20.280 -      return {tokenize: inText, cc: [], indented: 0, startOfLine: true, tagName: null, context: null};
  20.281 -    },
  20.282 -
  20.283 -    token: function(stream, state) {
  20.284 -      if (stream.sol()) {
  20.285 -        state.startOfLine = true;
  20.286 -        state.indented = stream.indentation();
  20.287 -      }
  20.288 -      if (stream.eatSpace()) return null;
  20.289 -
  20.290 -      setStyle = type = tagName = null;
  20.291 -      var style = state.tokenize(stream, state);
  20.292 -      state.type = type;
  20.293 -      if ((style || type) && style != "comment") {
  20.294 -        curState = state;
  20.295 -        while (true) {
  20.296 -          var comb = state.cc.pop() || element;
  20.297 -          if (comb(type || style)) break;
  20.298 -        }
  20.299 -      }
  20.300 -      state.startOfLine = false;
  20.301 -      return setStyle || style;
  20.302 -    },
  20.303 -
  20.304 -    indent: function(state, textAfter, fullLine) {
  20.305 -      var context = state.context;
  20.306 -      if ((state.tokenize != inTag && state.tokenize != inText) ||
  20.307 -          context && context.noIndent)
  20.308 -        return fullLine ? fullLine.match(/^(\s*)/)[0].length : 0;
  20.309 -      if (alignCDATA && /<!\[CDATA\[/.test(textAfter)) return 0;
  20.310 -      if (context && /^<\//.test(textAfter))
  20.311 -        context = context.prev;
  20.312 -      while (context && !context.startOfLine)
  20.313 -        context = context.prev;
  20.314 -      if (context) return context.indent + indentUnit;
  20.315 -      else return 0;
  20.316 -    },
  20.317 -
  20.318 -    electricChars: "/",
  20.319 -
  20.320 -    configuration: parserConfig.htmlMode ? "html" : "xml"
  20.321 -  };
  20.322 -});
  20.323 -
  20.324 -CodeMirror.defineMIME("text/xml", "xml");
  20.325 -CodeMirror.defineMIME("application/xml", "xml");
  20.326 -if (!CodeMirror.mimeModes.hasOwnProperty("text/html"))
  20.327 -  CodeMirror.defineMIME("text/html", {name: "xml", htmlMode: true});
    21.1 --- a/dew/src/main/resources/org/apidesign/bck2brwsr/dew/js/codemirror/theme/elegant.css	Tue Feb 11 10:48:24 2014 +0100
    21.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    21.3 @@ -1,10 +0,0 @@
    21.4 -.cm-s-elegant span.cm-number, .cm-s-elegant span.cm-string, .cm-s-elegant span.cm-atom {color: #762;}
    21.5 -.cm-s-elegant span.cm-comment {color: #262; font-style: italic; line-height: 1em;}
    21.6 -.cm-s-elegant span.cm-meta {color: #555; font-style: italic; line-height: 1em;}
    21.7 -.cm-s-elegant span.cm-variable {color: black;}
    21.8 -.cm-s-elegant span.cm-variable-2 {color: #b11;}
    21.9 -.cm-s-elegant span.cm-qualifier {color: #555;}
   21.10 -.cm-s-elegant span.cm-keyword {color: #730;}
   21.11 -.cm-s-elegant span.cm-builtin {color: #30a;}
   21.12 -.cm-s-elegant span.cm-error {background-color: #fdd;}
   21.13 -.cm-s-elegant span.cm-link {color: #762;}
    22.1 --- a/dew/src/test/java/org/apidesign/bck2brwsr/dew/CompileTest.java	Tue Feb 11 10:48:24 2014 +0100
    22.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    22.3 @@ -1,45 +0,0 @@
    22.4 -/**
    22.5 - * Back 2 Browser Bytecode Translator
    22.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
    22.7 - *
    22.8 - * This program is free software: you can redistribute it and/or modify
    22.9 - * it under the terms of the GNU General Public License as published by
   22.10 - * the Free Software Foundation, version 2 of the License.
   22.11 - *
   22.12 - * This program is distributed in the hope that it will be useful,
   22.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
   22.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   22.15 - * GNU General Public License for more details.
   22.16 - *
   22.17 - * You should have received a copy of the GNU General Public License
   22.18 - * along with this program. Look for COPYING file in the top folder.
   22.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
   22.20 - */
   22.21 -package org.apidesign.bck2brwsr.dew;
   22.22 -
   22.23 -import java.io.IOException;
   22.24 -import static org.testng.Assert.*;
   22.25 -import org.testng.annotations.Test;
   22.26 -
   22.27 -/**
   22.28 - *
   22.29 - * @author Jaroslav Tulach <jtulach@netbeans.org>
   22.30 - */
   22.31 -public class CompileTest  {
   22.32 -    @Test public void testCompile() throws IOException {
   22.33 -        String html = "<html><body>"
   22.34 -                + " <button id='btn'>Hello!</button>"
   22.35 -                + "</body></html>";
   22.36 -        String java = "package x.y.z;"
   22.37 -                + "import org.apidesign.bck2brwsr.htmlpage.api.*;"
   22.38 -                + "import static org.apidesign.bck2brwsr.htmlpage.api.OnEvent.*;"
   22.39 -            + "@Page(xhtml=\"index.html\", className=\"Index\")"
   22.40 -            + "class X { "
   22.41 -            + "   @On(event=CLICK, id=\"btn\") static void clcs() {}"
   22.42 -            + "}";
   22.43 -        Compile result = Compile.create(html, java);
   22.44 -
   22.45 -        assertNotNull(result.get("x/y/z/X.class"), "Class X is compiled: " + result);
   22.46 -        assertNotNull(result.get("x/y/z/Index.class"), "Class Index is compiled: " + result);
   22.47 -    }
   22.48 -}
    23.1 --- a/ide/editor/pom.xml	Tue Feb 11 10:48:24 2014 +0100
    23.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    23.3 @@ -1,185 +0,0 @@
    23.4 -<?xml version="1.0" encoding="UTF-8"?>
    23.5 -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    23.6 -    <modelVersion>4.0.0</modelVersion>
    23.7 -    <parent>
    23.8 -        <artifactId>ide</artifactId>
    23.9 -        <groupId>org.apidesign.bck2brwsr</groupId>
   23.10 -        <version>0.9-SNAPSHOT</version>
   23.11 -    </parent>
   23.12 -
   23.13 -    <groupId>org.apidesign.bck2brwsr.ide</groupId>
   23.14 -    <artifactId>editor</artifactId>
   23.15 -    <version>0.9-SNAPSHOT</version>
   23.16 -    <packaging>nbm</packaging>
   23.17 -
   23.18 -    <name>Editor Support for Bck2Brwsr</name>
   23.19 -
   23.20 -    <properties>
   23.21 -        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
   23.22 -        <endorsed.dir>${project.build.directory}/endorsed</endorsed.dir>
   23.23 -    </properties>
   23.24 -
   23.25 -    <repositories>
   23.26 -        <!--
   23.27 -        Repository hosting NetBeans modules, especially APIs.
   23.28 -        Versions are based on IDE releases, e.g.: RELEASE691
   23.29 -        To create your own repository, use: nbm:populate-repository
   23.30 -        -->
   23.31 -        <repository>
   23.32 -            <id>netbeans</id>
   23.33 -            <name>NetBeans</name>
   23.34 -            <url>http://bits.netbeans.org/maven2/</url>
   23.35 -            <snapshots>
   23.36 -                <enabled>false</enabled>
   23.37 -            </snapshots>
   23.38 -        </repository>
   23.39 -    </repositories>
   23.40 -
   23.41 -    <dependencies>
   23.42 -        <dependency>
   23.43 -            <groupId>org.netbeans.api</groupId>
   23.44 -            <artifactId>org-netbeans-api-annotations-common</artifactId>
   23.45 -        </dependency>
   23.46 -        <dependency>
   23.47 -            <groupId>org.netbeans.api</groupId>
   23.48 -            <artifactId>org-netbeans-modules-java-source</artifactId>
   23.49 -        </dependency>
   23.50 -        <dependency>
   23.51 -            <groupId>org.netbeans.api</groupId>
   23.52 -            <artifactId>org-netbeans-libs-javacapi</artifactId>
   23.53 -        </dependency>
   23.54 -        <dependency>
   23.55 -            <groupId>org.netbeans.api</groupId>
   23.56 -            <artifactId>org-netbeans-spi-java-hints</artifactId>
   23.57 -        </dependency>
   23.58 -        <dependency>
   23.59 -            <groupId>org.netbeans.api</groupId>
   23.60 -            <artifactId>org-netbeans-modules-parsing-api</artifactId>
   23.61 -        </dependency>
   23.62 -        <dependency>
   23.63 -            <groupId>org.netbeans.api</groupId>
   23.64 -            <artifactId>org-netbeans-spi-editor-hints</artifactId>
   23.65 -        </dependency>
   23.66 -        <dependency>
   23.67 -            <groupId>org.netbeans.api</groupId>
   23.68 -            <artifactId>org-openide-util</artifactId>
   23.69 -        </dependency>
   23.70 -        <dependency>
   23.71 -            <groupId>org.netbeans.api</groupId>
   23.72 -            <artifactId>org-netbeans-modules-java-lexer</artifactId>
   23.73 -        </dependency>
   23.74 -        <dependency>
   23.75 -            <groupId>org.netbeans.api</groupId>
   23.76 -            <artifactId>org-netbeans-modules-lexer</artifactId>
   23.77 -        </dependency>
   23.78 -        <dependency>
   23.79 -            <groupId>org.apidesign.bck2brwsr</groupId>
   23.80 -            <artifactId>core</artifactId>
   23.81 -            <version>0.9-SNAPSHOT</version>
   23.82 -            <type>jar</type>
   23.83 -            <scope>test</scope>
   23.84 -        </dependency>
   23.85 -        <dependency>
   23.86 -            <groupId>org.netbeans.api</groupId>
   23.87 -            <artifactId>org-netbeans-modules-java-hints-test</artifactId>
   23.88 -            <scope>test</scope>
   23.89 -        </dependency>
   23.90 -        <dependency>
   23.91 -            <groupId>org.netbeans.api</groupId>
   23.92 -            <artifactId>org-netbeans-libs-junit4</artifactId>
   23.93 -            <scope>test</scope>
   23.94 -        </dependency>
   23.95 -        <dependency>
   23.96 -            <groupId>org.netbeans.modules</groupId>
   23.97 -            <artifactId>org-netbeans-lib-nbjavac</artifactId>
   23.98 -            <scope>test</scope>
   23.99 -        </dependency>
  23.100 -        <dependency>
  23.101 -            <groupId>org.testng</groupId>
  23.102 -            <artifactId>testng</artifactId>
  23.103 -            <scope>test</scope>
  23.104 -        </dependency>
  23.105 -    </dependencies>
  23.106 -
  23.107 -    <build>
  23.108 -        <plugins>
  23.109 -            <plugin>
  23.110 -                <groupId>org.codehaus.mojo</groupId>
  23.111 -                <artifactId>nbm-maven-plugin</artifactId>
  23.112 -                <version>3.8</version>
  23.113 -                <extensions>true</extensions>
  23.114 -            </plugin>
  23.115 -
  23.116 -            <plugin>
  23.117 -                <!-- NetBeans 6.9+ requires JDK 6 -->
  23.118 -                <groupId>org.apache.maven.plugins</groupId>
  23.119 -                <artifactId>maven-compiler-plugin</artifactId>
  23.120 -                <version>2.5.1</version>
  23.121 -                <configuration>
  23.122 -                    <source>1.6</source>
  23.123 -                    <target>1.6</target>
  23.124 -                    <compilerArguments>
  23.125 -                        <endorseddirs>${endorsed.dir}</endorseddirs>
  23.126 -                    </compilerArguments>
  23.127 -                </configuration>
  23.128 -            </plugin>
  23.129 -
  23.130 -            <plugin>
  23.131 -                <groupId>org.apache.maven.plugins</groupId>
  23.132 -                <artifactId>maven-jar-plugin</artifactId>
  23.133 -                <version>2.4</version>
  23.134 -                <configuration>
  23.135 -                    <!-- to have the jar plugin pickup the nbm generated manifest -->
  23.136 -                    <useDefaultManifestFile>true</useDefaultManifestFile>
  23.137 -                </configuration>
  23.138 -            </plugin>
  23.139 -
  23.140 -            <plugin>
  23.141 -                <groupId>org.apache.maven.plugins</groupId>
  23.142 -                <artifactId>maven-dependency-plugin</artifactId>
  23.143 -                <executions>
  23.144 -                    <execution>
  23.145 -                        <id>endorsed</id>
  23.146 -                        <phase>validate</phase>
  23.147 -                        <goals>
  23.148 -                            <goal>copy</goal>
  23.149 -                        </goals>
  23.150 -                    </execution>
  23.151 -                </executions>
  23.152 -                <configuration>
  23.153 -                    <outputDirectory>${endorsed.dir}</outputDirectory>
  23.154 -                    <silent>true</silent>
  23.155 -                    <artifactItems>
  23.156 -                        <artifactItem>
  23.157 -                            <groupId>org.netbeans.api</groupId>
  23.158 -                            <artifactId>org-netbeans-libs-javacapi</artifactId>
  23.159 -                            <version>${netbeans.version}</version>
  23.160 -                        </artifactItem>
  23.161 -                        <artifactItem>
  23.162 -                            <groupId>org.netbeans.external</groupId>
  23.163 -                            <artifactId>nb-javac-api</artifactId>
  23.164 -                            <version>${netbeans.version}</version>
  23.165 -                        </artifactItem>
  23.166 -                        <artifactItem>
  23.167 -                            <groupId>org.netbeans.modules</groupId>
  23.168 -                            <artifactId>org-netbeans-libs-javacimpl</artifactId>
  23.169 -                            <version>${netbeans.version}</version>
  23.170 -                        </artifactItem>
  23.171 -                        <artifactItem>
  23.172 -                            <groupId>org.netbeans.external</groupId>
  23.173 -                            <artifactId>nb-javac-impl</artifactId>
  23.174 -                            <version>${netbeans.version}</version>
  23.175 -                        </artifactItem>
  23.176 -                    </artifactItems>
  23.177 -                </configuration>
  23.178 -            </plugin>
  23.179 -            <plugin>
  23.180 -                <groupId>org.apache.maven.plugins</groupId>
  23.181 -                <artifactId>maven-surefire-plugin</artifactId>
  23.182 -                <configuration>
  23.183 -                    <argLine>-Djava.endorsed.dirs=${endorsed.dir}</argLine>
  23.184 -                </configuration>
  23.185 -            </plugin>
  23.186 -        </plugins>
  23.187 -    </build>
  23.188 -</project>
    24.1 --- a/ide/editor/src/main/java/org/apidesign/bck2brwsr/ide/editor/JNIHelper.java	Tue Feb 11 10:48:24 2014 +0100
    24.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    24.3 @@ -1,80 +0,0 @@
    24.4 -/**
    24.5 - * Back 2 Browser Bytecode Translator
    24.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
    24.7 - *
    24.8 - * This program is free software: you can redistribute it and/or modify
    24.9 - * it under the terms of the GNU General Public License as published by
   24.10 - * the Free Software Foundation, version 2 of the License.
   24.11 - *
   24.12 - * This program is distributed in the hope that it will be useful,
   24.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
   24.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   24.15 - * GNU General Public License for more details.
   24.16 - *
   24.17 - * You should have received a copy of the GNU General Public License
   24.18 - * along with this program. Look for COPYING file in the top folder.
   24.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
   24.20 - */
   24.21 -package org.apidesign.bck2brwsr.ide.editor;
   24.22 -
   24.23 -import java.lang.reflect.Method;
   24.24 -import java.util.HashMap;
   24.25 -import java.util.Map;
   24.26 -
   24.27 -/**
   24.28 - * JNI Helper.
   24.29 - * To facilitate lookup of methods by name and signature, instead of manually parsing signatures,
   24.30 - * constructs the map of all methods and uses Class.getName() to generate almost-correct signatures.
   24.31 - */
   24.32 -class JNIHelper {
   24.33 -
   24.34 -    static Method method(String clazz, String method, String signature) {
   24.35 -        final Map<String, Method> methods = methodMap(JNIHelper.clazz(clazz));
   24.36 -        return methods.get(methodKey(method, signature));
   24.37 -    }
   24.38 -
   24.39 -    static Class<?> clazz(String clazz) {
   24.40 -        try {
   24.41 -            return Class.forName(clazz);
   24.42 -        } catch (ClassNotFoundException e) {
   24.43 -            throw new IllegalArgumentException(e);
   24.44 -        }
   24.45 -    }
   24.46 -
   24.47 -    static Map<String, Method> methodMap(final Class<?> clazz) {
   24.48 -        final Map<String, Method> map = new HashMap<String, Method>();
   24.49 -        final Method[] methods = clazz.getDeclaredMethods();
   24.50 -        for (int i = 0; i < methods.length; i++) {
   24.51 -            final Method method = methods[i];
   24.52 -            map.put(methodKey(method.getName(), signature(method)), method);
   24.53 -        }
   24.54 -        return map;
   24.55 -    }
   24.56 -
   24.57 -    static String methodKey(String method, String signature) {
   24.58 -        return method + '@' + signature;
   24.59 -    }
   24.60 -
   24.61 -    static String signature(final Method method) {
   24.62 -        final Class<?>[] parameterTypes = method.getParameterTypes();
   24.63 -        final StringBuilder b = new StringBuilder();
   24.64 -        for (int j = 0; j < parameterTypes.length; j++) {
   24.65 -            b.append(signature(parameterTypes[j]));
   24.66 -        }
   24.67 -        return b.toString();
   24.68 -    }
   24.69 -
   24.70 -    static String signature(final Class<?> clazz) {
   24.71 -        if (clazz == boolean.class) return "Z";
   24.72 -        else if (clazz == byte.class) return "B";
   24.73 -        else if (clazz == char.class) return "C";
   24.74 -        else if (clazz == double.class) return "D";
   24.75 -        else if (clazz == float.class) return "F";
   24.76 -        else if (clazz == int.class) return "I";
   24.77 -        else if (clazz == long.class) return "J";
   24.78 -        else if (clazz == short.class) return "S";
   24.79 -        else if (clazz == void.class) return "V";
   24.80 -        else if (clazz.isArray()) return clazz.getName().replace('.','/');
   24.81 -        else return "L" + clazz.getName().replace('.','/') + ";";
   24.82 -    }
   24.83 -}
    25.1 --- a/ide/editor/src/main/java/org/apidesign/bck2brwsr/ide/editor/JSEmbeddingProvider.java	Tue Feb 11 10:48:24 2014 +0100
    25.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    25.3 @@ -1,188 +0,0 @@
    25.4 -/**
    25.5 - * Back 2 Browser Bytecode Translator
    25.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
    25.7 - *
    25.8 - * This program is free software: you can redistribute it and/or modify
    25.9 - * it under the terms of the GNU General Public License as published by
   25.10 - * the Free Software Foundation, version 2 of the License.
   25.11 - *
   25.12 - * This program is distributed in the hope that it will be useful,
   25.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
   25.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   25.15 - * GNU General Public License for more details.
   25.16 - *
   25.17 - * You should have received a copy of the GNU General Public License
   25.18 - * along with this program. Look for COPYING file in the top folder.
   25.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
   25.20 - */
   25.21 -package org.apidesign.bck2brwsr.ide.editor;
   25.22 -
   25.23 -import com.sun.source.tree.AnnotationTree;
   25.24 -import com.sun.source.tree.AssignmentTree;
   25.25 -import com.sun.source.tree.CompilationUnitTree;
   25.26 -import com.sun.source.tree.ExpressionTree;
   25.27 -import com.sun.source.tree.LiteralTree;
   25.28 -import com.sun.source.tree.MethodTree;
   25.29 -import com.sun.source.util.SourcePositions;
   25.30 -import com.sun.source.util.TreePath;
   25.31 -import com.sun.source.util.TreePathScanner;
   25.32 -import com.sun.source.util.Trees;
   25.33 -import java.io.IOException;
   25.34 -import java.util.ArrayList;
   25.35 -import java.util.Collection;
   25.36 -import java.util.Collections;
   25.37 -import java.util.List;
   25.38 -import java.util.concurrent.atomic.AtomicBoolean;
   25.39 -import javax.lang.model.element.TypeElement;
   25.40 -import javax.swing.text.Document;
   25.41 -import org.netbeans.api.editor.mimelookup.MimeRegistration;
   25.42 -import org.netbeans.api.java.source.CompilationInfo;
   25.43 -import org.netbeans.api.java.source.JavaParserResultTask;
   25.44 -import org.netbeans.api.java.source.JavaSource;
   25.45 -import org.netbeans.api.lexer.Language;
   25.46 -import org.netbeans.api.lexer.TokenHierarchy;
   25.47 -import org.netbeans.api.lexer.TokenSequence;
   25.48 -import org.netbeans.modules.parsing.api.Snapshot;
   25.49 -import org.netbeans.modules.parsing.spi.Parser;
   25.50 -import org.netbeans.modules.parsing.spi.Scheduler;
   25.51 -import org.netbeans.modules.parsing.spi.SchedulerEvent;
   25.52 -import org.netbeans.modules.parsing.spi.SchedulerTask;
   25.53 -import org.netbeans.modules.parsing.spi.TaskFactory;
   25.54 -import org.openide.util.Exceptions;
   25.55 -
   25.56 -/**
   25.57 - *
   25.58 - * @author Tomas Zezula
   25.59 - */
   25.60 -public final class JSEmbeddingProvider extends JavaParserResultTask<Parser.Result> {
   25.61 -
   25.62 -    private static final int PRIORITY = 1000;
   25.63 -    private static final String JS_ANNOTATION = "org.apidesign.bck2brwsr.core.JavaScriptBody";  //NOI18N
   25.64 -    private static final String BODY = "body";                            //NOI18N
   25.65 -    private static final String JAVA_MIME_TYPE = "text/x-java";           //NOI18N
   25.66 -    private static final String JAVASCRIPT_MIME_TYPE = "text/javascript"; //NOI18N
   25.67 -    private final AtomicBoolean canceled = new AtomicBoolean();
   25.68 -
   25.69 -    private JSEmbeddingProvider() {
   25.70 -        super(JavaSource.Phase.ELEMENTS_RESOLVED);
   25.71 -    }
   25.72 -
   25.73 -    @Override
   25.74 -    public int getPriority() {
   25.75 -        return PRIORITY;
   25.76 -    }
   25.77 -
   25.78 -    @Override
   25.79 -    public void cancel() {
   25.80 -        canceled.set(true);
   25.81 -    }
   25.82 -
   25.83 -    @Override
   25.84 -    public Class<? extends Scheduler> getSchedulerClass() {
   25.85 -        return Scheduler.EDITOR_SENSITIVE_TASK_SCHEDULER;
   25.86 -    }
   25.87 -
   25.88 -    @Override
   25.89 -    public void run(Parser.Result t, SchedulerEvent se) {
   25.90 -        canceled.set(false);
   25.91 -        final CompilationInfo ci = CompilationInfo.get(t);
   25.92 -        final CompilationUnitTree cu = ci.getCompilationUnit();
   25.93 -        final Trees trees = ci.getTrees();
   25.94 -        final SourcePositions sp = trees.getSourcePositions();
   25.95 -        final Finder f = new Finder(trees);
   25.96 -        final List<LiteralTree> result = new ArrayList<LiteralTree>();
   25.97 -        f.scan(cu, result);
   25.98 -        if (!result.isEmpty()) {
   25.99 -            try {
  25.100 -                final TokenHierarchy<Document> tk = TokenHierarchy.get(ci.getDocument());
  25.101 -                final Language<?> java = Language.find(JAVA_MIME_TYPE);
  25.102 -                final Language<?> javaScript = Language.find(JAVASCRIPT_MIME_TYPE);
  25.103 -                if (java != null && javaScript != null) {
  25.104 -                    final TokenSequence<?> seq = tk.tokenSequence(java);
  25.105 -                    if (seq != null) {
  25.106 -                        for (LiteralTree lt : result) {
  25.107 -                            final int start = (int) sp.getStartPosition(cu, lt);
  25.108 -                            final int end = (int) sp.getEndPosition(cu, lt);
  25.109 -                            seq.move(start);
  25.110 -                            while (seq.moveNext() && seq.offset() < end) {
  25.111 -                                seq.createEmbedding(javaScript, 1, 1, true);
  25.112 -                            }
  25.113 -                        }
  25.114 -                    }
  25.115 -                }
  25.116 -            } catch (IOException ioe) {
  25.117 -                Exceptions.printStackTrace(ioe);
  25.118 -            }
  25.119 -        }
  25.120 -    }
  25.121 -
  25.122 -
  25.123 -
  25.124 -
  25.125 -    private static final class Finder extends TreePathScanner<Void, List<? super LiteralTree>> {
  25.126 -
  25.127 -        private final Trees trees;
  25.128 -        private CompilationUnitTree cu;
  25.129 -        private boolean inEmbedding;
  25.130 -
  25.131 -        Finder(final Trees trees) {
  25.132 -            this.trees = trees;
  25.133 -        }
  25.134 -
  25.135 -        @Override
  25.136 -        public Void visitCompilationUnit(
  25.137 -                final CompilationUnitTree unit,
  25.138 -                final List p) {
  25.139 -            this.cu = unit;
  25.140 -            return super.visitCompilationUnit(unit, p);
  25.141 -        }
  25.142 -
  25.143 -
  25.144 -
  25.145 -        @Override
  25.146 -        public Void visitMethod(
  25.147 -                final MethodTree m,
  25.148 -                final List<? super LiteralTree> p) {
  25.149 -            for (AnnotationTree a : m.getModifiers().getAnnotations()) {
  25.150 -                final TypeElement ae = (TypeElement) trees.getElement(TreePath.getPath(cu, a.getAnnotationType()));
  25.151 -                if (ae != null && JS_ANNOTATION.contentEquals(ae.getQualifiedName())) {
  25.152 -                    final List<? extends ExpressionTree> args =  a.getArguments();
  25.153 -                    for (ExpressionTree kvp : args) {
  25.154 -                        if (kvp instanceof AssignmentTree) {
  25.155 -                            final AssignmentTree assignemt = (AssignmentTree) kvp;
  25.156 -                            if (BODY.equals(assignemt.getVariable().toString())) {
  25.157 -                                inEmbedding = true;
  25.158 -                                try {
  25.159 -                                    scan(assignemt.getExpression(), p);
  25.160 -                                } finally {
  25.161 -                                    inEmbedding = false;
  25.162 -                                }
  25.163 -                            }
  25.164 -                        }
  25.165 -                    }
  25.166 -                }
  25.167 -            }
  25.168 -            return null;
  25.169 -        }
  25.170 -
  25.171 -        @Override
  25.172 -        public Void visitLiteral(LiteralTree node, List<? super LiteralTree> p) {
  25.173 -            if (inEmbedding) {
  25.174 -                p.add(node);
  25.175 -            }
  25.176 -            return super.visitLiteral(node, p);
  25.177 -        }
  25.178 -
  25.179 -    }
  25.180 -
  25.181 -    @MimeRegistration(
  25.182 -            service = TaskFactory.class,
  25.183 -            mimeType = JAVA_MIME_TYPE)
  25.184 -    public static final class Factory extends TaskFactory {
  25.185 -        @Override
  25.186 -        public Collection<? extends SchedulerTask> create(Snapshot snpsht) {
  25.187 -            return Collections.singleton(new JSEmbeddingProvider());
  25.188 -        }
  25.189 -    }
  25.190 -
  25.191 -}
    26.1 --- a/ide/editor/src/main/java/org/apidesign/bck2brwsr/ide/editor/JSNI2JavaScriptBody.java	Tue Feb 11 10:48:24 2014 +0100
    26.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    26.3 @@ -1,149 +0,0 @@
    26.4 -/**
    26.5 - * Back 2 Browser Bytecode Translator
    26.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
    26.7 - *
    26.8 - * This program is free software: you can redistribute it and/or modify
    26.9 - * it under the terms of the GNU General Public License as published by
   26.10 - * the Free Software Foundation, version 2 of the License.
   26.11 - *
   26.12 - * This program is distributed in the hope that it will be useful,
   26.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
   26.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   26.15 - * GNU General Public License for more details.
   26.16 - *
   26.17 - * You should have received a copy of the GNU General Public License
   26.18 - * along with this program. Look for COPYING file in the top folder.
   26.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
   26.20 - */
   26.21 -package org.apidesign.bck2brwsr.ide.editor;
   26.22 -
   26.23 -import com.sun.source.tree.AnnotationTree;
   26.24 -import com.sun.source.tree.ExpressionTree;
   26.25 -import com.sun.source.tree.LiteralTree;
   26.26 -import com.sun.source.tree.MethodTree;
   26.27 -import com.sun.source.tree.Tree.Kind;
   26.28 -import com.sun.source.tree.VariableTree;
   26.29 -import com.sun.source.util.TreePath;
   26.30 -import java.util.ArrayList;
   26.31 -import java.util.Arrays;
   26.32 -import java.util.Collections;
   26.33 -import java.util.List;
   26.34 -import org.netbeans.api.java.lexer.JavaTokenId;
   26.35 -import static org.netbeans.api.java.lexer.JavaTokenId.BLOCK_COMMENT;
   26.36 -import static org.netbeans.api.java.lexer.JavaTokenId.JAVADOC_COMMENT;
   26.37 -import static org.netbeans.api.java.lexer.JavaTokenId.LINE_COMMENT;
   26.38 -import static org.netbeans.api.java.lexer.JavaTokenId.WHITESPACE;
   26.39 -import org.netbeans.api.java.source.CompilationInfo;
   26.40 -import org.netbeans.api.java.source.TreeMaker;
   26.41 -import org.netbeans.api.lexer.Token;
   26.42 -import org.netbeans.api.lexer.TokenSequence;
   26.43 -import org.netbeans.spi.editor.hints.ErrorDescription;
   26.44 -import org.netbeans.spi.editor.hints.Fix;
   26.45 -import org.netbeans.spi.java.hints.ErrorDescriptionFactory;
   26.46 -import org.netbeans.spi.java.hints.Hint;
   26.47 -import org.netbeans.spi.java.hints.HintContext;
   26.48 -import org.netbeans.spi.java.hints.JavaFix;
   26.49 -import org.netbeans.spi.java.hints.TriggerTreeKind;
   26.50 -import org.openide.util.NbBundle.Messages;
   26.51 -
   26.52 -@Hint(displayName = "#DN_JSNI2JavaScriptBody", description = "#DESC_JSNI2JavaScriptBody", category = "general")
   26.53 -@Messages({
   26.54 -    "DN_JSNI2JavaScriptBody=JSNI to @JavaScriptBody",
   26.55 -    "DESC_JSNI2JavaScriptBody=JSNI to @JavaScriptBody"
   26.56 -})
   26.57 -public class JSNI2JavaScriptBody {
   26.58 -
   26.59 -    @TriggerTreeKind(Kind.METHOD)
   26.60 -    @Messages("ERR_JSNI2JavaScriptBody=Can convert JSNI to @JavaScriptBody")
   26.61 -    public static ErrorDescription computeWarning(final HintContext ctx) {
   26.62 -        Token<JavaTokenId> token = findBlockToken(ctx.getInfo(), ctx.getPath(), ctx);
   26.63 -
   26.64 -        if (token == null) {
   26.65 -            return null;
   26.66 -        }
   26.67 -
   26.68 -        Fix fix = new FixImpl(ctx.getInfo(), ctx.getPath()).toEditorFix();
   26.69 -        return ErrorDescriptionFactory.forName(ctx, ctx.getPath(), Bundle.ERR_JSNI2JavaScriptBody(), fix);
   26.70 -    }
   26.71 -
   26.72 -    private static Token<JavaTokenId> findBlockToken(CompilationInfo info, TreePath path, HintContext ctx) {
   26.73 -        int end = (int) info.getTrees().getSourcePositions().getEndPosition(path.getCompilationUnit(), path.getLeaf());
   26.74 -        TokenSequence<JavaTokenId> ts = info.getTokenHierarchy().tokenSequence(JavaTokenId.language());
   26.75 -
   26.76 -        if (ts == null) return null;
   26.77 -
   26.78 -        ts.move(end);
   26.79 -
   26.80 -        if ((ctx != null && ctx.isCanceled()) || !ts.movePrevious() || ts.token().id() != JavaTokenId.SEMICOLON) return null;
   26.81 -
   26.82 -        OUTER: while (ts.movePrevious()) {
   26.83 -            if (ctx != null && ctx.isCanceled()) return null;
   26.84 -
   26.85 -            switch (ts.token().id()) {
   26.86 -                case WHITESPACE: break;
   26.87 -                case LINE_COMMENT: break;
   26.88 -                case JAVADOC_COMMENT: break;
   26.89 -                case BLOCK_COMMENT:
   26.90 -                    final CharSequence tok = ts.token().text();
   26.91 -                    final int l = tok.length(); 
   26.92 -                    if (l > 4 
   26.93 -                        && tok.subSequence(0, 4).toString().equals("/*-{") // NOI18N
   26.94 -                        && tok.subSequence(l - 4, l).toString().equals("}-*/") // NOI18N
   26.95 -                    ) {
   26.96 -                        return ts.offsetToken();
   26.97 -                    }
   26.98 -                    break;
   26.99 -                default:
  26.100 -                    break OUTER;
  26.101 -            }
  26.102 -        }
  26.103 -
  26.104 -        return null;
  26.105 -    }
  26.106 -
  26.107 -    private static final class FixImpl extends JavaFix {
  26.108 -
  26.109 -        public FixImpl(CompilationInfo info, TreePath tp) {
  26.110 -            super(info, tp);
  26.111 -        }
  26.112 -
  26.113 -        @Override
  26.114 -        @Messages("FIX_JSNI2JavaScriptBody=Convert JSNI to @JavaScriptBody")
  26.115 -        protected String getText() {
  26.116 -            return Bundle.FIX_JSNI2JavaScriptBody();
  26.117 -        }
  26.118 -
  26.119 -        @Override
  26.120 -        protected void performRewrite(TransformationContext ctx) {
  26.121 -            Token<JavaTokenId> jsniComment = findBlockToken(ctx.getWorkingCopy(), ctx.getPath(), null);
  26.122 -
  26.123 -            if (jsniComment == null) {
  26.124 -                //XXX: warn?
  26.125 -                return ;
  26.126 -            }
  26.127 -            
  26.128 -            JsniCommentTokenizer tok = new JsniCommentTokenizer();
  26.129 -            ManglingSink ms = new ManglingSink();
  26.130 -            final CharSequence cmnt = jsniComment.text();
  26.131 -            tok.process(cmnt.subSequence(4, cmnt.length() - 4), ms);
  26.132 -
  26.133 -            TreeMaker make = ctx.getWorkingCopy().getTreeMaker();
  26.134 -            MethodTree mt = (MethodTree) ctx.getPath().getLeaf();
  26.135 -            List<LiteralTree> params = new ArrayList<LiteralTree>();
  26.136 -
  26.137 -            for (VariableTree p : mt.getParameters()) {
  26.138 -                params.add(make.Literal(p.getName().toString()));
  26.139 -            }
  26.140 -
  26.141 -            AnnotationTree jsBody = make.Annotation(make.QualIdent("org.apidesign.bck2brwsr.core.JavaScriptBody"),
  26.142 -                Arrays.<ExpressionTree>asList(
  26.143 -                    make.Assignment(make.Identifier("args"), make.NewArray(null, Collections.<ExpressionTree>emptyList(), params)),
  26.144 -                    make.Assignment(make.Identifier("body"), make.Literal(ms.out.toString()))
  26.145 -                )
  26.146 -            );
  26.147 -
  26.148 -
  26.149 -            ctx.getWorkingCopy().rewrite(mt.getModifiers(), make.addModifiersAnnotation(mt.getModifiers(), jsBody));
  26.150 -        }
  26.151 -    }
  26.152 -}
    27.1 --- a/ide/editor/src/main/java/org/apidesign/bck2brwsr/ide/editor/JsniCommentTokenizer.java	Tue Feb 11 10:48:24 2014 +0100
    27.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    27.3 @@ -1,70 +0,0 @@
    27.4 -/**
    27.5 - * Back 2 Browser Bytecode Translator
    27.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
    27.7 - *
    27.8 - * This program is free software: you can redistribute it and/or modify
    27.9 - * it under the terms of the GNU General Public License as published by
   27.10 - * the Free Software Foundation, version 2 of the License.
   27.11 - *
   27.12 - * This program is distributed in the hope that it will be useful,
   27.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
   27.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   27.15 - * GNU General Public License for more details.
   27.16 - *
   27.17 - * You should have received a copy of the GNU General Public License
   27.18 - * along with this program. Look for COPYING file in the top folder.
   27.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
   27.20 - */
   27.21 -package org.apidesign.bck2brwsr.ide.editor;
   27.22 -
   27.23 -import java.util.regex.Matcher;
   27.24 -import java.util.regex.Pattern;
   27.25 -
   27.26 -final class JsniCommentTokenizer {
   27.27 -
   27.28 -    /**
   27.29 -     * Tokenize the contents of JSNI comment into the provided {@linkplain Sink}.
   27.30 -     * @param in the contents of JSNI comment
   27.31 -     * @param out the sink that consumes parsed tokens
   27.32 -     */
   27.33 -    public void process(final CharSequence in, final Sink out) {
   27.34 -        final Matcher member = Pattern.compile("@([^:]+)::([a-zA-Z_$][a-zA-Z\\d_$]*)").matcher(in);
   27.35 -        final Matcher signature = Pattern.compile("\\(([^\\)]*)\\)").matcher(in);
   27.36 -
   27.37 -        int i = 0;
   27.38 -        while (true) {
   27.39 -            if (member.find(i)) {
   27.40 -                final int memberStart = member.start();
   27.41 -                final int memberEnd = member.end();
   27.42 -                if (memberStart > i) out.javascript(in.subSequence(i, memberStart).toString());
   27.43 -
   27.44 -                final String clazz = member.group(1);
   27.45 -                final String name = member.group(2);
   27.46 -
   27.47 -                if (in.charAt(memberEnd) == '(') {
   27.48 -                    if (!signature.find(memberEnd)) {
   27.49 -                        throw new IllegalStateException("Expected method signature");
   27.50 -                    }
   27.51 -                    assert signature.start() == memberEnd;
   27.52 -                    out.method(clazz, name, signature.group(1));
   27.53 -                    i = signature.end();
   27.54 -                } else {
   27.55 -                    out.field(clazz, name);
   27.56 -                    i = memberEnd;
   27.57 -                }
   27.58 -            } else {
   27.59 -                out.javascript(in.subSequence(i, in.length()).toString());
   27.60 -                break;
   27.61 -            }
   27.62 -        }
   27.63 -    }
   27.64 -
   27.65 -
   27.66 -    static interface Sink {
   27.67 -        void javascript(String s);
   27.68 -
   27.69 -        void method(String clazz, String method, String signature);
   27.70 -
   27.71 -        void field(String clazz, String field);
   27.72 -    }
   27.73 -}
    28.1 --- a/ide/editor/src/main/java/org/apidesign/bck2brwsr/ide/editor/ManglingSink.java	Tue Feb 11 10:48:24 2014 +0100
    28.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    28.3 @@ -1,71 +0,0 @@
    28.4 -/**
    28.5 - * Back 2 Browser Bytecode Translator
    28.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
    28.7 - *
    28.8 - * This program is free software: you can redistribute it and/or modify
    28.9 - * it under the terms of the GNU General Public License as published by
   28.10 - * the Free Software Foundation, version 2 of the License.
   28.11 - *
   28.12 - * This program is distributed in the hope that it will be useful,
   28.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
   28.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   28.15 - * GNU General Public License for more details.
   28.16 - *
   28.17 - * You should have received a copy of the GNU General Public License
   28.18 - * along with this program. Look for COPYING file in the top folder.
   28.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
   28.20 - */
   28.21 -package org.apidesign.bck2brwsr.ide.editor;
   28.22 -
   28.23 -/**
   28.24 - * An implementation of {@linkplain JsniCommentTokenizer.Sink} that generates B2B
   28.25 - */
   28.26 -class ManglingSink implements JsniCommentTokenizer.Sink {
   28.27 -
   28.28 -    final StringBuilder out = new StringBuilder();
   28.29 -
   28.30 -    public void javascript(String s) {
   28.31 -        out.append(s);
   28.32 -    }
   28.33 -
   28.34 -    public void method(String clazz, String method, String signature) {
   28.35 -        out.append(mangle(clazz, method, signature));
   28.36 -    }
   28.37 -
   28.38 -    public void field(String clazz, String field) {
   28.39 -//        out.append(field);
   28.40 -        out.append('_').append(field).append('(').append(')');
   28.41 -    }
   28.42 -
   28.43 -
   28.44 -    @Override
   28.45 -    public String toString() {
   28.46 -        return out.toString();
   28.47 -    }
   28.48 -
   28.49 -
   28.50 -    static String mangle(String clazz, String method, String signature) {
   28.51 -        final StringBuilder builder = new StringBuilder();
   28.52 -        builder.append(method);
   28.53 -        builder.append("__");
   28.54 -        builder.append(mangle(JNIHelper.signature(JNIHelper.method(clazz, method, signature).getReturnType())));
   28.55 -        builder.append(mangle(signature));
   28.56 -        return builder.toString();
   28.57 -    }
   28.58 -
   28.59 -
   28.60 -    static String mangle(String txt) {
   28.61 -        final StringBuilder sb = new StringBuilder();
   28.62 -        for (int i = 0; i < txt.length(); i++) {
   28.63 -            final char ch = txt.charAt(i);
   28.64 -            switch (ch) {
   28.65 -                case '/': sb.append('_'); break;
   28.66 -                case '_': sb.append("_1"); break;
   28.67 -                case ';': sb.append("_2"); break;
   28.68 -                case '[': sb.append("_3"); break;
   28.69 -                default: sb.append(ch); break;
   28.70 -            }
   28.71 -        }
   28.72 -        return sb.toString();
   28.73 -    }
   28.74 -}
    29.1 --- a/ide/editor/src/main/nbm/manifest.mf	Tue Feb 11 10:48:24 2014 +0100
    29.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    29.3 @@ -1,2 +0,0 @@
    29.4 -Manifest-Version: 1.0
    29.5 -OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/jackpot30/test/hints/Bundle.properties
    30.1 --- a/ide/editor/src/main/resources/org/netbeans/modules/jackpot30/test/hints/Bundle.properties	Tue Feb 11 10:48:24 2014 +0100
    30.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    30.3 @@ -1,21 +0,0 @@
    30.4 -#
    30.5 -# Back 2 Browser Bytecode Translator
    30.6 -# Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
    30.7 -#
    30.8 -# This program is free software: you can redistribute it and/or modify
    30.9 -# it under the terms of the GNU General Public License as published by
   30.10 -# the Free Software Foundation, version 2 of the License.
   30.11 -#
   30.12 -# This program is distributed in the hope that it will be useful,
   30.13 -# but WITHOUT ANY WARRANTY; without even the implied warranty of
   30.14 -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   30.15 -# GNU General Public License for more details.
   30.16 -#
   30.17 -# You should have received a copy of the GNU General Public License
   30.18 -# along with this program. Look for COPYING file in the top folder.
   30.19 -# If not, see http://opensource.org/licenses/GPL-2.0.
   30.20 -#
   30.21 -
   30.22 -OpenIDE-Module-Name=Bck2Brwsr Editor Support
   30.23 -OpenIDE-Module-Short-Description=Provides hints, coloring, etc. for the bck2brwsr.apidesign.org project
   30.24 -OpenIDE-Module-Display-Category=Java
    31.1 --- a/ide/editor/src/test/java/org/apidesign/bck2brwsr/ide/editor/DejsniReaderTest.java	Tue Feb 11 10:48:24 2014 +0100
    31.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    31.3 @@ -1,84 +0,0 @@
    31.4 -/**
    31.5 - * Back 2 Browser Bytecode Translator
    31.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
    31.7 - *
    31.8 - * This program is free software: you can redistribute it and/or modify
    31.9 - * it under the terms of the GNU General Public License as published by
   31.10 - * the Free Software Foundation, version 2 of the License.
   31.11 - *
   31.12 - * This program is distributed in the hope that it will be useful,
   31.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
   31.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   31.15 - * GNU General Public License for more details.
   31.16 - *
   31.17 - * You should have received a copy of the GNU General Public License
   31.18 - * along with this program. Look for COPYING file in the top folder.
   31.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
   31.20 - */
   31.21 -package org.apidesign.bck2brwsr.ide.editor;
   31.22 -
   31.23 -import org.apidesign.bck2brwsr.core.JavaScriptBody;
   31.24 -import org.netbeans.modules.java.hints.test.api.HintTest;
   31.25 -import org.openide.filesystems.FileUtil;
   31.26 -import org.testng.annotations.Test;
   31.27 -
   31.28 -public class DejsniReaderTest {
   31.29 -
   31.30 -    @Test
   31.31 -    public void test1() throws Exception {
   31.32 -        String s = "class Test {\n" +
   31.33 -                "    /** javadoc */\n" +
   31.34 -                "    public native void test() /*-{\n" +
   31.35 -                "        // body\n" +
   31.36 -                "    }-*/;\n" +
   31.37 -                "}\n";
   31.38 -
   31.39 -        String expected = " import org.apidesign.bck2brwsr.core.JavaScriptBody;\n"
   31.40 -              + "class Test {\n" +
   31.41 -                "\n" +
   31.42 -                "    /** javadoc */\n" +
   31.43 -                "    @JavaScriptBody(args = {}, body = \"\\n        // body\\n  \")\n" +
   31.44 -                "    public native void test();\n" +
   31.45 -                "}\n";
   31.46 -        
   31.47 -          HintTest.create()
   31.48 -                .input(s)
   31.49 -                .classpath(FileUtil.getArchiveRoot(JavaScriptBody.class.getProtectionDomain().getCodeSource().getLocation()))
   31.50 -                .run(JSNI2JavaScriptBody.class)
   31.51 -                .findWarning("2:23-2:27:verifier:" + Bundle.ERR_JSNI2JavaScriptBody())
   31.52 -                .applyFix()
   31.53 -                .assertCompilable()
   31.54 -                .assertOutput(expected);
   31.55 -    }
   31.56 -
   31.57 -
   31.58 -    @Test
   31.59 -    public void test2() throws Exception {
   31.60 -        String s = "class Test {\n" +
   31.61 -                "    /** javadoc */\n" +
   31.62 -                "    @SuppressWarnings(\"unused\")\n" +
   31.63 -                "    // comment\n" +
   31.64 -                "    public native void test() /*-{\n" +
   31.65 -                "        // body\n" +
   31.66 -                "    }-*/;\n" +
   31.67 -                "}\n";
   31.68 -
   31.69 -        String expected = " import org.apidesign.bck2brwsr.core.JavaScriptBody;\n"
   31.70 -              + "class Test {\n" +
   31.71 -                "\n" +
   31.72 -                "    /** javadoc */\n" +
   31.73 -                "    @SuppressWarnings(\"unused\")\n" +
   31.74 -                "    // comment\n" +
   31.75 -                "    @JavaScriptBody(args = {}, body = \"\\n        // body\\n  \")\n" +
   31.76 -                "    public native void test();\n" +
   31.77 -                "}\n";
   31.78 -          HintTest.create()
   31.79 -                .input(s)
   31.80 -                .classpath(FileUtil.getArchiveRoot(JavaScriptBody.class.getProtectionDomain().getCodeSource().getLocation()))
   31.81 -                .run(JSNI2JavaScriptBody.class)
   31.82 -                .findWarning("4:23-4:27:verifier:" + Bundle.ERR_JSNI2JavaScriptBody())
   31.83 -                .applyFix()
   31.84 -                .assertCompilable()
   31.85 -                .assertOutput(expected);
   31.86 -    }
   31.87 -}
   31.88 \ No newline at end of file
    32.1 --- a/ide/editor/src/test/java/org/apidesign/bck2brwsr/ide/editor/JSNI2JavaScriptBodyTest.java	Tue Feb 11 10:48:24 2014 +0100
    32.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    32.3 @@ -1,46 +0,0 @@
    32.4 -/**
    32.5 - * Back 2 Browser Bytecode Translator
    32.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
    32.7 - *
    32.8 - * This program is free software: you can redistribute it and/or modify
    32.9 - * it under the terms of the GNU General Public License as published by
   32.10 - * the Free Software Foundation, version 2 of the License.
   32.11 - *
   32.12 - * This program is distributed in the hope that it will be useful,
   32.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
   32.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   32.15 - * GNU General Public License for more details.
   32.16 - *
   32.17 - * You should have received a copy of the GNU General Public License
   32.18 - * along with this program. Look for COPYING file in the top folder.
   32.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
   32.20 - */
   32.21 -package org.apidesign.bck2brwsr.ide.editor;
   32.22 -
   32.23 -import org.apidesign.bck2brwsr.core.JavaScriptBody;
   32.24 -import org.netbeans.modules.java.hints.test.api.HintTest;
   32.25 -import org.openide.filesystems.FileUtil;
   32.26 -import org.testng.annotations.Test;
   32.27 -
   32.28 -public class JSNI2JavaScriptBodyTest {
   32.29 -
   32.30 -    @Test
   32.31 -    public void testFixWorking() throws Exception {
   32.32 -        HintTest.create()
   32.33 -                .input("package test;\n" +
   32.34 -                       "public class Test {\n" +
   32.35 -                       "    public native void run(int a) /*-{ this.a = a; }-*/;\n" +
   32.36 -                       "}\n")
   32.37 -                .classpath(FileUtil.getArchiveRoot(JavaScriptBody.class.getProtectionDomain().getCodeSource().getLocation()))
   32.38 -                .run(JSNI2JavaScriptBody.class)
   32.39 -                .findWarning("2:23-2:26:verifier:" + Bundle.ERR_JSNI2JavaScriptBody())
   32.40 -                .applyFix()
   32.41 -                .assertCompilable()
   32.42 -                .assertOutput("package test;\n" +
   32.43 -                              "import org.apidesign.bck2brwsr.core.JavaScriptBody;\n" +
   32.44 -                              "public class Test {\n" +
   32.45 -                              "    @JavaScriptBody(args = {\"a\"}, body = \" this.a = a; \")\n" +
   32.46 -                              "    public native void run(int a);\n" +
   32.47 -                              "}\n");
   32.48 -    }
   32.49 -}
    33.1 --- a/ide/editor/src/test/java/org/apidesign/bck2brwsr/ide/editor/JsniCommentTokenizerTest.java	Tue Feb 11 10:48:24 2014 +0100
    33.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    33.3 @@ -1,154 +0,0 @@
    33.4 -/**
    33.5 - * Back 2 Browser Bytecode Translator
    33.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
    33.7 - *
    33.8 - * This program is free software: you can redistribute it and/or modify
    33.9 - * it under the terms of the GNU General Public License as published by
   33.10 - * the Free Software Foundation, version 2 of the License.
   33.11 - *
   33.12 - * This program is distributed in the hope that it will be useful,
   33.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
   33.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   33.15 - * GNU General Public License for more details.
   33.16 - *
   33.17 - * You should have received a copy of the GNU General Public License
   33.18 - * along with this program. Look for COPYING file in the top folder.
   33.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
   33.20 - */
   33.21 -package org.apidesign.bck2brwsr.ide.editor;
   33.22 -
   33.23 -import java.io.IOException;
   33.24 -import java.util.ArrayList;
   33.25 -import java.util.List;
   33.26 -import org.testng.Assert;
   33.27 -import org.testng.annotations.Test;
   33.28 -
   33.29 -public class JsniCommentTokenizerTest {
   33.30 -
   33.31 -    private static class MockSink implements JsniCommentTokenizer.Sink {
   33.32 -        final List<String> out = new ArrayList<String>();
   33.33 -
   33.34 -        public void javascript(String s) {
   33.35 -            out.add("J " + s);
   33.36 -        }
   33.37 -
   33.38 -        public void method(String clazz, String method, String signature) {
   33.39 -            out.add("M " + clazz + "|" + method + "|" + signature);
   33.40 -        }
   33.41 -
   33.42 -        public void field(String clazz, String field) {
   33.43 -            out.add("F " + clazz + "|" + field);
   33.44 -        }
   33.45 -    }
   33.46 -
   33.47 -
   33.48 -    @Test
   33.49 -    public void testProcess_nop() throws IOException {
   33.50 -        final String in = "foo bar";
   33.51 -        final List<String> expected = new ArrayList<String>();
   33.52 -        expected.add("J foo bar");
   33.53 -
   33.54 -        final JsniCommentTokenizer jsniCommentTokenizer = new JsniCommentTokenizer();
   33.55 -        final MockSink out = new MockSink();
   33.56 -        jsniCommentTokenizer.process(in, out);
   33.57 -
   33.58 -        Assert.assertEquals(expected, out.out);
   33.59 -    }
   33.60 -
   33.61 -    @Test
   33.62 -    public void testProcess_read_static_field() throws IOException {
   33.63 -        final String in = " @com.google.gwt.examples.JSNIExample::myStaticField = val + \" and stuff\";";
   33.64 -        final List<String> expected = new ArrayList<String>();
   33.65 -        expected.add("J  ");
   33.66 -        expected.add("F com.google.gwt.examples.JSNIExample|myStaticField");
   33.67 -        expected.add("J  = val + \" and stuff\";");
   33.68 -
   33.69 -        final JsniCommentTokenizer jsniCommentTokenizer = new JsniCommentTokenizer();
   33.70 -        final MockSink out = new MockSink();
   33.71 -        jsniCommentTokenizer.process(in, out);
   33.72 -
   33.73 -        Assert.assertEquals(expected, out.out);
   33.74 -    }
   33.75 -
   33.76 -    @Test
   33.77 -    public void testProcess_write_instance_field() throws IOException {
   33.78 -        final String in = " x.@com.google.gwt.examples.JSNIExample::myInstanceField = val + \" and stuff\";";
   33.79 -        final List<String> expected = new ArrayList<String>();
   33.80 -        expected.add("J  x.");
   33.81 -        expected.add("F com.google.gwt.examples.JSNIExample|myInstanceField");
   33.82 -        expected.add("J  = val + \" and stuff\";");
   33.83 -
   33.84 -        final JsniCommentTokenizer jsniCommentTokenizer = new JsniCommentTokenizer();
   33.85 -        final MockSink out = new MockSink();
   33.86 -        jsniCommentTokenizer.process(in, out);
   33.87 -
   33.88 -        Assert.assertEquals(expected, out.out);
   33.89 -    }
   33.90 -
   33.91 -    @Test
   33.92 -    public void testProcess_read_instance_field() throws IOException {
   33.93 -        final String in = " var val = this.@com.google.gwt.examples.JSNIExample::myInstanceField;";
   33.94 -        final List<String> expected = new ArrayList<String>();
   33.95 -        expected.add("J  var val = this.");
   33.96 -        expected.add("F com.google.gwt.examples.JSNIExample|myInstanceField");
   33.97 -        expected.add("J ;");
   33.98 -
   33.99 -        final JsniCommentTokenizer jsniCommentTokenizer = new JsniCommentTokenizer();
  33.100 -        final MockSink out = new MockSink();
  33.101 -        jsniCommentTokenizer.process(in, out);
  33.102 -
  33.103 -        Assert.assertEquals(expected, out.out);
  33.104 -    }
  33.105 -
  33.106 -
  33.107 -    @Test
  33.108 -    public void testProcess_static_method() throws IOException {
  33.109 -        final String in = " @com.google.gwt.examples.JSNIExample::staticFoo(Ljava/lang/String;)(s);";
  33.110 -        final List<String> expected = new ArrayList<String>();
  33.111 -        expected.add("J  ");
  33.112 -        expected.add("M com.google.gwt.examples.JSNIExample|staticFoo|Ljava/lang/String;");
  33.113 -        expected.add("J (s);");
  33.114 -
  33.115 -        final JsniCommentTokenizer jsniCommentTokenizer = new JsniCommentTokenizer();
  33.116 -        final MockSink out = new MockSink();
  33.117 -        jsniCommentTokenizer.process(in, out);
  33.118 -
  33.119 -        Assert.assertEquals(expected, out.out);
  33.120 -    }
  33.121 -
  33.122 -
  33.123 -    @Test
  33.124 -    public void testProcess_instance_method() throws IOException {
  33.125 -        final String in = " x.@com.google.gwt.examples.JSNIExample::instanceFoo(Ljava/lang/String;)(s);";
  33.126 -        final List<String> expected = new ArrayList<String>();
  33.127 -        expected.add("J  x.");
  33.128 -        expected.add("M com.google.gwt.examples.JSNIExample|instanceFoo|Ljava/lang/String;");
  33.129 -        expected.add("J (s);");
  33.130 -
  33.131 -        final JsniCommentTokenizer jsniCommentTokenizer = new JsniCommentTokenizer();
  33.132 -        final MockSink out = new MockSink();
  33.133 -        jsniCommentTokenizer.process(in, out);
  33.134 -
  33.135 -        Assert.assertEquals(expected, out.out);
  33.136 -    }
  33.137 -
  33.138 -
  33.139 -    @Test
  33.140 -    public void testProcess_multiline() throws IOException {
  33.141 -        final String in =
  33.142 -            " x.@com.google.gwt.examples.JSNIExample::instanceFoo(Ljava/lang/String;)(s);" +
  33.143 -            " @com.google.gwt.examples.JSNIExample::myStaticField = val + \" and stuff\";";
  33.144 -        final List<String> expected = new ArrayList<String>();
  33.145 -        expected.add("J  x.");
  33.146 -        expected.add("M com.google.gwt.examples.JSNIExample|instanceFoo|Ljava/lang/String;");
  33.147 -        expected.add("J (s); ");
  33.148 -        expected.add("F com.google.gwt.examples.JSNIExample|myStaticField");
  33.149 -        expected.add("J  = val + \" and stuff\";");
  33.150 -
  33.151 -        final JsniCommentTokenizer jsniCommentTokenizer = new JsniCommentTokenizer();
  33.152 -        final MockSink out = new MockSink();
  33.153 -        jsniCommentTokenizer.process(in, out);
  33.154 -
  33.155 -        Assert.assertEquals(expected, out.out);
  33.156 -    }
  33.157 -}
    34.1 --- a/ide/editor/src/test/java/org/apidesign/bck2brwsr/ide/editor/ManglingSinkTest.java	Tue Feb 11 10:48:24 2014 +0100
    34.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    34.3 @@ -1,58 +0,0 @@
    34.4 -/**
    34.5 - * Back 2 Browser Bytecode Translator
    34.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
    34.7 - *
    34.8 - * This program is free software: you can redistribute it and/or modify
    34.9 - * it under the terms of the GNU General Public License as published by
   34.10 - * the Free Software Foundation, version 2 of the License.
   34.11 - *
   34.12 - * This program is distributed in the hope that it will be useful,
   34.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
   34.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   34.15 - * GNU General Public License for more details.
   34.16 - *
   34.17 - * You should have received a copy of the GNU General Public License
   34.18 - * along with this program. Look for COPYING file in the top folder.
   34.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
   34.20 - */
   34.21 -package org.apidesign.bck2brwsr.ide.editor;
   34.22 -
   34.23 -import org.testng.Assert;
   34.24 -import org.testng.annotations.Test;
   34.25 -
   34.26 -
   34.27 -public class ManglingSinkTest {
   34.28 -
   34.29 -    @Test
   34.30 -    public void testMangle_1() {
   34.31 -        Assert.assertEquals(
   34.32 -                "binarySearch__I_3BIIB",
   34.33 -                ManglingSink.mangle("java.util.Arrays", "binarySearch", "[BIIB")
   34.34 -        );
   34.35 -    }
   34.36 -
   34.37 -    @Test
   34.38 -    public void testMangle_2() {
   34.39 -        Assert.assertEquals(
   34.40 -                "sort__V_3I",
   34.41 -                ManglingSink.mangle("java.util.Arrays", "sort", "[I")
   34.42 -        );
   34.43 -    }
   34.44 -
   34.45 -    @Test
   34.46 -    public void testMangle_3() {
   34.47 -        Assert.assertEquals(
   34.48 -                "binarySearch__I_3Ljava_lang_Object_2IILjava_lang_Object_2",
   34.49 -                ManglingSink.mangle("java.util.Arrays", "binarySearch", "[Ljava/lang/Object;IILjava/lang/Object;")
   34.50 -        );
   34.51 -    }
   34.52 -
   34.53 -
   34.54 -    @Test
   34.55 -    public void testField() {
   34.56 -        final ManglingSink manglingSink = new ManglingSink();
   34.57 -        manglingSink.field(null, "value");
   34.58 -
   34.59 -        Assert.assertEquals("_value()", manglingSink.toString());
   34.60 -    }
   34.61 -}
    35.1 --- a/ide/pom.xml	Tue Feb 11 10:48:24 2014 +0100
    35.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    35.3 @@ -1,29 +0,0 @@
    35.4 -<?xml version="1.0" encoding="UTF-8"?>
    35.5 -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    35.6 -  <modelVersion>4.0.0</modelVersion>
    35.7 -  <parent>
    35.8 -    <artifactId>bck2brwsr</artifactId>
    35.9 -    <groupId>org.apidesign</groupId>
   35.10 -    <version>0.9-SNAPSHOT</version>
   35.11 -  </parent>
   35.12 -  <groupId>org.apidesign.bck2brwsr</groupId>
   35.13 -  <artifactId>ide</artifactId>
   35.14 -  <version>0.9-SNAPSHOT</version>
   35.15 -  <packaging>pom</packaging>
   35.16 -  <name>IDE Support</name>
   35.17 -  <modules>
   35.18 -    <module>editor</module>
   35.19 -  </modules>
   35.20 -  <build>
   35.21 -      <plugins>
   35.22 -          <plugin>
   35.23 -              <groupId>org.apache.maven.plugins</groupId>
   35.24 -              <artifactId>maven-deploy-plugin</artifactId>
   35.25 -              <version>2.7</version>
   35.26 -              <configuration>
   35.27 -                  <skip>true</skip>
   35.28 -              </configuration>
   35.29 -          </plugin>      
   35.30 -      </plugins>
   35.31 -  </build>
   35.32 -</project>
    36.1 --- a/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/PageProcessor.java	Tue Feb 11 10:48:24 2014 +0100
    36.2 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/PageProcessor.java	Tue Feb 11 13:31:42 2014 +0100
    36.3 @@ -1226,6 +1226,12 @@
    36.4              isModel[0] = true;
    36.5          } else {
    36.6              ret = tm.toString();
    36.7 +            int idx = ret.indexOf("<any?>.");
    36.8 +            if (idx >= 0) {
    36.9 +                ret = ret.substring(idx + 7);
   36.10 +                isEnum[0] = false;
   36.11 +                return ret;
   36.12 +            }
   36.13          }
   36.14          TypeMirror enm = processingEnv.getElementUtils().getTypeElement("java.lang.Enum").asType();
   36.15          enm = processingEnv.getTypeUtils().erasure(enm);
    37.1 --- a/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/JSONTest.java	Tue Feb 11 10:48:24 2014 +0100
    37.2 +++ b/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/JSONTest.java	Tue Feb 11 13:31:42 2014 +0100
    37.3 @@ -281,31 +281,31 @@
    37.4          assert Sex.FEMALE.equals(p.getSex()) : "Expecting FEMALE: " + p.getSex();
    37.5      }
    37.6      
    37.7 -    @Http(@Http.Resource(
    37.8 -        content = "{'info':[{'firstName': 'Gitar', 'sex': 'FEMALE'}]}", 
    37.9 -        path="/people.json", 
   37.10 -        mimeType = "application/json"
   37.11 -    ))
   37.12 -    @BrwsrTest public void loadAndParseArrayInPeople() throws InterruptedException {
   37.13 -        if (js == null) {
   37.14 -            js = new JSONik();
   37.15 -            js.applyBindings();
   37.16 -        
   37.17 -            js.fetchPeople("people.json");
   37.18 -        }
   37.19 -        
   37.20 -        if (0 == js.getFetchedCount()) {
   37.21 -            throw new InterruptedException();
   37.22 -        }
   37.23 -
   37.24 -        assert js.getFetchedCount() == 1 : "One person loaded: " + js.getFetchedCount();
   37.25 -        
   37.26 -        Person p = js.getFetched();
   37.27 -        
   37.28 -        assert p != null : "We should get our person back: " + p;
   37.29 -        assert "Gitar".equals(p.getFirstName()) : "Expecting Gitar: " + p.getFirstName();
   37.30 -        assert Sex.FEMALE.equals(p.getSex()) : "Expecting FEMALE: " + p.getSex();
   37.31 -    }
   37.32 +//    @Http(@Http.Resource(
   37.33 +//        content = "{'info':[{'firstName': 'Gitar', 'sex': 'FEMALE'}]}", 
   37.34 +//        path="/people.json", 
   37.35 +//        mimeType = "application/json"
   37.36 +//    ))
   37.37 +//    @BrwsrTest public void loadAndParseArrayInPeople() throws InterruptedException {
   37.38 +//        if (js == null) {
   37.39 +//            js = new JSONik();
   37.40 +//            js.applyBindings();
   37.41 +//        
   37.42 +//            js.fetchPeople("people.json");
   37.43 +//        }
   37.44 +//        
   37.45 +//        if (0 == js.getFetchedCount()) {
   37.46 +//            throw new InterruptedException();
   37.47 +//        }
   37.48 +//
   37.49 +//        assert js.getFetchedCount() == 1 : "One person loaded: " + js.getFetchedCount();
   37.50 +//        
   37.51 +//        Person p = js.getFetched();
   37.52 +//        
   37.53 +//        assert p != null : "We should get our person back: " + p;
   37.54 +//        assert "Gitar".equals(p.getFirstName()) : "Expecting Gitar: " + p.getFirstName();
   37.55 +//        assert Sex.FEMALE.equals(p.getSex()) : "Expecting FEMALE: " + p.getSex();
   37.56 +//    }
   37.57      
   37.58      @Http(@Http.Resource(
   37.59          content = "{'age':[1, 2, 3]}", 
    38.1 --- a/javaquery/demo-twitter/bck2brwsr-assembly.xml	Tue Feb 11 10:48:24 2014 +0100
    38.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    38.3 @@ -1,62 +0,0 @@
    38.4 -<?xml version="1.0"?>
    38.5 -<!--
    38.6 -
    38.7 -    Back 2 Browser Bytecode Translator
    38.8 -    Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
    38.9 -
   38.10 -    This program is free software: you can redistribute it and/or modify
   38.11 -    it under the terms of the GNU General Public License as published by
   38.12 -    the Free Software Foundation, version 2 of the License.
   38.13 -
   38.14 -    This program is distributed in the hope that it will be useful,
   38.15 -    but WITHOUT ANY WARRANTY; without even the implied warranty of
   38.16 -    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   38.17 -    GNU General Public License for more details.
   38.18 -
   38.19 -    You should have received a copy of the GNU General Public License
   38.20 -    along with this program. Look for COPYING file in the top folder.
   38.21 -    If not, see http://opensource.org/licenses/GPL-2.0.
   38.22 -
   38.23 --->
   38.24 -<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   38.25 -  xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
   38.26 -  
   38.27 -  <id>bck2brwsr</id>
   38.28 -  <formats>
   38.29 -      <format>zip</format>
   38.30 -  </formats>
   38.31 -  <baseDirectory>public_html</baseDirectory>
   38.32 -  <dependencySets>
   38.33 -    <dependencySet>
   38.34 -        <useProjectArtifact>false</useProjectArtifact>
   38.35 -        <scope>runtime</scope>
   38.36 -        <outputDirectory>lib</outputDirectory>
   38.37 -        <includes>
   38.38 -            <include>*:jar</include>
   38.39 -            <include>*:rt</include>
   38.40 -        </includes>
   38.41 -    </dependencySet>
   38.42 -  </dependencySets> 
   38.43 -  <fileSets>
   38.44 -      <fileSet>
   38.45 -          <directory>${project.build.directory}/classes/org/apidesign/bck2brwsr/demo/twitter/</directory>
   38.46 -          <includes>
   38.47 -              <include>**/*</include>
   38.48 -          </includes>
   38.49 -          <excludes>
   38.50 -              <exclude>**/*.class</exclude>
   38.51 -          </excludes>
   38.52 -          <outputDirectory>/</outputDirectory>
   38.53 -      </fileSet>
   38.54 -  </fileSets>
   38.55 -  <files>
   38.56 -    <file>
   38.57 -      <source>${project.build.directory}/${project.build.finalName}.jar</source>
   38.58 -      <outputDirectory>/</outputDirectory>
   38.59 -    </file>
   38.60 -    <file>
   38.61 -      <source>${project.build.directory}/bck2brwsr.js</source>
   38.62 -      <outputDirectory>/</outputDirectory>
   38.63 -    </file>
   38.64 -  </files>
   38.65 -</assembly>
   38.66 \ No newline at end of file
    39.1 --- a/javaquery/demo-twitter/nb-configuration.xml	Tue Feb 11 10:48:24 2014 +0100
    39.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    39.3 @@ -1,37 +0,0 @@
    39.4 -<?xml version="1.0" encoding="UTF-8"?>
    39.5 -<!--
    39.6 -
    39.7 -    Back 2 Browser Bytecode Translator
    39.8 -    Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
    39.9 -
   39.10 -    This program is free software: you can redistribute it and/or modify
   39.11 -    it under the terms of the GNU General Public License as published by
   39.12 -    the Free Software Foundation, version 2 of the License.
   39.13 -
   39.14 -    This program is distributed in the hope that it will be useful,
   39.15 -    but WITHOUT ANY WARRANTY; without even the implied warranty of
   39.16 -    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   39.17 -    GNU General Public License for more details.
   39.18 -
   39.19 -    You should have received a copy of the GNU General Public License
   39.20 -    along with this program. Look for COPYING file in the top folder.
   39.21 -    If not, see http://opensource.org/licenses/GPL-2.0.
   39.22 -
   39.23 --->
   39.24 -<project-shared-configuration>
   39.25 -    <!--
   39.26 -This file contains additional configuration written by modules in the NetBeans IDE.
   39.27 -The configuration is intended to be shared among all the users of project and
   39.28 -therefore it is assumed to be part of version control checkout.
   39.29 -Without this configuration present, some functionality in the IDE may be limited or fail altogether.
   39.30 --->
   39.31 -    <properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1">
   39.32 -        <!--
   39.33 -Properties that influence various parts of the IDE, especially code formatting and the like. 
   39.34 -You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up.
   39.35 -That way multiple projects can share the same settings (useful for formatting rules for example).
   39.36 -Any value defined here will override the pom.xml file value but is only applicable to the current project.
   39.37 --->
   39.38 -        <netbeans.compile.on.save>none</netbeans.compile.on.save>
   39.39 -    </properties>
   39.40 -</project-shared-configuration>
    40.1 --- a/javaquery/demo-twitter/nbactions.xml	Tue Feb 11 10:48:24 2014 +0100
    40.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    40.3 @@ -1,29 +0,0 @@
    40.4 -<?xml version="1.0" encoding="UTF-8"?>
    40.5 -<!--
    40.6 -
    40.7 -    Back 2 Browser Bytecode Translator
    40.8 -    Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
    40.9 -
   40.10 -    This program is free software: you can redistribute it and/or modify
   40.11 -    it under the terms of the GNU General Public License as published by
   40.12 -    the Free Software Foundation, version 2 of the License.
   40.13 -
   40.14 -    This program is distributed in the hope that it will be useful,
   40.15 -    but WITHOUT ANY WARRANTY; without even the implied warranty of
   40.16 -    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   40.17 -    GNU General Public License for more details.
   40.18 -
   40.19 -    You should have received a copy of the GNU General Public License
   40.20 -    along with this program. Look for COPYING file in the top folder.
   40.21 -    If not, see http://opensource.org/licenses/GPL-2.0.
   40.22 -
   40.23 --->
   40.24 -<actions>
   40.25 -    <action>
   40.26 -        <actionName>run</actionName>
   40.27 -        <goals>
   40.28 -            <goal>process-classes</goal>
   40.29 -            <goal>bck2brwsr:brwsr</goal>
   40.30 -        </goals>
   40.31 -    </action>
   40.32 -</actions>
    41.1 --- a/javaquery/demo-twitter/pom.xml	Tue Feb 11 10:48:24 2014 +0100
    41.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    41.3 @@ -1,151 +0,0 @@
    41.4 -<?xml version="1.0" encoding="UTF-8"?>
    41.5 -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    41.6 -  <modelVersion>4.0.0</modelVersion>
    41.7 -  <parent>
    41.8 -    <artifactId>javaquery</artifactId>
    41.9 -    <groupId>org.apidesign.bck2brwsr</groupId>
   41.10 -    <version>0.9-SNAPSHOT</version>
   41.11 -  </parent>
   41.12 -
   41.13 -  <groupId>org.apidesign.bck2brwsr</groupId>
   41.14 -  <artifactId>demo-twitter</artifactId>
   41.15 -  <version>0.9-SNAPSHOT</version>
   41.16 -  <packaging>jar</packaging>
   41.17 -
   41.18 -  <name>Bck2Brwsr's Twttr</name>
   41.19 -  <description>
   41.20 -      Rewrite of knockoutjs example to use model written in Java and
   41.21 -      execute using Bck2Brwsr virtual machine.
   41.22 -  </description>
   41.23 -
   41.24 -  <repositories>
   41.25 -      <repository>
   41.26 -          <id>java.net</id>
   41.27 -          <name>Java.net</name>
   41.28 -          <url>https://maven.java.net/content/repositories/releases/</url>
   41.29 -          <snapshots>
   41.30 -          </snapshots>
   41.31 -      </repository>
   41.32 -      <repository>
   41.33 -          <id>netbeans</id>
   41.34 -          <name>NetBeans</name>
   41.35 -          <url>http://bits.netbeans.org/maven2/</url>
   41.36 -      </repository>
   41.37 -  </repositories>
   41.38 -  <pluginRepositories>
   41.39 -      <pluginRepository>
   41.40 -          <id>java.net</id>
   41.41 -          <name>Java.net</name>
   41.42 -          <url>https://maven.java.net/content/repositories/releases/</url>
   41.43 -          <snapshots>
   41.44 -          </snapshots>
   41.45 -      </pluginRepository>
   41.46 -  </pluginRepositories>
   41.47 -
   41.48 -  <properties>
   41.49 -    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
   41.50 -    <bck2brwsr.obfuscationlevel>MINIMAL</bck2brwsr.obfuscationlevel>
   41.51 -  </properties>
   41.52 -  <build>
   41.53 -      <plugins>
   41.54 -            <plugin>
   41.55 -                <groupId>org.apidesign.bck2brwsr</groupId>
   41.56 -                <artifactId>bck2brwsr-maven-plugin</artifactId>
   41.57 -                <version>${project.version}</version>
   41.58 -                <executions>
   41.59 -                    <execution>
   41.60 -                        <goals>
   41.61 -                            <goal>brwsr</goal>
   41.62 -                            <goal>j2js</goal>
   41.63 -                        </goals>
   41.64 -                    </execution>
   41.65 -                </executions>
   41.66 -                <configuration>
   41.67 -                    <startpage>org/apidesign/bck2brwsr/demo/twitter/index.html</startpage>
   41.68 -                    <javascript>${project.build.directory}/bck2brwsr.js</javascript>
   41.69 -                    <obfuscation>${bck2brwsr.obfuscationlevel}</obfuscation>
   41.70 -                </configuration>
   41.71 -            </plugin>
   41.72 -         <plugin>
   41.73 -            <groupId>org.apache.maven.plugins</groupId>
   41.74 -            <artifactId>maven-compiler-plugin</artifactId>
   41.75 -            <version>2.3.2</version>
   41.76 -            <configuration>
   41.77 -               <source>1.7</source>
   41.78 -               <target>1.7</target>
   41.79 -            </configuration>
   41.80 -         </plugin>
   41.81 -         <plugin>
   41.82 -             <groupId>org.apache.maven.plugins</groupId>
   41.83 -             <artifactId>maven-jar-plugin</artifactId>
   41.84 -             <version>2.4</version>
   41.85 -             <configuration>
   41.86 -                 <archive>
   41.87 -                     <manifest>
   41.88 -                         <addClasspath>true</addClasspath>
   41.89 -                         <classpathPrefix>lib/</classpathPrefix>
   41.90 -                     </manifest>
   41.91 -                 </archive>
   41.92 -             </configuration>
   41.93 -         </plugin>
   41.94 -         <plugin>
   41.95 -           <groupId>org.apache.maven.plugins</groupId>
   41.96 -           <artifactId>maven-deploy-plugin</artifactId>
   41.97 -           <version>2.7</version>
   41.98 -           <configuration>
   41.99 -             <skip>true</skip>
  41.100 -           </configuration>
  41.101 -         </plugin>      
  41.102 -         <plugin>
  41.103 -             <artifactId>maven-assembly-plugin</artifactId>
  41.104 -             <version>2.4</version>
  41.105 -             <executions>
  41.106 -                 <execution>
  41.107 -                     <id>distro-assembly</id>
  41.108 -                     <phase>package</phase>
  41.109 -                     <goals>
  41.110 -                         <goal>single</goal>
  41.111 -                     </goals>
  41.112 -                     <configuration>
  41.113 -                         <descriptors>
  41.114 -                             <descriptor>bck2brwsr-assembly.xml</descriptor>
  41.115 -                         </descriptors>
  41.116 -                     </configuration>
  41.117 -                 </execution>
  41.118 -             </executions>                
  41.119 -         </plugin>      
  41.120 -      </plugins>
  41.121 -  </build>
  41.122 -
  41.123 -  <dependencies>
  41.124 -    <dependency>
  41.125 -      <groupId>org.apidesign.bck2brwsr</groupId>
  41.126 -      <artifactId>emul</artifactId>
  41.127 -      <version>${project.version}</version>
  41.128 -      <classifier>rt</classifier>
  41.129 -    </dependency>
  41.130 -    <dependency>
  41.131 -      <groupId>org.apidesign.bck2brwsr</groupId>
  41.132 -      <artifactId>javaquery.api</artifactId>
  41.133 -      <version>${project.version}</version>
  41.134 -    </dependency>
  41.135 -    <dependency>
  41.136 -      <groupId>org.testng</groupId>
  41.137 -      <artifactId>testng</artifactId>
  41.138 -      <version>6.5.2</version>
  41.139 -      <scope>test</scope>
  41.140 -    </dependency>
  41.141 -    <dependency>
  41.142 -      <groupId>org.apidesign.bck2brwsr</groupId>
  41.143 -      <artifactId>vmtest</artifactId>
  41.144 -      <version>${project.version}</version>
  41.145 -      <scope>test</scope>
  41.146 -    </dependency>
  41.147 -    <dependency>
  41.148 -      <groupId>org.apidesign.bck2brwsr</groupId>
  41.149 -      <artifactId>launcher.http</artifactId>
  41.150 -      <version>${project.version}</version>
  41.151 -      <scope>runtime</scope>
  41.152 -    </dependency>
  41.153 -  </dependencies>
  41.154 -</project>
    42.1 --- a/javaquery/demo-twitter/src/main/java/org/apidesign/bck2brwsr/demo/twitter/TwitterClient.java	Tue Feb 11 10:48:24 2014 +0100
    42.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    42.3 @@ -1,194 +0,0 @@
    42.4 -/**
    42.5 - * Back 2 Browser Bytecode Translator
    42.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
    42.7 - *
    42.8 - * This program is free software: you can redistribute it and/or modify
    42.9 - * it under the terms of the GNU General Public License as published by
   42.10 - * the Free Software Foundation, version 2 of the License.
   42.11 - *
   42.12 - * This program is distributed in the hope that it will be useful,
   42.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
   42.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   42.15 - * GNU General Public License for more details.
   42.16 - *
   42.17 - * You should have received a copy of the GNU General Public License
   42.18 - * along with this program. Look for COPYING file in the top folder.
   42.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
   42.20 - */
   42.21 -package org.apidesign.bck2brwsr.demo.twitter;
   42.22 -
   42.23 -import java.util.Arrays;
   42.24 -import java.util.List;
   42.25 -import org.apidesign.bck2brwsr.htmlpage.api.*;
   42.26 -import org.apidesign.bck2brwsr.htmlpage.api.Page;
   42.27 -import org.apidesign.bck2brwsr.htmlpage.api.Property;
   42.28 -import org.apidesign.bck2brwsr.htmlpage.api.ComputedProperty;
   42.29 -
   42.30 -/** Controller class for access to Twitter.
   42.31 - * 
   42.32 - * @author Jaroslav Tulach
   42.33 - */
   42.34 -@Page(xhtml="index.html", className="TwitterModel", properties={
   42.35 -    @Property(name="savedLists", type=Tweeters.class, array = true),
   42.36 -    @Property(name="activeTweetersName", type=String.class),
   42.37 -    @Property(name="activeTweeters", type=String.class, array = true),
   42.38 -    @Property(name="userNameToAdd", type=String.class),
   42.39 -    @Property(name="currentTweets", type=Tweet.class, array = true)
   42.40 -})
   42.41 -public class TwitterClient {
   42.42 -    @Model(className = "Tweeters", properties = {
   42.43 -        @Property(name="name", type = String.class),
   42.44 -        @Property(name="userNames", type = String.class, array = true)
   42.45 -    })
   42.46 -    static class Twttrs {
   42.47 -    }
   42.48 -    @Model(className = "Tweet", properties = {
   42.49 -        @Property(name = "from_user", type = String.class),
   42.50 -        @Property(name = "from_user_id", type = int.class),
   42.51 -        @Property(name = "profile_image_url", type = String.class),
   42.52 -        @Property(name = "text", type = String.class),
   42.53 -        @Property(name = "created_at", type = String.class),
   42.54 -    })
   42.55 -    static final class Twt {
   42.56 -        @ComputedProperty static String html(String text) {
   42.57 -            StringBuilder sb = new StringBuilder(320);
   42.58 -            for (int pos = 0;;) {
   42.59 -                int http = text.indexOf("http", pos);
   42.60 -                if (http == -1) {
   42.61 -                    sb.append(text.substring(pos));
   42.62 -                    return sb.toString();
   42.63 -                }
   42.64 -                int spc = text.indexOf(' ', http);
   42.65 -                if (spc == -1) {
   42.66 -                    spc = text.length();
   42.67 -                }
   42.68 -                sb.append(text.substring(pos, http));
   42.69 -                String url = text.substring(http, spc);
   42.70 -                sb.append("<a href='").append(url).append("'>").append(url).append("</a>");
   42.71 -                pos = spc;
   42.72 -            }
   42.73 -        }
   42.74 -        
   42.75 -        @ComputedProperty static String userUrl(String from_user) {
   42.76 -            return "http://twitter.com/" + from_user;
   42.77 -        }
   42.78 -    }
   42.79 -    @Model(className = "TwitterQuery", properties = {
   42.80 -        @Property(array = true, name = "results", type = Twt.class)
   42.81 -    })
   42.82 -    public static final class TwttrQr {
   42.83 -    }
   42.84 -    
   42.85 -    @OnReceive(url="{root}/search.json?{query}&callback={me}", jsonp="me")
   42.86 -    static void queryTweets(TwitterModel page, TwitterQuery q) {
   42.87 -        page.getCurrentTweets().clear();
   42.88 -        page.getCurrentTweets().addAll(q.getResults());
   42.89 -    }
   42.90 -    
   42.91 -    @OnPropertyChange("activeTweetersName")
   42.92 -    static void changeTweetersList(TwitterModel model) {
   42.93 -        Tweeters people = findByName(model.getSavedLists(), model.getActiveTweetersName());        
   42.94 -        model.getActiveTweeters().clear();
   42.95 -        model.getActiveTweeters().addAll(people.getUserNames());
   42.96 -    }
   42.97 -    
   42.98 -    @OnPropertyChange({ "activeTweeters", "activeTweetersCount" })
   42.99 -    static void refreshTweets(TwitterModel model) {
  42.100 -        StringBuilder sb = new StringBuilder();
  42.101 -        sb.append("rpp=25&q=");
  42.102 -        String sep = "";
  42.103 -        for (String p : model.getActiveTweeters()) {
  42.104 -            sb.append(sep);
  42.105 -            sb.append("from:");
  42.106 -            sb.append(p);
  42.107 -            sep = " OR ";
  42.108 -        }
  42.109 -        model.queryTweets("http://search.twitter.com", sb.toString());
  42.110 -    }
  42.111 -    
  42.112 -    static {
  42.113 -        final TwitterModel model = new TwitterModel();
  42.114 -        final List<Tweeters> svdLst = model.getSavedLists();
  42.115 -        svdLst.add(newTweeters("API Design", "JaroslavTulach"));
  42.116 -        svdLst.add(newTweeters("Celebrities", "JohnCleese", "MCHammer", "StephenFry", "algore", "StevenSanderson"));
  42.117 -        svdLst.add(newTweeters("Microsoft people", "BillGates", "shanselman", "ScottGu"));
  42.118 -        svdLst.add(newTweeters("NetBeans", "GeertjanW","monacotoni", "NetBeans", "petrjiricka"));
  42.119 -        svdLst.add(newTweeters("Tech pundits", "Scobleizer", "LeoLaporte", "techcrunch", "BoingBoing", "timoreilly", "codinghorror"));
  42.120 -
  42.121 -        model.setActiveTweetersName("NetBeans");
  42.122 -
  42.123 -        model.applyBindings();
  42.124 -    }
  42.125 -    
  42.126 -    @ComputedProperty
  42.127 -    static boolean hasUnsavedChanges(List<String> activeTweeters, List<Tweeters> savedLists, String activeTweetersName) {
  42.128 -        Tweeters tw = findByName(savedLists, activeTweetersName);
  42.129 -        if (activeTweeters == null) {
  42.130 -            return false;
  42.131 -        }
  42.132 -        return !tw.getUserNames().equals(activeTweeters);
  42.133 -    }
  42.134 -    
  42.135 -    @ComputedProperty
  42.136 -    static int activeTweetersCount(List<String> activeTweeters) {
  42.137 -        return activeTweeters.size();
  42.138 -    }
  42.139 -    
  42.140 -    @ComputedProperty
  42.141 -    static boolean userNameToAddIsValid(
  42.142 -        String userNameToAdd, String activeTweetersName, List<Tweeters> savedLists, List<String> activeTweeters
  42.143 -    ) {
  42.144 -        return userNameToAdd != null && 
  42.145 -            userNameToAdd.matches("[a-zA-Z0-9_]{1,15}") &&
  42.146 -            !activeTweeters.contains(userNameToAdd);
  42.147 -    }
  42.148 -    
  42.149 -    @OnFunction
  42.150 -    static void deleteList(TwitterModel model) {
  42.151 -        final List<Tweeters> sl = model.getSavedLists();
  42.152 -        sl.remove(findByName(sl, model.getActiveTweetersName()));
  42.153 -        if (sl.isEmpty()) {
  42.154 -            final Tweeters t = new Tweeters();
  42.155 -            t.setName("New");
  42.156 -            sl.add(t);
  42.157 -        }
  42.158 -        model.setActiveTweetersName(sl.get(0).getName());
  42.159 -    }
  42.160 -    
  42.161 -    @OnFunction
  42.162 -    static void saveChanges(TwitterModel model) {
  42.163 -        Tweeters t = findByName(model.getSavedLists(), model.getActiveTweetersName());
  42.164 -        int indx = model.getSavedLists().indexOf(t);
  42.165 -        if (indx != -1) {
  42.166 -            t.setName(model.getActiveTweetersName());
  42.167 -            t.getUserNames().clear();
  42.168 -            t.getUserNames().addAll(model.getActiveTweeters());
  42.169 -        }
  42.170 -    }
  42.171 -    
  42.172 -    @OnFunction
  42.173 -    static void addUser(TwitterModel model) {
  42.174 -        String n = model.getUserNameToAdd();
  42.175 -        model.getActiveTweeters().add(n);
  42.176 -    }
  42.177 -    @OnFunction
  42.178 -    static void removeUser(String data, TwitterModel model) {
  42.179 -        model.getActiveTweeters().remove(data);
  42.180 -    }
  42.181 -    
  42.182 -    private static Tweeters findByName(List<Tweeters> list, String name) {
  42.183 -        for (Tweeters l : list) {
  42.184 -            if (l.getName() != null && l.getName().equals(name)) {
  42.185 -                return l;
  42.186 -            }
  42.187 -        }
  42.188 -        return list.isEmpty() ? new Tweeters() : list.get(0);
  42.189 -    }
  42.190 -    
  42.191 -    private static Tweeters newTweeters(String listName, String... userNames) {
  42.192 -        Tweeters t = new Tweeters();
  42.193 -        t.setName(listName);
  42.194 -        t.getUserNames().addAll(Arrays.asList(userNames));
  42.195 -        return t;
  42.196 -    }
  42.197 -}
    43.1 --- a/javaquery/demo-twitter/src/main/resources/org/apidesign/bck2brwsr/demo/twitter/index.html	Tue Feb 11 10:48:24 2014 +0100
    43.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    43.3 @@ -1,99 +0,0 @@
    43.4 -<?xml version="1.0" encoding="UTF-8"?>
    43.5 -<!--
    43.6 -
    43.7 -    Back 2 Browser Bytecode Translator
    43.8 -    Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
    43.9 -
   43.10 -    This program is free software: you can redistribute it and/or modify
   43.11 -    it under the terms of the GNU General Public License as published by
   43.12 -    the Free Software Foundation, version 2 of the License.
   43.13 -
   43.14 -    This program is distributed in the hope that it will be useful,
   43.15 -    but WITHOUT ANY WARRANTY; without even the implied warranty of
   43.16 -    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   43.17 -    GNU General Public License for more details.
   43.18 -
   43.19 -    You should have received a copy of the GNU General Public License
   43.20 -    along with this program. Look for COPYING file in the top folder.
   43.21 -    If not, see http://opensource.org/licenses/GPL-2.0.
   43.22 -
   43.23 --->
   43.24 -
   43.25 -<!--
   43.26 -    Copied from knockout.js Twitter example:
   43.27 -    http://knockoutjs.com/examples/twitter.html
   43.28 --->
   43.29 -
   43.30 -<!DOCTYPE html>
   43.31 -<html xmlns="http://www.w3.org/1999/xhtml">
   43.32 -    <head>
   43.33 -        <title>Bck2Brwsr's Twitter</title>
   43.34 -    </head>
   43.35 -    <body>
   43.36 -        <link href='twitterExample.css' rel='Stylesheet' ></link>
   43.37 -        
   43.38 -        <style type='text/css'>
   43.39 -           .liveExample select { height: 1.7em; }
   43.40 -           .liveExample button { height: 2em; }
   43.41 -        </style>
   43.42 -        
   43.43 -        
   43.44 -        <h2>Bck2Brwsr's Twitter</h2>
   43.45 -        
   43.46 -        <p>
   43.47 -        This code based on original <a href="http://knockoutjs.com/examples/twitter.html">knockout.js Twitter example</a> and
   43.48 -        uses almost unmodified HTML code. It just changes the model. It 
   43.49 -        is written in Java language and it is executed using <a href="http://bck2brwsr.apidesign.org">Bck2Brwsr</a>
   43.50 -        virtual machine. The Java source code has about 190 lines and is available 
   43.51 -        <a href="http://source.apidesign.org/hg/bck2brwsr/file/7fc6b7e9c982/javaquery/demo-twitter/src/main/java/org/apidesign/bck2brwsr/demo/twitter/TwitterClient.java">here</a>
   43.52 -        - in fact it may even be more dense than the original JavaScript model.
   43.53 -        </p>
   43.54 -        
   43.55 -        <div class='liveExample'>
   43.56 -            <div class='configuration'>
   43.57 -                <div class='listChooser'>
   43.58 -                    <button data-bind='click: deleteList, enable: activeTweetersName'>Delete</button>
   43.59 -                    <button data-bind='click: saveChanges, enable: hasUnsavedChanges'>Save</button> 
   43.60 -                    <select data-bind='options: savedLists, optionsValue: "name", value: activeTweetersName'> </select>
   43.61 -                </div>
   43.62 -
   43.63 -                <p>Currently viewing <span data-bind='text: activeTweetersCount'> </span> user(s):</p>
   43.64 -                <div class='currentUsers' >
   43.65 -                    <ul data-bind='foreach: activeTweeters'>
   43.66 -                        <li>
   43.67 -                            <button data-bind='click: $root.removeUser'>Remove</button>
   43.68 -                            <div data-bind='text: $data'> </div>
   43.69 -                        </li>
   43.70 -                    </ul>
   43.71 -                </div>
   43.72 -
   43.73 -                <form data-bind='submit: addUser'>
   43.74 -                    <label>Add user:</label>
   43.75 -                    <input data-bind='value: userNameToAdd, valueUpdate: "keyup", css: { invalid: !userNameToAddIsValid() }' />
   43.76 -                    <button data-bind='enable: userNameToAddIsValid' type='submit'>Add</button>
   43.77 -                </form>
   43.78 -            </div>
   43.79 -            <div class='tweets'>
   43.80 -                <div class='loadingIndicator'>Loading...</div>
   43.81 -                <table data-bind='foreach: currentTweets' width='100%'>
   43.82 -                    <tr>
   43.83 -                        <td><img data-bind='attr: { src: profile_image_url }' /></td>
   43.84 -                        <td>
   43.85 -                            <a class='twitterUser' data-bind='attr: { href: userUrl }, text: from_user'> </a>
   43.86 -                            <span data-bind='html: html'> </span>
   43.87 -                            <div class='tweetInfo' data-bind='text: created_at'> </div>
   43.88 -                        </td>
   43.89 -                    </tr>
   43.90 -                </table>
   43.91 -            </div>
   43.92 -        </div>
   43.93 -        
   43.94 -        <script src="bck2brwsr.js"></script>
   43.95 -        <script type="text/javascript">
   43.96 -            var vm = bck2brwsr('demo-twitter-0.8-SNAPSHOT.jar');
   43.97 -            vm.loadClass('org.apidesign.bck2brwsr.demo.twitter.TwitterClient');
   43.98 -        </script>
   43.99 -
  43.100 -
  43.101 -    </body>
  43.102 -</html>
    44.1 --- a/javaquery/demo-twitter/src/main/resources/org/apidesign/bck2brwsr/demo/twitter/twitterExample.css	Tue Feb 11 10:48:24 2014 +0100
    44.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    44.3 @@ -1,50 +0,0 @@
    44.4 -/**
    44.5 - * Back 2 Browser Bytecode Translator
    44.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
    44.7 - *
    44.8 - * This program is free software: you can redistribute it and/or modify
    44.9 - * it under the terms of the GNU General Public License as published by
   44.10 - * the Free Software Foundation, version 2 of the License.
   44.11 - *
   44.12 - * This program is distributed in the hope that it will be useful,
   44.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
   44.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   44.15 - * GNU General Public License for more details.
   44.16 - *
   44.17 - * You should have received a copy of the GNU General Public License
   44.18 - * along with this program. Look for COPYING file in the top folder.
   44.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
   44.20 - */
   44.21 -
   44.22 -/*
   44.23 -    Copied from knockout.js Twitter example:
   44.24 -    http://knockoutjs.com/examples/twitter.html
   44.25 -*/
   44.26 -
   44.27 -.configuration, .tweets, .tweets td { font-family: Verdana; font-size: 13px; }
   44.28 -.configuration { background-color: #DEDEDE; border: 2px solid gray; float:left; height: 40em; width: 40%; padding: 0.5em; border-right-width:0; }
   44.29 -.tweets { width: 55%; border: 2px solid gray; height: 40em; overflow: scroll; overflow-x: hidden; background-color: Black; color: White; padding: 0.5em; position: relative; }
   44.30 -.tweets table { border-width: 0;}
   44.31 -.tweets tr { vertical-align: top; }
   44.32 -.tweets td { padding: 0.4em 0.3em 1em 0.4em; border-width: 0; }
   44.33 -.tweets img { width: 4em; }
   44.34 -.tweetInfo { color: Gray; font-size: 0.9em; }
   44.35 -.twitterUser { color: #77AAFF; text-decoration: none; font-size: 1.1em; font-weight: bold; }
   44.36 -input.invalid { border: 1px solid red !important; background-color: #FFAAAA !important; }
   44.37 -
   44.38 -.listChooser select, .listChooser button { vertical-align:top; }
   44.39 -.listChooser select { width: 60%; font-size:1.2em; height:1.4em; }
   44.40 -.listChooser button { width: 19%; height:1.68em; float:right; }
   44.41 -
   44.42 -.currentUsers { height: 28em; overflow-y: auto; overflow-x: hidden; }
   44.43 -.currentUsers button { float: right; height: 2.5em; margin: 0.1em; padding-left: 1em; padding-right: 1em; }
   44.44 -.currentUsers ul, .configuration li { list-style: none; margin: 0; padding: 0 }
   44.45 -.currentUsers li { height: 2.4em; font-size: 1.2em; background-color: #A7D0E3; border: 1px solid gray; margin-bottom: 0.3em; -webkit-border-radius: 5px; -moz-border-radius: 5px; -webkit-box-shadow: 0 0.2em 0.5em gray; -moz-box-shadow: 0 0.2em 0.5em gray; }
   44.46 -.currentUsers li div { padding: 0.6em; }
   44.47 -.currentUsers li:hover { background-color: #EEC; }
   44.48 -
   44.49 -.configuration form label { width: 25%; display: inline-block; text-align:right; overflow: hidden; }
   44.50 -.configuration form input { width:40%; font-size: 1.3em; border:1px solid silver; background-color: White; padding: 0.1em; }
   44.51 -.configuration form button { width: 20%; margin-left: 0.3em; height: 2em; }
   44.52 -
   44.53 -.loadingIndicator { position: absolute; top: 0.1em; left: 0.1em; font: 0.8em Arial; background-color: #229; color: White; padding: 0.2em 0.5em 0.2em 0.5em; display: none; }
    45.1 --- a/javaquery/demo-twitter/src/test/java/org/apidesign/bck2brwsr/demo/twitter/TwitterClientTest.java	Tue Feb 11 10:48:24 2014 +0100
    45.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    45.3 @@ -1,67 +0,0 @@
    45.4 -/**
    45.5 - * Back 2 Browser Bytecode Translator
    45.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
    45.7 - *
    45.8 - * This program is free software: you can redistribute it and/or modify
    45.9 - * it under the terms of the GNU General Public License as published by
   45.10 - * the Free Software Foundation, version 2 of the License.
   45.11 - *
   45.12 - * This program is distributed in the hope that it will be useful,
   45.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
   45.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   45.15 - * GNU General Public License for more details.
   45.16 - *
   45.17 - * You should have received a copy of the GNU General Public License
   45.18 - * along with this program. Look for COPYING file in the top folder.
   45.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
   45.20 - */
   45.21 -package org.apidesign.bck2brwsr.demo.twitter;
   45.22 -
   45.23 -import java.util.List;
   45.24 -import static org.testng.Assert.*;
   45.25 -import org.testng.annotations.BeforeMethod;
   45.26 -import org.testng.annotations.Test;
   45.27 -
   45.28 -/** We can unit test the TwitterModel smoothly.
   45.29 - *
   45.30 - * @author Jaroslav Tulach <jtulach@netbeans.org>
   45.31 - */
   45.32 -public class TwitterClientTest {
   45.33 -    private TwitterModel model;
   45.34 -    
   45.35 -
   45.36 -    @BeforeMethod
   45.37 -    public void initModel() {
   45.38 -        model = new TwitterModel().applyBindings();
   45.39 -    }
   45.40 -
   45.41 -    @Test public void testIsValidToAdd() {
   45.42 -        model.setUserNameToAdd("Joe");
   45.43 -        Tweeters t = new Tweeters();
   45.44 -        t.setName("test");
   45.45 -        model.getSavedLists().add(t);
   45.46 -        model.setActiveTweetersName("test");
   45.47 -        
   45.48 -        assertTrue(model.isUserNameToAddIsValid(), "Joe is OK");
   45.49 -        TwitterClient.addUser(model);
   45.50 -        assertFalse(model.isUserNameToAddIsValid(), "Can't add Joe for the 2nd time");
   45.51 -        assertEquals(t.getUserNames().size(), 0, "Original tweeters list remains empty");
   45.52 -        
   45.53 -        List<String> mod = model.getActiveTweeters();
   45.54 -        assertTrue(model.isHasUnsavedChanges(), "We have modifications");
   45.55 -        assertEquals(mod.size(), 1, "One element in the list");
   45.56 -        assertEquals(mod.get(0), "Joe", "Its name is Joe");
   45.57 -        
   45.58 -        assertSame(model.getActiveTweeters(), mod, "Editing list is the modified one");
   45.59 -        
   45.60 -        TwitterClient.saveChanges(model);
   45.61 -        assertFalse(model.isHasUnsavedChanges(), "Does not have anything to save");
   45.62 -        
   45.63 -        assertSame(model.getActiveTweeters(), mod, "Still editing the old modified one");
   45.64 -    }
   45.65 -    
   45.66 -    @Test public void httpAtTheEnd() {
   45.67 -        String res = TwitterClient.Twt.html("Ahoj http://kuk");
   45.68 -        assertEquals(res, "Ahoj <a href='http://kuk'>http://kuk</a>");
   45.69 -    }
   45.70 -}
    46.1 --- a/javaquery/demo-twitter/src/test/java/org/apidesign/bck2brwsr/demo/twitter/TwitterProtocolTest.java	Tue Feb 11 10:48:24 2014 +0100
    46.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    46.3 @@ -1,94 +0,0 @@
    46.4 -/**
    46.5 - * Back 2 Browser Bytecode Translator
    46.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
    46.7 - *
    46.8 - * This program is free software: you can redistribute it and/or modify
    46.9 - * it under the terms of the GNU General Public License as published by
   46.10 - * the Free Software Foundation, version 2 of the License.
   46.11 - *
   46.12 - * This program is distributed in the hope that it will be useful,
   46.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
   46.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   46.15 - * GNU General Public License for more details.
   46.16 - *
   46.17 - * You should have received a copy of the GNU General Public License
   46.18 - * along with this program. Look for COPYING file in the top folder.
   46.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
   46.20 - */
   46.21 -package org.apidesign.bck2brwsr.demo.twitter;
   46.22 -
   46.23 -import org.apidesign.bck2brwsr.vmtest.BrwsrTest;
   46.24 -import org.apidesign.bck2brwsr.vmtest.Http;
   46.25 -import org.apidesign.bck2brwsr.vmtest.VMTest;
   46.26 -import org.testng.annotations.Factory;
   46.27 -
   46.28 -/**
   46.29 - *
   46.30 - * @author Jaroslav Tulach <jtulach@netbeans.org>
   46.31 - */
   46.32 -public class TwitterProtocolTest {
   46.33 -    private TwitterModel page;
   46.34 -    @Http(@Http.Resource(
   46.35 -        path = "/search.json",
   46.36 -        mimeType = "application/json",
   46.37 -        parameters = {"callback"},
   46.38 -        content = "$0({\"completed_in\":0.04,\"max_id\":320055706885689344,\"max_id_str\""
   46.39 -        + ":\"320055706885689344\",\"page\":1,\"query\":\"from%3AJaroslavTulach\",\"refresh_url\":"
   46.40 -        + "\"?since_id=320055706885689344&q=from%3AJaroslavTulach\","
   46.41 -        + "\"results\":[{\"created_at\":\"Fri, 05 Apr 2013 06:10:01 +0000\","
   46.42 -        + "\"from_user\":\"JaroslavTulach\",\"from_user_id\":420944648,\"from_user_id_str\":"
   46.43 -        + "\"420944648\",\"from_user_name\":\"Jaroslav Tulach\",\"geo\":null,\"id\":320055706885689344,"
   46.44 -        + "\"id_str\":\"320055706885689344\",\"iso_language_code\":\"en\",\"metadata\":{\"result_type\":"
   46.45 -        + "\"recent\"},\"profile_image_url\":\"http:\\/\\/a0.twimg.com\\/profile_images\\/1656828312\\/jst_normal.gif\","
   46.46 -        + "\"profile_image_url_https\":\"https:\\/\\/si0.twimg.com\\/profile_images\\/1656828312\\/jst_normal.gif\","
   46.47 -        + "\"source\":\"&lt;a href=&quot;http:\\/\\/twitter.com\\/&quot;&gt;web&lt;\\/a&gt;\",\"text\":"
   46.48 -        + "\"@tom_enebo Amzng! Not that I would like #ruby, but I am really glad you guys stabilized the plugin + "
   46.49 -        + "made it work in #netbeans 7.3! Gd wrk.\",\"to_user\":\"tom_enebo\",\"to_user_id\":14498747,"
   46.50 -        + "\"to_user_id_str\":\"14498747\",\"to_user_name\":\"tom_enebo\",\"in_reply_to_status_id\":319832359509839872,"
   46.51 -        + "\"in_reply_to_status_id_str\":\"319832359509839872\"},{\"created_at\":\"Thu, 04 Apr 2013 07:33:06 +0000\","
   46.52 -        + "\"from_user\":\"JaroslavTulach\",\"from_user_id\":420944648,\"from_user_id_str\":"
   46.53 -        + "\"420944648\",\"from_user_name\":\"Jaroslav Tulach\",\"geo\":null,\"id\":319714227088678913,"
   46.54 -        + "\"id_str\":\"319714227088678913\",\"iso_language_code\":\"en\",\"metadata\":{\"result_type\":"
   46.55 -        + "\"recent\"},\"profile_image_url\":\"http:\\/\\/a0.twimg.com\\/profile_images\\/1656828312\\/jst_normal.gif\","
   46.56 -        + "\"profile_image_url_https\":\"https:\\/\\/si0.twimg.com\\/profile_images\\/1656828312\\/jst_normal.gif\","
   46.57 -        + "\"source\":\"&lt;a href=&quot;http:\\/\\/twitter.com\\/&quot;&gt;web&lt;\\/a&gt;\",\"text\":"
   46.58 -        + "\"RT @drkrab: At #erlangfactory @joerl: Frameworks grow in complexity until nobody can use them.\"},"
   46.59 -        + "{\"created_at\":\"Tue, 02 Apr 2013 07:44:34 +0000\",\"from_user\":\"JaroslavTulach\","
   46.60 -        + "\"from_user_id\":420944648,\"from_user_id_str\":\"420944648\",\"from_user_name\":\"Jaroslav Tulach\","
   46.61 -        + "\"geo\":null,\"id\":318992336145248256,\"id_str\":\"318992336145248256\",\"iso_language_code\":\"en\","
   46.62 -        + "\"metadata\":{\"result_type\":\"recent\"},\"profile_image_url\":"
   46.63 -        + "\"http:\\/\\/a0.twimg.com\\/profile_images\\/1656828312\\/jst_normal.gif\","
   46.64 -        + "\"profile_image_url_https\":\"https:\\/\\/si0.twimg.com\\/profile_images\\/1656828312\\/jst_normal.gif\","
   46.65 -        + "\"source\":\"&lt;a href=&quot;http:\\/\\/twitter.com\\/&quot;&gt;web&lt;\\/a&gt;\",\"text\":"
   46.66 -        + "\"Twitter renamed to twttr http:\\/\\/t.co\\/tqaN4T1xlZ - good, I don't have to rename #bck2brwsr!\"},"
   46.67 -        + "{\"created_at\":\"Sun, 31 Mar 2013 03:52:04 +0000\",\"from_user\":\"JaroslavTulach\",\"from_user_id\":420944648,"
   46.68 -        + "\"from_user_id_str\":\"420944648\",\"from_user_name\":\"Jaroslav Tulach\",\"geo\":null,"
   46.69 -        + "\"id\":318209051223789568,\"id_str\":\"318209051223789568\",\"iso_language_code\":\"en\",\"metadata\":"
   46.70 -        + "{\"result_type\":\"recent\"},\"profile_image_url\":"
   46.71 -        + "\"http:\\/\\/a0.twimg.com\\/profile_images\\/1656828312\\/jst_normal.gif\","
   46.72 -        + "\"profile_image_url_https\":\"https:\\/\\/si0.twimg.com\\/profile_images\\/1656828312\\/jst_normal.gif\","
   46.73 -        + "\"source\":\"&lt;a href=&quot;http:\\/\\/twitter.com\\/&quot;&gt;web&lt;\\/a&gt;\",\"text\":"
   46.74 -        + "\"Math proofs without words. Ingenious: http:\\/\\/t.co\\/sz7yVbfpGw\"}],\"results_per_page\":100,"
   46.75 -        + "\"since_id\":0,\"since_id_str\":\"0\"})"
   46.76 -    ))
   46.77 -    @BrwsrTest public void readFromTwttr() throws InterruptedException {
   46.78 -        if (page == null) {
   46.79 -            page = new TwitterModel();
   46.80 -            page.applyBindings();
   46.81 -            page.queryTweets("", "q=xyz");
   46.82 -        }
   46.83 -
   46.84 -        if (page.getCurrentTweets().isEmpty()) {
   46.85 -            throw new InterruptedException();
   46.86 -        }
   46.87 -
   46.88 -        assert 4 == page.getCurrentTweets().size() : "Four tweets: " + page.getCurrentTweets();
   46.89 -        
   46.90 -        String firstDate = page.getCurrentTweets().get(0).getCreated_at();
   46.91 -        assert "Fri, 05 Apr 2013 06:10:01 +0000".equals(firstDate) : "Date is OK: " + firstDate;
   46.92 -    }
   46.93 -    
   46.94 -    @Factory public static Object[] create() {
   46.95 -        return VMTest.create(TwitterProtocolTest.class);
   46.96 -    }
   46.97 -}
    47.1 --- a/javaquery/pom.xml	Tue Feb 11 10:48:24 2014 +0100
    47.2 +++ b/javaquery/pom.xml	Tue Feb 11 13:31:42 2014 +0100
    47.3 @@ -15,7 +15,6 @@
    47.4          <module>api</module>
    47.5          <module>demo-calculator</module>
    47.6          <module>demo-calculator-dynamic</module>
    47.7 -    <module>demo-twitter</module>
    47.8 -    <module>canvas</module>
    47.9 +        <module>canvas</module>
   47.10    </modules>
   47.11 -</project>
   47.12 \ No newline at end of file
   47.13 +</project>
    48.1 --- a/ko/archetype-test/src/test/java/org/apidesign/bck2brwsr/ko/archetype/test/VerifyArchetypeTest.java	Tue Feb 11 10:48:24 2014 +0100
    48.2 +++ b/ko/archetype-test/src/test/java/org/apidesign/bck2brwsr/ko/archetype/test/VerifyArchetypeTest.java	Tue Feb 11 13:31:42 2014 +0100
    48.3 @@ -74,8 +74,8 @@
    48.4          
    48.5          v.verifyErrorFreeLog();
    48.6          
    48.7 -        // does pre-compilation to JavaScript
    48.8 -        v.verifyTextInLog("j2js");
    48.9 +        // no longer does pre-compilation to JavaScript
   48.10 +        // v.verifyTextInLog("j2js");
   48.11          // uses Bck2BrwsrLauncher
   48.12          v.verifyTextInLog("BaseHTTPLauncher showBrwsr");
   48.13          // building zip:
    49.1 --- a/ko/archetype/src/main/resources/archetype-resources/pom.xml	Tue Feb 11 10:48:24 2014 +0100
    49.2 +++ b/ko/archetype/src/main/resources/archetype-resources/pom.xml	Tue Feb 11 13:31:42 2014 +0100
    49.3 @@ -43,6 +43,7 @@
    49.4      <bck2brwsr.launcher.version>${project.version}</bck2brwsr.launcher.version>
    49.5      <bck2brwsr.obfuscationlevel>MINIMAL</bck2brwsr.obfuscationlevel>
    49.6      <brwsr.startpage>pages/index.html</brwsr.startpage>
    49.7 +    <netbeans.compile.on.save>none</netbeans.compile.on.save>
    49.8    </properties>
    49.9    <build>
   49.10        <plugins>
   49.11 @@ -64,6 +65,19 @@
   49.12                </configuration>
   49.13            </plugin>
   49.14            <plugin>
   49.15 +              <groupId>org.netbeans.html</groupId>
   49.16 +              <artifactId>html4j-maven-plugin</artifactId>
   49.17 +              <version>${net.java.html.version}</version>
   49.18 +              <executions>
   49.19 +                  <execution>
   49.20 +                      <id>js-classes</id>
   49.21 +                      <goals>
   49.22 +                          <goal>process-js-annotations</goal>
   49.23 +                      </goals>
   49.24 +                  </execution>
   49.25 +              </executions>
   49.26 +          </plugin>          
   49.27 +          <plugin>
   49.28                <groupId>org.apache.maven.plugins</groupId>
   49.29                <artifactId>maven-compiler-plugin</artifactId>
   49.30                <version>2.3.2</version>
   49.31 @@ -110,7 +124,7 @@
   49.32      <dependency>
   49.33        <groupId>org.testng</groupId>
   49.34        <artifactId>testng</artifactId>
   49.35 -      <version>6.5.2</version>
   49.36 +      <version>6.7</version>
   49.37        <scope>test</scope>
   49.38      </dependency>
   49.39      <dependency>
   49.40 @@ -126,11 +140,17 @@
   49.41        <scope>test</scope>
   49.42      </dependency>
   49.43      <dependency>
   49.44 -      <groupId>org.apidesign.html</groupId>
   49.45 +      <groupId>org.netbeans.html</groupId>
   49.46        <artifactId>net.java.html.json</artifactId>
   49.47        <version>\${net.java.html.version}</version>
   49.48        <type>jar</type>
   49.49      </dependency>
   49.50 +    <dependency>
   49.51 +      <groupId>org.netbeans.html</groupId>
   49.52 +      <artifactId>net.java.html.boot</artifactId>
   49.53 +      <version>\${net.java.html.version}</version>
   49.54 +      <type>jar</type>
   49.55 +    </dependency>    
   49.56    </dependencies>
   49.57    <profiles>
   49.58        <profile>
   49.59 @@ -182,8 +202,8 @@
   49.60            </build>
   49.61            <dependencies>
   49.62                <dependency>
   49.63 -                  <groupId>org.apidesign.html</groupId>
   49.64 -                  <artifactId>ko-fx</artifactId>
   49.65 +                  <groupId>org.netbeans.html</groupId>
   49.66 +                  <artifactId>ko4j</artifactId>
   49.67                    <version>\${net.java.html.version}</version>
   49.68                </dependency>
   49.69                <dependency>
   49.70 @@ -205,27 +225,15 @@
   49.71            <build>
   49.72                <plugins>
   49.73                    <plugin>
   49.74 -                      <groupId>org.apidesign.bck2brwsr</groupId>
   49.75 -                      <artifactId>bck2brwsr-maven-plugin</artifactId>
   49.76 -                      <executions>
   49.77 -                          <execution>
   49.78 -                              <goals>
   49.79 -                                  <goal>j2js</goal>
   49.80 -                              </goals>
   49.81 -                          </execution>
   49.82 -                      </executions>
   49.83 -                      <configuration>
   49.84 -                          <javascript>\${project.build.directory}/bck2brwsr.js</javascript>
   49.85 -                          <obfuscation>\${bck2brwsr.obfuscationlevel}</obfuscation>
   49.86 -                      </configuration>
   49.87 -                  </plugin>
   49.88 -                  <plugin>
   49.89                        <groupId>org.apache.maven.plugins</groupId>
   49.90                        <artifactId>maven-compiler-plugin</artifactId>
   49.91                        <configuration>
   49.92                            <compilerArguments>
   49.93                                <bootclasspath>netbeans.ignore.jdk.bootclasspath</bootclasspath>
   49.94                            </compilerArguments>
   49.95 +                          <testExcludes>
   49.96 +                              <exclude>**/JsInteractionTest*</exclude>
   49.97 +                          </testExcludes>
   49.98                        </configuration>
   49.99                    </plugin>
  49.100                    <plugin>
  49.101 @@ -261,6 +269,14 @@
  49.102                    <version>\${bck2brwsr.version}</version>
  49.103                    <scope>runtime</scope>
  49.104                </dependency>
  49.105 +              <dependency>
  49.106 +                  <groupId>org.apidesign.bck2brwsr</groupId>
  49.107 +                  <artifactId>vm4brwsr</artifactId>
  49.108 +                  <classifier>js</classifier>
  49.109 +                  <type>zip</type>
  49.110 +                  <version>\${bck2brwsr.version}</version>
  49.111 +                  <scope>provided</scope>
  49.112 +              </dependency>
  49.113            </dependencies>
  49.114        </profile>
  49.115    </profiles>
    50.1 --- a/ko/archetype/src/main/resources/archetype-resources/src/main/assembly/bck2brwsr.xml	Tue Feb 11 10:48:24 2014 +0100
    50.2 +++ b/ko/archetype/src/main/resources/archetype-resources/src/main/assembly/bck2brwsr.xml	Tue Feb 11 13:31:42 2014 +0100
    50.3 @@ -17,19 +17,18 @@
    50.4              <include>*:rt</include>
    50.5          </includes>
    50.6      </dependencySet>
    50.7 +    <dependencySet>
    50.8 +        <useProjectArtifact>false</useProjectArtifact>
    50.9 +        <scope>provided</scope>
   50.10 +        <includes>
   50.11 +            <include>*:js</include>
   50.12 +        </includes>
   50.13 +        <unpack>true</unpack>
   50.14 +        <outputDirectory>/</outputDirectory>
   50.15 +    </dependencySet>
   50.16    </dependencySets> 
   50.17    <fileSets>
   50.18        <fileSet>
   50.19 -          <directory>${project.build.directory}/classes/${package.replace('.','/')}/</directory>
   50.20 -          <includes>
   50.21 -              <include>**/*</include>
   50.22 -          </includes>
   50.23 -          <excludes>
   50.24 -              <exclude>**/*.class</exclude>
   50.25 -          </excludes>
   50.26 -          <outputDirectory>/</outputDirectory>
   50.27 -      </fileSet>
   50.28 -      <fileSet>
   50.29            <directory>src/main/webapp/pages</directory>
   50.30            <outputDirectory>/</outputDirectory>
   50.31            <filtered>true</filtered>
   50.32 @@ -40,9 +39,5 @@
   50.33        <source>${project.build.directory}/${project.build.finalName}.jar</source>
   50.34        <outputDirectory>/</outputDirectory>
   50.35      </file>
   50.36 -    <file>
   50.37 -      <source>${project.build.directory}/bck2brwsr.js</source>
   50.38 -      <outputDirectory>/</outputDirectory>
   50.39 -    </file>
   50.40    </files>
   50.41  </assembly>
   50.42 \ No newline at end of file
    51.1 --- a/ko/archetype/src/main/resources/archetype-resources/src/main/java/DataModel.java	Tue Feb 11 10:48:24 2014 +0100
    51.2 +++ b/ko/archetype/src/main/resources/archetype-resources/src/main/java/DataModel.java	Tue Feb 11 13:31:42 2014 +0100
    51.3 @@ -25,7 +25,21 @@
    51.4      @Function static void turnOn(Data model) {
    51.5          model.setOn(true);
    51.6      }
    51.7 -    @Function static void turnOff(Data model) {
    51.8 -        model.setOn(false);
    51.9 +
   51.10 +    @Function static void turnOff(final Data model) {
   51.11 +        confirmByUser("Really turn off?", new Runnable() {
   51.12 +            @Override
   51.13 +            public void run() {
   51.14 +                model.setOn(false);
   51.15 +            }
   51.16 +        });
   51.17      }
   51.18 +    
   51.19 +    /** Shows direct interaction with JavaScript */
   51.20 +    @net.java.html.js.JavaScriptBody(
   51.21 +        args = { "msg", "callback" }, 
   51.22 +        javacall = true, 
   51.23 +        body = "alert(msg); callback.@java.lang.Runnable::run()();"
   51.24 +    )
   51.25 +    static native void confirmByUser(String msg, Runnable callback);
   51.26  }
    52.1 --- a/ko/archetype/src/main/resources/archetype-resources/src/main/webapp/pages/index.html	Tue Feb 11 10:48:24 2014 +0100
    52.2 +++ b/ko/archetype/src/main/resources/archetype-resources/src/main/webapp/pages/index.html	Tue Feb 11 13:31:42 2014 +0100
    52.3 @@ -9,12 +9,21 @@
    52.4                  0% { -webkit-transform: rotate(0deg); }
    52.5                  100% { -webkit-transform: rotate(360deg); }
    52.6              }
    52.7 +            @keyframes spin {
    52.8 +                0% { transform: rotate(0deg); }
    52.9 +                100% { transform: rotate(360deg); }
   52.10 +            }
   52.11  
   52.12              .rotate {
   52.13                  -webkit-animation-name: spin;
   52.14                  -webkit-animation-duration: 3s;
   52.15                  -webkit-animation-iteration-count: infinite;
   52.16                  -webkit-animation-direction: alternate;
   52.17 +                
   52.18 +                animation-name: spin;
   52.19 +                animation-duration: 3s;
   52.20 +                animation-iteration-count: infinite;
   52.21 +                animation-direction: alternate;
   52.22              }
   52.23  
   52.24              #scene {
    53.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    53.2 +++ b/ko/archetype/src/main/resources/archetype-resources/src/test/java/JsInteractionTest.java	Tue Feb 11 13:31:42 2014 +0100
    53.3 @@ -0,0 +1,103 @@
    53.4 +package ${package};
    53.5 +
    53.6 +import java.io.Closeable;
    53.7 +import java.io.Reader;
    53.8 +import java.net.URL;
    53.9 +import java.util.ArrayList;
   53.10 +import java.util.List;
   53.11 +import javax.script.Invocable;
   53.12 +import javax.script.ScriptEngine;
   53.13 +import javax.script.ScriptEngineManager;
   53.14 +import javax.script.ScriptException;
   53.15 +import org.apidesign.html.boot.spi.Fn;
   53.16 +import static org.testng.Assert.assertEquals;
   53.17 +import org.testng.annotations.AfterMethod;
   53.18 +import org.testng.annotations.BeforeMethod;
   53.19 +import org.testng.annotations.Test;
   53.20 +
   53.21 +/** Tests for behavior of @JavaScriptBody methods. Set your JavaScript 
   53.22 + * environment up (for example define <code>alert</code> or use some
   53.23 + * emulation library like <em>env.js</em>), register script presenter 
   53.24 + * and then you can call methods that deal with JavaScript in your tests.
   53.25 + */
   53.26 +public class JsInteractionTest {
   53.27 +    private Closeable jsEngine;
   53.28 +    @BeforeMethod public void initializeJSEngine() throws Exception {
   53.29 +        jsEngine = Fn.activate(new ScriptPresenter());
   53.30 +    }
   53.31 +    
   53.32 +    @AfterMethod public void shutdownJSEngine() throws Exception {
   53.33 +        jsEngine.close();
   53.34 +    }
   53.35 +    
   53.36 +    @Test public void testCallbackFromJavaScript() throws Exception {
   53.37 +        class R implements Runnable {
   53.38 +            int called;
   53.39 +
   53.40 +            @Override
   53.41 +            public void run() {
   53.42 +                called++;
   53.43 +            }
   53.44 +        }
   53.45 +        R callback = new R();
   53.46 +        
   53.47 +        DataModel.confirmByUser("Hello", callback);
   53.48 +        
   53.49 +        assertEquals(callback.called, 1, "One immediate callback");
   53.50 +    }
   53.51 +
   53.52 +    private static class ScriptPresenter implements Fn.Presenter {
   53.53 +        private final ScriptEngine eng;
   53.54 +        
   53.55 +        public ScriptPresenter() throws ScriptException {
   53.56 +            eng = new ScriptEngineManager().getEngineByName("javascript");
   53.57 +            eng.eval("function alert(msg) { Packages.java.lang.System.out.println(msg); };");
   53.58 +        }
   53.59 +
   53.60 +        @Override
   53.61 +        public Fn defineFn(String code, String... names) {
   53.62 +            StringBuilder sb = new StringBuilder();
   53.63 +            sb.append("(function() {");
   53.64 +            sb.append("  return function(");
   53.65 +            String sep = "";
   53.66 +            for (String n : names) {
   53.67 +                sb.append(sep).append(n);
   53.68 +                sep = ",";
   53.69 +            }
   53.70 +            sb.append(") {\n");
   53.71 +            sb.append(code);
   53.72 +            sb.append("};");
   53.73 +            sb.append("})()");
   53.74 +            
   53.75 +            final Object fn;
   53.76 +            try {
   53.77 +                fn = eng.eval(sb.toString());
   53.78 +            } catch (ScriptException ex) {
   53.79 +                throw new IllegalStateException(ex);
   53.80 +            }
   53.81 +            return new Fn(this) {
   53.82 +                @Override
   53.83 +                public Object invoke(Object thiz, Object... args) throws Exception {
   53.84 +                    List<Object> all = new ArrayList<Object>(args.length + 1);
   53.85 +                    all.add(thiz == null ? fn : thiz);
   53.86 +                    for (int i = 0; i < args.length; i++) {
   53.87 +                        all.add(args[i]);
   53.88 +                    }
   53.89 +                    Object ret = ((Invocable)eng).invokeMethod(fn, "call", all.toArray()); // NOI18N
   53.90 +                    return fn.equals(ret) ? null : thiz;
   53.91 +                }
   53.92 +            };
   53.93 +        }
   53.94 +
   53.95 +        @Override
   53.96 +        public void displayPage(URL page, Runnable onPageLoad) {
   53.97 +            // not really displaying anything
   53.98 +            onPageLoad.run();
   53.99 +        }
  53.100 +
  53.101 +        @Override
  53.102 +        public void loadScript(Reader code) throws Exception {
  53.103 +            eng.eval(code);
  53.104 +        }
  53.105 +    }
  53.106 +}
    54.1 --- a/ko/bck2brwsr/pom.xml	Tue Feb 11 10:48:24 2014 +0100
    54.2 +++ b/ko/bck2brwsr/pom.xml	Tue Feb 11 13:31:42 2014 +0100
    54.3 @@ -62,6 +62,12 @@
    54.4        <version>${project.version}</version>
    54.5        <type>jar</type>
    54.6        <scope>test</scope>
    54.7 +      <exclusions>
    54.8 +        <exclusion>
    54.9 +          <artifactId>json</artifactId>
   54.10 +          <groupId>org.json</groupId>
   54.11 +        </exclusion>
   54.12 +      </exclusions>
   54.13      </dependency>
   54.14      <dependency>
   54.15        <groupId>org.apidesign.bck2brwsr</groupId>
   54.16 @@ -74,14 +80,20 @@
   54.17        <artifactId>launcher.http</artifactId>
   54.18        <version>${project.version}</version>
   54.19        <scope>test</scope>
   54.20 +      <exclusions>
   54.21 +        <exclusion>
   54.22 +          <artifactId>asm</artifactId>
   54.23 +          <groupId>org.ow2.asm</groupId>
   54.24 +        </exclusion>
   54.25 +      </exclusions>
   54.26      </dependency>
   54.27      <dependency>
   54.28 -      <groupId>org.apidesign.html</groupId>
   54.29 +      <groupId>org.netbeans.html</groupId>
   54.30        <artifactId>net.java.html.json</artifactId>
   54.31        <version>${net.java.html.version}</version>
   54.32      </dependency>
   54.33      <dependency>
   54.34 -      <groupId>org.apidesign.html</groupId>
   54.35 +      <groupId>org.netbeans.html</groupId>
   54.36        <artifactId>net.java.html.json.tck</artifactId>
   54.37        <version>${net.java.html.version}</version>
   54.38        <scope>test</scope>
   54.39 @@ -93,10 +105,31 @@
   54.40        <type>jar</type>
   54.41      </dependency>
   54.42      <dependency>
   54.43 -      <groupId>org.apidesign.html</groupId>
   54.44 +      <groupId>org.netbeans.html</groupId>
   54.45        <artifactId>net.java.html.boot</artifactId>
   54.46 -      <version>0.5</version>
   54.47 +      <version>${net.java.html.version}</version>
   54.48        <type>jar</type>
   54.49 +      <exclusions>
   54.50 +        <exclusion>
   54.51 +          <artifactId>asm</artifactId>
   54.52 +          <groupId>org.ow2.asm</groupId>
   54.53 +        </exclusion>
   54.54 +      </exclusions>
   54.55 +    </dependency>
   54.56 +    <dependency>
   54.57 +      <groupId>org.netbeans.html</groupId>
   54.58 +      <artifactId>ko4j</artifactId>
   54.59 +      <version>${net.java.html.version}</version>
   54.60 +      <exclusions>
   54.61 +        <exclusion>
   54.62 +          <artifactId>json</artifactId>
   54.63 +          <groupId>org.json</groupId>
   54.64 +        </exclusion>
   54.65 +        <exclusion>
   54.66 +          <artifactId>org.json-osgi</artifactId>
   54.67 +          <groupId>de.twentyeleven.skysail</groupId>
   54.68 +        </exclusion>
   54.69 +      </exclusions>
   54.70      </dependency>
   54.71    </dependencies>
   54.72  </project>
    55.1 --- a/ko/bck2brwsr/src/main/java/org/apidesign/bck2brwsr/ko2brwsr/BrwsrCtxImpl.java	Tue Feb 11 10:48:24 2014 +0100
    55.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    55.3 @@ -1,166 +0,0 @@
    55.4 -/**
    55.5 - * Back 2 Browser Bytecode Translator
    55.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
    55.7 - *
    55.8 - * This program is free software: you can redistribute it and/or modify
    55.9 - * it under the terms of the GNU General Public License as published by
   55.10 - * the Free Software Foundation, version 2 of the License.
   55.11 - *
   55.12 - * This program is distributed in the hope that it will be useful,
   55.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
   55.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   55.15 - * GNU General Public License for more details.
   55.16 - *
   55.17 - * You should have received a copy of the GNU General Public License
   55.18 - * along with this program. Look for COPYING file in the top folder.
   55.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
   55.20 - */
   55.21 -package org.apidesign.bck2brwsr.ko2brwsr;
   55.22 -
   55.23 -import java.io.ByteArrayOutputStream;
   55.24 -import java.io.IOException;
   55.25 -import java.io.InputStream;
   55.26 -import java.io.InputStreamReader;
   55.27 -import org.apidesign.html.json.spi.FunctionBinding;
   55.28 -import org.apidesign.html.json.spi.JSONCall;
   55.29 -import org.apidesign.html.json.spi.PropertyBinding;
   55.30 -import org.apidesign.html.json.spi.Technology;
   55.31 -import org.apidesign.html.json.spi.Transfer;
   55.32 -import org.apidesign.html.json.spi.WSTransfer;
   55.33 -
   55.34 -/**
   55.35 - *
   55.36 - * @author Jaroslav Tulach <jtulach@netbeans.org>
   55.37 - */
   55.38 -final class BrwsrCtxImpl implements Technology<Object>, Transfer, WSTransfer<LoadWS> {
   55.39 -    private BrwsrCtxImpl() {}
   55.40 -    
   55.41 -    public static final BrwsrCtxImpl DEFAULT = new BrwsrCtxImpl();
   55.42 -    
   55.43 -    @Override
   55.44 -    public void extract(Object obj, String[] props, Object[] values) {
   55.45 -        ConvertTypes.extractJSON(obj, props, values);
   55.46 -    }
   55.47 -
   55.48 -    @Override
   55.49 -    public void loadJSON(final JSONCall call) {
   55.50 -        class R implements Runnable {
   55.51 -            final boolean success;
   55.52 -
   55.53 -            public R(boolean success) {
   55.54 -                this.success = success;
   55.55 -            }
   55.56 -            
   55.57 -            Object[] arr = { null };
   55.58 -            @Override
   55.59 -            public void run() {
   55.60 -                if (success) {
   55.61 -                    call.notifySuccess(arr[0]);
   55.62 -                } else {
   55.63 -                    Throwable t;
   55.64 -                    if (arr[0] instanceof Throwable) {
   55.65 -                        t = (Throwable) arr[0];
   55.66 -                    } else {
   55.67 -                        if (arr[0] == null) {
   55.68 -                            t = new IOException();
   55.69 -                        } else {
   55.70 -                            t = new IOException(arr[0].toString());
   55.71 -                        }
   55.72 -                    }
   55.73 -                    call.notifyError(t);
   55.74 -                }
   55.75 -            }
   55.76 -        }
   55.77 -        R success = new R(true);
   55.78 -        R failure = new R(false);
   55.79 -        if (call.isJSONP()) {
   55.80 -            String me = ConvertTypes.createJSONP(success.arr, success);
   55.81 -            ConvertTypes.loadJSONP(call.composeURL(me), me);
   55.82 -        } else {
   55.83 -            String data = null;
   55.84 -            if (call.isDoOutput()) {
   55.85 -                try {
   55.86 -                    ByteArrayOutputStream bos = new ByteArrayOutputStream();
   55.87 -                    call.writeData(bos);
   55.88 -                    data = new String(bos.toByteArray(), "UTF-8");
   55.89 -                } catch (IOException ex) {
   55.90 -                    call.notifyError(ex);
   55.91 -                }
   55.92 -            }
   55.93 -            ConvertTypes.loadJSON(call.composeURL(null), success.arr, success, failure, call.getMethod(), data);
   55.94 -        }
   55.95 -    }
   55.96 -
   55.97 -    @Override
   55.98 -    public Object wrapModel(Object model) {
   55.99 -        return model;
  55.100 -    }
  55.101 -
  55.102 -    @Override
  55.103 -    public void bind(PropertyBinding b, Object model, Object data) {
  55.104 -        Knockout.bind(data, b, b.getPropertyName(), 
  55.105 -            "getValue__Ljava_lang_Object_2", 
  55.106 -            b.isReadOnly() ? null : "setValue__VLjava_lang_Object_2", 
  55.107 -            false, false
  55.108 -        );
  55.109 -    }
  55.110 -
  55.111 -    @Override
  55.112 -    public void valueHasMutated(Object data, String propertyName) {
  55.113 -        Knockout.valueHasMutated(data, propertyName);
  55.114 -    }
  55.115 -
  55.116 -    @Override
  55.117 -    public void expose(FunctionBinding fb, Object model, Object d) {
  55.118 -        Knockout.expose(d, fb, fb.getFunctionName(), "call__VLjava_lang_Object_2Ljava_lang_Object_2");
  55.119 -    }
  55.120 -
  55.121 -    @Override
  55.122 -    public void applyBindings(Object data) {
  55.123 -        Knockout.applyBindings(data);
  55.124 -    }
  55.125 -
  55.126 -    @Override
  55.127 -    public Object wrapArray(Object[] arr) {
  55.128 -        return arr;
  55.129 -    }
  55.130 -
  55.131 -    @Override
  55.132 -    public <M> M toModel(Class<M> modelClass, Object data) {
  55.133 -        return modelClass.cast(data);
  55.134 -    }
  55.135 -
  55.136 -    @Override
  55.137 -    public Object toJSON(InputStream is) throws IOException {
  55.138 -        StringBuilder sb = new StringBuilder();
  55.139 -        InputStreamReader r = new InputStreamReader(is);
  55.140 -        for (;;) {
  55.141 -            int ch = r.read();
  55.142 -            if (ch == -1) {
  55.143 -                break;
  55.144 -            }
  55.145 -            sb.append((char)ch);
  55.146 -        }
  55.147 -        return ConvertTypes.parse(sb.toString());
  55.148 -    }
  55.149 -
  55.150 -    @Override
  55.151 -    public void runSafe(Runnable r) {
  55.152 -        r.run();
  55.153 -    }
  55.154 -
  55.155 -    @Override
  55.156 -    public LoadWS open(String url, JSONCall callback) {
  55.157 -        return new LoadWS(callback, url);
  55.158 -    }
  55.159 -
  55.160 -    @Override
  55.161 -    public void send(LoadWS socket, JSONCall data) {
  55.162 -        socket.send(data);
  55.163 -    }
  55.164 -
  55.165 -    @Override
  55.166 -    public void close(LoadWS socket) {
  55.167 -        socket.close();
  55.168 -    }
  55.169 -}
    56.1 --- a/ko/bck2brwsr/src/main/java/org/apidesign/bck2brwsr/ko2brwsr/BrwsrCtxPrvdr.java	Tue Feb 11 10:48:24 2014 +0100
    56.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    56.3 @@ -1,53 +0,0 @@
    56.4 -/**
    56.5 - * Back 2 Browser Bytecode Translator
    56.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
    56.7 - *
    56.8 - * This program is free software: you can redistribute it and/or modify
    56.9 - * it under the terms of the GNU General Public License as published by
   56.10 - * the Free Software Foundation, version 2 of the License.
   56.11 - *
   56.12 - * This program is distributed in the hope that it will be useful,
   56.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
   56.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   56.15 - * GNU General Public License for more details.
   56.16 - *
   56.17 - * You should have received a copy of the GNU General Public License
   56.18 - * along with this program. Look for COPYING file in the top folder.
   56.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
   56.20 - */
   56.21 -package org.apidesign.bck2brwsr.ko2brwsr;
   56.22 -
   56.23 -import org.apidesign.bck2brwsr.core.JavaScriptBody;
   56.24 -import org.apidesign.html.context.spi.Contexts;
   56.25 -import org.apidesign.html.json.spi.Technology;
   56.26 -import org.apidesign.html.json.spi.Transfer;
   56.27 -import org.apidesign.html.json.spi.WSTransfer;
   56.28 -import org.openide.util.lookup.ServiceProvider;
   56.29 -
   56.30 -/** This is an implementation package - just
   56.31 - * include its JAR on classpath and use official {@link Context} API
   56.32 - * to access the functionality.
   56.33 - * <p>
   56.34 - * Provides binding between models and <a href="http://bck2brwsr.apidesign.org">
   56.35 - * Bck2Brwsr</a> VM.
   56.36 - * Registers {@link ContextProvider}, so {@link ServiceLoader} can find it.
   56.37 - *
   56.38 - * @author Jaroslav Tulach <jtulach@netbeans.org>
   56.39 - */
   56.40 -@ServiceProvider(service = Contexts.Provider.class)
   56.41 -public final class BrwsrCtxPrvdr implements Contexts.Provider {
   56.42 -
   56.43 -    @Override
   56.44 -    public void fillContext(Contexts.Builder context, Class<?> requestor) {
   56.45 -        if (bck2BrwsrVM()) {
   56.46 -            context.register(Technology.class, BrwsrCtxImpl.DEFAULT, 50).
   56.47 -            register(Transfer.class, BrwsrCtxImpl.DEFAULT, 50).
   56.48 -            register(WSTransfer.class, BrwsrCtxImpl.DEFAULT, 50);
   56.49 -        }
   56.50 -    }
   56.51 -    
   56.52 -    @JavaScriptBody(args = {  }, body = "return true;")
   56.53 -    private static boolean bck2BrwsrVM() {
   56.54 -        return false;
   56.55 -    }
   56.56 -}
    57.1 --- a/ko/bck2brwsr/src/main/java/org/apidesign/bck2brwsr/ko2brwsr/ConvertTypes.java	Tue Feb 11 10:48:24 2014 +0100
    57.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    57.3 @@ -1,157 +0,0 @@
    57.4 -/**
    57.5 - * Back 2 Browser Bytecode Translator
    57.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
    57.7 - *
    57.8 - * This program is free software: you can redistribute it and/or modify
    57.9 - * it under the terms of the GNU General Public License as published by
   57.10 - * the Free Software Foundation, version 2 of the License.
   57.11 - *
   57.12 - * This program is distributed in the hope that it will be useful,
   57.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
   57.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   57.15 - * GNU General Public License for more details.
   57.16 - *
   57.17 - * You should have received a copy of the GNU General Public License
   57.18 - * along with this program. Look for COPYING file in the top folder.
   57.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
   57.20 - */
   57.21 -package org.apidesign.bck2brwsr.ko2brwsr;
   57.22 -
   57.23 -import org.apidesign.bck2brwsr.core.JavaScriptBody;
   57.24 -
   57.25 -/**
   57.26 - *
   57.27 - * @author Jaroslav Tulach <jtulach@netbeans.org>
   57.28 - */
   57.29 -final class ConvertTypes {
   57.30 -    ConvertTypes() {
   57.31 -    }
   57.32 -    
   57.33 -    public static String toString(Object object, String property) {
   57.34 -        Object ret = getProperty(object, property);
   57.35 -        return ret == null ? null : ret.toString();
   57.36 -    }
   57.37 -
   57.38 -    public static double toDouble(Object object, String property) {
   57.39 -        Object ret = getProperty(object, property);
   57.40 -        return ret instanceof Number ? ((Number)ret).doubleValue() : Double.NaN;
   57.41 -    }
   57.42 -
   57.43 -    public static int toInt(Object object, String property) {
   57.44 -        Object ret = getProperty(object, property);
   57.45 -        return ret instanceof Number ? ((Number)ret).intValue() : Integer.MIN_VALUE;
   57.46 -    }
   57.47 -
   57.48 -    public static <T> T toModel(Class<T> modelClass, Object object, String property) {
   57.49 -        Object ret = getProperty(object, property);
   57.50 -        if (ret == null || modelClass.isInstance(ret)) {
   57.51 -            return modelClass.cast(ret);
   57.52 -        }
   57.53 -        throw new IllegalStateException("Value " + ret + " is not of type " + modelClass);
   57.54 -    }
   57.55 -    
   57.56 -    public static String toJSON(Object value) {
   57.57 -        if (value == null) {
   57.58 -            return "null";
   57.59 -        }
   57.60 -        if (value instanceof Enum) {
   57.61 -            value = value.toString();
   57.62 -        }
   57.63 -        if (value instanceof String) {
   57.64 -            return '"' + 
   57.65 -                ((String)value).
   57.66 -                    replace("\"", "\\\"").
   57.67 -                    replace("\n", "\\n").
   57.68 -                    replace("\r", "\\r").
   57.69 -                    replace("\t", "\\t")
   57.70 -                + '"';
   57.71 -        }
   57.72 -        return value.toString();
   57.73 -    }
   57.74 -    
   57.75 -    @JavaScriptBody(args = { "object", "property" },
   57.76 -        body = 
   57.77 -          "if (property === null) return object;\n"
   57.78 -        + "if (object === null) return null;\n"
   57.79 -        + "var p = object[property]; return p ? p : null;"
   57.80 -    )
   57.81 -    private static Object getProperty(Object object, String property) {
   57.82 -        return null;
   57.83 -    }
   57.84 -    
   57.85 -    public static String createJSONP(Object[] jsonResult, Runnable whenDone) {
   57.86 -        int h = whenDone.hashCode();
   57.87 -        String name;
   57.88 -        for (;;) {
   57.89 -            name = "jsonp" + Integer.toHexString(h);
   57.90 -            if (defineIfUnused(name, jsonResult, whenDone)) {
   57.91 -                return name;
   57.92 -            }
   57.93 -            h++;
   57.94 -        }
   57.95 -    }
   57.96 -
   57.97 -    @JavaScriptBody(args = { "name", "arr", "run" }, body = 
   57.98 -        "if (window[name]) return false;\n "
   57.99 -      + "window[name] = function(data) {\n "
  57.100 -      + "  delete window[name];\n"
  57.101 -      + "  var el = window.document.getElementById(name);\n"
  57.102 -      + "  el.parentNode.removeChild(el);\n"
  57.103 -      + "  arr[0] = data;\n"
  57.104 -      + "  run.run__V();\n"
  57.105 -      + "};\n"
  57.106 -      + "return true;\n"
  57.107 -    )
  57.108 -    private static boolean defineIfUnused(String name, Object[] arr, Runnable run) {
  57.109 -        return true;
  57.110 -    }
  57.111 -    
  57.112 -    @JavaScriptBody(args = { "s" }, body = "return eval('(' + s + ')');")
  57.113 -    static Object parse(String s) {
  57.114 -        return s;
  57.115 -    }
  57.116 -    
  57.117 -    @JavaScriptBody(args = { "url", "arr", "callback", "onError", "method", "data" }, body = ""
  57.118 -        + "var request = new XMLHttpRequest();\n"
  57.119 -        + "if (!method) method = 'GET';\n"
  57.120 -        + "request.open(method, url, true);\n"
  57.121 -        + "request.setRequestHeader('Content-Type', 'application/json; charset=utf-8');\n"
  57.122 -        + "request.onreadystatechange = function() {\n"
  57.123 -        + "  if (this.readyState!==4) return;\n"
  57.124 -        + "  try {\n"
  57.125 -        + "    arr[0] = eval('(' + this.response + ')');\n"
  57.126 -        + "  } catch (error) {;\n"
  57.127 -        + "    arr[0] = this.response;\n"
  57.128 -        + "  }\n"
  57.129 -        + "  callback.run__V();\n"
  57.130 -        + "};\n"
  57.131 -        + "request.onerror = function (e) {\n"
  57.132 -        + "  arr[0] = e; onError.run__V();\n"
  57.133 -        + "}\n"
  57.134 -        + "if (data) request.send(data);"
  57.135 -        + "else request.send();"
  57.136 -    )
  57.137 -    static void loadJSON(
  57.138 -        String url, Object[] jsonResult, Runnable whenDone, Runnable whenErr, String method, String data
  57.139 -    ) {
  57.140 -    }
  57.141 -    
  57.142 -    @JavaScriptBody(args = { "url", "jsonp" }, body = 
  57.143 -        "var scrpt = window.document.createElement('script');\n "
  57.144 -        + "scrpt.setAttribute('src', url);\n "
  57.145 -        + "scrpt.setAttribute('id', jsonp);\n "
  57.146 -        + "scrpt.setAttribute('type', 'text/javascript');\n "
  57.147 -        + "var body = document.getElementsByTagName('body')[0];\n "
  57.148 -        + "body.appendChild(scrpt);\n"
  57.149 -    )
  57.150 -    static void loadJSONP(String url, String jsonp) {
  57.151 -        
  57.152 -    }
  57.153 -    
  57.154 -    public static void extractJSON(Object jsonObject, String[] props, Object[] values) {
  57.155 -        for (int i = 0; i < props.length; i++) {
  57.156 -            values[i] = getProperty(jsonObject, props[i]);
  57.157 -        }
  57.158 -    }
  57.159 -    
  57.160 -}
    58.1 --- a/ko/bck2brwsr/src/main/java/org/apidesign/bck2brwsr/ko2brwsr/Knockout.java	Tue Feb 11 10:48:24 2014 +0100
    58.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    58.3 @@ -1,131 +0,0 @@
    58.4 -/**
    58.5 - * Back 2 Browser Bytecode Translator
    58.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
    58.7 - *
    58.8 - * This program is free software: you can redistribute it and/or modify
    58.9 - * it under the terms of the GNU General Public License as published by
   58.10 - * the Free Software Foundation, version 2 of the License.
   58.11 - *
   58.12 - * This program is distributed in the hope that it will be useful,
   58.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
   58.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   58.15 - * GNU General Public License for more details.
   58.16 - *
   58.17 - * You should have received a copy of the GNU General Public License
   58.18 - * along with this program. Look for COPYING file in the top folder.
   58.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
   58.20 - */
   58.21 -package org.apidesign.bck2brwsr.ko2brwsr;
   58.22 -
   58.23 -import java.lang.reflect.Method;
   58.24 -import java.util.List;
   58.25 -import org.apidesign.bck2brwsr.core.ExtraJavaScript;
   58.26 -import org.apidesign.bck2brwsr.core.JavaScriptBody;
   58.27 -
   58.28 -/** Provides binding between models and bck2brwsr VM.
   58.29 - *
   58.30 - * @author Jaroslav Tulach <jtulach@netbeans.org>
   58.31 - */
   58.32 -@ExtraJavaScript(resource = "/org/apidesign/bck2brwsr/htmlpage/knockout-2.2.1.js")
   58.33 -final class Knockout {
   58.34 -    /** used by tests */
   58.35 -    static Knockout next;
   58.36 -    private final Object model;
   58.37 -
   58.38 -    Knockout(Object model) {
   58.39 -        this.model = model == null ? this : model;
   58.40 -    }
   58.41 -    
   58.42 -    public static <M> Knockout applyBindings(
   58.43 -        Object model, String[] propsGettersAndSetters,
   58.44 -        String[] methodsAndSignatures
   58.45 -    ) {
   58.46 -        applyImpl(propsGettersAndSetters, model.getClass(), model, model, methodsAndSignatures);
   58.47 -        return new Knockout(model);
   58.48 -    }
   58.49 -    public static <M> Knockout applyBindings(
   58.50 -        Class<M> modelClass, M model, String[] propsGettersAndSetters,
   58.51 -        String[] methodsAndSignatures
   58.52 -    ) {
   58.53 -        Knockout bindings = next;
   58.54 -        next = null;
   58.55 -        if (bindings == null) {
   58.56 -            bindings = new Knockout(null);
   58.57 -        }
   58.58 -        applyImpl(propsGettersAndSetters, modelClass, bindings, model, methodsAndSignatures);
   58.59 -        applyBindings(bindings);
   58.60 -        return bindings;
   58.61 -    }
   58.62 -
   58.63 -    public void valueHasMutated(String prop) {
   58.64 -        valueHasMutated(model, prop);
   58.65 -    }
   58.66 -    @JavaScriptBody(args = { "self", "prop" }, body =
   58.67 -        "var p = self[prop]; if (p) p.valueHasMutated();"
   58.68 -    )
   58.69 -    public static void valueHasMutated(Object self, String prop) {
   58.70 -    }
   58.71 -    
   58.72 -
   58.73 -    @JavaScriptBody(args = { "id", "ev" }, body = "ko.utils.triggerEvent(window.document.getElementById(id), ev.substring(2));")
   58.74 -    public static void triggerEvent(String id, String ev) {
   58.75 -    }
   58.76 -    
   58.77 -    @JavaScriptBody(args = { "bindings", "model", "prop", "getter", "setter", "primitive", "array" }, body =
   58.78 -          "var bnd = {\n"
   58.79 -        + "  'read': function() {\n"
   58.80 -        + "    var v = model[getter]();\n"
   58.81 -        + "    if (array) v = v.koArray(); else if (v !== null) v = v.valueOf();\n"
   58.82 -        + "    return v;\n"
   58.83 -        + "  },\n"
   58.84 -        + "  'owner': bindings\n"
   58.85 -        + "};\n"
   58.86 -        + "if (setter != null) {\n"
   58.87 -        + "  bnd['write'] = function(val) {\n"
   58.88 -        + "    var v = val === null ? null : val.valueOf();"
   58.89 -        + "    model[setter](v);\n"
   58.90 -        + "  };\n"
   58.91 -        + "}\n"
   58.92 -        + "bindings[prop] = ko['computed'](bnd);"
   58.93 -    )
   58.94 -    static void bind(
   58.95 -        Object bindings, Object model, String prop, String getter, String setter, boolean primitive, boolean array
   58.96 -    ) {
   58.97 -    }
   58.98 -
   58.99 -    @JavaScriptBody(args = { "bindings", "model", "prop", "sig" }, body = 
  58.100 -        "bindings[prop] = function(data, ev) { model[sig](data, ev); };"
  58.101 -    )
  58.102 -    static void expose(
  58.103 -        Object bindings, Object model, String prop, String sig
  58.104 -    ) {
  58.105 -    }
  58.106 -    
  58.107 -    @JavaScriptBody(args = { "bindings" }, body = "ko.applyBindings(bindings);")
  58.108 -    static void applyBindings(Object bindings) {}
  58.109 -    
  58.110 -    private static void applyImpl(
  58.111 -        String[] propsGettersAndSetters,
  58.112 -        Class<?> modelClass,
  58.113 -        Object bindings,
  58.114 -        Object model,
  58.115 -        String[] methodsAndSignatures
  58.116 -    ) throws IllegalStateException, SecurityException {
  58.117 -        for (int i = 0; i < propsGettersAndSetters.length; i += 4) {
  58.118 -            try {
  58.119 -                Method getter = modelClass.getMethod(propsGettersAndSetters[i + 3]);
  58.120 -                bind(bindings, model, propsGettersAndSetters[i],
  58.121 -                    propsGettersAndSetters[i + 1],
  58.122 -                    propsGettersAndSetters[i + 2],
  58.123 -                    getter.getReturnType().isPrimitive(),
  58.124 -                    List.class.isAssignableFrom(getter.getReturnType()));
  58.125 -            } catch (NoSuchMethodException ex) {
  58.126 -                throw new IllegalStateException(ex.getMessage());
  58.127 -            }
  58.128 -        }
  58.129 -        for (int i = 0; i < methodsAndSignatures.length; i += 2) {
  58.130 -            expose(
  58.131 -                bindings, model, methodsAndSignatures[i], methodsAndSignatures[i + 1]);
  58.132 -        }
  58.133 -    }
  58.134 -}
    59.1 --- a/ko/bck2brwsr/src/main/java/org/apidesign/bck2brwsr/ko2brwsr/LoadWS.java	Tue Feb 11 10:48:24 2014 +0100
    59.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    59.3 @@ -1,126 +0,0 @@
    59.4 -/**
    59.5 - * Back 2 Browser Bytecode Translator
    59.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
    59.7 - *
    59.8 - * This program is free software: you can redistribute it and/or modify
    59.9 - * it under the terms of the GNU General Public License as published by
   59.10 - * the Free Software Foundation, version 2 of the License.
   59.11 - *
   59.12 - * This program is distributed in the hope that it will be useful,
   59.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
   59.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   59.15 - * GNU General Public License for more details.
   59.16 - *
   59.17 - * You should have received a copy of the GNU General Public License
   59.18 - * along with this program. Look for COPYING file in the top folder.
   59.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
   59.20 - */
   59.21 -package org.apidesign.bck2brwsr.ko2brwsr;
   59.22 -
   59.23 -import net.java.html.js.JavaScriptBody;
   59.24 -import org.apidesign.html.json.spi.JSONCall;
   59.25 -
   59.26 -/** Communication with WebSockets for WebView 1.8.
   59.27 - *
   59.28 - * @author Jaroslav Tulach <jtulach@netbeans.org>
   59.29 - */
   59.30 -final class LoadWS {
   59.31 -    private static final boolean SUPPORTED = isWebSocket();
   59.32 -    private final Object ws;
   59.33 -    private final JSONCall call;
   59.34 -    LoadWS(JSONCall first, String url) {
   59.35 -        call = first;
   59.36 -        ws = initWebSocket(this, url);
   59.37 -        if (ws == null) {
   59.38 -            first.notifyError(new IllegalArgumentException("Wrong URL: " + url));
   59.39 -        }
   59.40 -    }
   59.41 -    
   59.42 -    static boolean isSupported() {
   59.43 -        return SUPPORTED;
   59.44 -    }
   59.45 -    
   59.46 -    void send(JSONCall call) {
   59.47 -        push(call);
   59.48 -    }
   59.49 -    
   59.50 -    private synchronized void push(JSONCall call) {
   59.51 -        send(ws, call.getMessage());
   59.52 -    }
   59.53 -
   59.54 -    void onOpen(Object ev) {
   59.55 -        if (!call.isDoOutput()) {
   59.56 -            call.notifySuccess(null);
   59.57 -        }
   59.58 -    }
   59.59 -    
   59.60 -    
   59.61 -    @JavaScriptBody(args = { "data" }, body = "try {\n"
   59.62 -        + "    return eval('(' + data + ')');\n"
   59.63 -        + "  } catch (error) {;\n"
   59.64 -        + "    return data;\n"
   59.65 -        + "  }\n"
   59.66 -    )
   59.67 -    private static native Object toJSON(String data);
   59.68 -    
   59.69 -    void onMessage(Object ev, String data) {
   59.70 -        Object json = toJSON(data);
   59.71 -        call.notifySuccess(json);
   59.72 -    }
   59.73 -    
   59.74 -    void onError(Object ev) {
   59.75 -        call.notifyError(new Exception(ev.toString()));
   59.76 -    }
   59.77 -
   59.78 -    void onClose(boolean wasClean, int code, String reason) {
   59.79 -        call.notifyError(null);
   59.80 -    }
   59.81 -    
   59.82 -    @JavaScriptBody(args = {}, body = "if (window.WebSocket) return true; else return false;")
   59.83 -    private static boolean isWebSocket() {
   59.84 -        return false;
   59.85 -    }
   59.86 -
   59.87 -    @JavaScriptBody(args = { "back", "url" }, javacall = true, body = ""
   59.88 -        + "if (window.WebSocket) {\n"
   59.89 -        + "  try {\n"
   59.90 -        + "    var ws = new window.WebSocket(url);\n"
   59.91 -        + "    ws.onopen = function(ev) {\n"
   59.92 -        + "      back.@org.apidesign.bck2brwsr.ko2brwsr.LoadWS::onOpen(Ljava/lang/Object;)(ev);\n"
   59.93 -        + "    };\n"
   59.94 -        + "    ws.onmessage = function(ev) {\n"
   59.95 -        + "      back.@org.apidesign.bck2brwsr.ko2brwsr.LoadWS::onMessage(Ljava/lang/Object;Ljava/lang/String;)(ev, ev.data);\n"
   59.96 -        + "    };\n"
   59.97 -        + "    ws.onerror = function(ev) {\n"
   59.98 -        + "      back.@org.apidesign.bck2brwsr.ko2brwsr.LoadWS::onError(Ljava/lang/Object;)(ev);\n"
   59.99 -        + "    };\n"
  59.100 -        + "    ws.onclose = function(ev) {\n"
  59.101 -        + "      back.@org.apidesign.bck2brwsr.ko2brwsr.LoadWS::onClose(ZILjava/lang/String;)(ev.wasClean, ev.code, ev.reason);\n"
  59.102 -        + "    };\n"
  59.103 -        + "    return ws;\n"
  59.104 -        + "  } catch (ex) {\n"
  59.105 -        + "    return null;\n"
  59.106 -        + "  }\n"
  59.107 -        + "} else {\n"
  59.108 -        + "  return null;\n"
  59.109 -        + "}\n"
  59.110 -    )
  59.111 -    private static Object initWebSocket(Object back, String url) {
  59.112 -        return null;
  59.113 -    }
  59.114 -    
  59.115 -
  59.116 -    @JavaScriptBody(args = { "ws", "msg" }, body = ""
  59.117 -        + "ws.send(msg);"
  59.118 -    )
  59.119 -    private void send(Object ws, String msg) {
  59.120 -    }
  59.121 -
  59.122 -    @JavaScriptBody(args = { "ws" }, body = "ws.close();")
  59.123 -    private static void close(Object ws) {
  59.124 -    }
  59.125 -
  59.126 -    void close() {
  59.127 -        close(ws);
  59.128 -    }
  59.129 -}
    60.1 --- a/ko/bck2brwsr/src/main/resources/org/apidesign/bck2brwsr/htmlpage/knockout-2.2.1.js	Tue Feb 11 10:48:24 2014 +0100
    60.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    60.3 @@ -1,3614 +0,0 @@
    60.4 -/*
    60.5 - * HTML via Java(tm) Language Bindings
    60.6 - * Copyright (C) 2013 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
    60.7 - *
    60.8 - * This program is free software: you can redistribute it and/or modify
    60.9 - * it under the terms of the GNU General Public License as published by
   60.10 - * the Free Software Foundation, version 2 of the License.
   60.11 - *
   60.12 - * This program is distributed in the hope that it will be useful,
   60.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
   60.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   60.15 - * GNU General Public License for more details. apidesign.org
   60.16 - * designates this particular file as subject to the
   60.17 - * "Classpath" exception as provided by apidesign.org
   60.18 - * in the License file that accompanied this code.
   60.19 - *
   60.20 - * You should have received a copy of the GNU General Public License
   60.21 - * along with this program. Look for COPYING file in the top folder.
   60.22 - * If not, see http://wiki.apidesign.org/wiki/GPLwithClassPathException
   60.23 - */
   60.24 -// Knockout JavaScript library v2.2.1
   60.25 -// (c) Steven Sanderson - http://knockoutjs.com/
   60.26 -// License: MIT (http://www.opensource.org/licenses/mit-license.php)
   60.27 -
   60.28 -(function(){
   60.29 -var DEBUG=true;
   60.30 -(function(window,document,navigator,jQuery,undefined){
   60.31 -!function(factory) {
   60.32 -    // Support three module loading scenarios
   60.33 -    if (typeof require === 'function' && typeof exports === 'object' && typeof module === 'object') {
   60.34 -        // [1] CommonJS/Node.js
   60.35 -        var target = module['exports'] || exports; // module.exports is for Node.js
   60.36 -        factory(target);
   60.37 -    } else if (typeof define === 'function' && define['amd']) {
   60.38 -        // [2] AMD anonymous module
   60.39 -        define(['exports'], factory);
   60.40 -    } else {
   60.41 -        // [3] No module loader (plain <script> tag) - put directly in global namespace
   60.42 -        factory(window['ko'] = {});
   60.43 -    }
   60.44 -}(function(koExports){
   60.45 -// Internally, all KO objects are attached to koExports (even the non-exported ones whose names will be minified by the closure compiler).
   60.46 -// In the future, the following "ko" variable may be made distinct from "koExports" so that private objects are not externally reachable.
   60.47 -var ko = typeof koExports !== 'undefined' ? koExports : {};
   60.48 -// Google Closure Compiler helpers (used only to make the minified file smaller)
   60.49 -ko.exportSymbol = function(koPath, object) {
   60.50 -	var tokens = koPath.split(".");
   60.51 -
   60.52 -	// In the future, "ko" may become distinct from "koExports" (so that non-exported objects are not reachable)
   60.53 -	// At that point, "target" would be set to: (typeof koExports !== "undefined" ? koExports : ko)
   60.54 -	var target = ko;
   60.55 -
   60.56 -	for (var i = 0; i < tokens.length - 1; i++)
   60.57 -		target = target[tokens[i]];
   60.58 -	target[tokens[tokens.length - 1]] = object;
   60.59 -};
   60.60 -ko.exportProperty = function(owner, publicName, object) {
   60.61 -  owner[publicName] = object;
   60.62 -};
   60.63 -ko.version = "2.2.1";
   60.64 -
   60.65 -ko.exportSymbol('version', ko.version);
   60.66 -ko.utils = new (function () {
   60.67 -    var stringTrimRegex = /^(\s|\u00A0)+|(\s|\u00A0)+$/g;
   60.68 -
   60.69 -    // Represent the known event types in a compact way, then at runtime transform it into a hash with event name as key (for fast lookup)
   60.70 -    var knownEvents = {}, knownEventTypesByEventName = {};
   60.71 -    var keyEventTypeName = /Firefox\/2/i.test(navigator.userAgent) ? 'KeyboardEvent' : 'UIEvents';
   60.72 -    knownEvents[keyEventTypeName] = ['keyup', 'keydown', 'keypress'];
   60.73 -    knownEvents['MouseEvents'] = ['click', 'dblclick', 'mousedown', 'mouseup', 'mousemove', 'mouseover', 'mouseout', 'mouseenter', 'mouseleave'];
   60.74 -    for (var eventType in knownEvents) {
   60.75 -        var knownEventsForType = knownEvents[eventType];
   60.76 -        if (knownEventsForType.length) {
   60.77 -            for (var i = 0, j = knownEventsForType.length; i < j; i++)
   60.78 -                knownEventTypesByEventName[knownEventsForType[i]] = eventType;
   60.79 -        }
   60.80 -    }
   60.81 -    var eventsThatMustBeRegisteredUsingAttachEvent = { 'propertychange': true }; // Workaround for an IE9 issue - https://github.com/SteveSanderson/knockout/issues/406
   60.82 -
   60.83 -    // Detect IE versions for bug workarounds (uses IE conditionals, not UA string, for robustness)
   60.84 -    // Note that, since IE 10 does not support conditional comments, the following logic only detects IE < 10.
   60.85 -    // Currently this is by design, since IE 10+ behaves correctly when treated as a standard browser.
   60.86 -    // If there is a future need to detect specific versions of IE10+, we will amend this.
   60.87 -    var ieVersion = (function() {
   60.88 -        var version = 3, div = document.createElement('div'), iElems = div.getElementsByTagName('i');
   60.89 -
   60.90 -        // Keep constructing conditional HTML blocks until we hit one that resolves to an empty fragment
   60.91 -        while (
   60.92 -            div.innerHTML = '<!--[if gt IE ' + (++version) + ']><i></i><![endif]-->',
   60.93 -            iElems[0]
   60.94 -        );
   60.95 -        return version > 4 ? version : undefined;
   60.96 -    }());
   60.97 -    var isIe6 = ieVersion === 6,
   60.98 -        isIe7 = ieVersion === 7;
   60.99 -
  60.100 -    function isClickOnCheckableElement(element, eventType) {
  60.101 -        if ((ko.utils.tagNameLower(element) !== "input") || !element.type) return false;
  60.102 -        if (eventType.toLowerCase() != "click") return false;
  60.103 -        var inputType = element.type;
  60.104 -        return (inputType == "checkbox") || (inputType == "radio");
  60.105 -    }
  60.106 -
  60.107 -    return {
  60.108 -        fieldsIncludedWithJsonPost: ['authenticity_token', /^__RequestVerificationToken(_.*)?$/],
  60.109 -
  60.110 -        arrayForEach: function (array, action) {
  60.111 -            for (var i = 0, j = array.length; i < j; i++)
  60.112 -                action(array[i]);
  60.113 -        },
  60.114 -
  60.115 -        arrayIndexOf: function (array, item) {
  60.116 -            if (typeof Array.prototype.indexOf == "function")
  60.117 -                return Array.prototype.indexOf.call(array, item);
  60.118 -            for (var i = 0, j = array.length; i < j; i++)
  60.119 -                if (array[i] === item)
  60.120 -                    return i;
  60.121 -            return -1;
  60.122 -        },
  60.123 -
  60.124 -        arrayFirst: function (array, predicate, predicateOwner) {
  60.125 -            for (var i = 0, j = array.length; i < j; i++)
  60.126 -                if (predicate.call(predicateOwner, array[i]))
  60.127 -                    return array[i];
  60.128 -            return null;
  60.129 -        },
  60.130 -
  60.131 -        arrayRemoveItem: function (array, itemToRemove) {
  60.132 -            var index = ko.utils.arrayIndexOf(array, itemToRemove);
  60.133 -            if (index >= 0)
  60.134 -                array.splice(index, 1);
  60.135 -        },
  60.136 -
  60.137 -        arrayGetDistinctValues: function (array) {
  60.138 -            array = array || [];
  60.139 -            var result = [];
  60.140 -            for (var i = 0, j = array.length; i < j; i++) {
  60.141 -                if (ko.utils.arrayIndexOf(result, array[i]) < 0)
  60.142 -                    result.push(array[i]);
  60.143 -            }
  60.144 -            return result;
  60.145 -        },
  60.146 -
  60.147 -        arrayMap: function (array, mapping) {
  60.148 -            array = array || [];
  60.149 -            var result = [];
  60.150 -            for (var i = 0, j = array.length; i < j; i++)
  60.151 -                result.push(mapping(array[i]));
  60.152 -            return result;
  60.153 -        },
  60.154 -
  60.155 -        arrayFilter: function (array, predicate) {
  60.156 -            array = array || [];
  60.157 -            var result = [];
  60.158 -            for (var i = 0, j = array.length; i < j; i++)
  60.159 -                if (predicate(array[i]))
  60.160 -                    result.push(array[i]);
  60.161 -            return result;
  60.162 -        },
  60.163 -
  60.164 -        arrayPushAll: function (array, valuesToPush) {
  60.165 -            if (valuesToPush instanceof Array)
  60.166 -                array.push.apply(array, valuesToPush);
  60.167 -            else
  60.168 -                for (var i = 0, j = valuesToPush.length; i < j; i++)
  60.169 -                    array.push(valuesToPush[i]);
  60.170 -            return array;
  60.171 -        },
  60.172 -
  60.173 -        extend: function (target, source) {
  60.174 -            if (source) {
  60.175 -                for(var prop in source) {
  60.176 -                    if(source.hasOwnProperty(prop)) {
  60.177 -                        target[prop] = source[prop];
  60.178 -                    }
  60.179 -                }
  60.180 -            }
  60.181 -            return target;
  60.182 -        },
  60.183 -
  60.184 -        emptyDomNode: function (domNode) {
  60.185 -            while (domNode.firstChild) {
  60.186 -                ko.removeNode(domNode.firstChild);
  60.187 -            }
  60.188 -        },
  60.189 -
  60.190 -        moveCleanedNodesToContainerElement: function(nodes) {
  60.191 -            // Ensure it's a real array, as we're about to reparent the nodes and
  60.192 -            // we don't want the underlying collection to change while we're doing that.
  60.193 -            var nodesArray = ko.utils.makeArray(nodes);
  60.194 -
  60.195 -            var container = document.createElement('div');
  60.196 -            for (var i = 0, j = nodesArray.length; i < j; i++) {
  60.197 -                container.appendChild(ko.cleanNode(nodesArray[i]));
  60.198 -            }
  60.199 -            return container;
  60.200 -        },
  60.201 -
  60.202 -        cloneNodes: function (nodesArray, shouldCleanNodes) {
  60.203 -            for (var i = 0, j = nodesArray.length, newNodesArray = []; i < j; i++) {
  60.204 -                var clonedNode = nodesArray[i].cloneNode(true);
  60.205 -                newNodesArray.push(shouldCleanNodes ? ko.cleanNode(clonedNode) : clonedNode);
  60.206 -            }
  60.207 -            return newNodesArray;
  60.208 -        },
  60.209 -
  60.210 -        setDomNodeChildren: function (domNode, childNodes) {
  60.211 -            ko.utils.emptyDomNode(domNode);
  60.212 -            if (childNodes) {
  60.213 -                for (var i = 0, j = childNodes.length; i < j; i++)
  60.214 -                    domNode.appendChild(childNodes[i]);
  60.215 -            }
  60.216 -        },
  60.217 -
  60.218 -        replaceDomNodes: function (nodeToReplaceOrNodeArray, newNodesArray) {
  60.219 -            var nodesToReplaceArray = nodeToReplaceOrNodeArray.nodeType ? [nodeToReplaceOrNodeArray] : nodeToReplaceOrNodeArray;
  60.220 -            if (nodesToReplaceArray.length > 0) {
  60.221 -                var insertionPoint = nodesToReplaceArray[0];
  60.222 -                var parent = insertionPoint.parentNode;
  60.223 -                for (var i = 0, j = newNodesArray.length; i < j; i++)
  60.224 -                    parent.insertBefore(newNodesArray[i], insertionPoint);
  60.225 -                for (var i = 0, j = nodesToReplaceArray.length; i < j; i++) {
  60.226 -                    ko.removeNode(nodesToReplaceArray[i]);
  60.227 -                }
  60.228 -            }
  60.229 -        },
  60.230 -
  60.231 -        setOptionNodeSelectionState: function (optionNode, isSelected) {
  60.232 -            // IE6 sometimes throws "unknown error" if you try to write to .selected directly, whereas Firefox struggles with setAttribute. Pick one based on browser.
  60.233 -            if (ieVersion < 7)
  60.234 -                optionNode.setAttribute("selected", isSelected);
  60.235 -            else
  60.236 -                optionNode.selected = isSelected;
  60.237 -        },
  60.238 -
  60.239 -        stringTrim: function (string) {
  60.240 -            return (string || "").replace(stringTrimRegex, "");
  60.241 -        },
  60.242 -
  60.243 -        stringTokenize: function (string, delimiter) {
  60.244 -            var result = [];
  60.245 -            var tokens = (string || "").split(delimiter);
  60.246 -            for (var i = 0, j = tokens.length; i < j; i++) {
  60.247 -                var trimmed = ko.utils.stringTrim(tokens[i]);
  60.248 -                if (trimmed !== "")
  60.249 -                    result.push(trimmed);
  60.250 -            }
  60.251 -            return result;
  60.252 -        },
  60.253 -
  60.254 -        stringStartsWith: function (string, startsWith) {
  60.255 -            string = string || "";
  60.256 -            if (startsWith.length > string.length)
  60.257 -                return false;
  60.258 -            return string.substring(0, startsWith.length) === startsWith;
  60.259 -        },
  60.260 -
  60.261 -        domNodeIsContainedBy: function (node, containedByNode) {
  60.262 -            if (containedByNode.compareDocumentPosition)
  60.263 -                return (containedByNode.compareDocumentPosition(node) & 16) == 16;
  60.264 -            while (node != null) {
  60.265 -                if (node == containedByNode)
  60.266 -                    return true;
  60.267 -                node = node.parentNode;
  60.268 -            }
  60.269 -            return false;
  60.270 -        },
  60.271 -
  60.272 -        domNodeIsAttachedToDocument: function (node) {
  60.273 -            return ko.utils.domNodeIsContainedBy(node, node.ownerDocument);
  60.274 -        },
  60.275 -
  60.276 -        tagNameLower: function(element) {
  60.277 -            // For HTML elements, tagName will always be upper case; for XHTML elements, it'll be lower case.
  60.278 -            // Possible future optimization: If we know it's an element from an XHTML document (not HTML),
  60.279 -            // we don't need to do the .toLowerCase() as it will always be lower case anyway.
  60.280 -            return element && element.tagName && element.tagName.toLowerCase();
  60.281 -        },
  60.282 -
  60.283 -        registerEventHandler: function (element, eventType, handler) {
  60.284 -            var mustUseAttachEvent = ieVersion && eventsThatMustBeRegisteredUsingAttachEvent[eventType];
  60.285 -            if (!mustUseAttachEvent && typeof jQuery != "undefined") {
  60.286 -                if (isClickOnCheckableElement(element, eventType)) {
  60.287 -                    // For click events on checkboxes, jQuery interferes with the event handling in an awkward way:
  60.288 -                    // it toggles the element checked state *after* the click event handlers run, whereas native
  60.289 -                    // click events toggle the checked state *before* the event handler.
  60.290 -                    // Fix this by intecepting the handler and applying the correct checkedness before it runs.
  60.291 -                    var originalHandler = handler;
  60.292 -                    handler = function(event, eventData) {
  60.293 -                        var jQuerySuppliedCheckedState = this.checked;
  60.294 -                        if (eventData)
  60.295 -                            this.checked = eventData.checkedStateBeforeEvent !== true;
  60.296 -                        originalHandler.call(this, event);
  60.297 -                        this.checked = jQuerySuppliedCheckedState; // Restore the state jQuery applied
  60.298 -                    };
  60.299 -                }
  60.300 -                jQuery(element)['bind'](eventType, handler);
  60.301 -            } else if (!mustUseAttachEvent && typeof element.addEventListener == "function")
  60.302 -                element.addEventListener(eventType, handler, false);
  60.303 -            else if (typeof element.attachEvent != "undefined")
  60.304 -                element.attachEvent("on" + eventType, function (event) {
  60.305 -                    handler.call(element, event);
  60.306 -                });
  60.307 -            else
  60.308 -                throw new Error("Browser doesn't support addEventListener or attachEvent");
  60.309 -        },
  60.310 -
  60.311 -        triggerEvent: function (element, eventType) {
  60.312 -            if (!(element && element.nodeType))
  60.313 -                throw new Error("element must be a DOM node when calling triggerEvent");
  60.314 -
  60.315 -            if (typeof jQuery != "undefined") {
  60.316 -                var eventData = [];
  60.317 -                if (isClickOnCheckableElement(element, eventType)) {
  60.318 -                    // Work around the jQuery "click events on checkboxes" issue described above by storing the original checked state before triggering the handler
  60.319 -                    eventData.push({ checkedStateBeforeEvent: element.checked });
  60.320 -                }
  60.321 -                jQuery(element)['trigger'](eventType, eventData);
  60.322 -            } else if (typeof document.createEvent == "function") {
  60.323 -                if (typeof element.dispatchEvent == "function") {
  60.324 -                    var eventCategory = knownEventTypesByEventName[eventType] || "HTMLEvents";
  60.325 -                    var event = document.createEvent(eventCategory);
  60.326 -                    event.initEvent(eventType, true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, element);
  60.327 -                    element.dispatchEvent(event);
  60.328 -                }
  60.329 -                else
  60.330 -                    throw new Error("The supplied element doesn't support dispatchEvent");
  60.331 -            } else if (typeof element.fireEvent != "undefined") {
  60.332 -                // Unlike other browsers, IE doesn't change the checked state of checkboxes/radiobuttons when you trigger their "click" event
  60.333 -                // so to make it consistent, we'll do it manually here
  60.334 -                if (isClickOnCheckableElement(element, eventType))
  60.335 -                    element.checked = element.checked !== true;
  60.336 -                element.fireEvent("on" + eventType);
  60.337 -            }
  60.338 -            else
  60.339 -                throw new Error("Browser doesn't support triggering events");
  60.340 -        },
  60.341 -
  60.342 -        unwrapObservable: function (value) {
  60.343 -            return ko.isObservable(value) ? value() : value;
  60.344 -        },
  60.345 -
  60.346 -        peekObservable: function (value) {
  60.347 -            return ko.isObservable(value) ? value.peek() : value;
  60.348 -        },
  60.349 -
  60.350 -        toggleDomNodeCssClass: function (node, classNames, shouldHaveClass) {
  60.351 -            if (classNames) {
  60.352 -                var cssClassNameRegex = /[\w-]+/g,
  60.353 -                    currentClassNames = node.className.match(cssClassNameRegex) || [];
  60.354 -                ko.utils.arrayForEach(classNames.match(cssClassNameRegex), function(className) {
  60.355 -                    var indexOfClass = ko.utils.arrayIndexOf(currentClassNames, className);
  60.356 -                    if (indexOfClass >= 0) {
  60.357 -                        if (!shouldHaveClass)
  60.358 -                            currentClassNames.splice(indexOfClass, 1);
  60.359 -                    } else {
  60.360 -                        if (shouldHaveClass)
  60.361 -                            currentClassNames.push(className);
  60.362 -                    }
  60.363 -                });
  60.364 -                node.className = currentClassNames.join(" ");
  60.365 -            }
  60.366 -        },
  60.367 -
  60.368 -        setTextContent: function(element, textContent) {
  60.369 -            var value = ko.utils.unwrapObservable(textContent);
  60.370 -            if ((value === null) || (value === undefined))
  60.371 -                value = "";
  60.372 -
  60.373 -            if (element.nodeType === 3) {
  60.374 -                element.data = value;
  60.375 -            } else {
  60.376 -                // We need there to be exactly one child: a text node.
  60.377 -                // If there are no children, more than one, or if it's not a text node,
  60.378 -                // we'll clear everything and create a single text node.
  60.379 -                var innerTextNode = ko.virtualElements.firstChild(element);
  60.380 -                if (!innerTextNode || innerTextNode.nodeType != 3 || ko.virtualElements.nextSibling(innerTextNode)) {
  60.381 -                    ko.virtualElements.setDomNodeChildren(element, [document.createTextNode(value)]);
  60.382 -                } else {
  60.383 -                    innerTextNode.data = value;
  60.384 -                }
  60.385 -
  60.386 -                ko.utils.forceRefresh(element);
  60.387 -            }
  60.388 -        },
  60.389 -
  60.390 -        setElementName: function(element, name) {
  60.391 -            element.name = name;
  60.392 -
  60.393 -            // Workaround IE 6/7 issue
  60.394 -            // - https://github.com/SteveSanderson/knockout/issues/197
  60.395 -            // - http://www.matts411.com/post/setting_the_name_attribute_in_ie_dom/
  60.396 -            if (ieVersion <= 7) {
  60.397 -                try {
  60.398 -                    element.mergeAttributes(document.createElement("<input name='" + element.name + "'/>"), false);
  60.399 -                }
  60.400 -                catch(e) {} // For IE9 with doc mode "IE9 Standards" and browser mode "IE9 Compatibility View"
  60.401 -            }
  60.402 -        },
  60.403 -
  60.404 -        forceRefresh: function(node) {
  60.405 -            // Workaround for an IE9 rendering bug - https://github.com/SteveSanderson/knockout/issues/209
  60.406 -            if (ieVersion >= 9) {
  60.407 -                // For text nodes and comment nodes (most likely virtual elements), we will have to refresh the container
  60.408 -                var elem = node.nodeType == 1 ? node : node.parentNode;
  60.409 -                if (elem.style)
  60.410 -                    elem.style.zoom = elem.style.zoom;
  60.411 -            }
  60.412 -        },
  60.413 -
  60.414 -        ensureSelectElementIsRenderedCorrectly: function(selectElement) {
  60.415 -            // Workaround for IE9 rendering bug - it doesn't reliably display all the text in dynamically-added select boxes unless you force it to re-render by updating the width.
  60.416 -            // (See https://github.com/SteveSanderson/knockout/issues/312, http://stackoverflow.com/questions/5908494/select-only-shows-first-char-of-selected-option)
  60.417 -            if (ieVersion >= 9) {
  60.418 -                var originalWidth = selectElement.style.width;
  60.419 -                selectElement.style.width = 0;
  60.420 -                selectElement.style.width = originalWidth;
  60.421 -            }
  60.422 -        },
  60.423 -
  60.424 -        range: function (min, max) {
  60.425 -            min = ko.utils.unwrapObservable(min);
  60.426 -            max = ko.utils.unwrapObservable(max);
  60.427 -            var result = [];
  60.428 -            for (var i = min; i <= max; i++)
  60.429 -                result.push(i);
  60.430 -            return result;
  60.431 -        },
  60.432 -
  60.433 -        makeArray: function(arrayLikeObject) {
  60.434 -            var result = [];
  60.435 -            for (var i = 0, j = arrayLikeObject.length; i < j; i++) {
  60.436 -                result.push(arrayLikeObject[i]);
  60.437 -            };
  60.438 -            return result;
  60.439 -        },
  60.440 -
  60.441 -        isIe6 : isIe6,
  60.442 -        isIe7 : isIe7,
  60.443 -        ieVersion : ieVersion,
  60.444 -
  60.445 -        getFormFields: function(form, fieldName) {
  60.446 -            var fields = ko.utils.makeArray(form.getElementsByTagName("input")).concat(ko.utils.makeArray(form.getElementsByTagName("textarea")));
  60.447 -            var isMatchingField = (typeof fieldName == 'string')
  60.448 -                ? function(field) { return field.name === fieldName }
  60.449 -                : function(field) { return fieldName.test(field.name) }; // Treat fieldName as regex or object containing predicate
  60.450 -            var matches = [];
  60.451 -            for (var i = fields.length - 1; i >= 0; i--) {
  60.452 -                if (isMatchingField(fields[i]))
  60.453 -                    matches.push(fields[i]);
  60.454 -            };
  60.455 -            return matches;
  60.456 -        },
  60.457 -
  60.458 -        parseJson: function (jsonString) {
  60.459 -            if (typeof jsonString == "string") {
  60.460 -                jsonString = ko.utils.stringTrim(jsonString);
  60.461 -                if (jsonString) {
  60.462 -                    if (window.JSON && window.JSON.parse) // Use native parsing where available
  60.463 -                        return window.JSON.parse(jsonString);
  60.464 -                    return (new Function("return " + jsonString))(); // Fallback on less safe parsing for older browsers
  60.465 -                }
  60.466 -            }
  60.467 -            return null;
  60.468 -        },
  60.469 -
  60.470 -        stringifyJson: function (data, replacer, space) {   // replacer and space are optional
  60.471 -            if ((typeof JSON == "undefined") || (typeof JSON.stringify == "undefined"))
  60.472 -                throw new Error("Cannot find JSON.stringify(). Some browsers (e.g., IE < 8) don't support it natively, but you can overcome this by adding a script reference to json2.js, downloadable from http://www.json.org/json2.js");
  60.473 -            return JSON.stringify(ko.utils.unwrapObservable(data), replacer, space);
  60.474 -        },
  60.475 -
  60.476 -        postJson: function (urlOrForm, data, options) {
  60.477 -            options = options || {};
  60.478 -            var params = options['params'] || {};
  60.479 -            var includeFields = options['includeFields'] || this.fieldsIncludedWithJsonPost;
  60.480 -            var url = urlOrForm;
  60.481 -
  60.482 -            // If we were given a form, use its 'action' URL and pick out any requested field values
  60.483 -            if((typeof urlOrForm == 'object') && (ko.utils.tagNameLower(urlOrForm) === "form")) {
  60.484 -                var originalForm = urlOrForm;
  60.485 -                url = originalForm.action;
  60.486 -                for (var i = includeFields.length - 1; i >= 0; i--) {
  60.487 -                    var fields = ko.utils.getFormFields(originalForm, includeFields[i]);
  60.488 -                    for (var j = fields.length - 1; j >= 0; j--)
  60.489 -                        params[fields[j].name] = fields[j].value;
  60.490 -                }
  60.491 -            }
  60.492 -
  60.493 -            data = ko.utils.unwrapObservable(data);
  60.494 -            var form = document.createElement("form");
  60.495 -            form.style.display = "none";
  60.496 -            form.action = url;
  60.497 -            form.method = "post";
  60.498 -            for (var key in data) {
  60.499 -                var input = document.createElement("input");
  60.500 -                input.name = key;
  60.501 -                input.value = ko.utils.stringifyJson(ko.utils.unwrapObservable(data[key]));
  60.502 -                form.appendChild(input);
  60.503 -            }
  60.504 -            for (var key in params) {
  60.505 -                var input = document.createElement("input");
  60.506 -                input.name = key;
  60.507 -                input.value = params[key];
  60.508 -                form.appendChild(input);
  60.509 -            }
  60.510 -            document.body.appendChild(form);
  60.511 -            options['submitter'] ? options['submitter'](form) : form.submit();
  60.512 -            setTimeout(function () { form.parentNode.removeChild(form); }, 0);
  60.513 -        }
  60.514 -    }
  60.515 -})();
  60.516 -
  60.517 -ko.exportSymbol('utils', ko.utils);
  60.518 -ko.exportSymbol('utils.arrayForEach', ko.utils.arrayForEach);
  60.519 -ko.exportSymbol('utils.arrayFirst', ko.utils.arrayFirst);
  60.520 -ko.exportSymbol('utils.arrayFilter', ko.utils.arrayFilter);
  60.521 -ko.exportSymbol('utils.arrayGetDistinctValues', ko.utils.arrayGetDistinctValues);
  60.522 -ko.exportSymbol('utils.arrayIndexOf', ko.utils.arrayIndexOf);
  60.523 -ko.exportSymbol('utils.arrayMap', ko.utils.arrayMap);
  60.524 -ko.exportSymbol('utils.arrayPushAll', ko.utils.arrayPushAll);
  60.525 -ko.exportSymbol('utils.arrayRemoveItem', ko.utils.arrayRemoveItem);
  60.526 -ko.exportSymbol('utils.extend', ko.utils.extend);
  60.527 -ko.exportSymbol('utils.fieldsIncludedWithJsonPost', ko.utils.fieldsIncludedWithJsonPost);
  60.528 -ko.exportSymbol('utils.getFormFields', ko.utils.getFormFields);
  60.529 -ko.exportSymbol('utils.peekObservable', ko.utils.peekObservable);
  60.530 -ko.exportSymbol('utils.postJson', ko.utils.postJson);
  60.531 -ko.exportSymbol('utils.parseJson', ko.utils.parseJson);
  60.532 -ko.exportSymbol('utils.registerEventHandler', ko.utils.registerEventHandler);
  60.533 -ko.exportSymbol('utils.stringifyJson', ko.utils.stringifyJson);
  60.534 -ko.exportSymbol('utils.range', ko.utils.range);
  60.535 -ko.exportSymbol('utils.toggleDomNodeCssClass', ko.utils.toggleDomNodeCssClass);
  60.536 -ko.exportSymbol('utils.triggerEvent', ko.utils.triggerEvent);
  60.537 -ko.exportSymbol('utils.unwrapObservable', ko.utils.unwrapObservable);
  60.538 -
  60.539 -if (!Function.prototype['bind']) {
  60.540 -    // Function.prototype.bind is a standard part of ECMAScript 5th Edition (December 2009, http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf)
  60.541 -    // In case the browser doesn't implement it natively, provide a JavaScript implementation. This implementation is based on the one in prototype.js
  60.542 -    Function.prototype['bind'] = function (object) {
  60.543 -        var originalFunction = this, args = Array.prototype.slice.call(arguments), object = args.shift();
  60.544 -        return function () {
  60.545 -            return originalFunction.apply(object, args.concat(Array.prototype.slice.call(arguments)));
  60.546 -        };
  60.547 -    };
  60.548 -}
  60.549 -
  60.550 -ko.utils.domData = new (function () {
  60.551 -    var uniqueId = 0;
  60.552 -    var dataStoreKeyExpandoPropertyName = "__ko__" + (new Date).getTime();
  60.553 -    var dataStore = {};
  60.554 -    return {
  60.555 -        get: function (node, key) {
  60.556 -            var allDataForNode = ko.utils.domData.getAll(node, false);
  60.557 -            return allDataForNode === undefined ? undefined : allDataForNode[key];
  60.558 -        },
  60.559 -        set: function (node, key, value) {
  60.560 -            if (value === undefined) {
  60.561 -                // Make sure we don't actually create a new domData key if we are actually deleting a value
  60.562 -                if (ko.utils.domData.getAll(node, false) === undefined)
  60.563 -                    return;
  60.564 -            }
  60.565 -            var allDataForNode = ko.utils.domData.getAll(node, true);
  60.566 -            allDataForNode[key] = value;
  60.567 -        },
  60.568 -        getAll: function (node, createIfNotFound) {
  60.569 -            var dataStoreKey = node[dataStoreKeyExpandoPropertyName];
  60.570 -            var hasExistingDataStore = dataStoreKey && (dataStoreKey !== "null") && dataStore[dataStoreKey];
  60.571 -            if (!hasExistingDataStore) {
  60.572 -                if (!createIfNotFound)
  60.573 -                    return undefined;
  60.574 -                dataStoreKey = node[dataStoreKeyExpandoPropertyName] = "ko" + uniqueId++;
  60.575 -                dataStore[dataStoreKey] = {};
  60.576 -            }
  60.577 -            return dataStore[dataStoreKey];
  60.578 -        },
  60.579 -        clear: function (node) {
  60.580 -            var dataStoreKey = node[dataStoreKeyExpandoPropertyName];
  60.581 -            if (dataStoreKey) {
  60.582 -                delete dataStore[dataStoreKey];
  60.583 -                node[dataStoreKeyExpandoPropertyName] = null;
  60.584 -                return true; // Exposing "did clean" flag purely so specs can infer whether things have been cleaned up as intended
  60.585 -            }
  60.586 -            return false;
  60.587 -        }
  60.588 -    }
  60.589 -})();
  60.590 -
  60.591 -ko.exportSymbol('utils.domData', ko.utils.domData);
  60.592 -ko.exportSymbol('utils.domData.clear', ko.utils.domData.clear); // Exporting only so specs can clear up after themselves fully
  60.593 -
  60.594 -ko.utils.domNodeDisposal = new (function () {
  60.595 -    var domDataKey = "__ko_domNodeDisposal__" + (new Date).getTime();
  60.596 -    var cleanableNodeTypes = { 1: true, 8: true, 9: true };       // Element, Comment, Document
  60.597 -    var cleanableNodeTypesWithDescendants = { 1: true, 9: true }; // Element, Document
  60.598 -
  60.599 -    function getDisposeCallbacksCollection(node, createIfNotFound) {
  60.600 -        var allDisposeCallbacks = ko.utils.domData.get(node, domDataKey);
  60.601 -        if ((allDisposeCallbacks === undefined) && createIfNotFound) {
  60.602 -            allDisposeCallbacks = [];
  60.603 -            ko.utils.domData.set(node, domDataKey, allDisposeCallbacks);
  60.604 -        }
  60.605 -        return allDisposeCallbacks;
  60.606 -    }
  60.607 -    function destroyCallbacksCollection(node) {
  60.608 -        ko.utils.domData.set(node, domDataKey, undefined);
  60.609 -    }
  60.610 -
  60.611 -    function cleanSingleNode(node) {
  60.612 -        // Run all the dispose callbacks
  60.613 -        var callbacks = getDisposeCallbacksCollection(node, false);
  60.614 -        if (callbacks) {
  60.615 -            callbacks = callbacks.slice(0); // Clone, as the array may be modified during iteration (typically, callbacks will remove themselves)
  60.616 -            for (var i = 0; i < callbacks.length; i++)
  60.617 -                callbacks[i](node);
  60.618 -        }
  60.619 -
  60.620 -        // Also erase the DOM data
  60.621 -        ko.utils.domData.clear(node);
  60.622 -
  60.623 -        // Special support for jQuery here because it's so commonly used.
  60.624 -        // Many jQuery plugins (including jquery.tmpl) store data using jQuery's equivalent of domData
  60.625 -        // so notify it to tear down any resources associated with the node & descendants here.
  60.626 -        if ((typeof jQuery == "function") && (typeof jQuery['cleanData'] == "function"))
  60.627 -            jQuery['cleanData']([node]);
  60.628 -
  60.629 -        // Also clear any immediate-child comment nodes, as these wouldn't have been found by
  60.630 -        // node.getElementsByTagName("*") in cleanNode() (comment nodes aren't elements)
  60.631 -        if (cleanableNodeTypesWithDescendants[node.nodeType])
  60.632 -            cleanImmediateCommentTypeChildren(node);
  60.633 -    }
  60.634 -
  60.635 -    function cleanImmediateCommentTypeChildren(nodeWithChildren) {
  60.636 -        var child, nextChild = nodeWithChildren.firstChild;
  60.637 -        while (child = nextChild) {
  60.638 -            nextChild = child.nextSibling;
  60.639 -            if (child.nodeType === 8)
  60.640 -                cleanSingleNode(child);
  60.641 -        }
  60.642 -    }
  60.643 -
  60.644 -    return {
  60.645 -        addDisposeCallback : function(node, callback) {
  60.646 -            if (typeof callback != "function")
  60.647 -                throw new Error("Callback must be a function");
  60.648 -            getDisposeCallbacksCollection(node, true).push(callback);
  60.649 -        },
  60.650 -
  60.651 -        removeDisposeCallback : function(node, callback) {
  60.652 -            var callbacksCollection = getDisposeCallbacksCollection(node, false);
  60.653 -            if (callbacksCollection) {
  60.654 -                ko.utils.arrayRemoveItem(callbacksCollection, callback);
  60.655 -                if (callbacksCollection.length == 0)
  60.656 -                    destroyCallbacksCollection(node);
  60.657 -            }
  60.658 -        },
  60.659 -
  60.660 -        cleanNode : function(node) {
  60.661 -            // First clean this node, where applicable
  60.662 -            if (cleanableNodeTypes[node.nodeType]) {
  60.663 -                cleanSingleNode(node);
  60.664 -
  60.665 -                // ... then its descendants, where applicable
  60.666 -                if (cleanableNodeTypesWithDescendants[node.nodeType]) {
  60.667 -                    // Clone the descendants list in case it changes during iteration
  60.668 -                    var descendants = [];
  60.669 -                    ko.utils.arrayPushAll(descendants, node.getElementsByTagName("*"));
  60.670 -                    for (var i = 0, j = descendants.length; i < j; i++)
  60.671 -                        cleanSingleNode(descendants[i]);
  60.672 -                }
  60.673 -            }
  60.674 -            return node;
  60.675 -        },
  60.676 -
  60.677 -        removeNode : function(node) {
  60.678 -            ko.cleanNode(node);
  60.679 -            if (node.parentNode)
  60.680 -                node.parentNode.removeChild(node);
  60.681 -        }
  60.682 -    }
  60.683 -})();
  60.684 -ko.cleanNode = ko.utils.domNodeDisposal.cleanNode; // Shorthand name for convenience
  60.685 -ko.removeNode = ko.utils.domNodeDisposal.removeNode; // Shorthand name for convenience
  60.686 -ko.exportSymbol('cleanNode', ko.cleanNode);
  60.687 -ko.exportSymbol('removeNode', ko.removeNode);
  60.688 -ko.exportSymbol('utils.domNodeDisposal', ko.utils.domNodeDisposal);
  60.689 -ko.exportSymbol('utils.domNodeDisposal.addDisposeCallback', ko.utils.domNodeDisposal.addDisposeCallback);
  60.690 -ko.exportSymbol('utils.domNodeDisposal.removeDisposeCallback', ko.utils.domNodeDisposal.removeDisposeCallback);
  60.691 -(function () {
  60.692 -    var leadingCommentRegex = /^(\s*)<!--(.*?)-->/;
  60.693 -
  60.694 -    function simpleHtmlParse(html) {
  60.695 -        // Based on jQuery's "clean" function, but only accounting for table-related elements.
  60.696 -        // If you have referenced jQuery, this won't be used anyway - KO will use jQuery's "clean" function directly
  60.697 -
  60.698 -        // Note that there's still an issue in IE < 9 whereby it will discard comment nodes that are the first child of
  60.699 -        // a descendant node. For example: "<div><!-- mycomment -->abc</div>" will get parsed as "<div>abc</div>"
  60.700 -        // This won't affect anyone who has referenced jQuery, and there's always the workaround of inserting a dummy node
  60.701 -        // (possibly a text node) in front of the comment. So, KO does not attempt to workaround this IE issue automatically at present.
  60.702 -
  60.703 -        // Trim whitespace, otherwise indexOf won't work as expected
  60.704 -        var tags = ko.utils.stringTrim(html).toLowerCase(), div = document.createElement("div");
  60.705 -
  60.706 -        // Finds the first match from the left column, and returns the corresponding "wrap" data from the right column
  60.707 -        var wrap = tags.match(/^<(thead|tbody|tfoot)/)              && [1, "<table>", "</table>"] ||
  60.708 -                   !tags.indexOf("<tr")                             && [2, "<table><tbody>", "</tbody></table>"] ||
  60.709 -                   (!tags.indexOf("<td") || !tags.indexOf("<th"))   && [3, "<table><tbody><tr>", "</tr></tbody></table>"] ||
  60.710 -                   /* anything else */                                 [0, "", ""];
  60.711 -
  60.712 -        // Go to html and back, then peel off extra wrappers
  60.713 -        // Note that we always prefix with some dummy text, because otherwise, IE<9 will strip out leading comment nodes in descendants. Total madness.
  60.714 -        var markup = "ignored<div>" + wrap[1] + html + wrap[2] + "</div>";
  60.715 -        if (typeof window['innerShiv'] == "function") {
  60.716 -            div.appendChild(window['innerShiv'](markup));
  60.717 -        } else {
  60.718 -            div.innerHTML = markup;
  60.719 -        }
  60.720 -
  60.721 -        // Move to the right depth
  60.722 -        while (wrap[0]--)
  60.723 -            div = div.lastChild;
  60.724 -
  60.725 -        return ko.utils.makeArray(div.lastChild.childNodes);
  60.726 -    }
  60.727 -
  60.728 -    function jQueryHtmlParse(html) {
  60.729 -        // jQuery's "parseHTML" function was introduced in jQuery 1.8.0 and is a documented public API.
  60.730 -        if (jQuery['parseHTML']) {
  60.731 -            return jQuery['parseHTML'](html);
  60.732 -        } else {
  60.733 -            // For jQuery < 1.8.0, we fall back on the undocumented internal "clean" function.
  60.734 -            var elems = jQuery['clean']([html]);
  60.735 -
  60.736 -            // As of jQuery 1.7.1, jQuery parses the HTML by appending it to some dummy parent nodes held in an in-memory document fragment.
  60.737 -            // Unfortunately, it never clears the dummy parent nodes from the document fragment, so it leaks memory over time.
  60.738 -            // Fix this by finding the top-most dummy parent element, and detaching it from its owner fragment.
  60.739 -            if (elems && elems[0]) {
  60.740 -                // Find the top-most parent element that's a direct child of a document fragment
  60.741 -                var elem = elems[0];
  60.742 -                while (elem.parentNode && elem.parentNode.nodeType !== 11 /* i.e., DocumentFragment */)
  60.743 -                    elem = elem.parentNode;
  60.744 -                // ... then detach it
  60.745 -                if (elem.parentNode)
  60.746 -                    elem.parentNode.removeChild(elem);
  60.747 -            }
  60.748 -
  60.749 -            return elems;
  60.750 -        }
  60.751 -    }
  60.752 -
  60.753 -    ko.utils.parseHtmlFragment = function(html) {
  60.754 -        return typeof jQuery != 'undefined' ? jQueryHtmlParse(html)   // As below, benefit from jQuery's optimisations where possible
  60.755 -                                            : simpleHtmlParse(html);  // ... otherwise, this simple logic will do in most common cases.
  60.756 -    };
  60.757 -
  60.758 -    ko.utils.setHtml = function(node, html) {
  60.759 -        ko.utils.emptyDomNode(node);
  60.760 -
  60.761 -        // There's no legitimate reason to display a stringified observable without unwrapping it, so we'll unwrap it
  60.762 -        html = ko.utils.unwrapObservable(html);
  60.763 -
  60.764 -        if ((html !== null) && (html !== undefined)) {
  60.765 -            if (typeof html != 'string')
  60.766 -                html = html.toString();
  60.767 -
  60.768 -            // jQuery contains a lot of sophisticated code to parse arbitrary HTML fragments,
  60.769 -            // for example <tr> elements which are not normally allowed to exist on their own.
  60.770 -            // If you've referenced jQuery we'll use that rather than duplicating its code.
  60.771 -            if (typeof jQuery != 'undefined') {
  60.772 -                jQuery(node)['html'](html);
  60.773 -            } else {
  60.774 -                // ... otherwise, use KO's own parsing logic.
  60.775 -                var parsedNodes = ko.utils.parseHtmlFragment(html);
  60.776 -                for (var i = 0; i < parsedNodes.length; i++)
  60.777 -                    node.appendChild(parsedNodes[i]);
  60.778 -            }
  60.779 -        }
  60.780 -    };
  60.781 -})();
  60.782 -
  60.783 -ko.exportSymbol('utils.parseHtmlFragment', ko.utils.parseHtmlFragment);
  60.784 -ko.exportSymbol('utils.setHtml', ko.utils.setHtml);
  60.785 -
  60.786 -ko.memoization = (function () {
  60.787 -    var memos = {};
  60.788 -
  60.789 -    function randomMax8HexChars() {
  60.790 -        return (((1 + Math.random()) * 0x100000000) | 0).toString(16).substring(1);
  60.791 -    }
  60.792 -    function generateRandomId() {
  60.793 -        return randomMax8HexChars() + randomMax8HexChars();
  60.794 -    }
  60.795 -    function findMemoNodes(rootNode, appendToArray) {
  60.796 -        if (!rootNode)
  60.797 -            return;
  60.798 -        if (rootNode.nodeType == 8) {
  60.799 -            var memoId = ko.memoization.parseMemoText(rootNode.nodeValue);
  60.800 -            if (memoId != null)
  60.801 -                appendToArray.push({ domNode: rootNode, memoId: memoId });
  60.802 -        } else if (rootNode.nodeType == 1) {
  60.803 -            for (var i = 0, childNodes = rootNode.childNodes, j = childNodes.length; i < j; i++)
  60.804 -                findMemoNodes(childNodes[i], appendToArray);
  60.805 -        }
  60.806 -    }
  60.807 -
  60.808 -    return {
  60.809 -        memoize: function (callback) {
  60.810 -            if (typeof callback != "function")
  60.811 -                throw new Error("You can only pass a function to ko.memoization.memoize()");
  60.812 -            var memoId = generateRandomId();
  60.813 -            memos[memoId] = callback;
  60.814 -            return "<!--[ko_memo:" + memoId + "]-->";
  60.815 -        },
  60.816 -
  60.817 -        unmemoize: function (memoId, callbackParams) {
  60.818 -            var callback = memos[memoId];
  60.819 -            if (callback === undefined)
  60.820 -                throw new Error("Couldn't find any memo with ID " + memoId + ". Perhaps it's already been unmemoized.");
  60.821 -            try {
  60.822 -                callback.apply(null, callbackParams || []);
  60.823 -                return true;
  60.824 -            }
  60.825 -            finally { delete memos[memoId]; }
  60.826 -        },
  60.827 -
  60.828 -        unmemoizeDomNodeAndDescendants: function (domNode, extraCallbackParamsArray) {
  60.829 -            var memos = [];
  60.830 -            findMemoNodes(domNode, memos);
  60.831 -            for (var i = 0, j = memos.length; i < j; i++) {
  60.832 -                var node = memos[i].domNode;
  60.833 -                var combinedParams = [node];
  60.834 -                if (extraCallbackParamsArray)
  60.835 -                    ko.utils.arrayPushAll(combinedParams, extraCallbackParamsArray);
  60.836 -                ko.memoization.unmemoize(memos[i].memoId, combinedParams);
  60.837 -                node.nodeValue = ""; // Neuter this node so we don't try to unmemoize it again
  60.838 -                if (node.parentNode)
  60.839 -                    node.parentNode.removeChild(node); // If possible, erase it totally (not always possible - someone else might just hold a reference to it then call unmemoizeDomNodeAndDescendants again)
  60.840 -            }
  60.841 -        },
  60.842 -
  60.843 -        parseMemoText: function (memoText) {
  60.844 -            var match = memoText.match(/^\[ko_memo\:(.*?)\]$/);
  60.845 -            return match ? match[1] : null;
  60.846 -        }
  60.847 -    };
  60.848 -})();
  60.849 -
  60.850 -ko.exportSymbol('memoization', ko.memoization);
  60.851 -ko.exportSymbol('memoization.memoize', ko.memoization.memoize);
  60.852 -ko.exportSymbol('memoization.unmemoize', ko.memoization.unmemoize);
  60.853 -ko.exportSymbol('memoization.parseMemoText', ko.memoization.parseMemoText);
  60.854 -ko.exportSymbol('memoization.unmemoizeDomNodeAndDescendants', ko.memoization.unmemoizeDomNodeAndDescendants);
  60.855 -ko.extenders = {
  60.856 -    'throttle': function(target, timeout) {
  60.857 -        // Throttling means two things:
  60.858 -
  60.859 -        // (1) For dependent observables, we throttle *evaluations* so that, no matter how fast its dependencies
  60.860 -        //     notify updates, the target doesn't re-evaluate (and hence doesn't notify) faster than a certain rate
  60.861 -        target['throttleEvaluation'] = timeout;
  60.862 -
  60.863 -        // (2) For writable targets (observables, or writable dependent observables), we throttle *writes*
  60.864 -        //     so the target cannot change value synchronously or faster than a certain rate
  60.865 -        var writeTimeoutInstance = null;
  60.866 -        return ko.dependentObservable({
  60.867 -            'read': target,
  60.868 -            'write': function(value) {
  60.869 -                clearTimeout(writeTimeoutInstance);
  60.870 -                writeTimeoutInstance = setTimeout(function() {
  60.871 -                    target(value);
  60.872 -                }, timeout);
  60.873 -            }
  60.874 -        });
  60.875 -    },
  60.876 -
  60.877 -    'notify': function(target, notifyWhen) {
  60.878 -        target["equalityComparer"] = notifyWhen == "always"
  60.879 -            ? function() { return false } // Treat all values as not equal
  60.880 -            : ko.observable["fn"]["equalityComparer"];
  60.881 -        return target;
  60.882 -    }
  60.883 -};
  60.884 -
  60.885 -function applyExtenders(requestedExtenders) {
  60.886 -    var target = this;
  60.887 -    if (requestedExtenders) {
  60.888 -        for (var key in requestedExtenders) {
  60.889 -            var extenderHandler = ko.extenders[key];
  60.890 -            if (typeof extenderHandler == 'function') {
  60.891 -                target = extenderHandler(target, requestedExtenders[key]);
  60.892 -            }
  60.893 -        }
  60.894 -    }
  60.895 -    return target;
  60.896 -}
  60.897 -
  60.898 -ko.exportSymbol('extenders', ko.extenders);
  60.899 -
  60.900 -ko.subscription = function (target, callback, disposeCallback) {
  60.901 -    this.target = target;
  60.902 -    this.callback = callback;
  60.903 -    this.disposeCallback = disposeCallback;
  60.904 -    ko.exportProperty(this, 'dispose', this.dispose);
  60.905 -};
  60.906 -ko.subscription.prototype.dispose = function () {
  60.907 -    this.isDisposed = true;
  60.908 -    this.disposeCallback();
  60.909 -};
  60.910 -
  60.911 -ko.subscribable = function () {
  60.912 -    this._subscriptions = {};
  60.913 -
  60.914 -    ko.utils.extend(this, ko.subscribable['fn']);
  60.915 -    ko.exportProperty(this, 'subscribe', this.subscribe);
  60.916 -    ko.exportProperty(this, 'extend', this.extend);
  60.917 -    ko.exportProperty(this, 'getSubscriptionsCount', this.getSubscriptionsCount);
  60.918 -}
  60.919 -
  60.920 -var defaultEvent = "change";
  60.921 -
  60.922 -ko.subscribable['fn'] = {
  60.923 -    subscribe: function (callback, callbackTarget, event) {
  60.924 -        event = event || defaultEvent;
  60.925 -        var boundCallback = callbackTarget ? callback.bind(callbackTarget) : callback;
  60.926 -
  60.927 -        var subscription = new ko.subscription(this, boundCallback, function () {
  60.928 -            ko.utils.arrayRemoveItem(this._subscriptions[event], subscription);
  60.929 -        }.bind(this));
  60.930 -
  60.931 -        if (!this._subscriptions[event])
  60.932 -            this._subscriptions[event] = [];
  60.933 -        this._subscriptions[event].push(subscription);
  60.934 -        return subscription;
  60.935 -    },
  60.936 -
  60.937 -    "notifySubscribers": function (valueToNotify, event) {
  60.938 -        event = event || defaultEvent;
  60.939 -        if (this._subscriptions[event]) {
  60.940 -            ko.dependencyDetection.ignore(function() {
  60.941 -                ko.utils.arrayForEach(this._subscriptions[event].slice(0), function (subscription) {
  60.942 -                    // In case a subscription was disposed during the arrayForEach cycle, check
  60.943 -                    // for isDisposed on each subscription before invoking its callback
  60.944 -                    if (subscription && (subscription.isDisposed !== true))
  60.945 -                        subscription.callback(valueToNotify);
  60.946 -                });
  60.947 -            }, this);
  60.948 -        }
  60.949 -    },
  60.950 -
  60.951 -    getSubscriptionsCount: function () {
  60.952 -        var total = 0;
  60.953 -        for (var eventName in this._subscriptions) {
  60.954 -            if (this._subscriptions.hasOwnProperty(eventName))
  60.955 -                total += this._subscriptions[eventName].length;
  60.956 -        }
  60.957 -        return total;
  60.958 -    },
  60.959 -
  60.960 -    extend: applyExtenders
  60.961 -};
  60.962 -
  60.963 -
  60.964 -ko.isSubscribable = function (instance) {
  60.965 -    return typeof instance.subscribe == "function" && typeof instance["notifySubscribers"] == "function";
  60.966 -};
  60.967 -
  60.968 -ko.exportSymbol('subscribable', ko.subscribable);
  60.969 -ko.exportSymbol('isSubscribable', ko.isSubscribable);
  60.970 -
  60.971 -ko.dependencyDetection = (function () {
  60.972 -    var _frames = [];
  60.973 -
  60.974 -    return {
  60.975 -        begin: function (callback) {
  60.976 -            _frames.push({ callback: callback, distinctDependencies:[] });
  60.977 -        },
  60.978 -
  60.979 -        end: function () {
  60.980 -            _frames.pop();
  60.981 -        },
  60.982 -
  60.983 -        registerDependency: function (subscribable) {
  60.984 -            if (!ko.isSubscribable(subscribable))
  60.985 -                throw new Error("Only subscribable things can act as dependencies");
  60.986 -            if (_frames.length > 0) {
  60.987 -                var topFrame = _frames[_frames.length - 1];
  60.988 -                if (!topFrame || ko.utils.arrayIndexOf(topFrame.distinctDependencies, subscribable) >= 0)
  60.989 -                    return;
  60.990 -                topFrame.distinctDependencies.push(subscribable);
  60.991 -                topFrame.callback(subscribable);
  60.992 -            }
  60.993 -        },
  60.994 -
  60.995 -        ignore: function(callback, callbackTarget, callbackArgs) {
  60.996 -            try {
  60.997 -                _frames.push(null);
  60.998 -                return callback.apply(callbackTarget, callbackArgs || []);
  60.999 -            } finally {
 60.1000 -                _frames.pop();
 60.1001 -            }
 60.1002 -        }
 60.1003 -    };
 60.1004 -})();
 60.1005 -var primitiveTypes = { 'undefined':true, 'boolean':true, 'number':true, 'string':true };
 60.1006 -
 60.1007 -ko.observable = function (initialValue) {
 60.1008 -    var _latestValue = initialValue;
 60.1009 -
 60.1010 -    function observable() {
 60.1011 -        if (arguments.length > 0) {
 60.1012 -            // Write
 60.1013 -
 60.1014 -            // Ignore writes if the value hasn't changed
 60.1015 -            if ((!observable['equalityComparer']) || !observable['equalityComparer'](_latestValue, arguments[0])) {
 60.1016 -                observable.valueWillMutate();
 60.1017 -                _latestValue = arguments[0];
 60.1018 -                if (DEBUG) observable._latestValue = _latestValue;
 60.1019 -                observable.valueHasMutated();
 60.1020 -            }
 60.1021 -            return this; // Permits chained assignments
 60.1022 -        }
 60.1023 -        else {
 60.1024 -            // Read
 60.1025 -            ko.dependencyDetection.registerDependency(observable); // The caller only needs to be notified of changes if they did a "read" operation
 60.1026 -            return _latestValue;
 60.1027 -        }
 60.1028 -    }
 60.1029 -    if (DEBUG) observable._latestValue = _latestValue;
 60.1030 -    ko.subscribable.call(observable);
 60.1031 -    observable.peek = function() { return _latestValue };
 60.1032 -    observable.valueHasMutated = function () { observable["notifySubscribers"](_latestValue); }
 60.1033 -    observable.valueWillMutate = function () { observable["notifySubscribers"](_latestValue, "beforeChange"); }
 60.1034 -    ko.utils.extend(observable, ko.observable['fn']);
 60.1035 -
 60.1036 -    ko.exportProperty(observable, 'peek', observable.peek);
 60.1037 -    ko.exportProperty(observable, "valueHasMutated", observable.valueHasMutated);
 60.1038 -    ko.exportProperty(observable, "valueWillMutate", observable.valueWillMutate);
 60.1039 -
 60.1040 -    return observable;
 60.1041 -}
 60.1042 -
 60.1043 -ko.observable['fn'] = {
 60.1044 -    "equalityComparer": function valuesArePrimitiveAndEqual(a, b) {
 60.1045 -        var oldValueIsPrimitive = (a === null) || (typeof(a) in primitiveTypes);
 60.1046 -        return oldValueIsPrimitive ? (a === b) : false;
 60.1047 -    }
 60.1048 -};
 60.1049 -
 60.1050 -var protoProperty = ko.observable.protoProperty = "__ko_proto__";
 60.1051 -ko.observable['fn'][protoProperty] = ko.observable;
 60.1052 -
 60.1053 -ko.hasPrototype = function(instance, prototype) {
 60.1054 -    if ((instance === null) || (instance === undefined) || (instance[protoProperty] === undefined)) return false;
 60.1055 -    if (instance[protoProperty] === prototype) return true;
 60.1056 -    return ko.hasPrototype(instance[protoProperty], prototype); // Walk the prototype chain
 60.1057 -};
 60.1058 -
 60.1059 -ko.isObservable = function (instance) {
 60.1060 -    return ko.hasPrototype(instance, ko.observable);
 60.1061 -}
 60.1062 -ko.isWriteableObservable = function (instance) {
 60.1063 -    // Observable
 60.1064 -    if ((typeof instance == "function") && instance[protoProperty] === ko.observable)
 60.1065 -        return true;
 60.1066 -    // Writeable dependent observable
 60.1067 -    if ((typeof instance == "function") && (instance[protoProperty] === ko.dependentObservable) && (instance.hasWriteFunction))
 60.1068 -        return true;
 60.1069 -    // Anything else
 60.1070 -    return false;
 60.1071 -}
 60.1072 -
 60.1073 -
 60.1074 -ko.exportSymbol('observable', ko.observable);
 60.1075 -ko.exportSymbol('isObservable', ko.isObservable);
 60.1076 -ko.exportSymbol('isWriteableObservable', ko.isWriteableObservable);
 60.1077 -ko.observableArray = function (initialValues) {
 60.1078 -    if (arguments.length == 0) {
 60.1079 -        // Zero-parameter constructor initializes to empty array
 60.1080 -        initialValues = [];
 60.1081 -    }
 60.1082 -    if ((initialValues !== null) && (initialValues !== undefined) && !('length' in initialValues))
 60.1083 -        throw new Error("The argument passed when initializing an observable array must be an array, or null, or undefined.");
 60.1084 -
 60.1085 -    var result = ko.observable(initialValues);
 60.1086 -    ko.utils.extend(result, ko.observableArray['fn']);
 60.1087 -    return result;
 60.1088 -}
 60.1089 -
 60.1090 -ko.observableArray['fn'] = {
 60.1091 -    'remove': function (valueOrPredicate) {
 60.1092 -        var underlyingArray = this.peek();
 60.1093 -        var removedValues = [];
 60.1094 -        var predicate = typeof valueOrPredicate == "function" ? valueOrPredicate : function (value) { return value === valueOrPredicate; };
 60.1095 -        for (var i = 0; i < underlyingArray.length; i++) {
 60.1096 -            var value = underlyingArray[i];
 60.1097 -            if (predicate(value)) {
 60.1098 -                if (removedValues.length === 0) {
 60.1099 -                    this.valueWillMutate();
 60.1100 -                }
 60.1101 -                removedValues.push(value);
 60.1102 -                underlyingArray.splice(i, 1);
 60.1103 -                i--;
 60.1104 -            }
 60.1105 -        }
 60.1106 -        if (removedValues.length) {
 60.1107 -            this.valueHasMutated();
 60.1108 -        }
 60.1109 -        return removedValues;
 60.1110 -    },
 60.1111 -
 60.1112 -    'removeAll': function (arrayOfValues) {
 60.1113 -        // If you passed zero args, we remove everything
 60.1114 -        if (arrayOfValues === undefined) {
 60.1115 -            var underlyingArray = this.peek();
 60.1116 -            var allValues = underlyingArray.slice(0);
 60.1117 -            this.valueWillMutate();
 60.1118 -            underlyingArray.splice(0, underlyingArray.length);
 60.1119 -            this.valueHasMutated();
 60.1120 -            return allValues;
 60.1121 -        }
 60.1122 -        // If you passed an arg, we interpret it as an array of entries to remove
 60.1123 -        if (!arrayOfValues)
 60.1124 -            return [];
 60.1125 -        return this['remove'](function (value) {
 60.1126 -            return ko.utils.arrayIndexOf(arrayOfValues, value) >= 0;
 60.1127 -        });
 60.1128 -    },
 60.1129 -
 60.1130 -    'destroy': function (valueOrPredicate) {
 60.1131 -        var underlyingArray = this.peek();
 60.1132 -        var predicate = typeof valueOrPredicate == "function" ? valueOrPredicate : function (value) { return value === valueOrPredicate; };
 60.1133 -        this.valueWillMutate();
 60.1134 -        for (var i = underlyingArray.length - 1; i >= 0; i--) {
 60.1135 -            var value = underlyingArray[i];
 60.1136 -            if (predicate(value))
 60.1137 -                underlyingArray[i]["_destroy"] = true;
 60.1138 -        }
 60.1139 -        this.valueHasMutated();
 60.1140 -    },
 60.1141 -
 60.1142 -    'destroyAll': function (arrayOfValues) {
 60.1143 -        // If you passed zero args, we destroy everything
 60.1144 -        if (arrayOfValues === undefined)
 60.1145 -            return this['destroy'](function() { return true });
 60.1146 -
 60.1147 -        // If you passed an arg, we interpret it as an array of entries to destroy
 60.1148 -        if (!arrayOfValues)
 60.1149 -            return [];
 60.1150 -        return this['destroy'](function (value) {
 60.1151 -            return ko.utils.arrayIndexOf(arrayOfValues, value) >= 0;
 60.1152 -        });
 60.1153 -    },
 60.1154 -
 60.1155 -    'indexOf': function (item) {
 60.1156 -        var underlyingArray = this();
 60.1157 -        return ko.utils.arrayIndexOf(underlyingArray, item);
 60.1158 -    },
 60.1159 -
 60.1160 -    'replace': function(oldItem, newItem) {
 60.1161 -        var index = this['indexOf'](oldItem);
 60.1162 -        if (index >= 0) {
 60.1163 -            this.valueWillMutate();
 60.1164 -            this.peek()[index] = newItem;
 60.1165 -            this.valueHasMutated();
 60.1166 -        }
 60.1167 -    }
 60.1168 -}
 60.1169 -
 60.1170 -// Populate ko.observableArray.fn with read/write functions from native arrays
 60.1171 -// Important: Do not add any additional functions here that may reasonably be used to *read* data from the array
 60.1172 -// because we'll eval them without causing subscriptions, so ko.computed output could end up getting stale
 60.1173 -ko.utils.arrayForEach(["pop", "push", "reverse", "shift", "sort", "splice", "unshift"], function (methodName) {
 60.1174 -    ko.observableArray['fn'][methodName] = function () {
 60.1175 -        // Use "peek" to avoid creating a subscription in any computed that we're executing in the context of
 60.1176 -        // (for consistency with mutating regular observables)
 60.1177 -        var underlyingArray = this.peek();
 60.1178 -        this.valueWillMutate();
 60.1179 -        var methodCallResult = underlyingArray[methodName].apply(underlyingArray, arguments);
 60.1180 -        this.valueHasMutated();
 60.1181 -        return methodCallResult;
 60.1182 -    };
 60.1183 -});
 60.1184 -
 60.1185 -// Populate ko.observableArray.fn with read-only functions from native arrays
 60.1186 -ko.utils.arrayForEach(["slice"], function (methodName) {
 60.1187 -    ko.observableArray['fn'][methodName] = function () {
 60.1188 -        var underlyingArray = this();
 60.1189 -        return underlyingArray[methodName].apply(underlyingArray, arguments);
 60.1190 -    };
 60.1191 -});
 60.1192 -
 60.1193 -ko.exportSymbol('observableArray', ko.observableArray);
 60.1194 -ko.dependentObservable = function (evaluatorFunctionOrOptions, evaluatorFunctionTarget, options) {
 60.1195 -    var _latestValue,
 60.1196 -        _hasBeenEvaluated = false,
 60.1197 -        _isBeingEvaluated = false,
 60.1198 -        readFunction = evaluatorFunctionOrOptions;
 60.1199 -
 60.1200 -    if (readFunction && typeof readFunction == "object") {
 60.1201 -        // Single-parameter syntax - everything is on this "options" param
 60.1202 -        options = readFunction;
 60.1203 -        readFunction = options["read"];
 60.1204 -    } else {
 60.1205 -        // Multi-parameter syntax - construct the options according to the params passed
 60.1206 -        options = options || {};
 60.1207 -        if (!readFunction)
 60.1208 -            readFunction = options["read"];
 60.1209 -    }
 60.1210 -    if (typeof readFunction != "function")
 60.1211 -        throw new Error("Pass a function that returns the value of the ko.computed");
 60.1212 -
 60.1213 -    function addSubscriptionToDependency(subscribable) {
 60.1214 -        _subscriptionsToDependencies.push(subscribable.subscribe(evaluatePossiblyAsync));
 60.1215 -    }
 60.1216 -
 60.1217 -    function disposeAllSubscriptionsToDependencies() {
 60.1218 -        ko.utils.arrayForEach(_subscriptionsToDependencies, function (subscription) {
 60.1219 -            subscription.dispose();
 60.1220 -        });
 60.1221 -        _subscriptionsToDependencies = [];
 60.1222 -    }
 60.1223 -
 60.1224 -    function evaluatePossiblyAsync() {
 60.1225 -        var throttleEvaluationTimeout = dependentObservable['throttleEvaluation'];
 60.1226 -        if (throttleEvaluationTimeout && throttleEvaluationTimeout >= 0) {
 60.1227 -            clearTimeout(evaluationTimeoutInstance);
 60.1228 -            evaluationTimeoutInstance = setTimeout(evaluateImmediate, throttleEvaluationTimeout);
 60.1229 -        } else
 60.1230 -            evaluateImmediate();
 60.1231 -    }
 60.1232 -
 60.1233 -    function evaluateImmediate() {
 60.1234 -        if (_isBeingEvaluated) {
 60.1235 -            // If the evaluation of a ko.computed causes side effects, it's possible that it will trigger its own re-evaluation.
 60.1236 -            // This is not desirable (it's hard for a developer to realise a chain of dependencies might cause this, and they almost
 60.1237 -            // certainly didn't intend infinite re-evaluations). So, for predictability, we simply prevent ko.computeds from causing
 60.1238 -            // their own re-evaluation. Further discussion at https://github.com/SteveSanderson/knockout/pull/387
 60.1239 -            return;
 60.1240 -        }
 60.1241 -
 60.1242 -        // Don't dispose on first evaluation, because the "disposeWhen" callback might
 60.1243 -        // e.g., dispose when the associated DOM element isn't in the doc, and it's not
 60.1244 -        // going to be in the doc until *after* the first evaluation
 60.1245 -        if (_hasBeenEvaluated && disposeWhen()) {
 60.1246 -            dispose();
 60.1247 -            return;
 60.1248 -        }
 60.1249 -
 60.1250 -        _isBeingEvaluated = true;
 60.1251 -        try {
 60.1252 -            // Initially, we assume that none of the subscriptions are still being used (i.e., all are candidates for disposal).
 60.1253 -            // Then, during evaluation, we cross off any that are in fact still being used.
 60.1254 -            var disposalCandidates = ko.utils.arrayMap(_subscriptionsToDependencies, function(item) {return item.target;});
 60.1255 -
 60.1256 -            ko.dependencyDetection.begin(function(subscribable) {
 60.1257 -                var inOld;
 60.1258 -                if ((inOld = ko.utils.arrayIndexOf(disposalCandidates, subscribable)) >= 0)
 60.1259 -                    disposalCandidates[inOld] = undefined; // Don't want to dispose this subscription, as it's still being used
 60.1260 -                else
 60.1261 -                    addSubscriptionToDependency(subscribable); // Brand new subscription - add it
 60.1262 -            });
 60.1263 -
 60.1264 -            var newValue = readFunction.call(evaluatorFunctionTarget);
 60.1265 -
 60.1266 -            // For each subscription no longer being used, remove it from the active subscriptions list and dispose it
 60.1267 -            for (var i = disposalCandidates.length - 1; i >= 0; i--) {
 60.1268 -                if (disposalCandidates[i])
 60.1269 -                    _subscriptionsToDependencies.splice(i, 1)[0].dispose();
 60.1270 -            }
 60.1271 -            _hasBeenEvaluated = true;
 60.1272 -
 60.1273 -            dependentObservable["notifySubscribers"](_latestValue, "beforeChange");
 60.1274 -            _latestValue = newValue;
 60.1275 -            if (DEBUG) dependentObservable._latestValue = _latestValue;
 60.1276 -        } finally {
 60.1277 -            ko.dependencyDetection.end();
 60.1278 -        }
 60.1279 -
 60.1280 -        dependentObservable["notifySubscribers"](_latestValue);
 60.1281 -        _isBeingEvaluated = false;
 60.1282 -        if (!_subscriptionsToDependencies.length)
 60.1283 -            dispose();
 60.1284 -    }
 60.1285 -
 60.1286 -    function dependentObservable() {
 60.1287 -        if (arguments.length > 0) {
 60.1288 -            if (typeof writeFunction === "function") {
 60.1289 -                // Writing a value
 60.1290 -                writeFunction.apply(evaluatorFunctionTarget, arguments);
 60.1291 -            } else {
 60.1292 -                throw new Error("Cannot write a value to a ko.computed unless you specify a 'write' option. If you wish to read the current value, don't pass any parameters.");
 60.1293 -            }
 60.1294 -            return this; // Permits chained assignments
 60.1295 -        } else {
 60.1296 -            // Reading the value
 60.1297 -            if (!_hasBeenEvaluated)
 60.1298 -                evaluateImmediate();
 60.1299 -            ko.dependencyDetection.registerDependency(dependentObservable);
 60.1300 -            return _latestValue;
 60.1301 -        }
 60.1302 -    }
 60.1303 -
 60.1304 -    function peek() {
 60.1305 -        if (!_hasBeenEvaluated)
 60.1306 -            evaluateImmediate();
 60.1307 -        return _latestValue;
 60.1308 -    }
 60.1309 -
 60.1310 -    function isActive() {
 60.1311 -        return !_hasBeenEvaluated || _subscriptionsToDependencies.length > 0;
 60.1312 -    }
 60.1313 -
 60.1314 -    // By here, "options" is always non-null
 60.1315 -    var writeFunction = options["write"],
 60.1316 -        disposeWhenNodeIsRemoved = options["disposeWhenNodeIsRemoved"] || options.disposeWhenNodeIsRemoved || null,
 60.1317 -        disposeWhen = options["disposeWhen"] || options.disposeWhen || function() { return false; },
 60.1318 -        dispose = disposeAllSubscriptionsToDependencies,
 60.1319 -        _subscriptionsToDependencies = [],
 60.1320 -        evaluationTimeoutInstance = null;
 60.1321 -
 60.1322 -    if (!evaluatorFunctionTarget)
 60.1323 -        evaluatorFunctionTarget = options["owner"];
 60.1324 -
 60.1325 -    dependentObservable.peek = peek;
 60.1326 -    dependentObservable.getDependenciesCount = function () { return _subscriptionsToDependencies.length; };
 60.1327 -    dependentObservable.hasWriteFunction = typeof options["write"] === "function";
 60.1328 -    dependentObservable.dispose = function () { dispose(); };
 60.1329 -    dependentObservable.isActive = isActive;
 60.1330 -    dependentObservable.valueHasMutated = function() {
 60.1331 -        _hasBeenEvaluated = false;
 60.1332 -        evaluateImmediate();
 60.1333 -    };
 60.1334 -
 60.1335 -    ko.subscribable.call(dependentObservable);
 60.1336 -    ko.utils.extend(dependentObservable, ko.dependentObservable['fn']);
 60.1337 -
 60.1338 -    ko.exportProperty(dependentObservable, 'peek', dependentObservable.peek);
 60.1339 -    ko.exportProperty(dependentObservable, 'dispose', dependentObservable.dispose);
 60.1340 -    ko.exportProperty(dependentObservable, 'isActive', dependentObservable.isActive);
 60.1341 -    ko.exportProperty(dependentObservable, 'getDependenciesCount', dependentObservable.getDependenciesCount);
 60.1342 -
 60.1343 -    // Evaluate, unless deferEvaluation is true
 60.1344 -    if (options['deferEvaluation'] !== true)
 60.1345 -        evaluateImmediate();
 60.1346 -
 60.1347 -    // Build "disposeWhenNodeIsRemoved" and "disposeWhenNodeIsRemovedCallback" option values.
 60.1348 -    // But skip if isActive is false (there will never be any dependencies to dispose).
 60.1349 -    // (Note: "disposeWhenNodeIsRemoved" option both proactively disposes as soon as the node is removed using ko.removeNode(),
 60.1350 -    // plus adds a "disposeWhen" callback that, on each evaluation, disposes if the node was removed by some other means.)
 60.1351 -    if (disposeWhenNodeIsRemoved && isActive()) {
 60.1352 -        dispose = function() {
 60.1353 -            ko.utils.domNodeDisposal.removeDisposeCallback(disposeWhenNodeIsRemoved, arguments.callee);
 60.1354 -            disposeAllSubscriptionsToDependencies();
 60.1355 -        };
 60.1356 -        ko.utils.domNodeDisposal.addDisposeCallback(disposeWhenNodeIsRemoved, dispose);
 60.1357 -        var existingDisposeWhenFunction = disposeWhen;
 60.1358 -        disposeWhen = function () {
 60.1359 -            return !ko.utils.domNodeIsAttachedToDocument(disposeWhenNodeIsRemoved) || existingDisposeWhenFunction();
 60.1360 -        }
 60.1361 -    }
 60.1362 -
 60.1363 -    return dependentObservable;
 60.1364 -};
 60.1365 -
 60.1366 -ko.isComputed = function(instance) {
 60.1367 -    return ko.hasPrototype(instance, ko.dependentObservable);
 60.1368 -};
 60.1369 -
 60.1370 -var protoProp = ko.observable.protoProperty; // == "__ko_proto__"
 60.1371 -ko.dependentObservable[protoProp] = ko.observable;
 60.1372 -
 60.1373 -ko.dependentObservable['fn'] = {};
 60.1374 -ko.dependentObservable['fn'][protoProp] = ko.dependentObservable;
 60.1375 -
 60.1376 -ko.exportSymbol('dependentObservable', ko.dependentObservable);
 60.1377 -ko.exportSymbol('computed', ko.dependentObservable); // Make "ko.computed" an alias for "ko.dependentObservable"
 60.1378 -ko.exportSymbol('isComputed', ko.isComputed);
 60.1379 -
 60.1380 -(function() {
 60.1381 -    var maxNestedObservableDepth = 10; // Escape the (unlikely) pathalogical case where an observable's current value is itself (or similar reference cycle)
 60.1382 -
 60.1383 -    ko.toJS = function(rootObject) {
 60.1384 -        if (arguments.length == 0)
 60.1385 -            throw new Error("When calling ko.toJS, pass the object you want to convert.");
 60.1386 -
 60.1387 -        // We just unwrap everything at every level in the object graph
 60.1388 -        return mapJsObjectGraph(rootObject, function(valueToMap) {
 60.1389 -            // Loop because an observable's value might in turn be another observable wrapper
 60.1390 -            for (var i = 0; ko.isObservable(valueToMap) && (i < maxNestedObservableDepth); i++)
 60.1391 -                valueToMap = valueToMap();
 60.1392 -            return valueToMap;
 60.1393 -        });
 60.1394 -    };
 60.1395 -
 60.1396 -    ko.toJSON = function(rootObject, replacer, space) {     // replacer and space are optional
 60.1397 -        var plainJavaScriptObject = ko.toJS(rootObject);
 60.1398 -        return ko.utils.stringifyJson(plainJavaScriptObject, replacer, space);
 60.1399 -    };
 60.1400 -
 60.1401 -    function mapJsObjectGraph(rootObject, mapInputCallback, visitedObjects) {
 60.1402 -        visitedObjects = visitedObjects || new objectLookup();
 60.1403 -
 60.1404 -        rootObject = mapInputCallback(rootObject);
 60.1405 -        var canHaveProperties = (typeof rootObject == "object") && (rootObject !== null) && (rootObject !== undefined) && (!(rootObject instanceof Date));
 60.1406 -        if (!canHaveProperties)
 60.1407 -            return rootObject;
 60.1408 -
 60.1409 -        var outputProperties = rootObject instanceof Array ? [] : {};
 60.1410 -        visitedObjects.save(rootObject, outputProperties);
 60.1411 -
 60.1412 -        visitPropertiesOrArrayEntries(rootObject, function(indexer) {
 60.1413 -            var propertyValue = mapInputCallback(rootObject[indexer]);
 60.1414 -
 60.1415 -            switch (typeof propertyValue) {
 60.1416 -                case "boolean":
 60.1417 -                case "number":
 60.1418 -                case "string":
 60.1419 -                case "function":
 60.1420 -                    outputProperties[indexer] = propertyValue;
 60.1421 -                    break;
 60.1422 -                case "object":
 60.1423 -                case "undefined":
 60.1424 -                    var previouslyMappedValue = visitedObjects.get(propertyValue);
 60.1425 -                    outputProperties[indexer] = (previouslyMappedValue !== undefined)
 60.1426 -                        ? previouslyMappedValue
 60.1427 -                        : mapJsObjectGraph(propertyValue, mapInputCallback, visitedObjects);
 60.1428 -                    break;
 60.1429 -            }
 60.1430 -        });
 60.1431 -
 60.1432 -        return outputProperties;
 60.1433 -    }
 60.1434 -
 60.1435 -    function visitPropertiesOrArrayEntries(rootObject, visitorCallback) {
 60.1436 -        if (rootObject instanceof Array) {
 60.1437 -            for (var i = 0; i < rootObject.length; i++)
 60.1438 -                visitorCallback(i);
 60.1439 -
 60.1440 -            // For arrays, also respect toJSON property for custom mappings (fixes #278)
 60.1441 -            if (typeof rootObject['toJSON'] == 'function')
 60.1442 -                visitorCallback('toJSON');
 60.1443 -        } else {
 60.1444 -            for (var propertyName in rootObject)
 60.1445 -                visitorCallback(propertyName);
 60.1446 -        }
 60.1447 -    };
 60.1448 -
 60.1449 -    function objectLookup() {
 60.1450 -        var keys = [];
 60.1451 -        var values = [];
 60.1452 -        this.save = function(key, value) {
 60.1453 -            var existingIndex = ko.utils.arrayIndexOf(keys, key);
 60.1454 -            if (existingIndex >= 0)
 60.1455 -                values[existingIndex] = value;
 60.1456 -            else {
 60.1457 -                keys.push(key);
 60.1458 -                values.push(value);
 60.1459 -            }
 60.1460 -        };
 60.1461 -        this.get = function(key) {
 60.1462 -            var existingIndex = ko.utils.arrayIndexOf(keys, key);
 60.1463 -            return (existingIndex >= 0) ? values[existingIndex] : undefined;
 60.1464 -        };
 60.1465 -    };
 60.1466 -})();
 60.1467 -
 60.1468 -ko.exportSymbol('toJS', ko.toJS);
 60.1469 -ko.exportSymbol('toJSON', ko.toJSON);
 60.1470 -(function () {
 60.1471 -    var hasDomDataExpandoProperty = '__ko__hasDomDataOptionValue__';
 60.1472 -
 60.1473 -    // Normally, SELECT elements and their OPTIONs can only take value of type 'string' (because the values
 60.1474 -    // are stored on DOM attributes). ko.selectExtensions provides a way for SELECTs/OPTIONs to have values
 60.1475 -    // that are arbitrary objects. This is very convenient when implementing things like cascading dropdowns.
 60.1476 -    ko.selectExtensions = {
 60.1477 -        readValue : function(element) {
 60.1478 -            switch (ko.utils.tagNameLower(element)) {
 60.1479 -                case 'option':
 60.1480 -                    if (element[hasDomDataExpandoProperty] === true)
 60.1481 -                        return ko.utils.domData.get(element, ko.bindingHandlers.options.optionValueDomDataKey);
 60.1482 -                    return ko.utils.ieVersion <= 7
 60.1483 -                        ? (element.getAttributeNode('value').specified ? element.value : element.text)
 60.1484 -                        : element.value;
 60.1485 -                case 'select':
 60.1486 -                    return element.selectedIndex >= 0 ? ko.selectExtensions.readValue(element.options[element.selectedIndex]) : undefined;
 60.1487 -                default:
 60.1488 -                    return element.value;
 60.1489 -            }
 60.1490 -        },
 60.1491 -
 60.1492 -        writeValue: function(element, value) {
 60.1493 -            switch (ko.utils.tagNameLower(element)) {
 60.1494 -                case 'option':
 60.1495 -                    switch(typeof value) {
 60.1496 -                        case "string":
 60.1497 -                            ko.utils.domData.set(element, ko.bindingHandlers.options.optionValueDomDataKey, undefined);
 60.1498 -                            if (hasDomDataExpandoProperty in element) { // IE <= 8 throws errors if you delete non-existent properties from a DOM node
 60.1499 -                                delete element[hasDomDataExpandoProperty];
 60.1500 -                            }
 60.1501 -                            element.value = value;
 60.1502 -                            break;
 60.1503 -                        default:
 60.1504 -                            // Store arbitrary object using DomData
 60.1505 -                            ko.utils.domData.set(element, ko.bindingHandlers.options.optionValueDomDataKey, value);
 60.1506 -                            element[hasDomDataExpandoProperty] = true;
 60.1507 -
 60.1508 -                            // Special treatment of numbers is just for backward compatibility. KO 1.2.1 wrote numerical values to element.value.
 60.1509 -                            element.value = typeof value === "number" ? value : "";
 60.1510 -                            break;
 60.1511 -                    }
 60.1512 -                    break;
 60.1513 -                case 'select':
 60.1514 -                    for (var i = element.options.length - 1; i >= 0; i--) {
 60.1515 -                        if (ko.selectExtensions.readValue(element.options[i]) == value) {
 60.1516 -                            element.selectedIndex = i;
 60.1517 -                            break;
 60.1518 -                        }
 60.1519 -                    }
 60.1520 -                    break;
 60.1521 -                default:
 60.1522 -                    if ((value === null) || (value === undefined))
 60.1523 -                        value = "";
 60.1524 -                    element.value = value;
 60.1525 -                    break;
 60.1526 -            }
 60.1527 -        }
 60.1528 -    };
 60.1529 -})();
 60.1530 -
 60.1531 -ko.exportSymbol('selectExtensions', ko.selectExtensions);
 60.1532 -ko.exportSymbol('selectExtensions.readValue', ko.selectExtensions.readValue);
 60.1533 -ko.exportSymbol('selectExtensions.writeValue', ko.selectExtensions.writeValue);
 60.1534 -ko.expressionRewriting = (function () {
 60.1535 -    var restoreCapturedTokensRegex = /\@ko_token_(\d+)\@/g;
 60.1536 -    var javaScriptReservedWords = ["true", "false"];
 60.1537 -
 60.1538 -    // Matches something that can be assigned to--either an isolated identifier or something ending with a property accessor
 60.1539 -    // This is designed to be simple and avoid false negatives, but could produce false positives (e.g., a+b.c).
 60.1540 -    var javaScriptAssignmentTarget = /^(?:[$_a-z][$\w]*|(.+)(\.\s*[$_a-z][$\w]*|\[.+\]))$/i;
 60.1541 -
 60.1542 -    function restoreTokens(string, tokens) {
 60.1543 -        var prevValue = null;
 60.1544 -        while (string != prevValue) { // Keep restoring tokens until it no longer makes a difference (they may be nested)
 60.1545 -            prevValue = string;
 60.1546 -            string = string.replace(restoreCapturedTokensRegex, function (match, tokenIndex) {
 60.1547 -                return tokens[tokenIndex];
 60.1548 -            });
 60.1549 -        }
 60.1550 -        return string;
 60.1551 -    }
 60.1552 -
 60.1553 -    function getWriteableValue(expression) {
 60.1554 -        if (ko.utils.arrayIndexOf(javaScriptReservedWords, ko.utils.stringTrim(expression).toLowerCase()) >= 0)
 60.1555 -            return false;
 60.1556 -        var match = expression.match(javaScriptAssignmentTarget);
 60.1557 -        return match === null ? false : match[1] ? ('Object(' + match[1] + ')' + match[2]) : expression;
 60.1558 -    }
 60.1559 -
 60.1560 -    function ensureQuoted(key) {
 60.1561 -        var trimmedKey = ko.utils.stringTrim(key);
 60.1562 -        switch (trimmedKey.length && trimmedKey.charAt(0)) {
 60.1563 -            case "'":
 60.1564 -            case '"':
 60.1565 -                return key;
 60.1566 -            default:
 60.1567 -                return "'" + trimmedKey + "'";
 60.1568 -        }
 60.1569 -    }
 60.1570 -
 60.1571 -    return {
 60.1572 -        bindingRewriteValidators: [],
 60.1573 -
 60.1574 -        parseObjectLiteral: function(objectLiteralString) {
 60.1575 -            // A full tokeniser+lexer would add too much weight to this library, so here's a simple parser
 60.1576 -            // that is sufficient just to split an object literal string into a set of top-level key-value pairs
 60.1577 -
 60.1578 -            var str = ko.utils.stringTrim(objectLiteralString);
 60.1579 -            if (str.length < 3)
 60.1580 -                return [];
 60.1581 -            if (str.charAt(0) === "{")// Ignore any braces surrounding the whole object literal
 60.1582 -                str = str.substring(1, str.length - 1);
 60.1583 -
 60.1584 -            // Pull out any string literals and regex literals
 60.1585 -            var tokens = [];
 60.1586 -            var tokenStart = null, tokenEndChar;
 60.1587 -            for (var position = 0; position < str.length; position++) {
 60.1588 -                var c = str.charAt(position);
 60.1589 -                if (tokenStart === null) {
 60.1590 -                    switch (c) {
 60.1591 -                        case '"':
 60.1592 -                        case "'":
 60.1593 -                        case "/":
 60.1594 -                            tokenStart = position;
 60.1595 -                            tokenEndChar = c;
 60.1596 -                            break;
 60.1597 -                    }
 60.1598 -                } else if ((c == tokenEndChar) && (str.charAt(position - 1) !== "\\")) {
 60.1599 -                    var token = str.substring(tokenStart, position + 1);
 60.1600 -                    tokens.push(token);
 60.1601 -                    var replacement = "@ko_token_" + (tokens.length - 1) + "@";
 60.1602 -                    str = str.substring(0, tokenStart) + replacement + str.substring(position + 1);
 60.1603 -                    position -= (token.length - replacement.length);
 60.1604 -                    tokenStart = null;
 60.1605 -                }
 60.1606 -            }
 60.1607 -
 60.1608 -            // Next pull out balanced paren, brace, and bracket blocks
 60.1609 -            tokenStart = null;
 60.1610 -            tokenEndChar = null;
 60.1611 -            var tokenDepth = 0, tokenStartChar = null;
 60.1612 -            for (var position = 0; position < str.length; position++) {
 60.1613 -                var c = str.charAt(position);
 60.1614 -                if (tokenStart === null) {
 60.1615 -                    switch (c) {
 60.1616 -                        case "{": tokenStart = position; tokenStartChar = c;
 60.1617 -                                  tokenEndChar = "}";
 60.1618 -                                  break;
 60.1619 -                        case "(": tokenStart = position; tokenStartChar = c;
 60.1620 -                                  tokenEndChar = ")";
 60.1621 -                                  break;
 60.1622 -                        case "[": tokenStart = position; tokenStartChar = c;
 60.1623 -                                  tokenEndChar = "]";
 60.1624 -                                  break;
 60.1625 -                    }
 60.1626 -                }
 60.1627 -
 60.1628 -                if (c === tokenStartChar)
 60.1629 -                    tokenDepth++;
 60.1630 -                else if (c === tokenEndChar) {
 60.1631 -                    tokenDepth--;
 60.1632 -                    if (tokenDepth === 0) {
 60.1633 -                        var token = str.substring(tokenStart, position + 1);
 60.1634 -                        tokens.push(token);
 60.1635 -                        var replacement = "@ko_token_" + (tokens.length - 1) + "@";
 60.1636 -                        str = str.substring(0, tokenStart) + replacement + str.substring(position + 1);
 60.1637 -                        position -= (token.length - replacement.length);
 60.1638 -                        tokenStart = null;
 60.1639 -                    }
 60.1640 -                }
 60.1641 -            }
 60.1642 -
 60.1643 -            // Now we can safely split on commas to get the key/value pairs
 60.1644 -            var result = [];
 60.1645 -            var keyValuePairs = str.split(",");
 60.1646 -            for (var i = 0, j = keyValuePairs.length; i < j; i++) {
 60.1647 -                var pair = keyValuePairs[i];
 60.1648 -                var colonPos = pair.indexOf(":");
 60.1649 -                if ((colonPos > 0) && (colonPos < pair.length - 1)) {
 60.1650 -                    var key = pair.substring(0, colonPos);
 60.1651 -                    var value = pair.substring(colonPos + 1);
 60.1652 -                    result.push({ 'key': restoreTokens(key, tokens), 'value': restoreTokens(value, tokens) });
 60.1653 -                } else {
 60.1654 -                    result.push({ 'unknown': restoreTokens(pair, tokens) });
 60.1655 -                }
 60.1656 -            }
 60.1657 -            return result;
 60.1658 -        },
 60.1659 -
 60.1660 -        preProcessBindings: function (objectLiteralStringOrKeyValueArray) {
 60.1661 -            var keyValueArray = typeof objectLiteralStringOrKeyValueArray === "string"
 60.1662 -                ? ko.expressionRewriting.parseObjectLiteral(objectLiteralStringOrKeyValueArray)
 60.1663 -                : objectLiteralStringOrKeyValueArray;
 60.1664 -            var resultStrings = [], propertyAccessorResultStrings = [];
 60.1665 -
 60.1666 -            var keyValueEntry;
 60.1667 -            for (var i = 0; keyValueEntry = keyValueArray[i]; i++) {
 60.1668 -                if (resultStrings.length > 0)
 60.1669 -                    resultStrings.push(",");
 60.1670 -
 60.1671 -                if (keyValueEntry['key']) {
 60.1672 -                    var quotedKey = ensureQuoted(keyValueEntry['key']), val = keyValueEntry['value'];
 60.1673 -                    resultStrings.push(quotedKey);
 60.1674 -                    resultStrings.push(":");
 60.1675 -                    resultStrings.push(val);
 60.1676 -
 60.1677 -                    if (val = getWriteableValue(ko.utils.stringTrim(val))) {
 60.1678 -                        if (propertyAccessorResultStrings.length > 0)
 60.1679 -                            propertyAccessorResultStrings.push(", ");
 60.1680 -                        propertyAccessorResultStrings.push(quotedKey + " : function(__ko_value) { " + val + " = __ko_value; }");
 60.1681 -                    }
 60.1682 -                } else if (keyValueEntry['unknown']) {
 60.1683 -                    resultStrings.push(keyValueEntry['unknown']);
 60.1684 -                }
 60.1685 -            }
 60.1686 -
 60.1687 -            var combinedResult = resultStrings.join("");
 60.1688 -            if (propertyAccessorResultStrings.length > 0) {
 60.1689 -                var allPropertyAccessors = propertyAccessorResultStrings.join("");
 60.1690 -                combinedResult = combinedResult + ", '_ko_property_writers' : { " + allPropertyAccessors + " } ";
 60.1691 -            }
 60.1692 -
 60.1693 -            return combinedResult;
 60.1694 -        },
 60.1695 -
 60.1696 -        keyValueArrayContainsKey: function(keyValueArray, key) {
 60.1697 -            for (var i = 0; i < keyValueArray.length; i++)
 60.1698 -                if (ko.utils.stringTrim(keyValueArray[i]['key']) == key)
 60.1699 -                    return true;
 60.1700 -            return false;
 60.1701 -        },
 60.1702 -
 60.1703 -        // Internal, private KO utility for updating model properties from within bindings
 60.1704 -        // property:            If the property being updated is (or might be) an observable, pass it here
 60.1705 -        //                      If it turns out to be a writable observable, it will be written to directly
 60.1706 -        // allBindingsAccessor: All bindings in the current execution context.
 60.1707 -        //                      This will be searched for a '_ko_property_writers' property in case you're writing to a non-observable
 60.1708 -        // key:                 The key identifying the property to be written. Example: for { hasFocus: myValue }, write to 'myValue' by specifying the key 'hasFocus'
 60.1709 -        // value:               The value to be written
 60.1710 -        // checkIfDifferent:    If true, and if the property being written is a writable observable, the value will only be written if
 60.1711 -        //                      it is !== existing value on that writable observable
 60.1712 -        writeValueToProperty: function(property, allBindingsAccessor, key, value, checkIfDifferent) {
 60.1713 -            if (!property || !ko.isWriteableObservable(property)) {
 60.1714 -                var propWriters = allBindingsAccessor()['_ko_property_writers'];
 60.1715 -                if (propWriters && propWriters[key])
 60.1716 -                    propWriters[key](value);
 60.1717 -            } else if (!checkIfDifferent || property.peek() !== value) {
 60.1718 -                property(value);
 60.1719 -            }
 60.1720 -        }
 60.1721 -    };
 60.1722 -})();
 60.1723 -
 60.1724 -ko.exportSymbol('expressionRewriting', ko.expressionRewriting);
 60.1725 -ko.exportSymbol('expressionRewriting.bindingRewriteValidators', ko.expressionRewriting.bindingRewriteValidators);
 60.1726 -ko.exportSymbol('expressionRewriting.parseObjectLiteral', ko.expressionRewriting.parseObjectLiteral);
 60.1727 -ko.exportSymbol('expressionRewriting.preProcessBindings', ko.expressionRewriting.preProcessBindings);
 60.1728 -
 60.1729 -// For backward compatibility, define the following aliases. (Previously, these function names were misleading because
 60.1730 -// they referred to JSON specifically, even though they actually work with arbitrary JavaScript object literal expressions.)
 60.1731 -ko.exportSymbol('jsonExpressionRewriting', ko.expressionRewriting);
 60.1732 -ko.exportSymbol('jsonExpressionRewriting.insertPropertyAccessorsIntoJson', ko.expressionRewriting.preProcessBindings);(function() {
 60.1733 -    // "Virtual elements" is an abstraction on top of the usual DOM API which understands the notion that comment nodes
 60.1734 -    // may be used to represent hierarchy (in addition to the DOM's natural hierarchy).
 60.1735 -    // If you call the DOM-manipulating functions on ko.virtualElements, you will be able to read and write the state
 60.1736 -    // of that virtual hierarchy
 60.1737 -    //
 60.1738 -    // The point of all this is to support containerless templates (e.g., <!-- ko foreach:someCollection -->blah<!-- /ko -->)
 60.1739 -    // without having to scatter special cases all over the binding and templating code.
 60.1740 -
 60.1741 -    // IE 9 cannot reliably read the "nodeValue" property of a comment node (see https://github.com/SteveSanderson/knockout/issues/186)
 60.1742 -    // but it does give them a nonstandard alternative property called "text" that it can read reliably. Other browsers don't have that property.
 60.1743 -    // So, use node.text where available, and node.nodeValue elsewhere
 60.1744 -    var commentNodesHaveTextProperty = document.createComment("test").text === "<!--test-->";
 60.1745 -
 60.1746 -    var startCommentRegex = commentNodesHaveTextProperty ? /^<!--\s*ko(?:\s+(.+\s*\:[\s\S]*))?\s*-->$/ : /^\s*ko(?:\s+(.+\s*\:[\s\S]*))?\s*$/;
 60.1747 -    var endCommentRegex =   commentNodesHaveTextProperty ? /^<!--\s*\/ko\s*-->$/ : /^\s*\/ko\s*$/;
 60.1748 -    var htmlTagsWithOptionallyClosingChildren = { 'ul': true, 'ol': true };
 60.1749 -
 60.1750 -    function isStartComment(node) {
 60.1751 -        return (node.nodeType == 8) && (commentNodesHaveTextProperty ? node.text : node.nodeValue).match(startCommentRegex);
 60.1752 -    }
 60.1753 -
 60.1754 -    function isEndComment(node) {
 60.1755 -        return (node.nodeType == 8) && (commentNodesHaveTextProperty ? node.text : node.nodeValue).match(endCommentRegex);
 60.1756 -    }
 60.1757 -
 60.1758 -    function getVirtualChildren(startComment, allowUnbalanced) {
 60.1759 -        var currentNode = startComment;
 60.1760 -        var depth = 1;
 60.1761 -        var children = [];
 60.1762 -        while (currentNode = currentNode.nextSibling) {
 60.1763 -            if (isEndComment(currentNode)) {
 60.1764 -                depth--;
 60.1765 -                if (depth === 0)
 60.1766 -                    return children;
 60.1767 -            }
 60.1768 -
 60.1769 -            children.push(currentNode);
 60.1770 -
 60.1771 -            if (isStartComment(currentNode))
 60.1772 -                depth++;
 60.1773 -        }
 60.1774 -        if (!allowUnbalanced)
 60.1775 -            throw new Error("Cannot find closing comment tag to match: " + startComment.nodeValue);
 60.1776 -        return null;
 60.1777 -    }
 60.1778 -
 60.1779 -    function getMatchingEndComment(startComment, allowUnbalanced) {
 60.1780 -        var allVirtualChildren = getVirtualChildren(startComment, allowUnbalanced);
 60.1781 -        if (allVirtualChildren) {
 60.1782 -            if (allVirtualChildren.length > 0)
 60.1783 -                return allVirtualChildren[allVirtualChildren.length - 1].nextSibling;
 60.1784 -            return startComment.nextSibling;
 60.1785 -        } else
 60.1786 -            return null; // Must have no matching end comment, and allowUnbalanced is true
 60.1787 -    }
 60.1788 -
 60.1789 -    function getUnbalancedChildTags(node) {
 60.1790 -        // e.g., from <div>OK</div><!-- ko blah --><span>Another</span>, returns: <!-- ko blah --><span>Another</span>
 60.1791 -        //       from <div>OK</div><!-- /ko --><!-- /ko -->,             returns: <!-- /ko --><!-- /ko -->
 60.1792 -        var childNode = node.firstChild, captureRemaining = null;
 60.1793 -        if (childNode) {
 60.1794 -            do {
 60.1795 -                if (captureRemaining)                   // We already hit an unbalanced node and are now just scooping up all subsequent nodes
 60.1796 -                    captureRemaining.push(childNode);
 60.1797 -                else if (isStartComment(childNode)) {
 60.1798 -                    var matchingEndComment = getMatchingEndComment(childNode, /* allowUnbalanced: */ true);
 60.1799 -                    if (matchingEndComment)             // It's a balanced tag, so skip immediately to the end of this virtual set
 60.1800 -                        childNode = matchingEndComment;
 60.1801 -                    else
 60.1802 -                        captureRemaining = [childNode]; // It's unbalanced, so start capturing from this point
 60.1803 -                } else if (isEndComment(childNode)) {
 60.1804 -                    captureRemaining = [childNode];     // It's unbalanced (if it wasn't, we'd have skipped over it already), so start capturing
 60.1805 -                }
 60.1806 -            } while (childNode = childNode.nextSibling);
 60.1807 -        }
 60.1808 -        return captureRemaining;
 60.1809 -    }
 60.1810 -
 60.1811 -    ko.virtualElements = {
 60.1812 -        allowedBindings: {},
 60.1813 -
 60.1814 -        childNodes: function(node) {
 60.1815 -            return isStartComment(node) ? getVirtualChildren(node) : node.childNodes;
 60.1816 -        },
 60.1817 -
 60.1818 -        emptyNode: function(node) {
 60.1819 -            if (!isStartComment(node))
 60.1820 -                ko.utils.emptyDomNode(node);
 60.1821 -            else {
 60.1822 -                var virtualChildren = ko.virtualElements.childNodes(node);
 60.1823 -                for (var i = 0, j = virtualChildren.length; i < j; i++)
 60.1824 -                    ko.removeNode(virtualChildren[i]);
 60.1825 -            }
 60.1826 -        },
 60.1827 -
 60.1828 -        setDomNodeChildren: function(node, childNodes) {
 60.1829 -            if (!isStartComment(node))
 60.1830 -                ko.utils.setDomNodeChildren(node, childNodes);
 60.1831 -            else {
 60.1832 -                ko.virtualElements.emptyNode(node);
 60.1833 -                var endCommentNode = node.nextSibling; // Must be the next sibling, as we just emptied the children
 60.1834 -                for (var i = 0, j = childNodes.length; i < j; i++)
 60.1835 -                    endCommentNode.parentNode.insertBefore(childNodes[i], endCommentNode);
 60.1836 -            }
 60.1837 -        },
 60.1838 -
 60.1839 -        prepend: function(containerNode, nodeToPrepend) {
 60.1840 -            if (!isStartComment(containerNode)) {
 60.1841 -                if (containerNode.firstChild)
 60.1842 -                    containerNode.insertBefore(nodeToPrepend, containerNode.firstChild);
 60.1843 -                else
 60.1844 -                    containerNode.appendChild(nodeToPrepend);
 60.1845 -            } else {
 60.1846 -                // Start comments must always have a parent and at least one following sibling (the end comment)
 60.1847 -                containerNode.parentNode.insertBefore(nodeToPrepend, containerNode.nextSibling);
 60.1848 -            }
 60.1849 -        },
 60.1850 -
 60.1851 -        insertAfter: function(containerNode, nodeToInsert, insertAfterNode) {
 60.1852 -            if (!insertAfterNode) {
 60.1853 -                ko.virtualElements.prepend(containerNode, nodeToInsert);
 60.1854 -            } else if (!isStartComment(containerNode)) {
 60.1855 -                // Insert after insertion point
 60.1856 -                if (insertAfterNode.nextSibling)
 60.1857 -                    containerNode.insertBefore(nodeToInsert, insertAfterNode.nextSibling);
 60.1858 -                else
 60.1859 -                    containerNode.appendChild(nodeToInsert);
 60.1860 -            } else {
 60.1861 -                // Children of start comments must always have a parent and at least one following sibling (the end comment)
 60.1862 -                containerNode.parentNode.insertBefore(nodeToInsert, insertAfterNode.nextSibling);
 60.1863 -            }
 60.1864 -        },
 60.1865 -
 60.1866 -        firstChild: function(node) {
 60.1867 -            if (!isStartComment(node))
 60.1868 -                return node.firstChild;
 60.1869 -            if (!node.nextSibling || isEndComment(node.nextSibling))
 60.1870 -                return null;
 60.1871 -            return node.nextSibling;
 60.1872 -        },
 60.1873 -
 60.1874 -        nextSibling: function(node) {
 60.1875 -            if (isStartComment(node))
 60.1876 -                node = getMatchingEndComment(node);
 60.1877 -            if (node.nextSibling && isEndComment(node.nextSibling))
 60.1878 -                return null;
 60.1879 -            return node.nextSibling;
 60.1880 -        },
 60.1881 -
 60.1882 -        virtualNodeBindingValue: function(node) {
 60.1883 -            var regexMatch = isStartComment(node);
 60.1884 -            return regexMatch ? regexMatch[1] : null;
 60.1885 -        },
 60.1886 -
 60.1887 -        normaliseVirtualElementDomStructure: function(elementVerified) {
 60.1888 -            // Workaround for https://github.com/SteveSanderson/knockout/issues/155
 60.1889 -            // (IE <= 8 or IE 9 quirks mode parses your HTML weirdly, treating closing </li> tags as if they don't exist, thereby moving comment nodes
 60.1890 -            // that are direct descendants of <ul> into the preceding <li>)
 60.1891 -            if (!htmlTagsWithOptionallyClosingChildren[ko.utils.tagNameLower(elementVerified)])
 60.1892 -                return;
 60.1893 -
 60.1894 -            // Scan immediate children to see if they contain unbalanced comment tags. If they do, those comment tags
 60.1895 -            // must be intended to appear *after* that child, so move them there.
 60.1896 -            var childNode = elementVerified.firstChild;
 60.1897 -            if (childNode) {
 60.1898 -                do {
 60.1899 -                    if (childNode.nodeType === 1) {
 60.1900 -                        var unbalancedTags = getUnbalancedChildTags(childNode);
 60.1901 -                        if (unbalancedTags) {
 60.1902 -                            // Fix up the DOM by moving the unbalanced tags to where they most likely were intended to be placed - *after* the child
 60.1903 -                            var nodeToInsertBefore = childNode.nextSibling;
 60.1904 -                            for (var i = 0; i < unbalancedTags.length; i++) {
 60.1905 -                                if (nodeToInsertBefore)
 60.1906 -                                    elementVerified.insertBefore(unbalancedTags[i], nodeToInsertBefore);
 60.1907 -                                else
 60.1908 -                                    elementVerified.appendChild(unbalancedTags[i]);
 60.1909 -                            }
 60.1910 -                        }
 60.1911 -                    }
 60.1912 -                } while (childNode = childNode.nextSibling);
 60.1913 -            }
 60.1914 -        }
 60.1915 -    };
 60.1916 -})();
 60.1917 -ko.exportSymbol('virtualElements', ko.virtualElements);
 60.1918 -ko.exportSymbol('virtualElements.allowedBindings', ko.virtualElements.allowedBindings);
 60.1919 -ko.exportSymbol('virtualElements.emptyNode', ko.virtualElements.emptyNode);
 60.1920 -//ko.exportSymbol('virtualElements.firstChild', ko.virtualElements.firstChild);     // firstChild is not minified
 60.1921 -ko.exportSymbol('virtualElements.insertAfter', ko.virtualElements.insertAfter);
 60.1922 -//ko.exportSymbol('virtualElements.nextSibling', ko.virtualElements.nextSibling);   // nextSibling is not minified
 60.1923 -ko.exportSymbol('virtualElements.prepend', ko.virtualElements.prepend);
 60.1924 -ko.exportSymbol('virtualElements.setDomNodeChildren', ko.virtualElements.setDomNodeChildren);
 60.1925 -(function() {
 60.1926 -    var defaultBindingAttributeName = "data-bind";
 60.1927 -
 60.1928 -    ko.bindingProvider = function() {
 60.1929 -        this.bindingCache = {};
 60.1930 -    };
 60.1931 -
 60.1932 -    ko.utils.extend(ko.bindingProvider.prototype, {
 60.1933 -        'nodeHasBindings': function(node) {
 60.1934 -            switch (node.nodeType) {
 60.1935 -                case 1: return node.getAttribute(defaultBindingAttributeName) != null;   // Element
 60.1936 -                case 8: return ko.virtualElements.virtualNodeBindingValue(node) != null; // Comment node
 60.1937 -                default: return false;
 60.1938 -            }
 60.1939 -        },
 60.1940 -
 60.1941 -        'getBindings': function(node, bindingContext) {
 60.1942 -            var bindingsString = this['getBindingsString'](node, bindingContext);
 60.1943 -            return bindingsString ? this['parseBindingsString'](bindingsString, bindingContext, node) : null;
 60.1944 -        },
 60.1945 -
 60.1946 -        // The following function is only used internally by this default provider.
 60.1947 -        // It's not part of the interface definition for a general binding provider.
 60.1948 -        'getBindingsString': function(node, bindingContext) {
 60.1949 -            switch (node.nodeType) {
 60.1950 -                case 1: return node.getAttribute(defaultBindingAttributeName);   // Element
 60.1951 -                case 8: return ko.virtualElements.virtualNodeBindingValue(node); // Comment node
 60.1952 -                default: return null;
 60.1953 -            }
 60.1954 -        },
 60.1955 -
 60.1956 -        // The following function is only used internally by this default provider.
 60.1957 -        // It's not part of the interface definition for a general binding provider.
 60.1958 -        'parseBindingsString': function(bindingsString, bindingContext, node) {
 60.1959 -            try {
 60.1960 -                var bindingFunction = createBindingsStringEvaluatorViaCache(bindingsString, this.bindingCache);
 60.1961 -                return bindingFunction(bindingContext, node);
 60.1962 -            } catch (ex) {
 60.1963 -                throw new Error("Unable to parse bindings.\nMessage: " + ex + ";\nBindings value: " + bindingsString);
 60.1964 -            }
 60.1965 -        }
 60.1966 -    });
 60.1967 -
 60.1968 -    ko.bindingProvider['instance'] = new ko.bindingProvider();
 60.1969 -
 60.1970 -    function createBindingsStringEvaluatorViaCache(bindingsString, cache) {
 60.1971 -        var cacheKey = bindingsString;
 60.1972 -        return cache[cacheKey]
 60.1973 -            || (cache[cacheKey] = createBindingsStringEvaluator(bindingsString));
 60.1974 -    }
 60.1975 -
 60.1976 -    function createBindingsStringEvaluator(bindingsString) {
 60.1977 -        // Build the source for a function that evaluates "expression"
 60.1978 -        // For each scope variable, add an extra level of "with" nesting
 60.1979 -        // Example result: with(sc1) { with(sc0) { return (expression) } }
 60.1980 -        var rewrittenBindings = ko.expressionRewriting.preProcessBindings(bindingsString),
 60.1981 -            functionBody = "with($context){with($data||{}){return{" + rewrittenBindings + "}}}";
 60.1982 -        return new Function("$context", "$element", functionBody);
 60.1983 -    }
 60.1984 -})();
 60.1985 -
 60.1986 -ko.exportSymbol('bindingProvider', ko.bindingProvider);
 60.1987 -(function () {
 60.1988 -    ko.bindingHandlers = {};
 60.1989 -
 60.1990 -    ko.bindingContext = function(dataItem, parentBindingContext, dataItemAlias) {
 60.1991 -        if (parentBindingContext) {
 60.1992 -            ko.utils.extend(this, parentBindingContext); // Inherit $root and any custom properties
 60.1993 -            this['$parentContext'] = parentBindingContext;
 60.1994 -            this['$parent'] = parentBindingContext['$data'];
 60.1995 -            this['$parents'] = (parentBindingContext['$parents'] || []).slice(0);
 60.1996 -            this['$parents'].unshift(this['$parent']);
 60.1997 -        } else {
 60.1998 -            this['$parents'] = [];
 60.1999 -            this['$root'] = dataItem;
 60.2000 -            // Export 'ko' in the binding context so it will be available in bindings and templates
 60.2001 -            // even if 'ko' isn't exported as a global, such as when using an AMD loader.
 60.2002 -            // See https://github.com/SteveSanderson/knockout/issues/490
 60.2003 -            this['ko'] = ko;
 60.2004 -        }
 60.2005 -        this['$data'] = dataItem;
 60.2006 -        if (dataItemAlias)
 60.2007 -            this[dataItemAlias] = dataItem;
 60.2008 -    }
 60.2009 -    ko.bindingContext.prototype['createChildContext'] = function (dataItem, dataItemAlias) {
 60.2010 -        return new ko.bindingContext(dataItem, this, dataItemAlias);
 60.2011 -    };
 60.2012 -    ko.bindingContext.prototype['extend'] = function(properties) {
 60.2013 -        var clone = ko.utils.extend(new ko.bindingContext(), this);
 60.2014 -        return ko.utils.extend(clone, properties);
 60.2015 -    };
 60.2016 -
 60.2017 -    function validateThatBindingIsAllowedForVirtualElements(bindingName) {
 60.2018 -        var validator = ko.virtualElements.allowedBindings[bindingName];
 60.2019 -        if (!validator)
 60.2020 -            throw new Error("The binding '" + bindingName + "' cannot be used with virtual elements")
 60.2021 -    }
 60.2022 -
 60.2023 -    function applyBindingsToDescendantsInternal (viewModel, elementOrVirtualElement, bindingContextsMayDifferFromDomParentElement) {
 60.2024 -        var currentChild, nextInQueue = ko.virtualElements.firstChild(elementOrVirtualElement);
 60.2025 -        while (currentChild = nextInQueue) {
 60.2026 -            // Keep a record of the next child *before* applying bindings, in case the binding removes the current child from its position
 60.2027 -            nextInQueue = ko.virtualElements.nextSibling(currentChild);
 60.2028 -            applyBindingsToNodeAndDescendantsInternal(viewModel, currentChild, bindingContextsMayDifferFromDomParentElement);
 60.2029 -        }
 60.2030 -    }
 60.2031 -
 60.2032 -    function applyBindingsToNodeAndDescendantsInternal (viewModel, nodeVerified, bindingContextMayDifferFromDomParentElement) {
 60.2033 -        var shouldBindDescendants = true;
 60.2034 -
 60.2035 -        // Perf optimisation: Apply bindings only if...
 60.2036 -        // (1) We need to store the binding context on this node (because it may differ from the DOM parent node's binding context)
 60.2037 -        //     Note that we can't store binding contexts on non-elements (e.g., text nodes), as IE doesn't allow expando properties for those
 60.2038 -        // (2) It might have bindings (e.g., it has a data-bind attribute, or it's a marker for a containerless template)
 60.2039 -        var isElement = (nodeVerified.nodeType === 1);
 60.2040 -        if (isElement) // Workaround IE <= 8 HTML parsing weirdness
 60.2041 -            ko.virtualElements.normaliseVirtualElementDomStructure(nodeVerified);
 60.2042 -
 60.2043 -        var shouldApplyBindings = (isElement && bindingContextMayDifferFromDomParentElement)             // Case (1)
 60.2044 -                               || ko.bindingProvider['instance']['nodeHasBindings'](nodeVerified);       // Case (2)
 60.2045 -        if (shouldApplyBindings)
 60.2046 -            shouldBindDescendants = applyBindingsToNodeInternal(nodeVerified, null, viewModel, bindingContextMayDifferFromDomParentElement).shouldBindDescendants;
 60.2047 -
 60.2048 -        if (shouldBindDescendants) {
 60.2049 -            // We're recursing automatically into (real or virtual) child nodes without changing binding contexts. So,
 60.2050 -            //  * For children of a *real* element, the binding context is certainly the same as on their DOM .parentNode,
 60.2051 -            //    hence bindingContextsMayDifferFromDomParentElement is false
 60.2052 -            //  * For children of a *virtual* element, we can't be sure. Evaluating .parentNode on those children may
 60.2053 -            //    skip over any number of intermediate virtual elements, any of which might define a custom binding context,
 60.2054 -            //    hence bindingContextsMayDifferFromDomParentElement is true
 60.2055 -            applyBindingsToDescendantsInternal(viewModel, nodeVerified, /* bindingContextsMayDifferFromDomParentElement: */ !isElement);
 60.2056 -        }
 60.2057 -    }
 60.2058 -
 60.2059 -    function applyBindingsToNodeInternal (node, bindings, viewModelOrBindingContext, bindingContextMayDifferFromDomParentElement) {
 60.2060 -        // Need to be sure that inits are only run once, and updates never run until all the inits have been run
 60.2061 -        var initPhase = 0; // 0 = before all inits, 1 = during inits, 2 = after all inits
 60.2062 -
 60.2063 -        // Each time the dependentObservable is evaluated (after data changes),
 60.2064 -        // the binding attribute is reparsed so that it can pick out the correct
 60.2065 -        // model properties in the context of the changed data.
 60.2066 -        // DOM event callbacks need to be able to access this changed data,
 60.2067 -        // so we need a single parsedBindings variable (shared by all callbacks
 60.2068 -        // associated with this node's bindings) that all the closures can access.
 60.2069 -        var parsedBindings;
 60.2070 -        function makeValueAccessor(bindingKey) {
 60.2071 -            return function () { return parsedBindings[bindingKey] }
 60.2072 -        }
 60.2073 -        function parsedBindingsAccessor() {
 60.2074 -            return parsedBindings;
 60.2075 -        }
 60.2076 -
 60.2077 -        var bindingHandlerThatControlsDescendantBindings;
 60.2078 -        ko.dependentObservable(
 60.2079 -            function () {
 60.2080 -                // Ensure we have a nonnull binding context to work with
 60.2081 -                var bindingContextInstance = viewModelOrBindingContext && (viewModelOrBindingContext instanceof ko.bindingContext)
 60.2082 -                    ? viewModelOrBindingContext
 60.2083 -                    : new ko.bindingContext(ko.utils.unwrapObservable(viewModelOrBindingContext));
 60.2084 -                var viewModel = bindingContextInstance['$data'];
 60.2085 -
 60.2086 -                // Optimization: Don't store the binding context on this node if it's definitely the same as on node.parentNode, because
 60.2087 -                // we can easily recover it just by scanning up the node's ancestors in the DOM
 60.2088 -                // (note: here, parent node means "real DOM parent" not "virtual parent", as there's no O(1) way to find the virtual parent)
 60.2089 -                if (bindingContextMayDifferFromDomParentElement)
 60.2090 -                    ko.storedBindingContextForNode(node, bindingContextInstance);
 60.2091 -
 60.2092 -                // Use evaluatedBindings if given, otherwise fall back on asking the bindings provider to give us some bindings
 60.2093 -                var evaluatedBindings = (typeof bindings == "function") ? bindings(bindingContextInstance, node) : bindings;
 60.2094 -                parsedBindings = evaluatedBindings || ko.bindingProvider['instance']['getBindings'](node, bindingContextInstance);
 60.2095 -
 60.2096 -                if (parsedBindings) {
 60.2097 -                    // First run all the inits, so bindings can register for notification on changes
 60.2098 -                    if (initPhase === 0) {
 60.2099 -                        initPhase = 1;
 60.2100 -                        for (var bindingKey in parsedBindings) {
 60.2101 -                            var binding = ko.bindingHandlers[bindingKey];
 60.2102 -                            if (binding && node.nodeType === 8)
 60.2103 -                                validateThatBindingIsAllowedForVirtualElements(bindingKey);
 60.2104 -
 60.2105 -                            if (binding && typeof binding["init"] == "function") {
 60.2106 -                                var handlerInitFn = binding["init"];
 60.2107 -                                var initResult = handlerInitFn(node, makeValueAccessor(bindingKey), parsedBindingsAccessor, viewModel, bindingContextInstance);
 60.2108 -
 60.2109 -                                // If this binding handler claims to control descendant bindings, make a note of this
 60.2110 -                                if (initResult && initResult['controlsDescendantBindings']) {
 60.2111 -                                    if (bindingHandlerThatControlsDescendantBindings !== undefined)
 60.2112 -                                        throw new Error("Multiple bindings (" + bindingHandlerThatControlsDescendantBindings + " and " + bindingKey + ") are trying to control descendant bindings of the same element. You cannot use these bindings together on the same element.");
 60.2113 -                                    bindingHandlerThatControlsDescendantBindings = bindingKey;
 60.2114 -                                }
 60.2115 -                            }
 60.2116 -                        }
 60.2117 -                        initPhase = 2;
 60.2118 -                    }
 60.2119 -
 60.2120 -                    // ... then run all the updates, which might trigger changes even on the first evaluation
 60.2121 -                    if (initPhase === 2) {
 60.2122 -                        for (var bindingKey in parsedBindings) {
 60.2123 -                            var binding = ko.bindingHandlers[bindingKey];
 60.2124 -                            if (binding && typeof binding["update"] == "function") {
 60.2125 -                                var handlerUpdateFn = binding["update"];
 60.2126 -                                handlerUpdateFn(node, makeValueAccessor(bindingKey), parsedBindingsAccessor, viewModel, bindingContextInstance);
 60.2127 -                            }
 60.2128 -                        }
 60.2129 -                    }
 60.2130 -                }
 60.2131 -            },
 60.2132 -            null,
 60.2133 -            { disposeWhenNodeIsRemoved : node }
 60.2134 -        );
 60.2135 -
 60.2136 -        return {
 60.2137 -            shouldBindDescendants: bindingHandlerThatControlsDescendantBindings === undefined
 60.2138 -        };
 60.2139 -    };
 60.2140 -
 60.2141 -    var storedBindingContextDomDataKey = "__ko_bindingContext__";
 60.2142 -    ko.storedBindingContextForNode = function (node, bindingContext) {
 60.2143 -        if (arguments.length == 2)
 60.2144 -            ko.utils.domData.set(node, storedBindingContextDomDataKey, bindingContext);
 60.2145 -        else
 60.2146 -            return ko.utils.domData.get(node, storedBindingContextDomDataKey);
 60.2147 -    }
 60.2148 -
 60.2149 -    ko.applyBindingsToNode = function (node, bindings, viewModel) {
 60.2150 -        if (node.nodeType === 1) // If it's an element, workaround IE <= 8 HTML parsing weirdness
 60.2151 -            ko.virtualElements.normaliseVirtualElementDomStructure(node);
 60.2152 -        return applyBindingsToNodeInternal(node, bindings, viewModel, true);
 60.2153 -    };
 60.2154 -
 60.2155 -    ko.applyBindingsToDescendants = function(viewModel, rootNode) {
 60.2156 -        if (rootNode.nodeType === 1 || rootNode.nodeType === 8)
 60.2157 -            applyBindingsToDescendantsInternal(viewModel, rootNode, true);
 60.2158 -    };
 60.2159 -
 60.2160 -    ko.applyBindings = function (viewModel, rootNode) {
 60.2161 -        if (rootNode && (rootNode.nodeType !== 1) && (rootNode.nodeType !== 8))
 60.2162 -            throw new Error("ko.applyBindings: first parameter should be your view model; second parameter should be a DOM node");
 60.2163 -        rootNode = rootNode || window.document.body; // Make "rootNode" parameter optional
 60.2164 -
 60.2165 -        applyBindingsToNodeAndDescendantsInternal(viewModel, rootNode, true);
 60.2166 -    };
 60.2167 -
 60.2168 -    // Retrieving binding context from arbitrary nodes
 60.2169 -    ko.contextFor = function(node) {
 60.2170 -        // We can only do something meaningful for elements and comment nodes (in particular, not text nodes, as IE can't store domdata for them)
 60.2171 -        switch (node.nodeType) {
 60.2172 -            case 1:
 60.2173 -            case 8:
 60.2174 -                var context = ko.storedBindingContextForNode(node);
 60.2175 -                if (context) return context;
 60.2176 -                if (node.parentNode) return ko.contextFor(node.parentNode);
 60.2177 -                break;
 60.2178 -        }
 60.2179 -        return undefined;
 60.2180 -    };
 60.2181 -    ko.dataFor = function(node) {
 60.2182 -        var context = ko.contextFor(node);
 60.2183 -        return context ? context['$data'] : undefined;
 60.2184 -    };
 60.2185 -
 60.2186 -    ko.exportSymbol('bindingHandlers', ko.bindingHandlers);
 60.2187 -    ko.exportSymbol('applyBindings', ko.applyBindings);
 60.2188 -    ko.exportSymbol('applyBindingsToDescendants', ko.applyBindingsToDescendants);
 60.2189 -    ko.exportSymbol('applyBindingsToNode', ko.applyBindingsToNode);
 60.2190 -    ko.exportSymbol('contextFor', ko.contextFor);
 60.2191 -    ko.exportSymbol('dataFor', ko.dataFor);
 60.2192 -})();
 60.2193 -var attrHtmlToJavascriptMap = { 'class': 'className', 'for': 'htmlFor' };
 60.2194 -ko.bindingHandlers['attr'] = {
 60.2195 -    'update': function(element, valueAccessor, allBindingsAccessor) {
 60.2196 -        var value = ko.utils.unwrapObservable(valueAccessor()) || {};
 60.2197 -        for (var attrName in value) {
 60.2198 -            if (typeof attrName == "string") {
 60.2199 -                var attrValue = ko.utils.unwrapObservable(value[attrName]);
 60.2200 -
 60.2201 -                // To cover cases like "attr: { checked:someProp }", we want to remove the attribute entirely
 60.2202 -                // when someProp is a "no value"-like value (strictly null, false, or undefined)
 60.2203 -                // (because the absence of the "checked" attr is how to mark an element as not checked, etc.)
 60.2204 -                var toRemove = (attrValue === false) || (attrValue === null) || (attrValue === undefined);
 60.2205 -                if (toRemove)
 60.2206 -                    element.removeAttribute(attrName);
 60.2207 -
 60.2208 -                // In IE <= 7 and IE8 Quirks Mode, you have to use the Javascript property name instead of the
 60.2209 -                // HTML attribute name for certain attributes. IE8 Standards Mode supports the correct behavior,
 60.2210 -                // but instead of figuring out the mode, we'll just set the attribute through the Javascript
 60.2211 -                // property for IE <= 8.
 60.2212 -                if (ko.utils.ieVersion <= 8 && attrName in attrHtmlToJavascriptMap) {
 60.2213 -                    attrName = attrHtmlToJavascriptMap[attrName];
 60.2214 -                    if (toRemove)
 60.2215 -                        element.removeAttribute(attrName);
 60.2216 -                    else
 60.2217 -                        element[attrName] = attrValue;
 60.2218 -                } else if (!toRemove) {
 60.2219 -                    try {
 60.2220 -                        element.setAttribute(attrName, attrValue.toString());
 60.2221 -                    } catch (err) {
 60.2222 -                        // ignore for now
 60.2223 -                        if (console) {
 60.2224 -                            console.log("Can't set attribute " + attrName + " to " + attrValue + " error: " + err);
 60.2225 -                        }
 60.2226 -                    }
 60.2227 -                }
 60.2228 -
 60.2229 -                // Treat "name" specially - although you can think of it as an attribute, it also needs
 60.2230 -                // special handling on older versions of IE (https://github.com/SteveSanderson/knockout/pull/333)
 60.2231 -                // Deliberately being case-sensitive here because XHTML would regard "Name" as a different thing
 60.2232 -                // entirely, and there's no strong reason to allow for such casing in HTML.
 60.2233 -                if (attrName === "name") {
 60.2234 -                    ko.utils.setElementName(element, toRemove ? "" : attrValue.toString());
 60.2235 -                }
 60.2236 -            }
 60.2237 -        }
 60.2238 -    }
 60.2239 -};
 60.2240 -ko.bindingHandlers['checked'] = {
 60.2241 -    'init': function (element, valueAccessor, allBindingsAccessor) {
 60.2242 -        var updateHandler = function() {
 60.2243 -            var valueToWrite;
 60.2244 -            if (element.type == "checkbox") {
 60.2245 -                valueToWrite = element.checked;
 60.2246 -            } else if ((element.type == "radio") && (element.checked)) {
 60.2247 -                valueToWrite = element.value;
 60.2248 -            } else {
 60.2249 -                return; // "checked" binding only responds to checkboxes and selected radio buttons
 60.2250 -            }
 60.2251 -
 60.2252 -            var modelValue = valueAccessor(), unwrappedValue = ko.utils.unwrapObservable(modelValue);
 60.2253 -            if ((element.type == "checkbox") && (unwrappedValue instanceof Array)) {
 60.2254 -                // For checkboxes bound to an array, we add/remove the checkbox value to that array
 60.2255 -                // This works for both observable and non-observable arrays
 60.2256 -                var existingEntryIndex = ko.utils.arrayIndexOf(unwrappedValue, element.value);
 60.2257 -                if (element.checked && (existingEntryIndex < 0))
 60.2258 -                    modelValue.push(element.value);
 60.2259 -                else if ((!element.checked) && (existingEntryIndex >= 0))
 60.2260 -                    modelValue.splice(existingEntryIndex, 1);
 60.2261 -            } else {
 60.2262 -                ko.expressionRewriting.writeValueToProperty(modelValue, allBindingsAccessor, 'checked', valueToWrite, true);
 60.2263 -            }
 60.2264 -        };
 60.2265 -        ko.utils.registerEventHandler(element, "click", updateHandler);
 60.2266 -
 60.2267 -        // IE 6 won't allow radio buttons to be selected unless they have a name
 60.2268 -        if ((element.type == "radio") && !element.name)
 60.2269 -            ko.bindingHandlers['uniqueName']['init'](element, function() { return true });
 60.2270 -    },
 60.2271 -    'update': function (element, valueAccessor) {
 60.2272 -        var value = ko.utils.unwrapObservable(valueAccessor());
 60.2273 -
 60.2274 -        if (element.type == "checkbox") {
 60.2275 -            if (value instanceof Array) {
 60.2276 -                // When bound to an array, the checkbox being checked represents its value being present in that array
 60.2277 -                element.checked = ko.utils.arrayIndexOf(value, element.value) >= 0;
 60.2278 -            } else {
 60.2279 -                // When bound to anything other value (not an array), the checkbox being checked represents the value being trueish
 60.2280 -                element.checked = value;
 60.2281 -            }
 60.2282 -        } else if (element.type == "radio") {
 60.2283 -            element.checked = (element.value == value);
 60.2284 -        }
 60.2285 -    }
 60.2286 -};
 60.2287 -var classesWrittenByBindingKey = '__ko__cssValue';
 60.2288 -ko.bindingHandlers['css'] = {
 60.2289 -    'update': function (element, valueAccessor) {
 60.2290 -        var value = ko.utils.unwrapObservable(valueAccessor());
 60.2291 -        if (typeof value == "object") {
 60.2292 -            for (var className in value) {
 60.2293 -                var shouldHaveClass = ko.utils.unwrapObservable(value[className]);
 60.2294 -                ko.utils.toggleDomNodeCssClass(element, className, shouldHaveClass);
 60.2295 -            }
 60.2296 -        } else {
 60.2297 -            value = String(value || ''); // Make sure we don't try to store or set a non-string value
 60.2298 -            ko.utils.toggleDomNodeCssClass(element, element[classesWrittenByBindingKey], false);
 60.2299 -            element[classesWrittenByBindingKey] = value;
 60.2300 -            ko.utils.toggleDomNodeCssClass(element, value, true);
 60.2301 -        }
 60.2302 -    }
 60.2303 -};
 60.2304 -ko.bindingHandlers['enable'] = {
 60.2305 -    'update': function (element, valueAccessor) {
 60.2306 -        var value = ko.utils.unwrapObservable(valueAccessor());
 60.2307 -        if (value && element.disabled)
 60.2308 -            element.removeAttribute("disabled");
 60.2309 -        else if ((!value) && (!element.disabled))
 60.2310 -            element.disabled = true;
 60.2311 -    }
 60.2312 -};
 60.2313 -
 60.2314 -ko.bindingHandlers['disable'] = {
 60.2315 -    'update': function (element, valueAccessor) {
 60.2316 -        ko.bindingHandlers['enable']['update'](element, function() { return !ko.utils.unwrapObservable(valueAccessor()) });
 60.2317 -    }
 60.2318 -};
 60.2319 -// For certain common events (currently just 'click'), allow a simplified data-binding syntax
 60.2320 -// e.g. click:handler instead of the usual full-length event:{click:handler}
 60.2321 -function makeEventHandlerShortcut(eventName) {
 60.2322 -    ko.bindingHandlers[eventName] = {
 60.2323 -        'init': function(element, valueAccessor, allBindingsAccessor, viewModel) {
 60.2324 -            var newValueAccessor = function () {
 60.2325 -                var result = {};
 60.2326 -                result[eventName] = valueAccessor();
 60.2327 -                return result;
 60.2328 -            };
 60.2329 -            return ko.bindingHandlers['event']['init'].call(this, element, newValueAccessor, allBindingsAccessor, viewModel);
 60.2330 -        }
 60.2331 -    }
 60.2332 -}
 60.2333 -
 60.2334 -ko.bindingHandlers['event'] = {
 60.2335 -    'init' : function (element, valueAccessor, allBindingsAccessor, viewModel) {
 60.2336 -        var eventsToHandle = valueAccessor() || {};
 60.2337 -        for(var eventNameOutsideClosure in eventsToHandle) {
 60.2338 -            (function() {
 60.2339 -                var eventName = eventNameOutsideClosure; // Separate variable to be captured by event handler closure
 60.2340 -                if (typeof eventName == "string") {
 60.2341 -                    ko.utils.registerEventHandler(element, eventName, function (event) {
 60.2342 -                        var handlerReturnValue;
 60.2343 -                        var handlerFunction = valueAccessor()[eventName];
 60.2344 -                        if (!handlerFunction)
 60.2345 -                            return;
 60.2346 -                        var allBindings = allBindingsAccessor();
 60.2347 -
 60.2348 -                        try {
 60.2349 -                            // Take all the event args, and prefix with the viewmodel
 60.2350 -                            var argsForHandler = ko.utils.makeArray(arguments);
 60.2351 -                            argsForHandler.unshift(viewModel);
 60.2352 -                            handlerReturnValue = handlerFunction.apply(viewModel, argsForHandler);
 60.2353 -                        } finally {
 60.2354 -                            if (handlerReturnValue !== true) { // Normally we want to prevent default action. Developer can override this be explicitly returning true.
 60.2355 -                                if (event.preventDefault)
 60.2356 -                                    event.preventDefault();
 60.2357 -                                else
 60.2358 -                                    event.returnValue = false;
 60.2359 -                            }
 60.2360 -                        }
 60.2361 -
 60.2362 -                        var bubble = allBindings[eventName + 'Bubble'] !== false;
 60.2363 -                        if (!bubble) {
 60.2364 -                            event.cancelBubble = true;
 60.2365 -                            if (event.stopPropagation)
 60.2366 -                                event.stopPropagation();
 60.2367 -                        }
 60.2368 -                    });
 60.2369 -                }
 60.2370 -            })();
 60.2371 -        }
 60.2372 -    }
 60.2373 -};
 60.2374 -// "foreach: someExpression" is equivalent to "template: { foreach: someExpression }"
 60.2375 -// "foreach: { data: someExpression, afterAdd: myfn }" is equivalent to "template: { foreach: someExpression, afterAdd: myfn }"
 60.2376 -ko.bindingHandlers['foreach'] = {
 60.2377 -    makeTemplateValueAccessor: function(valueAccessor) {
 60.2378 -        return function() {
 60.2379 -            var modelValue = valueAccessor(),
 60.2380 -                unwrappedValue = ko.utils.peekObservable(modelValue);    // Unwrap without setting a dependency here
 60.2381 -
 60.2382 -            // If unwrappedValue is the array, pass in the wrapped value on its own
 60.2383 -            // The value will be unwrapped and tracked within the template binding
 60.2384 -            // (See https://github.com/SteveSanderson/knockout/issues/523)
 60.2385 -            if ((!unwrappedValue) || typeof unwrappedValue.length == "number")
 60.2386 -                return { 'foreach': modelValue, 'templateEngine': ko.nativeTemplateEngine.instance };
 60.2387 -
 60.2388 -            // If unwrappedValue.data is the array, preserve all relevant options and unwrap again value so we get updates
 60.2389 -            ko.utils.unwrapObservable(modelValue);
 60.2390 -            return {
 60.2391 -                'foreach': unwrappedValue['data'],
 60.2392 -                'as': unwrappedValue['as'],
 60.2393 -                'includeDestroyed': unwrappedValue['includeDestroyed'],
 60.2394 -                'afterAdd': unwrappedValue['afterAdd'],
 60.2395 -                'beforeRemove': unwrappedValue['beforeRemove'],
 60.2396 -                'afterRender': unwrappedValue['afterRender'],
 60.2397 -                'beforeMove': unwrappedValue['beforeMove'],
 60.2398 -                'afterMove': unwrappedValue['afterMove'],
 60.2399 -                'templateEngine': ko.nativeTemplateEngine.instance
 60.2400 -            };
 60.2401 -        };
 60.2402 -    },
 60.2403 -    'init': function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
 60.2404 -        return ko.bindingHandlers['template']['init'](element, ko.bindingHandlers['foreach'].makeTemplateValueAccessor(valueAccessor));
 60.2405 -    },
 60.2406 -    'update': function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
 60.2407 -        return ko.bindingHandlers['template']['update'](element, ko.bindingHandlers['foreach'].makeTemplateValueAccessor(valueAccessor), allBindingsAccessor, viewModel, bindingContext);
 60.2408 -    }
 60.2409 -};
 60.2410 -ko.expressionRewriting.bindingRewriteValidators['foreach'] = false; // Can't rewrite control flow bindings
 60.2411 -ko.virtualElements.allowedBindings['foreach'] = true;
 60.2412 -var hasfocusUpdatingProperty = '__ko_hasfocusUpdating';
 60.2413 -ko.bindingHandlers['hasfocus'] = {
 60.2414 -    'init': function(element, valueAccessor, allBindingsAccessor) {
 60.2415 -        var handleElementFocusChange = function(isFocused) {
 60.2416 -            // Where possible, ignore which event was raised and determine focus state using activeElement,
 60.2417 -            // as this avoids phantom focus/blur events raised when changing tabs in modern browsers.
 60.2418 -            // However, not all KO-targeted browsers (Firefox 2) support activeElement. For those browsers,
 60.2419 -            // prevent a loss of focus when changing tabs/windows by setting a flag that prevents hasfocus
 60.2420 -            // from calling 'blur()' on the element when it loses focus.
 60.2421 -            // Discussion at https://github.com/SteveSanderson/knockout/pull/352
 60.2422 -            element[hasfocusUpdatingProperty] = true;
 60.2423 -            var ownerDoc = element.ownerDocument;
 60.2424 -            if ("activeElement" in ownerDoc) {
 60.2425 -                isFocused = (ownerDoc.activeElement === element);
 60.2426 -            }
 60.2427 -            var modelValue = valueAccessor();
 60.2428 -            ko.expressionRewriting.writeValueToProperty(modelValue, allBindingsAccessor, 'hasfocus', isFocused, true);
 60.2429 -            element[hasfocusUpdatingProperty] = false;
 60.2430 -        };
 60.2431 -        var handleElementFocusIn = handleElementFocusChange.bind(null, true);
 60.2432 -        var handleElementFocusOut = handleElementFocusChange.bind(null, false);
 60.2433 -
 60.2434 -        ko.utils.registerEventHandler(element, "focus", handleElementFocusIn);
 60.2435 -        ko.utils.registerEventHandler(element, "focusin", handleElementFocusIn); // For IE
 60.2436 -        ko.utils.registerEventHandler(element, "blur",  handleElementFocusOut);
 60.2437 -        ko.utils.registerEventHandler(element, "focusout",  handleElementFocusOut); // For IE
 60.2438 -    },
 60.2439 -    'update': function(element, valueAccessor) {
 60.2440 -        var value = ko.utils.unwrapObservable(valueAccessor());
 60.2441 -        if (!element[hasfocusUpdatingProperty]) {
 60.2442 -            value ? element.focus() : element.blur();
 60.2443 -            ko.dependencyDetection.ignore(ko.utils.triggerEvent, null, [element, value ? "focusin" : "focusout"]); // For IE, which doesn't reliably fire "focus" or "blur" events synchronously
 60.2444 -        }
 60.2445 -    }
 60.2446 -};
 60.2447 -ko.bindingHandlers['html'] = {
 60.2448 -    'init': function() {
 60.2449 -        // Prevent binding on the dynamically-injected HTML (as developers are unlikely to expect that, and it has security implications)
 60.2450 -        return { 'controlsDescendantBindings': true };
 60.2451 -    },
 60.2452 -    'update': function (element, valueAccessor) {
 60.2453 -        // setHtml will unwrap the value if needed
 60.2454 -        ko.utils.setHtml(element, valueAccessor());
 60.2455 -    }
 60.2456 -};
 60.2457 -var withIfDomDataKey = '__ko_withIfBindingData';
 60.2458 -// Makes a binding like with or if
 60.2459 -function makeWithIfBinding(bindingKey, isWith, isNot, makeContextCallback) {
 60.2460 -    ko.bindingHandlers[bindingKey] = {
 60.2461 -        'init': function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
 60.2462 -            ko.utils.domData.set(element, withIfDomDataKey, {});
 60.2463 -            return { 'controlsDescendantBindings': true };
 60.2464 -        },
 60.2465 -        'update': function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
 60.2466 -            var withIfData = ko.utils.domData.get(element, withIfDomDataKey),
 60.2467 -                dataValue = ko.utils.unwrapObservable(valueAccessor()),
 60.2468 -                shouldDisplay = !isNot !== !dataValue, // equivalent to isNot ? !dataValue : !!dataValue
 60.2469 -                isFirstRender = !withIfData.savedNodes,
 60.2470 -                needsRefresh = isFirstRender || isWith || (shouldDisplay !== withIfData.didDisplayOnLastUpdate);
 60.2471 -
 60.2472 -            if (needsRefresh) {
 60.2473 -                if (isFirstRender) {
 60.2474 -                    withIfData.savedNodes = ko.utils.cloneNodes(ko.virtualElements.childNodes(element), true /* shouldCleanNodes */);
 60.2475 -                }
 60.2476 -
 60.2477 -                if (shouldDisplay) {
 60.2478 -                    if (!isFirstRender) {
 60.2479 -                        ko.virtualElements.setDomNodeChildren(element, ko.utils.cloneNodes(withIfData.savedNodes));
 60.2480 -                    }
 60.2481 -                    ko.applyBindingsToDescendants(makeContextCallback ? makeContextCallback(bindingContext, dataValue) : bindingContext, element);
 60.2482 -                } else {
 60.2483 -                    ko.virtualElements.emptyNode(element);
 60.2484 -                }
 60.2485 -
 60.2486 -                withIfData.didDisplayOnLastUpdate = shouldDisplay;
 60.2487 -            }
 60.2488 -        }
 60.2489 -    };
 60.2490 -    ko.expressionRewriting.bindingRewriteValidators[bindingKey] = false; // Can't rewrite control flow bindings
 60.2491 -    ko.virtualElements.allowedBindings[bindingKey] = true;
 60.2492 -}
 60.2493 -
 60.2494 -// Construct the actual binding handlers
 60.2495 -makeWithIfBinding('if');
 60.2496 -makeWithIfBinding('ifnot', false /* isWith */, true /* isNot */);
 60.2497 -makeWithIfBinding('with', true /* isWith */, false /* isNot */,
 60.2498 -    function(bindingContext, dataValue) {
 60.2499 -        return bindingContext['createChildContext'](dataValue);
 60.2500 -    }
 60.2501 -);
 60.2502 -function ensureDropdownSelectionIsConsistentWithModelValue(element, modelValue, preferModelValue) {
 60.2503 -    if (preferModelValue) {
 60.2504 -        if (modelValue !== ko.selectExtensions.readValue(element))
 60.2505 -            ko.selectExtensions.writeValue(element, modelValue);
 60.2506 -    }
 60.2507 -
 60.2508 -    // No matter which direction we're syncing in, we want the end result to be equality between dropdown value and model value.
 60.2509 -    // If they aren't equal, either we prefer the dropdown value, or the model value couldn't be represented, so either way,
 60.2510 -    // change the model value to match the dropdown.
 60.2511 -    if (modelValue !== ko.selectExtensions.readValue(element))
 60.2512 -        ko.dependencyDetection.ignore(ko.utils.triggerEvent, null, [element, "change"]);
 60.2513 -};
 60.2514 -
 60.2515 -ko.bindingHandlers['options'] = {
 60.2516 -    'update': function (element, valueAccessor, allBindingsAccessor) {
 60.2517 -        if (ko.utils.tagNameLower(element) !== "select")
 60.2518 -            throw new Error("options binding applies only to SELECT elements");
 60.2519 -
 60.2520 -        var selectWasPreviouslyEmpty = element.length == 0;
 60.2521 -        var previousSelectedValues = ko.utils.arrayMap(ko.utils.arrayFilter(element.childNodes, function (node) {
 60.2522 -            return node.tagName && (ko.utils.tagNameLower(node) === "option") && node.selected;
 60.2523 -        }), function (node) {
 60.2524 -            return ko.selectExtensions.readValue(node) || node.innerText || node.textContent;
 60.2525 -        });
 60.2526 -        var previousScrollTop = element.scrollTop;
 60.2527 -
 60.2528 -        var value = ko.utils.unwrapObservable(valueAccessor());
 60.2529 -        var selectedValue = element.value;
 60.2530 -
 60.2531 -        // Remove all existing <option>s.
 60.2532 -        // Need to use .remove() rather than .removeChild() for <option>s otherwise IE behaves oddly (https://github.com/SteveSanderson/knockout/issues/134)
 60.2533 -        while (element.length > 0) {
 60.2534 -            ko.cleanNode(element.options[0]);
 60.2535 -            element.remove(0);
 60.2536 -        }
 60.2537 -
 60.2538 -        if (value) {
 60.2539 -            var allBindings = allBindingsAccessor(),
 60.2540 -                includeDestroyed = allBindings['optionsIncludeDestroyed'];
 60.2541 -
 60.2542 -            if (typeof value.length != "number")
 60.2543 -                value = [value];
 60.2544 -            if (allBindings['optionsCaption']) {
 60.2545 -                var option = document.createElement("option");
 60.2546 -                ko.utils.setHtml(option, allBindings['optionsCaption']);
 60.2547 -                ko.selectExtensions.writeValue(option, undefined);
 60.2548 -                element.appendChild(option);
 60.2549 -            }
 60.2550 -
 60.2551 -            for (var i = 0, j = value.length; i < j; i++) {
 60.2552 -                // Skip destroyed items
 60.2553 -                var arrayEntry = value[i];
 60.2554 -                if (arrayEntry && arrayEntry['_destroy'] && !includeDestroyed)
 60.2555 -                    continue;
 60.2556 -
 60.2557 -                var option = document.createElement("option");
 60.2558 -
 60.2559 -                function applyToObject(object, predicate, defaultValue) {
 60.2560 -                    var predicateType = typeof predicate;
 60.2561 -                    if (predicateType == "function")    // Given a function; run it against the data value
 60.2562 -                        return predicate(object);
 60.2563 -                    else if (predicateType == "string") // Given a string; treat it as a property name on the data value
 60.2564 -                        return object[predicate];
 60.2565 -                    else                                // Given no optionsText arg; use the data value itself
 60.2566 -                        return defaultValue;
 60.2567 -                }
 60.2568 -
 60.2569 -                // Apply a value to the option element
 60.2570 -                var optionValue = applyToObject(arrayEntry, allBindings['optionsValue'], arrayEntry);
 60.2571 -                ko.selectExtensions.writeValue(option, ko.utils.unwrapObservable(optionValue));
 60.2572 -
 60.2573 -                // Apply some text to the option element
 60.2574 -                var optionText = applyToObject(arrayEntry, allBindings['optionsText'], optionValue);
 60.2575 -                ko.utils.setTextContent(option, optionText);
 60.2576 -
 60.2577 -                element.appendChild(option);
 60.2578 -            }
 60.2579 -
 60.2580 -            // IE6 doesn't like us to assign selection to OPTION nodes before they're added to the document.
 60.2581 -            // That's why we first added them without selection. Now it's time to set the selection.
 60.2582 -            var newOptions = element.getElementsByTagName("option");
 60.2583 -            var countSelectionsRetained = 0;
 60.2584 -            for (var i = 0, j = newOptions.length; i < j; i++) {
 60.2585 -                if (ko.utils.arrayIndexOf(previousSelectedValues, ko.selectExtensions.readValue(newOptions[i])) >= 0) {
 60.2586 -                    ko.utils.setOptionNodeSelectionState(newOptions[i], true);
 60.2587 -                    countSelectionsRetained++;
 60.2588 -                }
 60.2589 -            }
 60.2590 -
 60.2591 -            element.scrollTop = previousScrollTop;
 60.2592 -
 60.2593 -            if (selectWasPreviouslyEmpty && ('value' in allBindings)) {
 60.2594 -                // Ensure consistency between model value and selected option.
 60.2595 -                // If the dropdown is being populated for the first time here (or was otherwise previously empty),
 60.2596 -                // the dropdown selection state is meaningless, so we preserve the model value.
 60.2597 -                ensureDropdownSelectionIsConsistentWithModelValue(element, ko.utils.peekObservable(allBindings['value']), /* preferModelValue */ true);
 60.2598 -            }
 60.2599 -
 60.2600 -            // Workaround for IE9 bug
 60.2601 -            ko.utils.ensureSelectElementIsRenderedCorrectly(element);
 60.2602 -        }
 60.2603 -    }
 60.2604 -};
 60.2605 -ko.bindingHandlers['options'].optionValueDomDataKey = '__ko.optionValueDomData__';
 60.2606 -ko.bindingHandlers['selectedOptions'] = {
 60.2607 -    'init': function (element, valueAccessor, allBindingsAccessor) {
 60.2608 -        ko.utils.registerEventHandler(element, "change", function () {
 60.2609 -            var value = valueAccessor(), valueToWrite = [];
 60.2610 -            ko.utils.arrayForEach(element.getElementsByTagName("option"), function(node) {
 60.2611 -                if (node.selected)
 60.2612 -                    valueToWrite.push(ko.selectExtensions.readValue(node));
 60.2613 -            });
 60.2614 -            ko.expressionRewriting.writeValueToProperty(value, allBindingsAccessor, 'value', valueToWrite);
 60.2615 -        });
 60.2616 -    },
 60.2617 -    'update': function (element, valueAccessor) {
 60.2618 -        if (ko.utils.tagNameLower(element) != "select")
 60.2619 -            throw new Error("values binding applies only to SELECT elements");
 60.2620 -
 60.2621 -        var newValue = ko.utils.unwrapObservable(valueAccessor());
 60.2622 -        if (newValue && typeof newValue.length == "number") {
 60.2623 -            ko.utils.arrayForEach(element.getElementsByTagName("option"), function(node) {
 60.2624 -                var isSelected = ko.utils.arrayIndexOf(newValue, ko.selectExtensions.readValue(node)) >= 0;
 60.2625 -                ko.utils.setOptionNodeSelectionState(node, isSelected);
 60.2626 -            });
 60.2627 -        }
 60.2628 -    }
 60.2629 -};
 60.2630 -ko.bindingHandlers['style'] = {
 60.2631 -    'update': function (element, valueAccessor) {
 60.2632 -        var value = ko.utils.unwrapObservable(valueAccessor() || {});
 60.2633 -        for (var styleName in value) {
 60.2634 -            if (typeof styleName == "string") {
 60.2635 -                var styleValue = ko.utils.unwrapObservable(value[styleName]);
 60.2636 -                element.style[styleName] = styleValue || ""; // Empty string removes the value, whereas null/undefined have no effect
 60.2637 -            }
 60.2638 -        }
 60.2639 -    }
 60.2640 -};
 60.2641 -ko.bindingHandlers['submit'] = {
 60.2642 -    'init': function (element, valueAccessor, allBindingsAccessor, viewModel) {
 60.2643 -        if (typeof valueAccessor() != "function")
 60.2644 -            throw new Error("The value for a submit binding must be a function");
 60.2645 -        ko.utils.registerEventHandler(element, "submit", function (event) {
 60.2646 -            var handlerReturnValue;
 60.2647 -            var value = valueAccessor();
 60.2648 -            try { handlerReturnValue = value.call(viewModel, element); }
 60.2649 -            finally {
 60.2650 -                if (handlerReturnValue !== true) { // Normally we want to prevent default action. Developer can override this be explicitly returning true.
 60.2651 -                    if (event.preventDefault)
 60.2652 -                        event.preventDefault();
 60.2653 -                    else
 60.2654 -                        event.returnValue = false;
 60.2655 -                }
 60.2656 -            }
 60.2657 -        });
 60.2658 -    }
 60.2659 -};
 60.2660 -ko.bindingHandlers['text'] = {
 60.2661 -    'update': function (element, valueAccessor) {
 60.2662 -        ko.utils.setTextContent(element, valueAccessor());
 60.2663 -    }
 60.2664 -};
 60.2665 -ko.virtualElements.allowedBindings['text'] = true;
 60.2666 -ko.bindingHandlers['uniqueName'] = {
 60.2667 -    'init': function (element, valueAccessor) {
 60.2668 -        if (valueAccessor()) {
 60.2669 -            var name = "ko_unique_" + (++ko.bindingHandlers['uniqueName'].currentIndex);
 60.2670 -            ko.utils.setElementName(element, name);
 60.2671 -        }
 60.2672 -    }
 60.2673 -};
 60.2674 -ko.bindingHandlers['uniqueName'].currentIndex = 0;
 60.2675 -ko.bindingHandlers['value'] = {
 60.2676 -    'init': function (element, valueAccessor, allBindingsAccessor) {
 60.2677 -        // Always catch "change" event; possibly other events too if asked
 60.2678 -        var eventsToCatch = ["change"];
 60.2679 -        var requestedEventsToCatch = allBindingsAccessor()["valueUpdate"];
 60.2680 -        var propertyChangedFired = false;
 60.2681 -        if (requestedEventsToCatch) {
 60.2682 -            if (typeof requestedEventsToCatch == "string") // Allow both individual event names, and arrays of event names
 60.2683 -                requestedEventsToCatch = [requestedEventsToCatch];
 60.2684 -            ko.utils.arrayPushAll(eventsToCatch, requestedEventsToCatch);
 60.2685 -            eventsToCatch = ko.utils.arrayGetDistinctValues(eventsToCatch);
 60.2686 -        }
 60.2687 -
 60.2688 -        var valueUpdateHandler = function() {
 60.2689 -            propertyChangedFired = false;
 60.2690 -            var modelValue = valueAccessor();
 60.2691 -            var elementValue = ko.selectExtensions.readValue(element);
 60.2692 -            ko.expressionRewriting.writeValueToProperty(modelValue, allBindingsAccessor, 'value', elementValue);
 60.2693 -        }
 60.2694 -
 60.2695 -        // Workaround for https://github.com/SteveSanderson/knockout/issues/122
 60.2696 -        // IE doesn't fire "change" events on textboxes if the user selects a value from its autocomplete list
 60.2697 -        var ieAutoCompleteHackNeeded = ko.utils.ieVersion && element.tagName.toLowerCase() == "input" && element.type == "text"
 60.2698 -                                       && element.autocomplete != "off" && (!element.form || element.form.autocomplete != "off");
 60.2699 -        if (ieAutoCompleteHackNeeded && ko.utils.arrayIndexOf(eventsToCatch, "propertychange") == -1) {
 60.2700 -            ko.utils.registerEventHandler(element, "propertychange", function () { propertyChangedFired = true });
 60.2701 -            ko.utils.registerEventHandler(element, "blur", function() {
 60.2702 -                if (propertyChangedFired) {
 60.2703 -                    valueUpdateHandler();
 60.2704 -                }
 60.2705 -            });
 60.2706 -        }
 60.2707 -
 60.2708 -        ko.utils.arrayForEach(eventsToCatch, function(eventName) {
 60.2709 -            // The syntax "after<eventname>" means "run the handler asynchronously after the event"
 60.2710 -            // This is useful, for example, to catch "keydown" events after the browser has updated the control
 60.2711 -            // (otherwise, ko.selectExtensions.readValue(this) will receive the control's value *before* the key event)
 60.2712 -            var handler = valueUpdateHandler;
 60.2713 -            if (ko.utils.stringStartsWith(eventName, "after")) {
 60.2714 -                handler = function() { setTimeout(valueUpdateHandler, 0) };
 60.2715 -                eventName = eventName.substring("after".length);
 60.2716 -            }
 60.2717 -            ko.utils.registerEventHandler(element, eventName, handler);
 60.2718 -        });
 60.2719 -    },
 60.2720 -    'update': function (element, valueAccessor) {
 60.2721 -        var valueIsSelectOption = ko.utils.tagNameLower(element) === "select";
 60.2722 -        var newValue = ko.utils.unwrapObservable(valueAccessor());
 60.2723 -        var elementValue = ko.selectExtensions.readValue(element);
 60.2724 -        var valueHasChanged = (newValue != elementValue);
 60.2725 -
 60.2726 -        // JavaScript's 0 == "" behavious is unfortunate here as it prevents writing 0 to an empty text box (loose equality suggests the values are the same).
 60.2727 -        // We don't want to do a strict equality comparison as that is more confusing for developers in certain cases, so we specifically special case 0 != "" here.
 60.2728 -        if ((newValue === 0) && (elementValue !== 0) && (elementValue !== "0"))
 60.2729 -            valueHasChanged = true;
 60.2730 -
 60.2731 -        if (valueHasChanged) {
 60.2732 -            var applyValueAction = function () { ko.selectExtensions.writeValue(element, newValue); };
 60.2733 -            applyValueAction();
 60.2734 -
 60.2735 -            // Workaround for IE6 bug: It won't reliably apply values to SELECT nodes during the same execution thread
 60.2736 -            // right after you've changed the set of OPTION nodes on it. So for that node type, we'll schedule a second thread
 60.2737 -            // to apply the value as well.
 60.2738 -            var alsoApplyAsynchronously = valueIsSelectOption;
 60.2739 -            if (alsoApplyAsynchronously)
 60.2740 -                setTimeout(applyValueAction, 0);
 60.2741 -        }
 60.2742 -
 60.2743 -        // If you try to set a model value that can't be represented in an already-populated dropdown, reject that change,
 60.2744 -        // because you're not allowed to have a model value that disagrees with a visible UI selection.
 60.2745 -        if (valueIsSelectOption && (element.length > 0))
 60.2746 -            ensureDropdownSelectionIsConsistentWithModelValue(element, newValue, /* preferModelValue */ false);
 60.2747 -    }
 60.2748 -};
 60.2749 -ko.bindingHandlers['visible'] = {
 60.2750 -    'update': function (element, valueAccessor) {
 60.2751 -        var value = ko.utils.unwrapObservable(valueAccessor());
 60.2752 -        var isCurrentlyVisible = !(element.style.display == "none");
 60.2753 -        if (value && !isCurrentlyVisible)
 60.2754 -            element.style.display = "";
 60.2755 -        else if ((!value) && isCurrentlyVisible)
 60.2756 -            element.style.display = "none";
 60.2757 -    }
 60.2758 -};
 60.2759 -// 'click' is just a shorthand for the usual full-length event:{click:handler}
 60.2760 -makeEventHandlerShortcut('click');
 60.2761 -// If you want to make a custom template engine,
 60.2762 -//
 60.2763 -// [1] Inherit from this class (like ko.nativeTemplateEngine does)
 60.2764 -// [2] Override 'renderTemplateSource', supplying a function with this signature:
 60.2765 -//
 60.2766 -//        function (templateSource, bindingContext, options) {
 60.2767 -//            // - templateSource.text() is the text of the template you should render
 60.2768 -//            // - bindingContext.$data is the data you should pass into the template
 60.2769 -//            //   - you might also want to make bindingContext.$parent, bindingContext.$parents,
 60.2770 -//            //     and bindingContext.$root available in the template too
 60.2771 -//            // - options gives you access to any other properties set on "data-bind: { template: options }"
 60.2772 -//            //
 60.2773 -//            // Return value: an array of DOM nodes
 60.2774 -//        }
 60.2775 -//
 60.2776 -// [3] Override 'createJavaScriptEvaluatorBlock', supplying a function with this signature:
 60.2777 -//
 60.2778 -//        function (script) {
 60.2779 -//            // Return value: Whatever syntax means "Evaluate the JavaScript statement 'script' and output the result"
 60.2780 -//            //               For example, the jquery.tmpl template engine converts 'someScript' to '${ someScript }'
 60.2781 -//        }
 60.2782 -//
 60.2783 -//     This is only necessary if you want to allow data-bind attributes to reference arbitrary template variables.
 60.2784 -//     If you don't want to allow that, you can set the property 'allowTemplateRewriting' to false (like ko.nativeTemplateEngine does)
 60.2785 -//     and then you don't need to override 'createJavaScriptEvaluatorBlock'.
 60.2786 -
 60.2787 -ko.templateEngine = function () { };
 60.2788 -
 60.2789 -ko.templateEngine.prototype['renderTemplateSource'] = function (templateSource, bindingContext, options) {
 60.2790 -    throw new Error("Override renderTemplateSource");
 60.2791 -};
 60.2792 -
 60.2793 -ko.templateEngine.prototype['createJavaScriptEvaluatorBlock'] = function (script) {
 60.2794 -    throw new Error("Override createJavaScriptEvaluatorBlock");
 60.2795 -};
 60.2796 -
 60.2797 -ko.templateEngine.prototype['makeTemplateSource'] = function(template, templateDocument) {
 60.2798 -    // Named template
 60.2799 -    if (typeof template == "string") {
 60.2800 -        templateDocument = templateDocument || document;
 60.2801 -        var elem = templateDocument.getElementById(template);
 60.2802 -        if (!elem)
 60.2803 -            throw new Error("Cannot find template with ID " + template);
 60.2804 -        return new ko.templateSources.domElement(elem);
 60.2805 -    } else if ((template.nodeType == 1) || (template.nodeType == 8)) {
 60.2806 -        // Anonymous template
 60.2807 -        return new ko.templateSources.anonymousTemplate(template);
 60.2808 -    } else
 60.2809 -        throw new Error("Unknown template type: " + template);
 60.2810 -};
 60.2811 -
 60.2812 -ko.templateEngine.prototype['renderTemplate'] = function (template, bindingContext, options, templateDocument) {
 60.2813 -    var templateSource = this['makeTemplateSource'](template, templateDocument);
 60.2814 -    return this['renderTemplateSource'](templateSource, bindingContext, options);
 60.2815 -};
 60.2816 -
 60.2817 -ko.templateEngine.prototype['isTemplateRewritten'] = function (template, templateDocument) {
 60.2818 -    // Skip rewriting if requested
 60.2819 -    if (this['allowTemplateRewriting'] === false)
 60.2820 -        return true;
 60.2821 -    return this['makeTemplateSource'](template, templateDocument)['data']("isRewritten");
 60.2822 -};
 60.2823 -
 60.2824 -ko.templateEngine.prototype['rewriteTemplate'] = function (template, rewriterCallback, templateDocument) {
 60.2825 -    var templateSource = this['makeTemplateSource'](template, templateDocument);
 60.2826 -    var rewritten = rewriterCallback(templateSource['text']());
 60.2827 -    templateSource['text'](rewritten);
 60.2828 -    templateSource['data']("isRewritten", true);
 60.2829 -};
 60.2830 -
 60.2831 -ko.exportSymbol('templateEngine', ko.templateEngine);
 60.2832 -
 60.2833 -ko.templateRewriting = (function () {
 60.2834 -    var memoizeDataBindingAttributeSyntaxRegex = /(<[a-z]+\d*(\s+(?!data-bind=)[a-z0-9\-]+(=(\"[^\"]*\"|\'[^\']*\'))?)*\s+)data-bind=(["'])([\s\S]*?)\5/gi;
 60.2835 -    var memoizeVirtualContainerBindingSyntaxRegex = /<!--\s*ko\b\s*([\s\S]*?)\s*-->/g;
 60.2836 -
 60.2837 -    function validateDataBindValuesForRewriting(keyValueArray) {
 60.2838 -        var allValidators = ko.expressionRewriting.bindingRewriteValidators;
 60.2839 -        for (var i = 0; i < keyValueArray.length; i++) {
 60.2840 -            var key = keyValueArray[i]['key'];
 60.2841 -            if (allValidators.hasOwnProperty(key)) {
 60.2842 -                var validator = allValidators[key];
 60.2843 -
 60.2844 -                if (typeof validator === "function") {
 60.2845 -                    var possibleErrorMessage = validator(keyValueArray[i]['value']);
 60.2846 -                    if (possibleErrorMessage)
 60.2847 -                        throw new Error(possibleErrorMessage);
 60.2848 -                } else if (!validator) {
 60.2849 -                    throw new Error("This template engine does not support the '" + key + "' binding within its templates");
 60.2850 -                }
 60.2851 -            }
 60.2852 -        }
 60.2853 -    }
 60.2854 -
 60.2855 -    function constructMemoizedTagReplacement(dataBindAttributeValue, tagToRetain, templateEngine) {
 60.2856 -        var dataBindKeyValueArray = ko.expressionRewriting.parseObjectLiteral(dataBindAttributeValue);
 60.2857 -        validateDataBindValuesForRewriting(dataBindKeyValueArray);
 60.2858 -        var rewrittenDataBindAttributeValue = ko.expressionRewriting.preProcessBindings(dataBindKeyValueArray);
 60.2859 -
 60.2860 -        // For no obvious reason, Opera fails to evaluate rewrittenDataBindAttributeValue unless it's wrapped in an additional
 60.2861 -        // anonymous function, even though Opera's built-in debugger can evaluate it anyway. No other browser requires this
 60.2862 -        // extra indirection.
 60.2863 -        var applyBindingsToNextSiblingScript =
 60.2864 -            "ko.__tr_ambtns(function($context,$element){return(function(){return{ " + rewrittenDataBindAttributeValue + " } })()})";
 60.2865 -        return templateEngine['createJavaScriptEvaluatorBlock'](applyBindingsToNextSiblingScript) + tagToRetain;
 60.2866 -    }
 60.2867 -
 60.2868 -    return {
 60.2869 -        ensureTemplateIsRewritten: function (template, templateEngine, templateDocument) {
 60.2870 -            if (!templateEngine['isTemplateRewritten'](template, templateDocument))
 60.2871 -                templateEngine['rewriteTemplate'](template, function (htmlString) {
 60.2872 -                    return ko.templateRewriting.memoizeBindingAttributeSyntax(htmlString, templateEngine);
 60.2873 -                }, templateDocument);
 60.2874 -        },
 60.2875 -
 60.2876 -        memoizeBindingAttributeSyntax: function (htmlString, templateEngine) {
 60.2877 -            return htmlString.replace(memoizeDataBindingAttributeSyntaxRegex, function () {
 60.2878 -                return constructMemoizedTagReplacement(/* dataBindAttributeValue: */ arguments[6], /* tagToRetain: */ arguments[1], templateEngine);
 60.2879 -            }).replace(memoizeVirtualContainerBindingSyntaxRegex, function() {
 60.2880 -                return constructMemoizedTagReplacement(/* dataBindAttributeValue: */ arguments[1], /* tagToRetain: */ "<!-- ko -->", templateEngine);
 60.2881 -            });
 60.2882 -        },
 60.2883 -
 60.2884 -        applyMemoizedBindingsToNextSibling: function (bindings) {
 60.2885 -            return ko.memoization.memoize(function (domNode, bindingContext) {
 60.2886 -                if (domNode.nextSibling)
 60.2887 -                    ko.applyBindingsToNode(domNode.nextSibling, bindings, bindingContext);
 60.2888 -            });
 60.2889 -        }
 60.2890 -    }
 60.2891 -})();
 60.2892 -
 60.2893 -
 60.2894 -// Exported only because it has to be referenced by string lookup from within rewritten template
 60.2895 -ko.exportSymbol('__tr_ambtns', ko.templateRewriting.applyMemoizedBindingsToNextSibling);
 60.2896 -(function() {
 60.2897 -    // A template source represents a read/write way of accessing a template. This is to eliminate the need for template loading/saving
 60.2898 -    // logic to be duplicated in every template engine (and means they can all work with anonymous templates, etc.)
 60.2899 -    //
 60.2900 -    // Two are provided by default:
 60.2901 -    //  1. ko.templateSources.domElement       - reads/writes the text content of an arbitrary DOM element
 60.2902 -    //  2. ko.templateSources.anonymousElement - uses ko.utils.domData to read/write text *associated* with the DOM element, but
 60.2903 -    //                                           without reading/writing the actual element text content, since it will be overwritten
 60.2904 -    //                                           with the rendered template output.
 60.2905 -    // You can implement your own template source if you want to fetch/store templates somewhere other than in DOM elements.
 60.2906 -    // Template sources need to have the following functions:
 60.2907 -    //   text() 			- returns the template text from your storage location
 60.2908 -    //   text(value)		- writes the supplied template text to your storage location
 60.2909 -    //   data(key)			- reads values stored using data(key, value) - see below
 60.2910 -    //   data(key, value)	- associates "value" with this template and the key "key". Is used to store information like "isRewritten".
 60.2911 -    //
 60.2912 -    // Optionally, template sources can also have the following functions:
 60.2913 -    //   nodes()            - returns a DOM element containing the nodes of this template, where available
 60.2914 -    //   nodes(value)       - writes the given DOM element to your storage location
 60.2915 -    // If a DOM element is available for a given template source, template engines are encouraged to use it in preference over text()
 60.2916 -    // for improved speed. However, all templateSources must supply text() even if they don't supply nodes().
 60.2917 -    //
 60.2918 -    // Once you've implemented a templateSource, make your template engine use it by subclassing whatever template engine you were
 60.2919 -    // using and overriding "makeTemplateSource" to return an instance of your custom template source.
 60.2920 -
 60.2921 -    ko.templateSources = {};
 60.2922 -
 60.2923 -    // ---- ko.templateSources.domElement -----
 60.2924 -
 60.2925 -    ko.templateSources.domElement = function(element) {
 60.2926 -        this.domElement = element;
 60.2927 -    }
 60.2928 -
 60.2929 -    ko.templateSources.domElement.prototype['text'] = function(/* valueToWrite */) {
 60.2930 -        var tagNameLower = ko.utils.tagNameLower(this.domElement),
 60.2931 -            elemContentsProperty = tagNameLower === "script" ? "text"
 60.2932 -                                 : tagNameLower === "textarea" ? "value"
 60.2933 -                                 : "innerHTML";
 60.2934 -
 60.2935 -        if (arguments.length == 0) {
 60.2936 -            return this.domElement[elemContentsProperty];
 60.2937 -        } else {
 60.2938 -            var valueToWrite = arguments[0];
 60.2939 -            if (elemContentsProperty === "innerHTML")
 60.2940 -                ko.utils.setHtml(this.domElement, valueToWrite);
 60.2941 -            else
 60.2942 -                this.domElement[elemContentsProperty] = valueToWrite;
 60.2943 -        }
 60.2944 -    };
 60.2945 -
 60.2946 -    ko.templateSources.domElement.prototype['data'] = function(key /*, valueToWrite */) {
 60.2947 -        if (arguments.length === 1) {
 60.2948 -            return ko.utils.domData.get(this.domElement, "templateSourceData_" + key);
 60.2949 -        } else {
 60.2950 -            ko.utils.domData.set(this.domElement, "templateSourceData_" + key, arguments[1]);
 60.2951 -        }
 60.2952 -    };
 60.2953 -
 60.2954 -    // ---- ko.templateSources.anonymousTemplate -----
 60.2955 -    // Anonymous templates are normally saved/retrieved as DOM nodes through "nodes".
 60.2956 -    // For compatibility, you can also read "text"; it will be serialized from the nodes on demand.
 60.2957 -    // Writing to "text" is still supported, but then the template data will not be available as DOM nodes.
 60.2958 -
 60.2959 -    var anonymousTemplatesDomDataKey = "__ko_anon_template__";
 60.2960 -    ko.templateSources.anonymousTemplate = function(element) {
 60.2961 -        this.domElement = element;
 60.2962 -    }
 60.2963 -    ko.templateSources.anonymousTemplate.prototype = new ko.templateSources.domElement();
 60.2964 -    ko.templateSources.anonymousTemplate.prototype['text'] = function(/* valueToWrite */) {
 60.2965 -        if (arguments.length == 0) {
 60.2966 -            var templateData = ko.utils.domData.get(this.domElement, anonymousTemplatesDomDataKey) || {};
 60.2967 -            if (templateData.textData === undefined && templateData.containerData)
 60.2968 -                templateData.textData = templateData.containerData.innerHTML;
 60.2969 -            return templateData.textData;
 60.2970 -        } else {
 60.2971 -            var valueToWrite = arguments[0];
 60.2972 -            ko.utils.domData.set(this.domElement, anonymousTemplatesDomDataKey, {textData: valueToWrite});
 60.2973 -        }
 60.2974 -    };
 60.2975 -    ko.templateSources.domElement.prototype['nodes'] = function(/* valueToWrite */) {
 60.2976 -        if (arguments.length == 0) {
 60.2977 -            var templateData = ko.utils.domData.get(this.domElement, anonymousTemplatesDomDataKey) || {};
 60.2978 -            return templateData.containerData;
 60.2979 -        } else {
 60.2980 -            var valueToWrite = arguments[0];
 60.2981 -            ko.utils.domData.set(this.domElement, anonymousTemplatesDomDataKey, {containerData: valueToWrite});
 60.2982 -        }
 60.2983 -    };
 60.2984 -
 60.2985 -    ko.exportSymbol('templateSources', ko.templateSources);
 60.2986 -    ko.exportSymbol('templateSources.domElement', ko.templateSources.domElement);
 60.2987 -    ko.exportSymbol('templateSources.anonymousTemplate', ko.templateSources.anonymousTemplate);
 60.2988 -})();
 60.2989 -(function () {
 60.2990 -    var _templateEngine;
 60.2991 -    ko.setTemplateEngine = function (templateEngine) {
 60.2992 -        if ((templateEngine != undefined) && !(templateEngine instanceof ko.templateEngine))
 60.2993 -            throw new Error("templateEngine must inherit from ko.templateEngine");
 60.2994 -        _templateEngine = templateEngine;
 60.2995 -    }
 60.2996 -
 60.2997 -    function invokeForEachNodeOrCommentInContinuousRange(firstNode, lastNode, action) {
 60.2998 -        var node, nextInQueue = firstNode, firstOutOfRangeNode = ko.virtualElements.nextSibling(lastNode);
 60.2999 -        while (nextInQueue && ((node = nextInQueue) !== firstOutOfRangeNode)) {
 60.3000 -            nextInQueue = ko.virtualElements.nextSibling(node);
 60.3001 -            if (node.nodeType === 1 || node.nodeType === 8)
 60.3002 -                action(node);
 60.3003 -        }
 60.3004 -    }
 60.3005 -
 60.3006 -    function activateBindingsOnContinuousNodeArray(continuousNodeArray, bindingContext) {
 60.3007 -        // To be used on any nodes that have been rendered by a template and have been inserted into some parent element
 60.3008 -        // Walks through continuousNodeArray (which *must* be continuous, i.e., an uninterrupted sequence of sibling nodes, because
 60.3009 -        // the algorithm for walking them relies on this), and for each top-level item in the virtual-element sense,
 60.3010 -        // (1) Does a regular "applyBindings" to associate bindingContext with this node and to activate any non-memoized bindings
 60.3011 -        // (2) Unmemoizes any memos in the DOM subtree (e.g., to activate bindings that had been memoized during template rewriting)
 60.3012 -
 60.3013 -        if (continuousNodeArray.length) {
 60.3014 -            var firstNode = continuousNodeArray[0], lastNode = continuousNodeArray[continuousNodeArray.length - 1];
 60.3015 -
 60.3016 -            // Need to applyBindings *before* unmemoziation, because unmemoization might introduce extra nodes (that we don't want to re-bind)
 60.3017 -            // whereas a regular applyBindings won't introduce new memoized nodes
 60.3018 -            invokeForEachNodeOrCommentInContinuousRange(firstNode, lastNode, function(node) {
 60.3019 -                ko.applyBindings(bindingContext, node);
 60.3020 -            });
 60.3021 -            invokeForEachNodeOrCommentInContinuousRange(firstNode, lastNode, function(node) {
 60.3022 -                ko.memoization.unmemoizeDomNodeAndDescendants(node, [bindingContext]);
 60.3023 -            });
 60.3024 -        }
 60.3025 -    }
 60.3026 -
 60.3027 -    function getFirstNodeFromPossibleArray(nodeOrNodeArray) {
 60.3028 -        return nodeOrNodeArray.nodeType ? nodeOrNodeArray
 60.3029 -                                        : nodeOrNodeArray.length > 0 ? nodeOrNodeArray[0]
 60.3030 -                                        : null;
 60.3031 -    }
 60.3032 -
 60.3033 -    function executeTemplate(targetNodeOrNodeArray, renderMode, template, bindingContext, options) {
 60.3034 -        options = options || {};
 60.3035 -        var firstTargetNode = targetNodeOrNodeArray && getFirstNodeFromPossibleArray(targetNodeOrNodeArray);
 60.3036 -        var templateDocument = firstTargetNode && firstTargetNode.ownerDocument;
 60.3037 -        var templateEngineToUse = (options['templateEngine'] || _templateEngine);
 60.3038 -        ko.templateRewriting.ensureTemplateIsRewritten(template, templateEngineToUse, templateDocument);
 60.3039 -        var renderedNodesArray = templateEngineToUse['renderTemplate'](template, bindingContext, options, templateDocument);
 60.3040 -
 60.3041 -        // Loosely check result is an array of DOM nodes
 60.3042 -        if ((typeof renderedNodesArray.length != "number") || (renderedNodesArray.length > 0 && typeof renderedNodesArray[0].nodeType != "number"))
 60.3043 -            throw new Error("Template engine must return an array of DOM nodes");
 60.3044 -
 60.3045 -        var haveAddedNodesToParent = false;
 60.3046 -        switch (renderMode) {
 60.3047 -            case "replaceChildren":
 60.3048 -                ko.virtualElements.setDomNodeChildren(targetNodeOrNodeArray, renderedNodesArray);
 60.3049 -                haveAddedNodesToParent = true;
 60.3050 -                break;
 60.3051 -            case "replaceNode":
 60.3052 -                ko.utils.replaceDomNodes(targetNodeOrNodeArray, renderedNodesArray);
 60.3053 -                haveAddedNodesToParent = true;
 60.3054 -                break;
 60.3055 -            case "ignoreTargetNode": break;
 60.3056 -            default:
 60.3057 -                throw new Error("Unknown renderMode: " + renderMode);
 60.3058 -        }
 60.3059 -
 60.3060 -        if (haveAddedNodesToParent) {
 60.3061 -            activateBindingsOnContinuousNodeArray(renderedNodesArray, bindingContext);
 60.3062 -            if (options['afterRender'])
 60.3063 -                ko.dependencyDetection.ignore(options['afterRender'], null, [renderedNodesArray, bindingContext['$data']]);
 60.3064 -        }
 60.3065 -
 60.3066 -        return renderedNodesArray;
 60.3067 -    }
 60.3068 -
 60.3069 -    ko.renderTemplate = function (template, dataOrBindingContext, options, targetNodeOrNodeArray, renderMode) {
 60.3070 -        options = options || {};
 60.3071 -        if ((options['templateEngine'] || _templateEngine) == undefined)
 60.3072 -            throw new Error("Set a template engine before calling renderTemplate");
 60.3073 -        renderMode = renderMode || "replaceChildren";
 60.3074 -
 60.3075 -        if (targetNodeOrNodeArray) {
 60.3076 -            var firstTargetNode = getFirstNodeFromPossibleArray(targetNodeOrNodeArray);
 60.3077 -
 60.3078 -            var whenToDispose = function () { return (!firstTargetNode) || !ko.utils.domNodeIsAttachedToDocument(firstTargetNode); }; // Passive disposal (on next evaluation)
 60.3079 -            var activelyDisposeWhenNodeIsRemoved = (firstTargetNode && renderMode == "replaceNode") ? firstTargetNode.parentNode : firstTargetNode;
 60.3080 -
 60.3081 -            return ko.dependentObservable( // So the DOM is automatically updated when any dependency changes
 60.3082 -                function () {
 60.3083 -                    // Ensure we've got a proper binding context to work with
 60.3084 -                    var bindingContext = (dataOrBindingContext && (dataOrBindingContext instanceof ko.bindingContext))
 60.3085 -                        ? dataOrBindingContext
 60.3086 -                        : new ko.bindingContext(ko.utils.unwrapObservable(dataOrBindingContext));
 60.3087 -
 60.3088 -                    // Support selecting template as a function of the data being rendered
 60.3089 -                    var templateName = typeof(template) == 'function' ? template(bindingContext['$data'], bindingContext) : template;
 60.3090 -
 60.3091 -                    var renderedNodesArray = executeTemplate(targetNodeOrNodeArray, renderMode, templateName, bindingContext, options);
 60.3092 -                    if (renderMode == "replaceNode") {
 60.3093 -                        targetNodeOrNodeArray = renderedNodesArray;
 60.3094 -                        firstTargetNode = getFirstNodeFromPossibleArray(targetNodeOrNodeArray);
 60.3095 -                    }
 60.3096 -                },
 60.3097 -                null,
 60.3098 -                { disposeWhen: whenToDispose, disposeWhenNodeIsRemoved: activelyDisposeWhenNodeIsRemoved }
 60.3099 -            );
 60.3100 -        } else {
 60.3101 -            // We don't yet have a DOM node to evaluate, so use a memo and render the template later when there is a DOM node
 60.3102 -            return ko.memoization.memoize(function (domNode) {
 60.3103 -                ko.renderTemplate(template, dataOrBindingContext, options, domNode, "replaceNode");
 60.3104 -            });
 60.3105 -        }
 60.3106 -    };
 60.3107 -
 60.3108 -    ko.renderTemplateForEach = function (template, arrayOrObservableArray, options, targetNode, parentBindingContext) {
 60.3109 -        // Since setDomNodeChildrenFromArrayMapping always calls executeTemplateForArrayItem and then
 60.3110 -        // activateBindingsCallback for added items, we can store the binding context in the former to use in the latter.
 60.3111 -        var arrayItemContext;
 60.3112 -
 60.3113 -        // This will be called by setDomNodeChildrenFromArrayMapping to get the nodes to add to targetNode
 60.3114 -        var executeTemplateForArrayItem = function (arrayValue, index) {
 60.3115 -            // Support selecting template as a function of the data being rendered
 60.3116 -            arrayItemContext = parentBindingContext['createChildContext'](ko.utils.unwrapObservable(arrayValue), options['as']);
 60.3117 -            arrayItemContext['$index'] = index;
 60.3118 -            var templateName = typeof(template) == 'function' ? template(arrayValue, arrayItemContext) : template;
 60.3119 -            return executeTemplate(null, "ignoreTargetNode", templateName, arrayItemContext, options);
 60.3120 -        }
 60.3121 -
 60.3122 -        // This will be called whenever setDomNodeChildrenFromArrayMapping has added nodes to targetNode
 60.3123 -        var activateBindingsCallback = function(arrayValue, addedNodesArray, index) {
 60.3124 -            activateBindingsOnContinuousNodeArray(addedNodesArray, arrayItemContext);
 60.3125 -            if (options['afterRender'])
 60.3126 -                options['afterRender'](addedNodesArray, arrayValue);
 60.3127 -        };
 60.3128 -
 60.3129 -        return ko.dependentObservable(function () {
 60.3130 -            var unwrappedArray = ko.utils.unwrapObservable(arrayOrObservableArray) || [];
 60.3131 -            if (typeof unwrappedArray.length == "undefined") // Coerce single value into array
 60.3132 -                unwrappedArray = [unwrappedArray];
 60.3133 -
 60.3134 -            // Filter out any entries marked as destroyed
 60.3135 -            var filteredArray = ko.utils.arrayFilter(unwrappedArray, function(item) {
 60.3136 -                return options['includeDestroyed'] || item === undefined || item === null || !ko.utils.unwrapObservable(item['_destroy']);
 60.3137 -            });
 60.3138 -
 60.3139 -            // Call setDomNodeChildrenFromArrayMapping, ignoring any observables unwrapped within (most likely from a callback function).
 60.3140 -            // If the array items are observables, though, they will be unwrapped in executeTemplateForArrayItem and managed within setDomNodeChildrenFromArrayMapping.
 60.3141 -            ko.dependencyDetection.ignore(ko.utils.setDomNodeChildrenFromArrayMapping, null, [targetNode, filteredArray, executeTemplateForArrayItem, options, activateBindingsCallback]);
 60.3142 -
 60.3143 -        }, null, { disposeWhenNodeIsRemoved: targetNode });
 60.3144 -    };
 60.3145 -
 60.3146 -    var templateComputedDomDataKey = '__ko__templateComputedDomDataKey__';
 60.3147 -    function disposeOldComputedAndStoreNewOne(element, newComputed) {
 60.3148 -        var oldComputed = ko.utils.domData.get(element, templateComputedDomDataKey);
 60.3149 -        if (oldComputed && (typeof(oldComputed.dispose) == 'function'))
 60.3150 -            oldComputed.dispose();
 60.3151 -        ko.utils.domData.set(element, templateComputedDomDataKey, (newComputed && newComputed.isActive()) ? newComputed : undefined);
 60.3152 -    }
 60.3153 -
 60.3154 -    ko.bindingHandlers['template'] = {
 60.3155 -        'init': function(element, valueAccessor) {
 60.3156 -            // Support anonymous templates
 60.3157 -            var bindingValue = ko.utils.unwrapObservable(valueAccessor());
 60.3158 -            if ((typeof bindingValue != "string") && (!bindingValue['name']) && (element.nodeType == 1 || element.nodeType == 8)) {
 60.3159 -                // It's an anonymous template - store the element contents, then clear the element
 60.3160 -                var templateNodes = element.nodeType == 1 ? element.childNodes : ko.virtualElements.childNodes(element),
 60.3161 -                    container = ko.utils.moveCleanedNodesToContainerElement(templateNodes); // This also removes the nodes from their current parent
 60.3162 -                new ko.templateSources.anonymousTemplate(element)['nodes'](container);
 60.3163 -            }
 60.3164 -            return { 'controlsDescendantBindings': true };
 60.3165 -        },
 60.3166 -        'update': function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
 60.3167 -            var templateName = ko.utils.unwrapObservable(valueAccessor()),
 60.3168 -                options = {},
 60.3169 -                shouldDisplay = true,
 60.3170 -                dataValue,
 60.3171 -                templateComputed = null;
 60.3172 -
 60.3173 -            if (typeof templateName != "string") {
 60.3174 -                options = templateName;
 60.3175 -                templateName = options['name'];
 60.3176 -
 60.3177 -                // Support "if"/"ifnot" conditions
 60.3178 -                if ('if' in options)
 60.3179 -                    shouldDisplay = ko.utils.unwrapObservable(options['if']);
 60.3180 -                if (shouldDisplay && 'ifnot' in options)
 60.3181 -                    shouldDisplay = !ko.utils.unwrapObservable(options['ifnot']);
 60.3182 -
 60.3183 -                dataValue = ko.utils.unwrapObservable(options['data']);
 60.3184 -            }
 60.3185 -
 60.3186 -            if ('foreach' in options) {
 60.3187 -                // Render once for each data point (treating data set as empty if shouldDisplay==false)
 60.3188 -                var dataArray = (shouldDisplay && options['foreach']) || [];
 60.3189 -                templateComputed = ko.renderTemplateForEach(templateName || element, dataArray, options, element, bindingContext);
 60.3190 -            } else if (!shouldDisplay) {
 60.3191 -                ko.virtualElements.emptyNode(element);
 60.3192 -            } else {
 60.3193 -                // Render once for this single data point (or use the viewModel if no data was provided)
 60.3194 -                var innerBindingContext = ('data' in options) ?
 60.3195 -                    bindingContext['createChildContext'](dataValue, options['as']) :  // Given an explitit 'data' value, we create a child binding context for it
 60.3196 -                    bindingContext;                                                        // Given no explicit 'data' value, we retain the same binding context
 60.3197 -                templateComputed = ko.renderTemplate(templateName || element, innerBindingContext, options, element);
 60.3198 -            }
 60.3199 -
 60.3200 -            // It only makes sense to have a single template computed per element (otherwise which one should have its output displayed?)
 60.3201 -            disposeOldComputedAndStoreNewOne(element, templateComputed);
 60.3202 -        }
 60.3203 -    };
 60.3204 -
 60.3205 -    // Anonymous templates can't be rewritten. Give a nice error message if you try to do it.
 60.3206 -    ko.expressionRewriting.bindingRewriteValidators['template'] = function(bindingValue) {
 60.3207 -        var parsedBindingValue = ko.expressionRewriting.parseObjectLiteral(bindingValue);
 60.3208 -
 60.3209 -        if ((parsedBindingValue.length == 1) && parsedBindingValue[0]['unknown'])
 60.3210 -            return null; // It looks like a string literal, not an object literal, so treat it as a named template (which is allowed for rewriting)
 60.3211 -
 60.3212 -        if (ko.expressionRewriting.keyValueArrayContainsKey(parsedBindingValue, "name"))
 60.3213 -            return null; // Named templates can be rewritten, so return "no error"
 60.3214 -        return "This template engine does not support anonymous templates nested within its templates";
 60.3215 -    };
 60.3216 -
 60.3217 -    ko.virtualElements.allowedBindings['template'] = true;
 60.3218 -})();
 60.3219 -
 60.3220 -ko.exportSymbol('setTemplateEngine', ko.setTemplateEngine);
 60.3221 -ko.exportSymbol('renderTemplate', ko.renderTemplate);
 60.3222 -
 60.3223 -ko.utils.compareArrays = (function () {
 60.3224 -    var statusNotInOld = 'added', statusNotInNew = 'deleted';
 60.3225 -
 60.3226 -    // Simple calculation based on Levenshtein distance.
 60.3227 -    function compareArrays(oldArray, newArray, dontLimitMoves) {
 60.3228 -        oldArray = oldArray || [];
 60.3229 -        newArray = newArray || [];
 60.3230 -
 60.3231 -        if (oldArray.length <= newArray.length)
 60.3232 -            return compareSmallArrayToBigArray(oldArray, newArray, statusNotInOld, statusNotInNew, dontLimitMoves);
 60.3233 -        else
 60.3234 -            return compareSmallArrayToBigArray(newArray, oldArray, statusNotInNew, statusNotInOld, dontLimitMoves);
 60.3235 -    }
 60.3236 -
 60.3237 -    function compareSmallArrayToBigArray(smlArray, bigArray, statusNotInSml, statusNotInBig, dontLimitMoves) {
 60.3238 -        var myMin = Math.min,
 60.3239 -            myMax = Math.max,
 60.3240 -            editDistanceMatrix = [],
 60.3241 -            smlIndex, smlIndexMax = smlArray.length,
 60.3242 -            bigIndex, bigIndexMax = bigArray.length,
 60.3243 -            compareRange = (bigIndexMax - smlIndexMax) || 1,
 60.3244 -            maxDistance = smlIndexMax + bigIndexMax + 1,
 60.3245 -            thisRow, lastRow,
 60.3246 -            bigIndexMaxForRow, bigIndexMinForRow;
 60.3247 -
 60.3248 -        for (smlIndex = 0; smlIndex <= smlIndexMax; smlIndex++) {
 60.3249 -            lastRow = thisRow;
 60.3250 -            editDistanceMatrix.push(thisRow = []);
 60.3251 -            bigIndexMaxForRow = myMin(bigIndexMax, smlIndex + compareRange);
 60.3252 -            bigIndexMinForRow = myMax(0, smlIndex - 1);
 60.3253 -            for (bigIndex = bigIndexMinForRow; bigIndex <= bigIndexMaxForRow; bigIndex++) {
 60.3254 -                if (!bigIndex)
 60.3255 -                    thisRow[bigIndex] = smlIndex + 1;
 60.3256 -                else if (!smlIndex)  // Top row - transform empty array into new array via additions
 60.3257 -                    thisRow[bigIndex] = bigIndex + 1;
 60.3258 -                else if (smlArray[smlIndex - 1] === bigArray[bigIndex - 1])
 60.3259 -                    thisRow[bigIndex] = lastRow[bigIndex - 1];                  // copy value (no edit)
 60.3260 -                else {
 60.3261 -                    var northDistance = lastRow[bigIndex] || maxDistance;       // not in big (deletion)
 60.3262 -                    var westDistance = thisRow[bigIndex - 1] || maxDistance;    // not in small (addition)
 60.3263 -                    thisRow[bigIndex] = myMin(northDistance, westDistance) + 1;
 60.3264 -                }
 60.3265 -            }
 60.3266 -        }
 60.3267 -
 60.3268 -        var editScript = [], meMinusOne, notInSml = [], notInBig = [];
 60.3269 -        for (smlIndex = smlIndexMax, bigIndex = bigIndexMax; smlIndex || bigIndex;) {
 60.3270 -            meMinusOne = editDistanceMatrix[smlIndex][bigIndex] - 1;
 60.3271 -            if (bigIndex && meMinusOne === editDistanceMatrix[smlIndex][bigIndex-1]) {
 60.3272 -                notInSml.push(editScript[editScript.length] = {     // added
 60.3273 -                    'status': statusNotInSml,
 60.3274 -                    'value': bigArray[--bigIndex],
 60.3275 -                    'index': bigIndex });
 60.3276 -            } else if (smlIndex && meMinusOne === editDistanceMatrix[smlIndex - 1][bigIndex]) {
 60.3277 -                notInBig.push(editScript[editScript.length] = {     // deleted
 60.3278 -                    'status': statusNotInBig,
 60.3279 -                    'value': smlArray[--smlIndex],
 60.3280 -                    'index': smlIndex });
 60.3281 -            } else {
 60.3282 -                editScript.push({
 60.3283 -                    'status': "retained",
 60.3284 -                    'value': bigArray[--bigIndex] });
 60.3285 -                --smlIndex;
 60.3286 -            }
 60.3287 -        }
 60.3288 -
 60.3289 -        if (notInSml.length && notInBig.length) {
 60.3290 -            // Set a limit on the number of consecutive non-matching comparisons; having it a multiple of
 60.3291 -            // smlIndexMax keeps the time complexity of this algorithm linear.
 60.3292 -            var limitFailedCompares = smlIndexMax * 10, failedCompares,
 60.3293 -                a, d, notInSmlItem, notInBigItem;
 60.3294 -            // Go through the items that have been added and deleted and try to find matches between them.
 60.3295 -            for (failedCompares = a = 0; (dontLimitMoves || failedCompares < limitFailedCompares) && (notInSmlItem = notInSml[a]); a++) {
 60.3296 -                for (d = 0; notInBigItem = notInBig[d]; d++) {
 60.3297 -                    if (notInSmlItem['value'] === notInBigItem['value']) {
 60.3298 -                        notInSmlItem['moved'] = notInBigItem['index'];
 60.3299 -                        notInBigItem['moved'] = notInSmlItem['index'];
 60.3300 -                        notInBig.splice(d,1);       // This item is marked as moved; so remove it from notInBig list
 60.3301 -                        failedCompares = d = 0;     // Reset failed compares count because we're checking for consecutive failures
 60.3302 -                        break;
 60.3303 -                    }
 60.3304 -                }
 60.3305 -                failedCompares += d;
 60.3306 -            }
 60.3307 -        }
 60.3308 -        return editScript.reverse();
 60.3309 -    }
 60.3310 -
 60.3311 -    return compareArrays;
 60.3312 -})();
 60.3313 -
 60.3314 -ko.exportSymbol('utils.compareArrays', ko.utils.compareArrays);
 60.3315 -
 60.3316 -(function () {
 60.3317 -    // Objective:
 60.3318 -    // * Given an input array, a container DOM node, and a function from array elements to arrays of DOM nodes,
 60.3319 -    //   map the array elements to arrays of DOM nodes, concatenate together all these arrays, and use them to populate the container DOM node
 60.3320 -    // * Next time we're given the same combination of things (with the array possibly having mutated), update the container DOM node
 60.3321 -    //   so that its children is again the concatenation of the mappings of the array elements, but don't re-map any array elements that we
 60.3322 -    //   previously mapped - retain those nodes, and just insert/delete other ones
 60.3323 -
 60.3324 -    // "callbackAfterAddingNodes" will be invoked after any "mapping"-generated nodes are inserted into the container node
 60.3325 -    // You can use this, for example, to activate bindings on those nodes.
 60.3326 -
 60.3327 -    function fixUpNodesToBeMovedOrRemoved(contiguousNodeArray) {
 60.3328 -        // Before moving, deleting, or replacing a set of nodes that were previously outputted by the "map" function, we have to reconcile
 60.3329 -        // them against what is in the DOM right now. It may be that some of the nodes have already been removed from the document,
 60.3330 -        // or that new nodes might have been inserted in the middle, for example by a binding. Also, there may previously have been
 60.3331 -        // leading comment nodes (created by rewritten string-based templates) that have since been removed during binding.
 60.3332 -        // So, this function translates the old "map" output array into its best guess of what set of current DOM nodes should be removed.
 60.3333 -        //
 60.3334 -        // Rules:
 60.3335 -        //   [A] Any leading nodes that aren't in the document any more should be ignored
 60.3336 -        //       These most likely correspond to memoization nodes that were already removed during binding
 60.3337 -        //       See https://github.com/SteveSanderson/knockout/pull/440
 60.3338 -        //   [B] We want to output a contiguous series of nodes that are still in the document. So, ignore any nodes that
 60.3339 -        //       have already been removed, and include any nodes that have been inserted among the previous collection
 60.3340 -
 60.3341 -        // Rule [A]
 60.3342 -        while (contiguousNodeArray.length && !ko.utils.domNodeIsAttachedToDocument(contiguousNodeArray[0]))
 60.3343 -            contiguousNodeArray.splice(0, 1);
 60.3344 -
 60.3345 -        // Rule [B]
 60.3346 -        if (contiguousNodeArray.length > 1) {
 60.3347 -            // Build up the actual new contiguous node set
 60.3348 -            var current = contiguousNodeArray[0], last = contiguousNodeArray[contiguousNodeArray.length - 1], newContiguousSet = [current];
 60.3349 -            while (current !== last) {
 60.3350 -                current = current.nextSibling;
 60.3351 -                if (!current) // Won't happen, except if the developer has manually removed some DOM elements (then we're in an undefined scenario)
 60.3352 -                    return;
 60.3353 -                newContiguousSet.push(current);
 60.3354 -            }
 60.3355 -
 60.3356 -            // ... then mutate the input array to match this.
 60.3357 -            // (The following line replaces the contents of contiguousNodeArray with newContiguousSet)
 60.3358 -            Array.prototype.splice.apply(contiguousNodeArray, [0, contiguousNodeArray.length].concat(newContiguousSet));
 60.3359 -        }
 60.3360 -        return contiguousNodeArray;
 60.3361 -    }
 60.3362 -
 60.3363 -    function mapNodeAndRefreshWhenChanged(containerNode, mapping, valueToMap, callbackAfterAddingNodes, index) {
 60.3364 -        // Map this array value inside a dependentObservable so we re-map when any dependency changes
 60.3365 -        var mappedNodes = [];
 60.3366 -        var dependentObservable = ko.dependentObservable(function() {
 60.3367 -            var newMappedNodes = mapping(valueToMap, index) || [];
 60.3368 -
 60.3369 -            // On subsequent evaluations, just replace the previously-inserted DOM nodes
 60.3370 -            if (mappedNodes.length > 0) {
 60.3371 -                ko.utils.replaceDomNodes(fixUpNodesToBeMovedOrRemoved(mappedNodes), newMappedNodes);
 60.3372 -                if (callbackAfterAddingNodes)
 60.3373 -                    ko.dependencyDetection.ignore(callbackAfterAddingNodes, null, [valueToMap, newMappedNodes, index]);
 60.3374 -            }
 60.3375 -
 60.3376 -            // Replace the contents of the mappedNodes array, thereby updating the record
 60.3377 -            // of which nodes would be deleted if valueToMap was itself later removed
 60.3378 -            mappedNodes.splice(0, mappedNodes.length);
 60.3379 -            ko.utils.arrayPushAll(mappedNodes, newMappedNodes);
 60.3380 -        }, null, { disposeWhenNodeIsRemoved: containerNode, disposeWhen: function() { return (mappedNodes.length == 0) || !ko.utils.domNodeIsAttachedToDocument(mappedNodes[0]) } });
 60.3381 -        return { mappedNodes : mappedNodes, dependentObservable : (dependentObservable.isActive() ? dependentObservable : undefined) };
 60.3382 -    }
 60.3383 -
 60.3384 -    var lastMappingResultDomDataKey = "setDomNodeChildrenFromArrayMapping_lastMappingResult";
 60.3385 -
 60.3386 -    ko.utils.setDomNodeChildrenFromArrayMapping = function (domNode, array, mapping, options, callbackAfterAddingNodes) {
 60.3387 -        // Compare the provided array against the previous one
 60.3388 -        array = array || [];
 60.3389 -        options = options || {};
 60.3390 -        var isFirstExecution = ko.utils.domData.get(domNode, lastMappingResultDomDataKey) === undefined;
 60.3391 -        var lastMappingResult = ko.utils.domData.get(domNode, lastMappingResultDomDataKey) || [];
 60.3392 -        var lastArray = ko.utils.arrayMap(lastMappingResult, function (x) { return x.arrayEntry; });
 60.3393 -        var editScript = ko.utils.compareArrays(lastArray, array);
 60.3394 -
 60.3395 -        // Build the new mapping result
 60.3396 -        var newMappingResult = [];
 60.3397 -        var lastMappingResultIndex = 0;
 60.3398 -        var newMappingResultIndex = 0;
 60.3399 -
 60.3400 -        var nodesToDelete = [];
 60.3401 -        var itemsToProcess = [];
 60.3402 -        var itemsForBeforeRemoveCallbacks = [];
 60.3403 -        var itemsForMoveCallbacks = [];
 60.3404 -        var itemsForAfterAddCallbacks = [];
 60.3405 -        var mapData;
 60.3406 -
 60.3407 -        function itemMovedOrRetained(editScriptIndex, oldPosition) {
 60.3408 -            mapData = lastMappingResult[oldPosition];
 60.3409 -            if (newMappingResultIndex !== oldPosition)
 60.3410 -                itemsForMoveCallbacks[editScriptIndex] = mapData;
 60.3411 -            // Since updating the index might change the nodes, do so before calling fixUpNodesToBeMovedOrRemoved
 60.3412 -            mapData.indexObservable(newMappingResultIndex++);
 60.3413 -            fixUpNodesToBeMovedOrRemoved(mapData.mappedNodes);
 60.3414 -            newMappingResult.push(mapData);
 60.3415 -            itemsToProcess.push(mapData);
 60.3416 -        }
 60.3417 -
 60.3418 -        function callCallback(callback, items) {
 60.3419 -            if (callback) {
 60.3420 -                for (var i = 0, n = items.length; i < n; i++) {
 60.3421 -                    if (items[i]) {
 60.3422 -                        ko.utils.arrayForEach(items[i].mappedNodes, function(node) {
 60.3423 -                            callback(node, i, items[i].arrayEntry);
 60.3424 -                        });
 60.3425 -                    }
 60.3426 -                }
 60.3427 -            }
 60.3428 -        }
 60.3429 -
 60.3430 -        for (var i = 0, editScriptItem, movedIndex; editScriptItem = editScript[i]; i++) {
 60.3431 -            movedIndex = editScriptItem['moved'];
 60.3432 -            switch (editScriptItem['status']) {
 60.3433 -                case "deleted":
 60.3434 -                    if (movedIndex === undefined) {
 60.3435 -                        mapData = lastMappingResult[lastMappingResultIndex];
 60.3436 -
 60.3437 -                        // Stop tracking changes to the mapping for these nodes
 60.3438 -                        if (mapData.dependentObservable)
 60.3439 -                            mapData.dependentObservable.dispose();
 60.3440 -
 60.3441 -                        // Queue these nodes for later removal
 60.3442 -                        nodesToDelete.push.apply(nodesToDelete, fixUpNodesToBeMovedOrRemoved(mapData.mappedNodes));
 60.3443 -                        if (options['beforeRemove']) {
 60.3444 -                            itemsForBeforeRemoveCallbacks[i] = mapData;
 60.3445 -                            itemsToProcess.push(mapData);
 60.3446 -                        }
 60.3447 -                    }
 60.3448 -                    lastMappingResultIndex++;
 60.3449 -                    break;
 60.3450 -
 60.3451 -                case "retained":
 60.3452 -                    itemMovedOrRetained(i, lastMappingResultIndex++);
 60.3453 -                    break;
 60.3454 -
 60.3455 -                case "added":
 60.3456 -                    if (movedIndex !== undefined) {
 60.3457 -                        itemMovedOrRetained(i, movedIndex);
 60.3458 -                    } else {
 60.3459 -                        mapData = { arrayEntry: editScriptItem['value'], indexObservable: ko.observable(newMappingResultIndex++) };
 60.3460 -                        newMappingResult.push(mapData);
 60.3461 -                        itemsToProcess.push(mapData);
 60.3462 -                        if (!isFirstExecution)
 60.3463 -                            itemsForAfterAddCallbacks[i] = mapData;
 60.3464 -                    }
 60.3465 -                    break;
 60.3466 -            }
 60.3467 -        }
 60.3468 -
 60.3469 -        // Call beforeMove first before any changes have been made to the DOM
 60.3470 -        callCallback(options['beforeMove'], itemsForMoveCallbacks);
 60.3471 -
 60.3472 -        // Next remove nodes for deleted items (or just clean if there's a beforeRemove callback)
 60.3473 -        ko.utils.arrayForEach(nodesToDelete, options['beforeRemove'] ? ko.cleanNode : ko.removeNode);
 60.3474 -
 60.3475 -        // Next add/reorder the remaining items (will include deleted items if there's a beforeRemove callback)
 60.3476 -        for (var i = 0, nextNode = ko.virtualElements.firstChild(domNode), lastNode, node; mapData = itemsToProcess[i]; i++) {
 60.3477 -            // Get nodes for newly added items
 60.3478 -            if (!mapData.mappedNodes)
 60.3479 -                ko.utils.extend(mapData, mapNodeAndRefreshWhenChanged(domNode, mapping, mapData.arrayEntry, callbackAfterAddingNodes, mapData.indexObservable));
 60.3480 -
 60.3481 -            // Put nodes in the right place if they aren't there already
 60.3482 -            for (var j = 0; node = mapData.mappedNodes[j]; nextNode = node.nextSibling, lastNode = node, j++) {
 60.3483 -                if (node !== nextNode)
 60.3484 -                    ko.virtualElements.insertAfter(domNode, node, lastNode);
 60.3485 -            }
 60.3486 -
 60.3487 -            // Run the callbacks for newly added nodes (for example, to apply bindings, etc.)
 60.3488 -            if (!mapData.initialized && callbackAfterAddingNodes) {
 60.3489 -                callbackAfterAddingNodes(mapData.arrayEntry, mapData.mappedNodes, mapData.indexObservable);
 60.3490 -                mapData.initialized = true;
 60.3491 -            }
 60.3492 -        }
 60.3493 -
 60.3494 -        // If there's a beforeRemove callback, call it after reordering.
 60.3495 -        // Note that we assume that the beforeRemove callback will usually be used to remove the nodes using
 60.3496 -        // some sort of animation, which is why we first reorder the nodes that will be removed. If the
 60.3497 -        // callback instead removes the nodes right away, it would be more efficient to skip reordering them.
 60.3498 -        // Perhaps we'll make that change in the future if this scenario becomes more common.
 60.3499 -        callCallback(options['beforeRemove'], itemsForBeforeRemoveCallbacks);
 60.3500 -
 60.3501 -        // Finally call afterMove and afterAdd callbacks
 60.3502 -        callCallback(options['afterMove'], itemsForMoveCallbacks);
 60.3503 -        callCallback(options['afterAdd'], itemsForAfterAddCallbacks);
 60.3504 -
 60.3505 -        // Store a copy of the array items we just considered so we can difference it next time
 60.3506 -        ko.utils.domData.set(domNode, lastMappingResultDomDataKey, newMappingResult);
 60.3507 -    }
 60.3508 -})();
 60.3509 -
 60.3510 -ko.exportSymbol('utils.setDomNodeChildrenFromArrayMapping', ko.utils.setDomNodeChildrenFromArrayMapping);
 60.3511 -ko.nativeTemplateEngine = function () {
 60.3512 -    this['allowTemplateRewriting'] = false;
 60.3513 -}
 60.3514 -
 60.3515 -ko.nativeTemplateEngine.prototype = new ko.templateEngine();
 60.3516 -ko.nativeTemplateEngine.prototype['renderTemplateSource'] = function (templateSource, bindingContext, options) {
 60.3517 -    var useNodesIfAvailable = !(ko.utils.ieVersion < 9), // IE<9 cloneNode doesn't work properly
 60.3518 -        templateNodesFunc = useNodesIfAvailable ? templateSource['nodes'] : null,
 60.3519 -        templateNodes = templateNodesFunc ? templateSource['nodes']() : null;
 60.3520 -
 60.3521 -    if (templateNodes) {
 60.3522 -        return ko.utils.makeArray(templateNodes.cloneNode(true).childNodes);
 60.3523 -    } else {
 60.3524 -        var templateText = templateSource['text']();
 60.3525 -        return ko.utils.parseHtmlFragment(templateText);
 60.3526 -    }
 60.3527 -};
 60.3528 -
 60.3529 -ko.nativeTemplateEngine.instance = new ko.nativeTemplateEngine();
 60.3530 -ko.setTemplateEngine(ko.nativeTemplateEngine.instance);
 60.3531 -
 60.3532 -ko.exportSymbol('nativeTemplateEngine', ko.nativeTemplateEngine);
 60.3533 -(function() {
 60.3534 -    ko.jqueryTmplTemplateEngine = function () {
 60.3535 -        // Detect which version of jquery-tmpl you're using. Unfortunately jquery-tmpl
 60.3536 -        // doesn't expose a version number, so we have to infer it.
 60.3537 -        // Note that as of Knockout 1.3, we only support jQuery.tmpl 1.0.0pre and later,
 60.3538 -        // which KO internally refers to as version "2", so older versions are no longer detected.
 60.3539 -        var jQueryTmplVersion = this.jQueryTmplVersion = (function() {
 60.3540 -            if ((typeof(jQuery) == "undefined") || !(jQuery['tmpl']))
 60.3541 -                return 0;
 60.3542 -            // Since it exposes no official version number, we use our own numbering system. To be updated as jquery-tmpl evolves.
 60.3543 -            try {
 60.3544 -                if (jQuery['tmpl']['tag']['tmpl']['open'].toString().indexOf('__') >= 0) {
 60.3545 -                    // Since 1.0.0pre, custom tags should append markup to an array called "__"
 60.3546 -                    return 2; // Final version of jquery.tmpl
 60.3547 -                }
 60.3548 -            } catch(ex) { /* Apparently not the version we were looking for */ }
 60.3549 -
 60.3550 -            return 1; // Any older version that we don't support
 60.3551 -        })();
 60.3552 -
 60.3553 -        function ensureHasReferencedJQueryTemplates() {
 60.3554 -            if (jQueryTmplVersion < 2)
 60.3555 -                throw new Error("Your version of jQuery.tmpl is too old. Please upgrade to jQuery.tmpl 1.0.0pre or later.");
 60.3556 -        }
 60.3557 -
 60.3558 -        function executeTemplate(compiledTemplate, data, jQueryTemplateOptions) {
 60.3559 -            return jQuery['tmpl'](compiledTemplate, data, jQueryTemplateOptions);
 60.3560 -        }
 60.3561 -
 60.3562 -        this['renderTemplateSource'] = function(templateSource, bindingContext, options) {
 60.3563 -            options = options || {};
 60.3564 -            ensureHasReferencedJQueryTemplates();
 60.3565 -
 60.3566 -            // Ensure we have stored a precompiled version of this template (don't want to reparse on every render)
 60.3567 -            var precompiled = templateSource['data']('precompiled');
 60.3568 -            if (!precompiled) {
 60.3569 -                var templateText = templateSource['text']() || "";
 60.3570 -                // Wrap in "with($whatever.koBindingContext) { ... }"
 60.3571 -                templateText = "{{ko_with $item.koBindingContext}}" + templateText + "{{/ko_with}}";
 60.3572 -
 60.3573 -                precompiled = jQuery['template'](null, templateText);
 60.3574 -                templateSource['data']('precompiled', precompiled);
 60.3575 -            }
 60.3576 -
 60.3577 -            var data = [bindingContext['$data']]; // Prewrap the data in an array to stop jquery.tmpl from trying to unwrap any arrays
 60.3578 -            var jQueryTemplateOptions = jQuery['extend']({ 'koBindingContext': bindingContext }, options['templateOptions']);
 60.3579 -
 60.3580 -            var resultNodes = executeTemplate(precompiled, data, jQueryTemplateOptions);
 60.3581 -            resultNodes['appendTo'](document.createElement("div")); // Using "appendTo" forces jQuery/jQuery.tmpl to perform necessary cleanup work
 60.3582 -
 60.3583 -            jQuery['fragments'] = {}; // Clear jQuery's fragment cache to avoid a memory leak after a large number of template renders
 60.3584 -            return resultNodes;
 60.3585 -        };
 60.3586 -
 60.3587 -        this['createJavaScriptEvaluatorBlock'] = function(script) {
 60.3588 -            return "{{ko_code ((function() { return " + script + " })()) }}";
 60.3589 -        };
 60.3590 -
 60.3591 -        this['addTemplate'] = function(templateName, templateMarkup) {
 60.3592 -            document.write("<script type='text/html' id='" + templateName + "'>" + templateMarkup + "</script>");
 60.3593 -        };
 60.3594 -
 60.3595 -        if (jQueryTmplVersion > 0) {
 60.3596 -            jQuery['tmpl']['tag']['ko_code'] = {
 60.3597 -                open: "__.push($1 || '');"
 60.3598 -            };
 60.3599 -            jQuery['tmpl']['tag']['ko_with'] = {
 60.3600 -                open: "with($1) {",
 60.3601 -                close: "} "
 60.3602 -            };
 60.3603 -        }
 60.3604 -    };
 60.3605 -
 60.3606 -    ko.jqueryTmplTemplateEngine.prototype = new ko.templateEngine();
 60.3607 -
 60.3608 -    // Use this one by default *only if jquery.tmpl is referenced*
 60.3609 -    var jqueryTmplTemplateEngineInstance = new ko.jqueryTmplTemplateEngine();
 60.3610 -    if (jqueryTmplTemplateEngineInstance.jQueryTmplVersion > 0)
 60.3611 -        ko.setTemplateEngine(jqueryTmplTemplateEngineInstance);
 60.3612 -
 60.3613 -    ko.exportSymbol('jqueryTmplTemplateEngine', ko.jqueryTmplTemplateEngine);
 60.3614 -})();
 60.3615 -});
 60.3616 -})(window,document,navigator,window["jQuery"]);
 60.3617 -})();
 60.3618 \ No newline at end of file
    61.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    61.2 +++ b/ko/bck2brwsr/src/test/java/org/apidesign/bck2brwsr/ko2brwsr/Bck2BrwsrJavaScriptBodyTest.java	Tue Feb 11 13:31:42 2014 +0100
    61.3 @@ -0,0 +1,34 @@
    61.4 +/**
    61.5 + * Back 2 Browser Bytecode Translator
    61.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
    61.7 + *
    61.8 + * This program is free software: you can redistribute it and/or modify
    61.9 + * it under the terms of the GNU General Public License as published by
   61.10 + * the Free Software Foundation, version 2 of the License.
   61.11 + *
   61.12 + * This program is distributed in the hope that it will be useful,
   61.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   61.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   61.15 + * GNU General Public License for more details.
   61.16 + *
   61.17 + * You should have received a copy of the GNU General Public License
   61.18 + * along with this program. Look for COPYING file in the top folder.
   61.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
   61.20 + */
   61.21 +package org.apidesign.bck2brwsr.ko2brwsr;
   61.22 +
   61.23 +import org.apidesign.bck2brwsr.vmtest.VMTest;
   61.24 +import org.apidesign.html.json.tck.JavaScriptTCK;
   61.25 +import org.apidesign.html.json.tck.KOTest;
   61.26 +import org.testng.annotations.Factory;
   61.27 +
   61.28 +/**
   61.29 + *
   61.30 + * @author Jaroslav Tulach <jtulach@netbeans.org>
   61.31 + */
   61.32 +public class Bck2BrwsrJavaScriptBodyTest extends JavaScriptTCK {
   61.33 +    @Factory public static Object[] tests() {
   61.34 +        return VMTest.newTests().withClasses(testClasses())
   61.35 +            .withTestAnnotation(KOTest.class).build();
   61.36 +    }
   61.37 +}
    62.1 --- a/ko/bck2brwsr/src/test/java/org/apidesign/bck2brwsr/ko2brwsr/Bck2BrwsrKnockoutTest.java	Tue Feb 11 10:48:24 2014 +0100
    62.2 +++ b/ko/bck2brwsr/src/test/java/org/apidesign/bck2brwsr/ko2brwsr/Bck2BrwsrKnockoutTest.java	Tue Feb 11 13:31:42 2014 +0100
    62.3 @@ -31,6 +31,7 @@
    62.4  import org.apidesign.html.json.spi.WSTransfer;
    62.5  import org.apidesign.html.json.tck.KOTest;
    62.6  import org.apidesign.html.json.tck.KnockoutTCK;
    62.7 +import org.netbeans.html.ko4j.KO4J;
    62.8  import org.openide.util.lookup.ServiceProvider;
    62.9  import org.testng.annotations.Factory;
   62.10  
   62.11 @@ -50,10 +51,11 @@
   62.12      
   62.13      @Override
   62.14      public BrwsrCtx createContext() {
   62.15 +        KO4J ko = new KO4J(null);
   62.16          return Contexts.newBuilder().
   62.17 -            register(Transfer.class, BrwsrCtxImpl.DEFAULT, 9).
   62.18 -            register(WSTransfer.class, BrwsrCtxImpl.DEFAULT, 9).
   62.19 -            register(Technology.class, BrwsrCtxImpl.DEFAULT, 9).build();
   62.20 +            register(Transfer.class, ko.transfer(), 9).
   62.21 +            register(WSTransfer.class, ko.websockets(), 9).
   62.22 +            register(Technology.class, ko.knockout(), 9).build();
   62.23      }
   62.24  
   62.25  
    63.1 --- a/ko/fx/pom.xml	Tue Feb 11 10:48:24 2014 +0100
    63.2 +++ b/ko/fx/pom.xml	Tue Feb 11 13:31:42 2014 +0100
    63.3 @@ -40,7 +40,7 @@
    63.4        <type>jar</type>
    63.5      </dependency>
    63.6      <dependency>
    63.7 -      <groupId>org.apidesign.html</groupId>
    63.8 +      <groupId>org.netbeans.html</groupId>
    63.9        <artifactId>net.java.html.json</artifactId>
   63.10        <version>${net.java.html.version}</version>
   63.11      </dependency>
   63.12 @@ -50,7 +50,7 @@
   63.13        <scope>test</scope>
   63.14      </dependency>
   63.15      <dependency>
   63.16 -      <groupId>org.apidesign.html</groupId>
   63.17 +      <groupId>org.netbeans.html</groupId>
   63.18        <artifactId>net.java.html.json.tck</artifactId>
   63.19        <version>${net.java.html.version}</version>
   63.20        <scope>test</scope>
   63.21 @@ -67,14 +67,14 @@
   63.22        <scope>test</scope>
   63.23      </dependency>
   63.24      <dependency>
   63.25 -      <groupId>org.apidesign.html</groupId>
   63.26 +      <groupId>org.netbeans.html</groupId>
   63.27        <artifactId>net.java.html.boot</artifactId>
   63.28        <version>${net.java.html.version}</version>
   63.29        <type>jar</type>
   63.30      </dependency>
   63.31      <dependency>
   63.32 -      <groupId>org.apidesign.html</groupId>
   63.33 -      <artifactId>ko-fx</artifactId>
   63.34 +      <groupId>org.netbeans.html</groupId>
   63.35 +      <artifactId>ko4j</artifactId>
   63.36        <version>${net.java.html.version}</version>
   63.37        <type>jar</type>
   63.38      </dependency>
   63.39 @@ -86,7 +86,7 @@
   63.40        <type>jar</type>
   63.41      </dependency>
   63.42      <dependency>
   63.43 -      <groupId>org.apidesign.html</groupId>
   63.44 +      <groupId>org.netbeans.html</groupId>
   63.45        <artifactId>ko-ws-tyrus</artifactId>
   63.46        <version>${net.java.html.version}</version>
   63.47        <scope>test</scope>
    64.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    64.2 +++ b/ko/fx/src/test/java/org/apidesign/bck2brwsr/kofx/JavaScriptBodyFXBrwsrTest.java	Tue Feb 11 13:31:42 2014 +0100
    64.3 @@ -0,0 +1,36 @@
    64.4 +/**
    64.5 + * Back 2 Browser Bytecode Translator
    64.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
    64.7 + *
    64.8 + * This program is free software: you can redistribute it and/or modify
    64.9 + * it under the terms of the GNU General Public License as published by
   64.10 + * the Free Software Foundation, version 2 of the License.
   64.11 + *
   64.12 + * This program is distributed in the hope that it will be useful,
   64.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   64.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   64.15 + * GNU General Public License for more details.
   64.16 + *
   64.17 + * You should have received a copy of the GNU General Public License
   64.18 + * along with this program. Look for COPYING file in the top folder.
   64.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
   64.20 + */
   64.21 +package org.apidesign.bck2brwsr.kofx;
   64.22 +
   64.23 +import org.apidesign.bck2brwsr.vmtest.VMTest;
   64.24 +import org.apidesign.html.json.tck.JavaScriptTCK;
   64.25 +import org.apidesign.html.json.tck.KOTest;
   64.26 +import org.testng.annotations.Factory;
   64.27 +
   64.28 +/**
   64.29 + *
   64.30 + * @author Jaroslav Tulach <jtulach@netbeans.org>
   64.31 + */
   64.32 +public class JavaScriptBodyFXBrwsrTest extends JavaScriptTCK {
   64.33 +    @Factory public static Object[] create() {
   64.34 +        return VMTest.newTests().
   64.35 +            withLaunchers("fxbrwsr").
   64.36 +            withClasses(testClasses()).
   64.37 +            withTestAnnotation(KOTest.class).build();
   64.38 +    }
   64.39 +}
    65.1 --- a/ko/fx/src/test/java/org/apidesign/bck2brwsr/kofx/KnockoutFXTest.java	Tue Feb 11 10:48:24 2014 +0100
    65.2 +++ b/ko/fx/src/test/java/org/apidesign/bck2brwsr/kofx/KnockoutFXTest.java	Tue Feb 11 13:31:42 2014 +0100
    65.3 @@ -28,17 +28,17 @@
    65.4  import net.java.html.BrwsrCtx;
    65.5  import net.java.html.js.JavaScriptBody;
    65.6  import org.apidesign.bck2brwsr.vmtest.VMTest;
    65.7 -import org.apidesign.html.boot.impl.FnUtils;
    65.8 +import org.apidesign.html.boot.spi.Fn;
    65.9  import org.apidesign.html.context.spi.Contexts;
   65.10  import org.apidesign.html.json.spi.Technology;
   65.11  import org.apidesign.html.json.spi.Transfer;
   65.12  import org.apidesign.html.json.spi.WSTransfer;
   65.13  import org.apidesign.html.json.tck.KOTest;
   65.14  import org.apidesign.html.json.tck.KnockoutTCK;
   65.15 -import org.apidesign.html.kofx.FXContext;
   65.16 -import org.apidesign.html.wstyrus.TyrusContext;
   65.17  import org.json.JSONException;
   65.18  import org.json.JSONObject;
   65.19 +import org.netbeans.html.ko4j.KO4J;
   65.20 +import org.netbeans.html.wstyrus.TyrusContext;
   65.21  import org.openide.util.lookup.ServiceProvider;
   65.22  import org.testng.annotations.Factory;
   65.23  
   65.24 @@ -60,34 +60,36 @@
   65.25  
   65.26      @Override
   65.27      public BrwsrCtx createContext() {
   65.28 -        FXContext fx = new FXContext(FnUtils.currentPresenter());
   65.29 +        KO4J ko = new KO4J(Fn.activePresenter());
   65.30          TyrusContext tc = new TyrusContext();
   65.31          Contexts.Builder b = Contexts.newBuilder().
   65.32 -            register(Technology.class, fx, 10).
   65.33 -            register(Transfer.class, fx, 10);
   65.34 +            register(Technology.class, ko.knockout(), 10).
   65.35 +            register(Transfer.class, ko.transfer(), 10);
   65.36          try {
   65.37              Class.forName("java.util.function.Function");
   65.38              // prefer WebView's WebSockets on JDK8
   65.39 -            b.register(WSTransfer.class, fx, 10);
   65.40 +            b.register(WSTransfer.class, ko.websockets(), 10);
   65.41          } catch (ClassNotFoundException ex) {
   65.42              // ok, JDK7 needs tyrus
   65.43              b.register(WSTransfer.class, tc, 20);
   65.44 +            b.register(Transfer.class, tc, 5);
   65.45          }
   65.46          return b.build();
   65.47      }
   65.48  
   65.49      @Override
   65.50      public Object createJSON(Map<String, Object> values) {
   65.51 -        JSONObject json = new JSONObject();
   65.52 +        Object json = createJSON();
   65.53          for (Map.Entry<String, Object> entry : values.entrySet()) {
   65.54 -            try {
   65.55 -                json.put(entry.getKey(), entry.getValue());
   65.56 -            } catch (JSONException ex) {
   65.57 -                throw new IllegalStateException(ex);
   65.58 -            }
   65.59 +            setProperty(json, entry.getKey(), entry.getValue());
   65.60          }
   65.61          return json;
   65.62      }
   65.63 +    
   65.64 +    @JavaScriptBody(args = {}, body = "return new Object();")
   65.65 +    private static native Object createJSON();
   65.66 +    @JavaScriptBody(args = { "json", "key", "value" }, body = "json[key] = value;")
   65.67 +    private static native void setProperty(Object json, String key, Object value);
   65.68  
   65.69      @Override
   65.70      @JavaScriptBody(args = { "s", "args" }, body = ""
    66.1 --- a/launcher/fx/pom.xml	Tue Feb 11 10:48:24 2014 +0100
    66.2 +++ b/launcher/fx/pom.xml	Tue Feb 11 13:31:42 2014 +0100
    66.3 @@ -75,7 +75,7 @@
    66.4        <version>4.1</version>
    66.5      </dependency>
    66.6      <dependency>
    66.7 -      <groupId>org.apidesign.html</groupId>
    66.8 +      <groupId>org.netbeans.html</groupId>
    66.9        <artifactId>net.java.html.boot</artifactId>
   66.10        <version>${net.java.html.version}</version>
   66.11      </dependency>
    67.1 --- a/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/BaseHTTPLauncher.java	Tue Feb 11 10:48:24 2014 +0100
    67.2 +++ b/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/BaseHTTPLauncher.java	Tue Feb 11 13:31:42 2014 +0100
    67.3 @@ -572,7 +572,10 @@
    67.4      }
    67.5  
    67.6      class Res {
    67.7 -        public InputStream get(String resource) throws IOException {
    67.8 +        public InputStream get(String resource, int skip) throws IOException {
    67.9 +            if (!resource.endsWith(".class")) {
   67.10 +                return getResource(resource, skip);
   67.11 +            }
   67.12              URL u = null;
   67.13              for (ClassLoader l : loaders) {
   67.14                  Enumeration<URL> en = l.getResources(resource);
   67.15 @@ -585,12 +588,30 @@
   67.16              }
   67.17              if (u != null) {
   67.18                  if (u.toExternalForm().contains("rt.jar")) {
   67.19 -                    LOG.log(Level.WARNING, "Fallback to bootclasspath for {0}", u);
   67.20 +                    LOG.log(Level.WARNING, "No fallback to bootclasspath for {0}", u);
   67.21 +                    return null;
   67.22                  }
   67.23                  return u.openStream();
   67.24              }
   67.25              throw new IOException("Can't find " + resource);
   67.26          }
   67.27 +        private InputStream getResource(String resource, int skip) throws IOException {
   67.28 +            for (ClassLoader l : loaders) {
   67.29 +                Enumeration<URL> en = l.getResources(resource);
   67.30 +                while (en.hasMoreElements()) {
   67.31 +                    final URL now = en.nextElement();
   67.32 +                    if (now.toExternalForm().contains("sisu-inject-bean")) {
   67.33 +                        // certainly we don't want this resource, as that
   67.34 +                        // module is not compiled with target 1.6, currently
   67.35 +                        continue;
   67.36 +                    }
   67.37 +                    if (--skip < 0) {
   67.38 +                        return now.openStream();
   67.39 +                    }
   67.40 +                }
   67.41 +            }
   67.42 +            throw new IOException("Not found (anymore of) " + resource);
   67.43 +        }
   67.44      }
   67.45  
   67.46      private static class Page extends HttpHandler {
   67.47 @@ -623,7 +644,7 @@
   67.48              }
   67.49              OutputStream os = response.getOutputStream();
   67.50              try { 
   67.51 -                InputStream is = res.get(r);
   67.52 +                InputStream is = res.get(r, 0);
   67.53                  copyStream(is, os, request.getRequestURL().toString(), replace);
   67.54              } catch (IOException ex) {
   67.55                  response.setDetailMessage(ex.getLocalizedMessage());
   67.56 @@ -695,7 +716,9 @@
   67.57              }
   67.58              InputStream is = null;
   67.59              try {
   67.60 -                is = loader.get(res);
   67.61 +                String skip = request.getParameter("skip");
   67.62 +                int skipCnt = skip == null ? 0 : Integer.parseInt(skip);
   67.63 +                is = loader.get(res, skipCnt);
   67.64                  response.setContentType("text/javascript");
   67.65                  Writer w = response.getWriter();
   67.66                  w.append("[");
    68.1 --- a/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/BrowserToolbar.java	Tue Feb 11 10:48:24 2014 +0100
    68.2 +++ b/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/BrowserToolbar.java	Tue Feb 11 13:31:42 2014 +0100
    68.3 @@ -117,7 +117,9 @@
    68.4              zoom = Math.abs( zoom )/100;
    68.5              if( zoom <= 0.0 )
    68.6                  return null;
    68.7 -            webView.impl_setScale( zoom );
    68.8 +            webView.setScaleX(zoom);
    68.9 +            webView.setScaleY(zoom);
   68.10 +            webView.setScaleZ(zoom);
   68.11              return (int)(100*zoom) + "%"; //NOI18N
   68.12          } catch( NumberFormatException nfe ) {
   68.13              //ignore
    69.1 --- a/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/Console.java	Tue Feb 11 10:48:24 2014 +0100
    69.2 +++ b/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/Console.java	Tue Feb 11 13:31:42 2014 +0100
    69.3 @@ -25,8 +25,8 @@
    69.4  import java.lang.reflect.Modifier;
    69.5  import java.net.URL;
    69.6  import java.util.Enumeration;
    69.7 +import net.java.html.js.JavaScriptBody;
    69.8  import netscape.javascript.JSObject;
    69.9 -import org.apidesign.bck2brwsr.core.JavaScriptBody;
   69.10  
   69.11  /**
   69.12   *
   69.13 @@ -60,8 +60,7 @@
   69.14      }
   69.15      
   69.16      private static void beginTest(Case c) {
   69.17 -        Object[] arr = new Object[2];
   69.18 -        beginTest(c.getClassName() + "." + c.getMethodName(), c, arr);
   69.19 +        Object[] arr = beginTest(c.getClassName() + "." + c.getMethodName(), c, new Object[2]);
   69.20          textArea = arr[0];
   69.21          statusArea = arr[1];
   69.22      }
   69.23 @@ -102,23 +101,23 @@
   69.24          + "ul.appendChild(li);\n"
   69.25          + "arr[0] = pre;\n"
   69.26          + "arr[1] = status;\n"
   69.27 +        + "return arr;"
   69.28      )
   69.29 -    private static native void beginTest(String test, Case c, Object[] arr);
   69.30 +    private static native Object[] beginTest(String test, Case c, Object[] arr);
   69.31      
   69.32 -    @JavaScriptBody(args = { "url", "callback", "arr" }, body =
   69.33 +    @JavaScriptBody(args = { "url", "callback" }, javacall = true, body =
   69.34            "var request = new XMLHttpRequest();\n"
   69.35          + "request.open('GET', url, true);\n"
   69.36          + "request.setRequestHeader('Content-Type', 'text/plain; charset=utf-8');\n"
   69.37          + "request.onreadystatechange = function() {\n"
   69.38          + "  if (this.readyState!==4) return;\n"
   69.39          + " try {\n"
   69.40 -        + "  arr[0] = this.responseText;\n"
   69.41 -        + "  callback.run();\n"
   69.42 +        + "  callback.@org.apidesign.bck2brwsr.launcher.fximpl.OnMessage::onMessage(Ljava/lang/String;)(this.responseText);\n"
   69.43          + " } catch (e) { alert(e); }\n"
   69.44          + "};\n"
   69.45          + "request.send();\n"
   69.46      )
   69.47 -    private static native void loadText(String url, Runnable callback, String[] arr) throws IOException;
   69.48 +    private static native void loadText(String url, OnMessage callback) throws IOException;
   69.49      
   69.50      public static void runHarness(String url) throws IOException {
   69.51          new Console().harness(url);
   69.52 @@ -129,7 +128,7 @@
   69.53          Request r = new Request(url);
   69.54      }
   69.55      
   69.56 -    private static class Request implements Runnable {
   69.57 +    private static class Request implements Runnable, OnMessage {
   69.58          private final String[] arr = { null };
   69.59          private final String url;
   69.60          private Case c;
   69.61 @@ -137,11 +136,17 @@
   69.62  
   69.63          private Request(String url) throws IOException {
   69.64              this.url = url;
   69.65 -            loadText(url, new Run(this), arr);
   69.66 +            loadText(url, this);
   69.67          }
   69.68          private Request(String url, String u) throws IOException {
   69.69              this.url = url;
   69.70 -            loadText(u, new Run(this), arr);
   69.71 +            loadText(u, this);
   69.72 +        }
   69.73 +
   69.74 +        @Override
   69.75 +        public void onMessage(String msg) {
   69.76 +            arr[0] = msg;
   69.77 +            run();
   69.78          }
   69.79          
   69.80          @Override
   69.81 @@ -177,7 +182,7 @@
   69.82              } catch (Exception ex) {
   69.83                  if (ex instanceof InterruptedException) {
   69.84                      log("Re-scheduling in 100ms");
   69.85 -                    schedule(new Run(this), 100);
   69.86 +                    schedule(this, 100);
   69.87                      return;
   69.88                  }
   69.89                  log(ex.getClass().getName() + ":" + ex.getMessage());
   69.90 @@ -250,7 +255,11 @@
   69.91      private static void turnAssetionStatusOn() {
   69.92      }
   69.93  
   69.94 -    @JavaScriptBody(args = { "r", "time" }, body = "return window.setTimeout(function() { r.run(); }, time);")
   69.95 +    @JavaScriptBody(args = { "r", "time" }, javacall = true, body = 
   69.96 +        "return window.setTimeout(function() { "
   69.97 +        + "r.@java.lang.Runnable::run()(); "
   69.98 +        + "}, time);"
   69.99 +    )
  69.100      private static native Object schedule(Runnable r, int time);
  69.101      
  69.102      private static final class Case {
    70.1 --- a/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/FXBrwsr.java	Tue Feb 11 10:48:24 2014 +0100
    70.2 +++ b/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/FXBrwsr.java	Tue Feb 11 13:31:42 2014 +0100
    70.3 @@ -34,6 +34,7 @@
    70.4  import javafx.scene.control.ToolBar;
    70.5  import javafx.scene.layout.BorderPane;
    70.6  import javafx.scene.layout.HBox;
    70.7 +import javafx.scene.layout.Priority;
    70.8  import javafx.scene.layout.VBox;
    70.9  import javafx.scene.text.Text;
   70.10  import javafx.scene.web.WebEngine;
   70.11 @@ -68,7 +69,9 @@
   70.12          hbox.setStyle( "-fx-background-color: #808080;");
   70.13          hbox.setAlignment(Pos.CENTER);
   70.14          hbox.getChildren().add(vbox);
   70.15 +        HBox.setHgrow(vbox, Priority.ALWAYS);
   70.16          vbox.getChildren().add(view);
   70.17 +        VBox.setVgrow(view, Priority.ALWAYS);
   70.18  
   70.19          BorderPane root = new BorderPane();
   70.20          final boolean showToolbar = "true".equals(this.getParameters().getNamed().get("toolbar")); // NOI18N
    71.1 --- a/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/JVMBridge.java	Tue Feb 11 10:48:24 2014 +0100
    71.2 +++ b/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/JVMBridge.java	Tue Feb 11 13:31:42 2014 +0100
    71.3 @@ -19,24 +19,30 @@
    71.4  
    71.5  import java.io.BufferedReader;
    71.6  import java.io.Reader;
    71.7 -import org.apidesign.html.boot.spi.Fn;
    71.8  import java.net.URL;
    71.9  import java.util.ArrayList;
   71.10  import java.util.Arrays;
   71.11  import java.util.Collection;
   71.12  import java.util.List;
   71.13  import java.util.TooManyListenersException;
   71.14 +import java.util.concurrent.Executor;
   71.15 +import java.util.logging.Level;
   71.16 +import java.util.logging.Logger;
   71.17 +import javafx.application.Platform;
   71.18  import javafx.beans.value.ChangeListener;
   71.19  import javafx.scene.web.WebEngine;
   71.20  import netscape.javascript.JSObject;
   71.21 -import org.apidesign.html.boot.impl.FindResources;
   71.22 -import org.apidesign.html.boot.impl.FnUtils;
   71.23 +import org.apidesign.html.boot.spi.Fn;
   71.24 +import org.netbeans.html.boot.impl.FindResources;
   71.25 +import org.netbeans.html.boot.impl.FnUtils;
   71.26  
   71.27  /**
   71.28   *
   71.29   * @author Jaroslav Tulach <jtulach@netbeans.org>
   71.30   */
   71.31  public final class JVMBridge {
   71.32 +    static final Logger LOG = Logger.getLogger(JVMBridge.class.getName());
   71.33 +    
   71.34      private final WebEngine engine;
   71.35      private final ClassLoader cl;
   71.36      private final WebPresenter presenter;
   71.37 @@ -70,11 +76,12 @@
   71.38      }
   71.39      
   71.40      public Class<?> loadClass(String name) throws ClassNotFoundException {
   71.41 -        FnUtils.currentPresenter(presenter);
   71.42 +        Fn.activate(presenter);
   71.43          return Class.forName(name, true, cl);
   71.44      }
   71.45      
   71.46 -    private final class WebPresenter implements FindResources, Fn.Presenter {
   71.47 +    private final class WebPresenter 
   71.48 +    implements FindResources, Fn.Presenter, Fn.ToJavaScript, Fn.FromJavaScript, Executor {
   71.49          @Override
   71.50          public void findResources(String name, Collection<? super URL> results, boolean oneIsEnough) {
   71.51              if (ldrs != null) for (ClassLoader l : ldrs) {
   71.52 @@ -87,6 +94,9 @@
   71.53  
   71.54          @Override
   71.55          public Fn defineFn(String code, String... names) {
   71.56 +            return defineJSFn(code, names);
   71.57 +        }
   71.58 +        private JSFn defineJSFn(String code, String... names) {
   71.59              StringBuilder sb = new StringBuilder();
   71.60              sb.append("(function() {");
   71.61              sb.append("  return function(");
   71.62 @@ -122,6 +132,91 @@
   71.63              }
   71.64              engine.executeScript(sb.toString());
   71.65          }
   71.66 +
   71.67 +        @Override
   71.68 +        public Object toJava(Object js) {
   71.69 +            return checkArray(js);
   71.70 +        }
   71.71 +
   71.72 +        @Override
   71.73 +        public Object toJavaScript(Object toReturn) {
   71.74 +            if (toReturn instanceof Object[]) {
   71.75 +                return convertArrays((Object[]) toReturn);
   71.76 +            }
   71.77 +            return toReturn;
   71.78 +        }
   71.79 +
   71.80 +        @Override
   71.81 +        public void execute(Runnable command) {
   71.82 +            if (Platform.isFxApplicationThread()) {
   71.83 +                command.run();
   71.84 +            } else {
   71.85 +                Platform.runLater(command);
   71.86 +            }
   71.87 +        }
   71.88 +        
   71.89 +        final JSObject convertArrays(Object[] arr) {
   71.90 +            for (int i = 0; i < arr.length; i++) {
   71.91 +                if (arr[i] instanceof Object[]) {
   71.92 +                    arr[i] = convertArrays((Object[]) arr[i]);
   71.93 +                }
   71.94 +            }
   71.95 +            final JSObject wrapArr = (JSObject) wrapArrFn().call("array", arr); // NOI18N
   71.96 +            return wrapArr;
   71.97 +        }
   71.98 +
   71.99 +        private JSObject wrapArrImpl;
  71.100 +
  71.101 +        private final JSObject wrapArrFn() {
  71.102 +            if (wrapArrImpl == null) {
  71.103 +                try {
  71.104 +                    wrapArrImpl = (JSObject) defineJSFn("  var k = {};"
  71.105 +                        + "  k.array= function() {"
  71.106 +                        + "    return Array.prototype.slice.call(arguments);"
  71.107 +                        + "  };"
  71.108 +                        + "  return k;"
  71.109 +                    ).invokeImpl(null, false);
  71.110 +                } catch (Exception ex) {
  71.111 +                    throw new IllegalStateException(ex);
  71.112 +                }
  71.113 +            }
  71.114 +            return wrapArrImpl;
  71.115 +        }
  71.116 +
  71.117 +        final Object checkArray(Object val) {
  71.118 +            int length = ((Number) arraySizeFn().call("array", val, null)).intValue();
  71.119 +            if (length == -1) {
  71.120 +                return val;
  71.121 +            }
  71.122 +            Object[] arr = new Object[length];
  71.123 +            arraySizeFn().call("array", val, arr);
  71.124 +            return arr;
  71.125 +        }
  71.126 +        private JSObject arraySize;
  71.127 +
  71.128 +        private final JSObject arraySizeFn() {
  71.129 +            if (arraySize == null) {
  71.130 +                try {
  71.131 +                    arraySize = (JSObject) defineJSFn("  var k = {};"
  71.132 +                        + "  k.array = function(arr, to) {"
  71.133 +                        + "    if (to === null) {"
  71.134 +                        + "      if (Object.prototype.toString.call(arr) === '[object Array]') return arr.length;"
  71.135 +                        + "      else return -1;"
  71.136 +                        + "    } else {"
  71.137 +                        + "      var l = arr.length;"
  71.138 +                        + "      for (var i = 0; i < l; i++) to[i] = arr[i];"
  71.139 +                        + "      return l;"
  71.140 +                        + "    }"
  71.141 +                        + "  };"
  71.142 +                        + "  return k;"
  71.143 +                    ).invokeImpl(null, false);
  71.144 +                } catch (Exception ex) {
  71.145 +                    throw new IllegalStateException(ex);
  71.146 +                }
  71.147 +            }
  71.148 +            return arraySize;
  71.149 +        }
  71.150 +        
  71.151      }
  71.152      
  71.153      private static final class JSFn extends Fn {
  71.154 @@ -134,12 +229,29 @@
  71.155  
  71.156          @Override
  71.157          public Object invoke(Object thiz, Object... args) throws Exception {
  71.158 +            return invokeImpl(thiz, true, args);
  71.159 +        }
  71.160 +
  71.161 +        final Object invokeImpl(Object thiz, boolean arrayChecks, Object... args) throws Exception {
  71.162              try {
  71.163                  List<Object> all = new ArrayList<Object>(args.length + 1);
  71.164                  all.add(thiz == null ? fn : thiz);
  71.165 -                all.addAll(Arrays.asList(args));
  71.166 +                for (int i = 0; i < args.length; i++) {
  71.167 +                    if (arrayChecks && args[i] instanceof Object[]) {
  71.168 +                        Object[] arr = (Object[]) args[i];
  71.169 +                        Object conv = ((WebPresenter) presenter()).convertArrays(arr);
  71.170 +                        args[i] = conv;
  71.171 +                    }
  71.172 +                    all.add(args[i]);
  71.173 +                }
  71.174                  Object ret = fn.call("call", all.toArray()); // NOI18N
  71.175 -                return ret == fn ? null : ret;
  71.176 +                if (ret == fn) {
  71.177 +                    return null;
  71.178 +                }
  71.179 +                if (!arrayChecks) {
  71.180 +                    return ret;
  71.181 +                }
  71.182 +                return ((WebPresenter) presenter()).checkArray(ret);
  71.183              } catch (Error t) {
  71.184                  t.printStackTrace();
  71.185                  throw t;
    72.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    72.2 +++ b/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/OnMessage.java	Tue Feb 11 13:31:42 2014 +0100
    72.3 @@ -0,0 +1,26 @@
    72.4 +/**
    72.5 + * Back 2 Browser Bytecode Translator
    72.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
    72.7 + *
    72.8 + * This program is free software: you can redistribute it and/or modify
    72.9 + * it under the terms of the GNU General Public License as published by
   72.10 + * the Free Software Foundation, version 2 of the License.
   72.11 + *
   72.12 + * This program is distributed in the hope that it will be useful,
   72.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   72.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   72.15 + * GNU General Public License for more details.
   72.16 + *
   72.17 + * You should have received a copy of the GNU General Public License
   72.18 + * along with this program. Look for COPYING file in the top folder.
   72.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
   72.20 + */
   72.21 +package org.apidesign.bck2brwsr.launcher.fximpl;
   72.22 +
   72.23 +/**
   72.24 + *
   72.25 + * @author Jaroslav Tulach <jtulach@netbeans.org>
   72.26 + */
   72.27 +interface OnMessage {
   72.28 +    public void onMessage(String msg);
   72.29 +}
    73.1 --- a/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/Run.java	Tue Feb 11 10:48:24 2014 +0100
    73.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    73.3 @@ -1,35 +0,0 @@
    73.4 -/**
    73.5 - * Back 2 Browser Bytecode Translator
    73.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
    73.7 - *
    73.8 - * This program is free software: you can redistribute it and/or modify
    73.9 - * it under the terms of the GNU General Public License as published by
   73.10 - * the Free Software Foundation, version 2 of the License.
   73.11 - *
   73.12 - * This program is distributed in the hope that it will be useful,
   73.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
   73.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   73.15 - * GNU General Public License for more details.
   73.16 - *
   73.17 - * You should have received a copy of the GNU General Public License
   73.18 - * along with this program. Look for COPYING file in the top folder.
   73.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
   73.20 - */
   73.21 -
   73.22 -package org.apidesign.bck2brwsr.launcher.fximpl;
   73.23 -
   73.24 -/**
   73.25 - *
   73.26 - * @author Jaroslav Tulach <jtulach@netbeans.org>
   73.27 - */
   73.28 -public final class Run implements Runnable {
   73.29 -    private final Runnable r;
   73.30 -    Run(Runnable r) {
   73.31 -        this.r = r;
   73.32 -    }
   73.33 -
   73.34 -    @Override
   73.35 -    public void run() {
   73.36 -        r.run();
   73.37 -    }
   73.38 -}
    74.1 --- a/launcher/fx/src/test/java/org/apidesign/bck2brwsr/launcher/fximpl/JsClassLoaderTest.java	Tue Feb 11 10:48:24 2014 +0100
    74.2 +++ b/launcher/fx/src/test/java/org/apidesign/bck2brwsr/launcher/fximpl/JsClassLoaderTest.java	Tue Feb 11 13:31:42 2014 +0100
    74.3 @@ -31,8 +31,8 @@
    74.4  import javax.script.ScriptEngineManager;
    74.5  import javax.script.ScriptException;
    74.6  import org.apidesign.html.boot.spi.Fn;
    74.7 -import org.apidesign.html.boot.impl.FindResources;
    74.8 -import org.apidesign.html.boot.impl.FnUtils;
    74.9 +import org.netbeans.html.boot.impl.FindResources;
   74.10 +import org.netbeans.html.boot.impl.FnUtils;
   74.11  import static org.testng.Assert.*;
   74.12  import org.testng.annotations.BeforeClass;
   74.13  import org.testng.annotations.BeforeMethod;
   74.14 @@ -92,7 +92,7 @@
   74.15                              all.addAll(Arrays.asList(args));
   74.16                              Invocable inv = (Invocable)eng;
   74.17                              Object ret = inv.invokeMethod(val, "call", all.toArray());
   74.18 -                            return ret == val ? null : ret;
   74.19 +                            return val.equals(ret) ? null : ret;
   74.20                          }
   74.21                      };
   74.22                  } catch (ScriptException ex) {
   74.23 @@ -118,7 +118,7 @@
   74.24      }
   74.25      
   74.26      @BeforeMethod public void registerPresenter() {
   74.27 -        FnUtils.currentPresenter(presenter);
   74.28 +        Fn.activate(presenter);
   74.29      }
   74.30      
   74.31      @Test public void noParamMethod() throws Throwable {
    75.1 --- a/launcher/fx/src/test/java/org/apidesign/bck2brwsr/launcher/fximpl/JsMethods.java	Tue Feb 11 10:48:24 2014 +0100
    75.2 +++ b/launcher/fx/src/test/java/org/apidesign/bck2brwsr/launcher/fximpl/JsMethods.java	Tue Feb 11 13:31:42 2014 +0100
    75.3 @@ -17,7 +17,7 @@
    75.4   */
    75.5  package org.apidesign.bck2brwsr.launcher.fximpl;
    75.6  
    75.7 -import org.apidesign.bck2brwsr.core.JavaScriptBody;
    75.8 +import net.java.html.js.JavaScriptBody;
    75.9  
   75.10  /**
   75.11   *
    76.1 --- a/launcher/http/src/main/java/org/apidesign/bck2brwsr/launcher/Bck2BrwsrLauncher.java	Tue Feb 11 10:48:24 2014 +0100
    76.2 +++ b/launcher/http/src/main/java/org/apidesign/bck2brwsr/launcher/Bck2BrwsrLauncher.java	Tue Feb 11 13:31:42 2014 +0100
    76.3 @@ -17,8 +17,15 @@
    76.4   */
    76.5  package org.apidesign.bck2brwsr.launcher;
    76.6  
    76.7 +import java.io.File;
    76.8 +import java.io.FileReader;
    76.9  import java.io.IOException;
   76.10  import java.io.InputStream;
   76.11 +import java.io.InputStreamReader;
   76.12 +import java.io.Reader;
   76.13 +import java.net.MalformedURLException;
   76.14 +import java.net.URL;
   76.15 +import java.util.logging.Level;
   76.16  import org.apidesign.vm4brwsr.Bck2Brwsr;
   76.17  
   76.18  /**
   76.19 @@ -42,19 +49,57 @@
   76.20          class R implements Bck2Brwsr.Resources {
   76.21              @Override
   76.22              public InputStream get(String resource) throws IOException {
   76.23 -                return loader.get(resource);
   76.24 +                return loader.get(resource, 0);
   76.25              }
   76.26          }
   76.27 -
   76.28 -        Bck2Brwsr.generate(sb, new R());
   76.29 +        String b2b = System.getProperty("bck2brwsr.js");
   76.30 +        if (b2b != null) {
   76.31 +            LOG.log(Level.INFO, "Serving bck2brwsr.js from {0}", b2b);
   76.32 +            URL bu;
   76.33 +            try {
   76.34 +                bu = new URL(b2b);
   76.35 +            } catch (MalformedURLException ex) {
   76.36 +                File f = new File(b2b);
   76.37 +                if (f.exists()) {
   76.38 +                    bu = f.toURI().toURL();
   76.39 +                } else {
   76.40 +                    throw ex;
   76.41 +                }
   76.42 +            }
   76.43 +            try (Reader r = new InputStreamReader(bu.openStream())) {
   76.44 +                char[] arr = new char[4096];
   76.45 +                for (;;) {
   76.46 +                   int len = r.read(arr);
   76.47 +                   if (len == -1) {
   76.48 +                       break;
   76.49 +                   }
   76.50 +                   sb.append(arr, 0, len);
   76.51 +                }
   76.52 +            }
   76.53 +        } else {
   76.54 +            LOG.log(Level.INFO, "Generating bck2brwsr.js from scratch", b2b);
   76.55 +            Bck2Brwsr.generate(sb, new R());
   76.56 +        }
   76.57          sb.append(
   76.58 -              "(function WrapperVM(global) {"
   76.59 -            + "  function ldCls(res) {\n"
   76.60 +              "(function WrapperVM(global) {\n"
   76.61 +            + "  var cache = {};\n"
   76.62 +            + "  function ldCls(res, skip) {\n"
   76.63 +            + "    var c = cache[res];\n"
   76.64 +            + "    if (c) {\n"
   76.65 +            + "      if (c[skip]) return c[skip];\n"
   76.66 +            + "      if (c[skip] === null) return null;\n"
   76.67 +            + "    } else {\n"
   76.68 +            + "      cache[res] = c = new Array();\n"
   76.69 +            + "    }\n"
   76.70              + "    var request = new XMLHttpRequest();\n"
   76.71 -            + "    request.open('GET', '/classes/' + res, false);\n"
   76.72 +            + "    request.open('GET', '/classes/' + res + '?skip=' + skip, false);\n"
   76.73              + "    request.send();\n"
   76.74 -            + "    if (request.status !== 200) return null;\n"
   76.75 +            + "    if (request.status !== 200) {\n"
   76.76 +            + "      c[skip] = null;\n"
   76.77 +            + "      return null;\n"
   76.78 +            + "    }\n"
   76.79              + "    var arr = eval('(' + request.responseText + ')');\n"
   76.80 +            + "    c[skip] = arr;\n"
   76.81              + "    return arr;\n"
   76.82              + "  }\n"
   76.83              + "  var prevvm = global.bck2brwsr;\n"
   76.84 @@ -65,6 +110,7 @@
   76.85              + "  };\n"
   76.86              + "})(this);\n"
   76.87          );
   76.88 +        LOG.log(Level.INFO, "Serving bck2brwsr.js", b2b);
   76.89      }
   76.90  
   76.91  }
    77.1 --- a/launcher/http/src/main/java/org/apidesign/bck2brwsr/launcher/JSLauncher.java	Tue Feb 11 10:48:24 2014 +0100
    77.2 +++ b/launcher/http/src/main/java/org/apidesign/bck2brwsr/launcher/JSLauncher.java	Tue Feb 11 13:31:42 2014 +0100
    77.3 @@ -126,6 +126,10 @@
    77.4                      u = en.nextElement();
    77.5                  }
    77.6                  if (u != null) {
    77.7 +                    if (u.toExternalForm().contains("rt.jar")) {
    77.8 +                        LOG.log(Level.WARNING, "No fallback to bootclasspath for {0}", u);
    77.9 +                        return null;
   77.10 +                    }
   77.11                      return u.openStream();
   77.12                  }
   77.13              }
    78.1 --- a/launcher/http/src/main/java/org/apidesign/bck2brwsr/launcher/impl/Console.java	Tue Feb 11 10:48:24 2014 +0100
    78.2 +++ b/launcher/http/src/main/java/org/apidesign/bck2brwsr/launcher/impl/Console.java	Tue Feb 11 13:31:42 2014 +0100
    78.3 @@ -220,14 +220,22 @@
    78.4       * @return the array of bytes in the given resource
    78.5       * @throws IOException I/O in case something goes wrong
    78.6       */
    78.7 -    public static byte[] read(String name) throws IOException {
    78.8 +    public static byte[] read(String name, int skip) throws IOException {
    78.9          URL u = null;
   78.10 -        Enumeration<URL> en = Console.class.getClassLoader().getResources(name);
   78.11 -        while (en.hasMoreElements()) {
   78.12 -            u = en.nextElement();
   78.13 +        if (!name.endsWith(".class")) {
   78.14 +            u = getResource(name, skip);
   78.15 +        } else {
   78.16 +            Enumeration<URL> en = Console.class.getClassLoader().getResources(name);
   78.17 +            while (en.hasMoreElements()) {
   78.18 +                u = en.nextElement();
   78.19 +            }
   78.20          }
   78.21          if (u == null) {
   78.22 -            throw new IOException("Can't find " + name);
   78.23 +            if (name.endsWith(".class")) {
   78.24 +                throw new IOException("Can't find " + name);
   78.25 +            } else {
   78.26 +                return null;
   78.27 +            }
   78.28          }
   78.29          try (InputStream is = u.openStream()) {
   78.30              byte[] arr;
   78.31 @@ -244,6 +252,19 @@
   78.32          }
   78.33      }
   78.34     
   78.35 +    private static URL getResource(String resource, int skip) throws IOException {
   78.36 +        URL u = null;
   78.37 +        Enumeration<URL> en = Console.class.getClassLoader().getResources(resource);
   78.38 +        while (en.hasMoreElements()) {
   78.39 +            final URL now = en.nextElement();
   78.40 +            if (--skip < 0) {
   78.41 +                u = now;
   78.42 +                break;
   78.43 +            }
   78.44 +        }
   78.45 +        return u;
   78.46 +    }
   78.47 +    
   78.48      @JavaScriptBody(args = {}, body = "vm.desiredAssertionStatus = true;")
   78.49      private static void turnAssetionStatusOn() {
   78.50      }
    79.1 --- a/pom.xml	Tue Feb 11 10:48:24 2014 +0100
    79.2 +++ b/pom.xml	Tue Feb 11 13:31:42 2014 +0100
    79.3 @@ -13,15 +13,14 @@
    79.4    </parent>  
    79.5    <properties>
    79.6        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    79.7 -      <netbeans.version>RELEASE73</netbeans.version>
    79.8 +      <netbeans.version>RELEASE74</netbeans.version>
    79.9        <license>COPYING</license>
   79.10 -      <net.java.html.version>0.6</net.java.html.version>
   79.11 +      <net.java.html.version>0.7.5</net.java.html.version>
   79.12 +      <netbeans.compile.on.save>none</netbeans.compile.on.save>
   79.13    </properties>
   79.14    <modules>
   79.15 -    <module>dew</module>
   79.16      <module>javaquery</module>
   79.17      <module>benchmarks</module>
   79.18 -    <module>ide</module>
   79.19      <module>ko</module>
   79.20      <module>launcher</module>
   79.21      <module>rt</module>
   79.22 @@ -90,10 +89,8 @@
   79.23                         <exclude>rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeParser.java</exclude>
   79.24                         <exclude>rt/archetype/src/main/resources/archetype-resources/**</exclude>
   79.25                         <exclude>rt/emul/compact/src/test/resources/**</exclude>
   79.26 -                       <exclude>dew/src/main/resources/org/apidesign/bck2brwsr/dew/**</exclude>
   79.27                         <exclude>javaquery/api/src/main/resources/org/apidesign/bck2brwsr/htmlpage/knockout*.js</exclude>
   79.28                         <exclude>ko/archetype/src/main/resources/archetype-resources/**</exclude>
   79.29 -                       <exclude>ko/*/src/main/resources/org/apidesign/*/*/knockout-2.2.1.js</exclude>
   79.30                    </excludes>
   79.31                </configuration>
   79.32            </plugin>-->
    80.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    80.2 +++ b/rt/emul/compact/src/main/java/java/io/BufferedInputStream.java	Tue Feb 11 13:31:42 2014 +0100
    80.3 @@ -0,0 +1,458 @@
    80.4 +/*
    80.5 + * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
    80.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    80.7 + *
    80.8 + * This code is free software; you can redistribute it and/or modify it
    80.9 + * under the terms of the GNU General Public License version 2 only, as
   80.10 + * published by the Free Software Foundation.  Oracle designates this
   80.11 + * particular file as subject to the "Classpath" exception as provided
   80.12 + * by Oracle in the LICENSE file that accompanied this code.
   80.13 + *
   80.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   80.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   80.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   80.17 + * version 2 for more details (a copy is included in the LICENSE file that
   80.18 + * accompanied this code).
   80.19 + *
   80.20 + * You should have received a copy of the GNU General Public License version
   80.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   80.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   80.23 + *
   80.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   80.25 + * or visit www.oracle.com if you need additional information or have any
   80.26 + * questions.
   80.27 + */
   80.28 +
   80.29 +package java.io;
   80.30 +
   80.31 +/**
   80.32 + * A <code>BufferedInputStream</code> adds
   80.33 + * functionality to another input stream-namely,
   80.34 + * the ability to buffer the input and to
   80.35 + * support the <code>mark</code> and <code>reset</code>
   80.36 + * methods. When  the <code>BufferedInputStream</code>
   80.37 + * is created, an internal buffer array is
   80.38 + * created. As bytes  from the stream are read
   80.39 + * or skipped, the internal buffer is refilled
   80.40 + * as necessary  from the contained input stream,
   80.41 + * many bytes at a time. The <code>mark</code>
   80.42 + * operation  remembers a point in the input
   80.43 + * stream and the <code>reset</code> operation
   80.44 + * causes all the  bytes read since the most
   80.45 + * recent <code>mark</code> operation to be
   80.46 + * reread before new bytes are  taken from
   80.47 + * the contained input stream.
   80.48 + *
   80.49 + * @author  Arthur van Hoff
   80.50 + * @since   JDK1.0
   80.51 + */
   80.52 +public
   80.53 +class BufferedInputStream extends FilterInputStream {
   80.54 +
   80.55 +    private static int defaultBufferSize = 8192;
   80.56 +
   80.57 +    /**
   80.58 +     * The internal buffer array where the data is stored. When necessary,
   80.59 +     * it may be replaced by another array of
   80.60 +     * a different size.
   80.61 +     */
   80.62 +    protected volatile byte buf[];
   80.63 +
   80.64 +
   80.65 +    /**
   80.66 +     * The index one greater than the index of the last valid byte in
   80.67 +     * the buffer.
   80.68 +     * This value is always
   80.69 +     * in the range <code>0</code> through <code>buf.length</code>;
   80.70 +     * elements <code>buf[0]</code>  through <code>buf[count-1]
   80.71 +     * </code>contain buffered input data obtained
   80.72 +     * from the underlying  input stream.
   80.73 +     */
   80.74 +    protected int count;
   80.75 +
   80.76 +    /**
   80.77 +     * The current position in the buffer. This is the index of the next
   80.78 +     * character to be read from the <code>buf</code> array.
   80.79 +     * <p>
   80.80 +     * This value is always in the range <code>0</code>
   80.81 +     * through <code>count</code>. If it is less
   80.82 +     * than <code>count</code>, then  <code>buf[pos]</code>
   80.83 +     * is the next byte to be supplied as input;
   80.84 +     * if it is equal to <code>count</code>, then
   80.85 +     * the  next <code>read</code> or <code>skip</code>
   80.86 +     * operation will require more bytes to be
   80.87 +     * read from the contained  input stream.
   80.88 +     *
   80.89 +     * @see     java.io.BufferedInputStream#buf
   80.90 +     */
   80.91 +    protected int pos;
   80.92 +
   80.93 +    /**
   80.94 +     * The value of the <code>pos</code> field at the time the last
   80.95 +     * <code>mark</code> method was called.
   80.96 +     * <p>
   80.97 +     * This value is always
   80.98 +     * in the range <code>-1</code> through <code>pos</code>.
   80.99 +     * If there is no marked position in  the input
  80.100 +     * stream, this field is <code>-1</code>. If
  80.101 +     * there is a marked position in the input
  80.102 +     * stream,  then <code>buf[markpos]</code>
  80.103 +     * is the first byte to be supplied as input
  80.104 +     * after a <code>reset</code> operation. If
  80.105 +     * <code>markpos</code> is not <code>-1</code>,
  80.106 +     * then all bytes from positions <code>buf[markpos]</code>
  80.107 +     * through  <code>buf[pos-1]</code> must remain
  80.108 +     * in the buffer array (though they may be
  80.109 +     * moved to  another place in the buffer array,
  80.110 +     * with suitable adjustments to the values
  80.111 +     * of <code>count</code>,  <code>pos</code>,
  80.112 +     * and <code>markpos</code>); they may not
  80.113 +     * be discarded unless and until the difference
  80.114 +     * between <code>pos</code> and <code>markpos</code>
  80.115 +     * exceeds <code>marklimit</code>.
  80.116 +     *
  80.117 +     * @see     java.io.BufferedInputStream#mark(int)
  80.118 +     * @see     java.io.BufferedInputStream#pos
  80.119 +     */
  80.120 +    protected int markpos = -1;
  80.121 +
  80.122 +    /**
  80.123 +     * The maximum read ahead allowed after a call to the
  80.124 +     * <code>mark</code> method before subsequent calls to the
  80.125 +     * <code>reset</code> method fail.
  80.126 +     * Whenever the difference between <code>pos</code>
  80.127 +     * and <code>markpos</code> exceeds <code>marklimit</code>,
  80.128 +     * then the  mark may be dropped by setting
  80.129 +     * <code>markpos</code> to <code>-1</code>.
  80.130 +     *
  80.131 +     * @see     java.io.BufferedInputStream#mark(int)
  80.132 +     * @see     java.io.BufferedInputStream#reset()
  80.133 +     */
  80.134 +    protected int marklimit;
  80.135 +
  80.136 +    /**
  80.137 +     * Check to make sure that underlying input stream has not been
  80.138 +     * nulled out due to close; if not return it;
  80.139 +     */
  80.140 +    private InputStream getInIfOpen() throws IOException {
  80.141 +        InputStream input = in;
  80.142 +        if (input == null)
  80.143 +            throw new IOException("Stream closed");
  80.144 +        return input;
  80.145 +    }
  80.146 +
  80.147 +    /**
  80.148 +     * Check to make sure that buffer has not been nulled out due to
  80.149 +     * close; if not return it;
  80.150 +     */
  80.151 +    private byte[] getBufIfOpen() throws IOException {
  80.152 +        byte[] buffer = buf;
  80.153 +        if (buffer == null)
  80.154 +            throw new IOException("Stream closed");
  80.155 +        return buffer;
  80.156 +    }
  80.157 +
  80.158 +    /**
  80.159 +     * Creates a <code>BufferedInputStream</code>
  80.160 +     * and saves its  argument, the input stream
  80.161 +     * <code>in</code>, for later use. An internal
  80.162 +     * buffer array is created and  stored in <code>buf</code>.
  80.163 +     *
  80.164 +     * @param   in   the underlying input stream.
  80.165 +     */
  80.166 +    public BufferedInputStream(InputStream in) {
  80.167 +        this(in, defaultBufferSize);
  80.168 +    }
  80.169 +
  80.170 +    /**
  80.171 +     * Creates a <code>BufferedInputStream</code>
  80.172 +     * with the specified buffer size,
  80.173 +     * and saves its  argument, the input stream
  80.174 +     * <code>in</code>, for later use.  An internal
  80.175 +     * buffer array of length  <code>size</code>
  80.176 +     * is created and stored in <code>buf</code>.
  80.177 +     *
  80.178 +     * @param   in     the underlying input stream.
  80.179 +     * @param   size   the buffer size.
  80.180 +     * @exception IllegalArgumentException if size <= 0.
  80.181 +     */
  80.182 +    public BufferedInputStream(InputStream in, int size) {
  80.183 +        super(in);
  80.184 +        if (size <= 0) {
  80.185 +            throw new IllegalArgumentException("Buffer size <= 0");
  80.186 +        }
  80.187 +        buf = new byte[size];
  80.188 +    }
  80.189 +
  80.190 +    /**
  80.191 +     * Fills the buffer with more data, taking into account
  80.192 +     * shuffling and other tricks for dealing with marks.
  80.193 +     * Assumes that it is being called by a synchronized method.
  80.194 +     * This method also assumes that all data has already been read in,
  80.195 +     * hence pos > count.
  80.196 +     */
  80.197 +    private void fill() throws IOException {
  80.198 +        byte[] buffer = getBufIfOpen();
  80.199 +        if (markpos < 0)
  80.200 +            pos = 0;            /* no mark: throw away the buffer */
  80.201 +        else if (pos >= buffer.length)  /* no room left in buffer */
  80.202 +            if (markpos > 0) {  /* can throw away early part of the buffer */
  80.203 +                int sz = pos - markpos;
  80.204 +                System.arraycopy(buffer, markpos, buffer, 0, sz);
  80.205 +                pos = sz;
  80.206 +                markpos = 0;
  80.207 +            } else if (buffer.length >= marklimit) {
  80.208 +                markpos = -1;   /* buffer got too big, invalidate mark */
  80.209 +                pos = 0;        /* drop buffer contents */
  80.210 +            } else {            /* grow buffer */
  80.211 +                int nsz = pos * 2;
  80.212 +                if (nsz > marklimit)
  80.213 +                    nsz = marklimit;
  80.214 +                byte nbuf[] = new byte[nsz];
  80.215 +                System.arraycopy(buffer, 0, nbuf, 0, pos);
  80.216 +                buffer = nbuf;
  80.217 +            }
  80.218 +        count = pos;
  80.219 +        int n = getInIfOpen().read(buffer, pos, buffer.length - pos);
  80.220 +        if (n > 0)
  80.221 +            count = n + pos;
  80.222 +    }
  80.223 +
  80.224 +    /**
  80.225 +     * See
  80.226 +     * the general contract of the <code>read</code>
  80.227 +     * method of <code>InputStream</code>.
  80.228 +     *
  80.229 +     * @return     the next byte of data, or <code>-1</code> if the end of the
  80.230 +     *             stream is reached.
  80.231 +     * @exception  IOException  if this input stream has been closed by
  80.232 +     *                          invoking its {@link #close()} method,
  80.233 +     *                          or an I/O error occurs.
  80.234 +     * @see        java.io.FilterInputStream#in
  80.235 +     */
  80.236 +    public synchronized int read() throws IOException {
  80.237 +        if (pos >= count) {
  80.238 +            fill();
  80.239 +            if (pos >= count)
  80.240 +                return -1;
  80.241 +        }
  80.242 +        return getBufIfOpen()[pos++] & 0xff;
  80.243 +    }
  80.244 +
  80.245 +    /**
  80.246 +     * Read characters into a portion of an array, reading from the underlying
  80.247 +     * stream at most once if necessary.
  80.248 +     */
  80.249 +    private int read1(byte[] b, int off, int len) throws IOException {
  80.250 +        int avail = count - pos;
  80.251 +        if (avail <= 0) {
  80.252 +            /* If the requested length is at least as large as the buffer, and
  80.253 +               if there is no mark/reset activity, do not bother to copy the
  80.254 +               bytes into the local buffer.  In this way buffered streams will
  80.255 +               cascade harmlessly. */
  80.256 +            if (len >= getBufIfOpen().length && markpos < 0) {
  80.257 +                return getInIfOpen().read(b, off, len);
  80.258 +            }
  80.259 +            fill();
  80.260 +            avail = count - pos;
  80.261 +            if (avail <= 0) return -1;
  80.262 +        }
  80.263 +        int cnt = (avail < len) ? avail : len;
  80.264 +        System.arraycopy(getBufIfOpen(), pos, b, off, cnt);
  80.265 +        pos += cnt;
  80.266 +        return cnt;
  80.267 +    }
  80.268 +
  80.269 +    /**
  80.270 +     * Reads bytes from this byte-input stream into the specified byte array,
  80.271 +     * starting at the given offset.
  80.272 +     *
  80.273 +     * <p> This method implements the general contract of the corresponding
  80.274 +     * <code>{@link InputStream#read(byte[], int, int) read}</code> method of
  80.275 +     * the <code>{@link InputStream}</code> class.  As an additional
  80.276 +     * convenience, it attempts to read as many bytes as possible by repeatedly
  80.277 +     * invoking the <code>read</code> method of the underlying stream.  This
  80.278 +     * iterated <code>read</code> continues until one of the following
  80.279 +     * conditions becomes true: <ul>
  80.280 +     *
  80.281 +     *   <li> The specified number of bytes have been read,
  80.282 +     *
  80.283 +     *   <li> The <code>read</code> method of the underlying stream returns
  80.284 +     *   <code>-1</code>, indicating end-of-file, or
  80.285 +     *
  80.286 +     *   <li> The <code>available</code> method of the underlying stream
  80.287 +     *   returns zero, indicating that further input requests would block.
  80.288 +     *
  80.289 +     * </ul> If the first <code>read</code> on the underlying stream returns
  80.290 +     * <code>-1</code> to indicate end-of-file then this method returns
  80.291 +     * <code>-1</code>.  Otherwise this method returns the number of bytes
  80.292 +     * actually read.
  80.293 +     *
  80.294 +     * <p> Subclasses of this class are encouraged, but not required, to
  80.295 +     * attempt to read as many bytes as possible in the same fashion.
  80.296 +     *
  80.297 +     * @param      b     destination buffer.
  80.298 +     * @param      off   offset at which to start storing bytes.
  80.299 +     * @param      len   maximum number of bytes to read.
  80.300 +     * @return     the number of bytes read, or <code>-1</code> if the end of
  80.301 +     *             the stream has been reached.
  80.302 +     * @exception  IOException  if this input stream has been closed by
  80.303 +     *                          invoking its {@link #close()} method,
  80.304 +     *                          or an I/O error occurs.
  80.305 +     */
  80.306 +    public synchronized int read(byte b[], int off, int len)
  80.307 +        throws IOException
  80.308 +    {
  80.309 +        getBufIfOpen(); // Check for closed stream
  80.310 +        if ((off | len | (off + len) | (b.length - (off + len))) < 0) {
  80.311 +            throw new IndexOutOfBoundsException();
  80.312 +        } else if (len == 0) {
  80.313 +            return 0;
  80.314 +        }
  80.315 +
  80.316 +        int n = 0;
  80.317 +        for (;;) {
  80.318 +            int nread = read1(b, off + n, len - n);
  80.319 +            if (nread <= 0)
  80.320 +                return (n == 0) ? nread : n;
  80.321 +            n += nread;
  80.322 +            if (n >= len)
  80.323 +                return n;
  80.324 +            // if not closed but no bytes available, return
  80.325 +            InputStream input = in;
  80.326 +            if (input != null && input.available() <= 0)
  80.327 +                return n;
  80.328 +        }
  80.329 +    }
  80.330 +
  80.331 +    /**
  80.332 +     * See the general contract of the <code>skip</code>
  80.333 +     * method of <code>InputStream</code>.
  80.334 +     *
  80.335 +     * @exception  IOException  if the stream does not support seek,
  80.336 +     *                          or if this input stream has been closed by
  80.337 +     *                          invoking its {@link #close()} method, or an
  80.338 +     *                          I/O error occurs.
  80.339 +     */
  80.340 +    public synchronized long skip(long n) throws IOException {
  80.341 +        getBufIfOpen(); // Check for closed stream
  80.342 +        if (n <= 0) {
  80.343 +            return 0;
  80.344 +        }
  80.345 +        long avail = count - pos;
  80.346 +
  80.347 +        if (avail <= 0) {
  80.348 +            // If no mark position set then don't keep in buffer
  80.349 +            if (markpos <0)
  80.350 +                return getInIfOpen().skip(n);
  80.351 +
  80.352 +            // Fill in buffer to save bytes for reset
  80.353 +            fill();
  80.354 +            avail = count - pos;
  80.355 +            if (avail <= 0)
  80.356 +                return 0;
  80.357 +        }
  80.358 +
  80.359 +        long skipped = (avail < n) ? avail : n;
  80.360 +        pos += skipped;
  80.361 +        return skipped;
  80.362 +    }
  80.363 +
  80.364 +    /**
  80.365 +     * Returns an estimate of the number of bytes that can be read (or
  80.366 +     * skipped over) from this input stream without blocking by the next
  80.367 +     * invocation of a method for this input stream. The next invocation might be
  80.368 +     * the same thread or another thread.  A single read or skip of this
  80.369 +     * many bytes will not block, but may read or skip fewer bytes.
  80.370 +     * <p>
  80.371 +     * This method returns the sum of the number of bytes remaining to be read in
  80.372 +     * the buffer (<code>count&nbsp;- pos</code>) and the result of calling the
  80.373 +     * {@link java.io.FilterInputStream#in in}.available().
  80.374 +     *
  80.375 +     * @return     an estimate of the number of bytes that can be read (or skipped
  80.376 +     *             over) from this input stream without blocking.
  80.377 +     * @exception  IOException  if this input stream has been closed by
  80.378 +     *                          invoking its {@link #close()} method,
  80.379 +     *                          or an I/O error occurs.
  80.380 +     */
  80.381 +    public synchronized int available() throws IOException {
  80.382 +        int n = count - pos;
  80.383 +        int avail = getInIfOpen().available();
  80.384 +        return n > (Integer.MAX_VALUE - avail)
  80.385 +                    ? Integer.MAX_VALUE
  80.386 +                    : n + avail;
  80.387 +    }
  80.388 +
  80.389 +    /**
  80.390 +     * See the general contract of the <code>mark</code>
  80.391 +     * method of <code>InputStream</code>.
  80.392 +     *
  80.393 +     * @param   readlimit   the maximum limit of bytes that can be read before
  80.394 +     *                      the mark position becomes invalid.
  80.395 +     * @see     java.io.BufferedInputStream#reset()
  80.396 +     */
  80.397 +    public synchronized void mark(int readlimit) {
  80.398 +        marklimit = readlimit;
  80.399 +        markpos = pos;
  80.400 +    }
  80.401 +
  80.402 +    /**
  80.403 +     * See the general contract of the <code>reset</code>
  80.404 +     * method of <code>InputStream</code>.
  80.405 +     * <p>
  80.406 +     * If <code>markpos</code> is <code>-1</code>
  80.407 +     * (no mark has been set or the mark has been
  80.408 +     * invalidated), an <code>IOException</code>
  80.409 +     * is thrown. Otherwise, <code>pos</code> is
  80.410 +     * set equal to <code>markpos</code>.
  80.411 +     *
  80.412 +     * @exception  IOException  if this stream has not been marked or,
  80.413 +     *                  if the mark has been invalidated, or the stream
  80.414 +     *                  has been closed by invoking its {@link #close()}
  80.415 +     *                  method, or an I/O error occurs.
  80.416 +     * @see        java.io.BufferedInputStream#mark(int)
  80.417 +     */
  80.418 +    public synchronized void reset() throws IOException {
  80.419 +        getBufIfOpen(); // Cause exception if closed
  80.420 +        if (markpos < 0)
  80.421 +            throw new IOException("Resetting to invalid mark");
  80.422 +        pos = markpos;
  80.423 +    }
  80.424 +
  80.425 +    /**
  80.426 +     * Tests if this input stream supports the <code>mark</code>
  80.427 +     * and <code>reset</code> methods. The <code>markSupported</code>
  80.428 +     * method of <code>BufferedInputStream</code> returns
  80.429 +     * <code>true</code>.
  80.430 +     *
  80.431 +     * @return  a <code>boolean</code> indicating if this stream type supports
  80.432 +     *          the <code>mark</code> and <code>reset</code> methods.
  80.433 +     * @see     java.io.InputStream#mark(int)
  80.434 +     * @see     java.io.InputStream#reset()
  80.435 +     */
  80.436 +    public boolean markSupported() {
  80.437 +        return true;
  80.438 +    }
  80.439 +
  80.440 +    /**
  80.441 +     * Closes this input stream and releases any system resources
  80.442 +     * associated with the stream.
  80.443 +     * Once the stream has been closed, further read(), available(), reset(),
  80.444 +     * or skip() invocations will throw an IOException.
  80.445 +     * Closing a previously closed stream has no effect.
  80.446 +     *
  80.447 +     * @exception  IOException  if an I/O error occurs.
  80.448 +     */
  80.449 +    public void close() throws IOException {
  80.450 +        byte[] buffer;
  80.451 +        while ( (buffer = buf) != null) {
  80.452 +            InputStream input = in;
  80.453 +            buf = null;
  80.454 +            in = null;
  80.455 +            if (input != null)
  80.456 +                input.close();
  80.457 +            return;
  80.458 +            // Else retry in case a new buf was CASed in fill()
  80.459 +        }
  80.460 +    }
  80.461 +}
    81.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    81.2 +++ b/rt/emul/compact/src/main/java/java/io/FileDescriptor.java	Tue Feb 11 13:31:42 2014 +0100
    81.3 @@ -0,0 +1,146 @@
    81.4 +/*
    81.5 + * Copyright (c) 1995, 2012, Oracle and/or its affiliates. All rights reserved.
    81.6 + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
    81.7 + *
    81.8 + *
    81.9 + *
   81.10 + *
   81.11 + *
   81.12 + *
   81.13 + *
   81.14 + *
   81.15 + *
   81.16 + *
   81.17 + *
   81.18 + *
   81.19 + *
   81.20 + *
   81.21 + *
   81.22 + *
   81.23 + *
   81.24 + *
   81.25 + *
   81.26 + *
   81.27 + */
   81.28 +
   81.29 +package java.io;
   81.30 +
   81.31 +import java.util.concurrent.atomic.AtomicInteger;
   81.32 +
   81.33 +/**
   81.34 + * Instances of the file descriptor class serve as an opaque handle
   81.35 + * to the underlying machine-specific structure representing an open
   81.36 + * file, an open socket, or another source or sink of bytes. The
   81.37 + * main practical use for a file descriptor is to create a
   81.38 + * <code>FileInputStream</code> or <code>FileOutputStream</code> to
   81.39 + * contain it.
   81.40 + * <p>
   81.41 + * Applications should not create their own file descriptors.
   81.42 + *
   81.43 + * @author  Pavani Diwanji
   81.44 + * @see     java.io.FileInputStream
   81.45 + * @see     java.io.FileOutputStream
   81.46 + * @since   JDK1.0
   81.47 + */
   81.48 +public final class FileDescriptor {
   81.49 +
   81.50 +    private int fd;
   81.51 +
   81.52 +    /**
   81.53 +     * A counter for tracking the FIS/FOS/RAF instances that
   81.54 +     * use this FileDescriptor. The FIS/FOS.finalize() will not release
   81.55 +     * the FileDescriptor if it is still under user by a stream.
   81.56 +     */
   81.57 +    private AtomicInteger useCount;
   81.58 +
   81.59 +    /**
   81.60 +     * Constructs an (invalid) FileDescriptor
   81.61 +     * object.
   81.62 +     */
   81.63 +    public /**/ FileDescriptor() {
   81.64 +        fd = -1;
   81.65 +        useCount = new AtomicInteger();
   81.66 +    }
   81.67 +
   81.68 +    private /* */ FileDescriptor(int fd) {
   81.69 +        this.fd = fd;
   81.70 +        useCount = new AtomicInteger();
   81.71 +    }
   81.72 +
   81.73 +    /**
   81.74 +     * A handle to the standard input stream. Usually, this file
   81.75 +     * descriptor is not used directly, but rather via the input stream
   81.76 +     * known as <code>System.in</code>.
   81.77 +     *
   81.78 +     * @see     java.lang.System#in
   81.79 +     */
   81.80 +    public static final FileDescriptor in = new FileDescriptor(0);
   81.81 +
   81.82 +    /**
   81.83 +     * A handle to the standard output stream. Usually, this file
   81.84 +     * descriptor is not used directly, but rather via the output stream
   81.85 +     * known as <code>System.out</code>.
   81.86 +     * @see     java.lang.System#out
   81.87 +     */
   81.88 +    public static final FileDescriptor out = new FileDescriptor(1);
   81.89 +
   81.90 +    /**
   81.91 +     * A handle to the standard error stream. Usually, this file
   81.92 +     * descriptor is not used directly, but rather via the output stream
   81.93 +     * known as <code>System.err</code>.
   81.94 +     *
   81.95 +     * @see     java.lang.System#err
   81.96 +     */
   81.97 +    public static final FileDescriptor err = new FileDescriptor(2);
   81.98 +
   81.99 +    /**
  81.100 +     * Tests if this file descriptor object is valid.
  81.101 +     *
  81.102 +     * @return  <code>true</code> if the file descriptor object represents a
  81.103 +     *          valid, open file, socket, or other active I/O connection;
  81.104 +     *          <code>false</code> otherwise.
  81.105 +     */
  81.106 +    public boolean valid() {
  81.107 +        return fd != -1;
  81.108 +    }
  81.109 +
  81.110 +    /**
  81.111 +     * Force all system buffers to synchronize with the underlying
  81.112 +     * device.  This method returns after all modified data and
  81.113 +     * attributes of this FileDescriptor have been written to the
  81.114 +     * relevant device(s).  In particular, if this FileDescriptor
  81.115 +     * refers to a physical storage medium, such as a file in a file
  81.116 +     * system, sync will not return until all in-memory modified copies
  81.117 +     * of buffers associated with this FileDescriptor have been
  81.118 +     * written to the physical medium.
  81.119 +     *
  81.120 +     * sync is meant to be used by code that requires physical
  81.121 +     * storage (such as a file) to be in a known state  For
  81.122 +     * example, a class that provided a simple transaction facility
  81.123 +     * might use sync to ensure that all changes to a file caused
  81.124 +     * by a given transaction were recorded on a storage medium.
  81.125 +     *
  81.126 +     * sync only affects buffers downstream of this FileDescriptor.  If
  81.127 +     * any in-memory buffering is being done by the application (for
  81.128 +     * example, by a BufferedOutputStream object), those buffers must
  81.129 +     * be flushed into the FileDescriptor (for example, by invoking
  81.130 +     * OutputStream.flush) before that data will be affected by sync.
  81.131 +     *
  81.132 +     * @exception SyncFailedException
  81.133 +     *        Thrown when the buffers cannot be flushed,
  81.134 +     *        or because the system cannot guarantee that all the
  81.135 +     *        buffers have been synchronized with physical media.
  81.136 +     * @since     JDK1.1
  81.137 +     */
  81.138 +    public native void sync() throws SyncFailedException;
  81.139 +
  81.140 +    // package private methods used by FIS, FOS and RAF
  81.141 +
  81.142 +    int incrementAndGetUseCount() {
  81.143 +        return useCount.incrementAndGet();
  81.144 +    }
  81.145 +
  81.146 +    int decrementAndGetUseCount() {
  81.147 +        return useCount.decrementAndGet();
  81.148 +    }
  81.149 +}
    82.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    82.2 +++ b/rt/emul/compact/src/main/java/java/io/FileInputStream.java	Tue Feb 11 13:31:42 2014 +0100
    82.3 @@ -0,0 +1,382 @@
    82.4 +/*
    82.5 + * Copyright (c) 1994, 2011, Oracle and/or its affiliates. All rights reserved.
    82.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    82.7 + *
    82.8 + * This code is free software; you can redistribute it and/or modify it
    82.9 + * under the terms of the GNU General Public License version 2 only, as
   82.10 + * published by the Free Software Foundation.  Oracle designates this
   82.11 + * particular file as subject to the "Classpath" exception as provided
   82.12 + * by Oracle in the LICENSE file that accompanied this code.
   82.13 + *
   82.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   82.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   82.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   82.17 + * version 2 for more details (a copy is included in the LICENSE file that
   82.18 + * accompanied this code).
   82.19 + *
   82.20 + * You should have received a copy of the GNU General Public License version
   82.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   82.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   82.23 + *
   82.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   82.25 + * or visit www.oracle.com if you need additional information or have any
   82.26 + * questions.
   82.27 + */
   82.28 +
   82.29 +package java.io;
   82.30 +
   82.31 +
   82.32 +
   82.33 +/**
   82.34 + * A <code>FileInputStream</code> obtains input bytes
   82.35 + * from a file in a file system. What files
   82.36 + * are  available depends on the host environment.
   82.37 + *
   82.38 + * <p><code>FileInputStream</code> is meant for reading streams of raw bytes
   82.39 + * such as image data. For reading streams of characters, consider using
   82.40 + * <code>FileReader</code>.
   82.41 + *
   82.42 + * @author  Arthur van Hoff
   82.43 + * @see     java.io.File
   82.44 + * @see     java.io.FileDescriptor
   82.45 + * @see     java.io.FileOutputStream
   82.46 + * @see     java.nio.file.Files#newInputStream
   82.47 + * @since   JDK1.0
   82.48 + */
   82.49 +public
   82.50 +class FileInputStream extends InputStream
   82.51 +{
   82.52 +    /* File Descriptor - handle to the open file */
   82.53 +    private final FileDescriptor fd;
   82.54 +
   82.55 +//    private FileChannel channel = null;
   82.56 +
   82.57 +    private final Object closeLock = new Object();
   82.58 +    private volatile boolean closed = false;
   82.59 +
   82.60 +    private static final ThreadLocal<Boolean> runningFinalize =
   82.61 +        new ThreadLocal<>();
   82.62 +
   82.63 +    private static boolean isRunningFinalize() {
   82.64 +        Boolean val;
   82.65 +        if ((val = runningFinalize.get()) != null)
   82.66 +            return val.booleanValue();
   82.67 +        return false;
   82.68 +    }
   82.69 +
   82.70 +    /**
   82.71 +     * Creates a <code>FileInputStream</code> by
   82.72 +     * opening a connection to an actual file,
   82.73 +     * the file named by the path name <code>name</code>
   82.74 +     * in the file system.  A new <code>FileDescriptor</code>
   82.75 +     * object is created to represent this file
   82.76 +     * connection.
   82.77 +     * <p>
   82.78 +     * First, if there is a security
   82.79 +     * manager, its <code>checkRead</code> method
   82.80 +     * is called with the <code>name</code> argument
   82.81 +     * as its argument.
   82.82 +     * <p>
   82.83 +     * If the named file does not exist, is a directory rather than a regular
   82.84 +     * file, or for some other reason cannot be opened for reading then a
   82.85 +     * <code>FileNotFoundException</code> is thrown.
   82.86 +     *
   82.87 +     * @param      name   the system-dependent file name.
   82.88 +     * @exception  FileNotFoundException  if the file does not exist,
   82.89 +     *                   is a directory rather than a regular file,
   82.90 +     *                   or for some other reason cannot be opened for
   82.91 +     *                   reading.
   82.92 +     * @exception  SecurityException      if a security manager exists and its
   82.93 +     *               <code>checkRead</code> method denies read access
   82.94 +     *               to the file.
   82.95 +     * @see        java.lang.SecurityManager#checkRead(java.lang.String)
   82.96 +     */
   82.97 +    public FileInputStream(String name) throws FileNotFoundException {
   82.98 +        this(name != null ? new File(name) : null);
   82.99 +    }
  82.100 +
  82.101 +    /**
  82.102 +     * Creates a <code>FileInputStream</code> by
  82.103 +     * opening a connection to an actual file,
  82.104 +     * the file named by the <code>File</code>
  82.105 +     * object <code>file</code> in the file system.
  82.106 +     * A new <code>FileDescriptor</code> object
  82.107 +     * is created to represent this file connection.
  82.108 +     * <p>
  82.109 +     * First, if there is a security manager,
  82.110 +     * its <code>checkRead</code> method  is called
  82.111 +     * with the path represented by the <code>file</code>
  82.112 +     * argument as its argument.
  82.113 +     * <p>
  82.114 +     * If the named file does not exist, is a directory rather than a regular
  82.115 +     * file, or for some other reason cannot be opened for reading then a
  82.116 +     * <code>FileNotFoundException</code> is thrown.
  82.117 +     *
  82.118 +     * @param      file   the file to be opened for reading.
  82.119 +     * @exception  FileNotFoundException  if the file does not exist,
  82.120 +     *                   is a directory rather than a regular file,
  82.121 +     *                   or for some other reason cannot be opened for
  82.122 +     *                   reading.
  82.123 +     * @exception  SecurityException      if a security manager exists and its
  82.124 +     *               <code>checkRead</code> method denies read access to the file.
  82.125 +     * @see        java.io.File#getPath()
  82.126 +     * @see        java.lang.SecurityManager#checkRead(java.lang.String)
  82.127 +     */
  82.128 +    public FileInputStream(File file) throws FileNotFoundException {
  82.129 +        throw new SecurityException();
  82.130 +    }
  82.131 +
  82.132 +    /**
  82.133 +     * Creates a <code>FileInputStream</code> by using the file descriptor
  82.134 +     * <code>fdObj</code>, which represents an existing connection to an
  82.135 +     * actual file in the file system.
  82.136 +     * <p>
  82.137 +     * If there is a security manager, its <code>checkRead</code> method is
  82.138 +     * called with the file descriptor <code>fdObj</code> as its argument to
  82.139 +     * see if it's ok to read the file descriptor. If read access is denied
  82.140 +     * to the file descriptor a <code>SecurityException</code> is thrown.
  82.141 +     * <p>
  82.142 +     * If <code>fdObj</code> is null then a <code>NullPointerException</code>
  82.143 +     * is thrown.
  82.144 +     * <p>
  82.145 +     * This constructor does not throw an exception if <code>fdObj</code>
  82.146 +     * is {@link java.io.FileDescriptor#valid() invalid}.
  82.147 +     * However, if the methods are invoked on the resulting stream to attempt
  82.148 +     * I/O on the stream, an <code>IOException</code> is thrown.
  82.149 +     *
  82.150 +     * @param      fdObj   the file descriptor to be opened for reading.
  82.151 +     * @throws     SecurityException      if a security manager exists and its
  82.152 +     *                 <code>checkRead</code> method denies read access to the
  82.153 +     *                 file descriptor.
  82.154 +     * @see        SecurityManager#checkRead(java.io.FileDescriptor)
  82.155 +     */
  82.156 +    public FileInputStream(FileDescriptor fdObj) {
  82.157 +        throw new SecurityException();
  82.158 +    }
  82.159 +
  82.160 +    /**
  82.161 +     * Opens the specified file for reading.
  82.162 +     * @param name the name of the file
  82.163 +     */
  82.164 +    private native void open(String name) throws FileNotFoundException;
  82.165 +
  82.166 +    /**
  82.167 +     * Reads a byte of data from this input stream. This method blocks
  82.168 +     * if no input is yet available.
  82.169 +     *
  82.170 +     * @return     the next byte of data, or <code>-1</code> if the end of the
  82.171 +     *             file is reached.
  82.172 +     * @exception  IOException  if an I/O error occurs.
  82.173 +     */
  82.174 +    public native int read() throws IOException;
  82.175 +
  82.176 +    /**
  82.177 +     * Reads a subarray as a sequence of bytes.
  82.178 +     * @param b the data to be written
  82.179 +     * @param off the start offset in the data
  82.180 +     * @param len the number of bytes that are written
  82.181 +     * @exception IOException If an I/O error has occurred.
  82.182 +     */
  82.183 +    private native int readBytes(byte b[], int off, int len) throws IOException;
  82.184 +
  82.185 +    /**
  82.186 +     * Reads up to <code>b.length</code> bytes of data from this input
  82.187 +     * stream into an array of bytes. This method blocks until some input
  82.188 +     * is available.
  82.189 +     *
  82.190 +     * @param      b   the buffer into which the data is read.
  82.191 +     * @return     the total number of bytes read into the buffer, or
  82.192 +     *             <code>-1</code> if there is no more data because the end of
  82.193 +     *             the file has been reached.
  82.194 +     * @exception  IOException  if an I/O error occurs.
  82.195 +     */
  82.196 +    public int read(byte b[]) throws IOException {
  82.197 +        return readBytes(b, 0, b.length);
  82.198 +    }
  82.199 +
  82.200 +    /**
  82.201 +     * Reads up to <code>len</code> bytes of data from this input stream
  82.202 +     * into an array of bytes. If <code>len</code> is not zero, the method
  82.203 +     * blocks until some input is available; otherwise, no
  82.204 +     * bytes are read and <code>0</code> is returned.
  82.205 +     *
  82.206 +     * @param      b     the buffer into which the data is read.
  82.207 +     * @param      off   the start offset in the destination array <code>b</code>
  82.208 +     * @param      len   the maximum number of bytes read.
  82.209 +     * @return     the total number of bytes read into the buffer, or
  82.210 +     *             <code>-1</code> if there is no more data because the end of
  82.211 +     *             the file has been reached.
  82.212 +     * @exception  NullPointerException If <code>b</code> is <code>null</code>.
  82.213 +     * @exception  IndexOutOfBoundsException If <code>off</code> is negative,
  82.214 +     * <code>len</code> is negative, or <code>len</code> is greater than
  82.215 +     * <code>b.length - off</code>
  82.216 +     * @exception  IOException  if an I/O error occurs.
  82.217 +     */
  82.218 +    public int read(byte b[], int off, int len) throws IOException {
  82.219 +        return readBytes(b, off, len);
  82.220 +    }
  82.221 +
  82.222 +    /**
  82.223 +     * Skips over and discards <code>n</code> bytes of data from the
  82.224 +     * input stream.
  82.225 +     *
  82.226 +     * <p>The <code>skip</code> method may, for a variety of
  82.227 +     * reasons, end up skipping over some smaller number of bytes,
  82.228 +     * possibly <code>0</code>. If <code>n</code> is negative, an
  82.229 +     * <code>IOException</code> is thrown, even though the <code>skip</code>
  82.230 +     * method of the {@link InputStream} superclass does nothing in this case.
  82.231 +     * The actual number of bytes skipped is returned.
  82.232 +     *
  82.233 +     * <p>This method may skip more bytes than are remaining in the backing
  82.234 +     * file. This produces no exception and the number of bytes skipped
  82.235 +     * may include some number of bytes that were beyond the EOF of the
  82.236 +     * backing file. Attempting to read from the stream after skipping past
  82.237 +     * the end will result in -1 indicating the end of the file.
  82.238 +     *
  82.239 +     * @param      n   the number of bytes to be skipped.
  82.240 +     * @return     the actual number of bytes skipped.
  82.241 +     * @exception  IOException  if n is negative, if the stream does not
  82.242 +     *             support seek, or if an I/O error occurs.
  82.243 +     */
  82.244 +    public native long skip(long n) throws IOException;
  82.245 +
  82.246 +    /**
  82.247 +     * Returns an estimate of the number of remaining bytes that can be read (or
  82.248 +     * skipped over) from this input stream without blocking by the next
  82.249 +     * invocation of a method for this input stream. The next invocation might be
  82.250 +     * the same thread or another thread.  A single read or skip of this
  82.251 +     * many bytes will not block, but may read or skip fewer bytes.
  82.252 +     *
  82.253 +     * <p> In some cases, a non-blocking read (or skip) may appear to be
  82.254 +     * blocked when it is merely slow, for example when reading large
  82.255 +     * files over slow networks.
  82.256 +     *
  82.257 +     * @return     an estimate of the number of remaining bytes that can be read
  82.258 +     *             (or skipped over) from this input stream without blocking.
  82.259 +     * @exception  IOException  if this file input stream has been closed by calling
  82.260 +     *             {@code close} or an I/O error occurs.
  82.261 +     */
  82.262 +    public native int available() throws IOException;
  82.263 +
  82.264 +    /**
  82.265 +     * Closes this file input stream and releases any system resources
  82.266 +     * associated with the stream.
  82.267 +     *
  82.268 +     * <p> If this stream has an associated channel then the channel is closed
  82.269 +     * as well.
  82.270 +     *
  82.271 +     * @exception  IOException  if an I/O error occurs.
  82.272 +     *
  82.273 +     * @revised 1.4
  82.274 +     * @spec JSR-51
  82.275 +     */
  82.276 +    public void close() throws IOException {
  82.277 +        synchronized (closeLock) {
  82.278 +            if (closed) {
  82.279 +                return;
  82.280 +            }
  82.281 +            closed = true;
  82.282 +        }
  82.283 +//        if (channel != null) {
  82.284 +//            /*
  82.285 +//             * Decrement the FD use count associated with the channel
  82.286 +//             * The use count is incremented whenever a new channel
  82.287 +//             * is obtained from this stream.
  82.288 +//             */
  82.289 +//           fd.decrementAndGetUseCount();
  82.290 +//           channel.close();
  82.291 +//        }
  82.292 +
  82.293 +        /*
  82.294 +         * Decrement the FD use count associated with this stream
  82.295 +         */
  82.296 +        int useCount = fd.decrementAndGetUseCount();
  82.297 +
  82.298 +        /*
  82.299 +         * If FileDescriptor is still in use by another stream, the finalizer
  82.300 +         * will not close it.
  82.301 +         */
  82.302 +        if ((useCount <= 0) || !isRunningFinalize()) {
  82.303 +            close0();
  82.304 +        }
  82.305 +    }
  82.306 +
  82.307 +    /**
  82.308 +     * Returns the <code>FileDescriptor</code>
  82.309 +     * object  that represents the connection to
  82.310 +     * the actual file in the file system being
  82.311 +     * used by this <code>FileInputStream</code>.
  82.312 +     *
  82.313 +     * @return     the file descriptor object associated with this stream.
  82.314 +     * @exception  IOException  if an I/O error occurs.
  82.315 +     * @see        java.io.FileDescriptor
  82.316 +     */
  82.317 +    public final FileDescriptor getFD() throws IOException {
  82.318 +        if (fd != null) return fd;
  82.319 +        throw new IOException();
  82.320 +    }
  82.321 +
  82.322 +    /**
  82.323 +     * Returns the unique {@link java.nio.channels.FileChannel FileChannel}
  82.324 +     * object associated with this file input stream.
  82.325 +     *
  82.326 +     * <p> The initial {@link java.nio.channels.FileChannel#position()
  82.327 +     * </code>position<code>} of the returned channel will be equal to the
  82.328 +     * number of bytes read from the file so far.  Reading bytes from this
  82.329 +     * stream will increment the channel's position.  Changing the channel's
  82.330 +     * position, either explicitly or by reading, will change this stream's
  82.331 +     * file position.
  82.332 +     *
  82.333 +     * @return  the file channel associated with this file input stream
  82.334 +     *
  82.335 +     * @since 1.4
  82.336 +     * @spec JSR-51
  82.337 +     */
  82.338 +//    public FileChannel getChannel() {
  82.339 +//        synchronized (this) {
  82.340 +//            if (channel == null) {
  82.341 +//                channel = FileChannelImpl.open(fd, true, false, this);
  82.342 +//
  82.343 +//                /*
  82.344 +//                 * Increment fd's use count. Invoking the channel's close()
  82.345 +//                 * method will result in decrementing the use count set for
  82.346 +//                 * the channel.
  82.347 +//                 */
  82.348 +//                fd.incrementAndGetUseCount();
  82.349 +//            }
  82.350 +//            return channel;
  82.351 +//        }
  82.352 +//    }
  82.353 +
  82.354 +    private static native void initIDs();
  82.355 +
  82.356 +    private native void close0() throws IOException;
  82.357 +
  82.358 +    static {
  82.359 +        initIDs();
  82.360 +    }
  82.361 +
  82.362 +    /**
  82.363 +     * Ensures that the <code>close</code> method of this file input stream is
  82.364 +     * called when there are no more references to it.
  82.365 +     *
  82.366 +     * @exception  IOException  if an I/O error occurs.
  82.367 +     * @see        java.io.FileInputStream#close()
  82.368 +     */
  82.369 +    protected void finalize() throws IOException {
  82.370 +        if ((fd != null) &&  (fd != FileDescriptor.in)) {
  82.371 +
  82.372 +            /*
  82.373 +             * Finalizer should not release the FileDescriptor if another
  82.374 +             * stream is still using it. If the user directly invokes
  82.375 +             * close() then the FileDescriptor is also released.
  82.376 +             */
  82.377 +            runningFinalize.set(Boolean.TRUE);
  82.378 +            try {
  82.379 +                close();
  82.380 +            } finally {
  82.381 +                runningFinalize.set(Boolean.FALSE);
  82.382 +            }
  82.383 +        }
  82.384 +    }
  82.385 +}
    83.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    83.2 +++ b/rt/emul/compact/src/main/java/java/io/FileOutputStream.java	Tue Feb 11 13:31:42 2014 +0100
    83.3 @@ -0,0 +1,422 @@
    83.4 +/*
    83.5 + * Copyright (c) 1994, 2011, Oracle and/or its affiliates. All rights reserved.
    83.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    83.7 + *
    83.8 + * This code is free software; you can redistribute it and/or modify it
    83.9 + * under the terms of the GNU General Public License version 2 only, as
   83.10 + * published by the Free Software Foundation.  Oracle designates this
   83.11 + * particular file as subject to the "Classpath" exception as provided
   83.12 + * by Oracle in the LICENSE file that accompanied this code.
   83.13 + *
   83.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   83.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   83.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   83.17 + * version 2 for more details (a copy is included in the LICENSE file that
   83.18 + * accompanied this code).
   83.19 + *
   83.20 + * You should have received a copy of the GNU General Public License version
   83.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   83.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   83.23 + *
   83.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   83.25 + * or visit www.oracle.com if you need additional information or have any
   83.26 + * questions.
   83.27 + */
   83.28 +
   83.29 +package java.io;
   83.30 +
   83.31 +
   83.32 +
   83.33 +/**
   83.34 + * A file output stream is an output stream for writing data to a
   83.35 + * <code>File</code> or to a <code>FileDescriptor</code>. Whether or not
   83.36 + * a file is available or may be created depends upon the underlying
   83.37 + * platform.  Some platforms, in particular, allow a file to be opened
   83.38 + * for writing by only one <tt>FileOutputStream</tt> (or other
   83.39 + * file-writing object) at a time.  In such situations the constructors in
   83.40 + * this class will fail if the file involved is already open.
   83.41 + *
   83.42 + * <p><code>FileOutputStream</code> is meant for writing streams of raw bytes
   83.43 + * such as image data. For writing streams of characters, consider using
   83.44 + * <code>FileWriter</code>.
   83.45 + *
   83.46 + * @author  Arthur van Hoff
   83.47 + * @see     java.io.File
   83.48 + * @see     java.io.FileDescriptor
   83.49 + * @see     java.io.FileInputStream
   83.50 + * @see     java.nio.file.Files#newOutputStream
   83.51 + * @since   JDK1.0
   83.52 + */
   83.53 +public
   83.54 +class FileOutputStream extends OutputStream
   83.55 +{
   83.56 +    /**
   83.57 +     * The system dependent file descriptor.
   83.58 +     */
   83.59 +    private final FileDescriptor fd;
   83.60 +
   83.61 +    /**
   83.62 +     * True if the file is opened for append.
   83.63 +     */
   83.64 +    private final boolean append;
   83.65 +
   83.66 +    /**
   83.67 +     * The associated channel, initalized lazily.
   83.68 +     */
   83.69 +//    private FileChannel channel;
   83.70 +
   83.71 +    private final Object closeLock = new Object();
   83.72 +    private volatile boolean closed = false;
   83.73 +    private static final ThreadLocal<Boolean> runningFinalize =
   83.74 +        new ThreadLocal<>();
   83.75 +
   83.76 +    private static boolean isRunningFinalize() {
   83.77 +        Boolean val;
   83.78 +        if ((val = runningFinalize.get()) != null)
   83.79 +            return val.booleanValue();
   83.80 +        return false;
   83.81 +    }
   83.82 +
   83.83 +    /**
   83.84 +     * Creates a file output stream to write to the file with the
   83.85 +     * specified name. A new <code>FileDescriptor</code> object is
   83.86 +     * created to represent this file connection.
   83.87 +     * <p>
   83.88 +     * First, if there is a security manager, its <code>checkWrite</code>
   83.89 +     * method is called with <code>name</code> as its argument.
   83.90 +     * <p>
   83.91 +     * If the file exists but is a directory rather than a regular file, does
   83.92 +     * not exist but cannot be created, or cannot be opened for any other
   83.93 +     * reason then a <code>FileNotFoundException</code> is thrown.
   83.94 +     *
   83.95 +     * @param      name   the system-dependent filename
   83.96 +     * @exception  FileNotFoundException  if the file exists but is a directory
   83.97 +     *                   rather than a regular file, does not exist but cannot
   83.98 +     *                   be created, or cannot be opened for any other reason
   83.99 +     * @exception  SecurityException  if a security manager exists and its
  83.100 +     *               <code>checkWrite</code> method denies write access
  83.101 +     *               to the file.
  83.102 +     * @see        java.lang.SecurityManager#checkWrite(java.lang.String)
  83.103 +     */
  83.104 +    public FileOutputStream(String name) throws FileNotFoundException {
  83.105 +        this(name != null ? new File(name) : null, false);
  83.106 +    }
  83.107 +
  83.108 +    /**
  83.109 +     * Creates a file output stream to write to the file with the specified
  83.110 +     * name.  If the second argument is <code>true</code>, then
  83.111 +     * bytes will be written to the end of the file rather than the beginning.
  83.112 +     * A new <code>FileDescriptor</code> object is created to represent this
  83.113 +     * file connection.
  83.114 +     * <p>
  83.115 +     * First, if there is a security manager, its <code>checkWrite</code>
  83.116 +     * method is called with <code>name</code> as its argument.
  83.117 +     * <p>
  83.118 +     * If the file exists but is a directory rather than a regular file, does
  83.119 +     * not exist but cannot be created, or cannot be opened for any other
  83.120 +     * reason then a <code>FileNotFoundException</code> is thrown.
  83.121 +     *
  83.122 +     * @param     name        the system-dependent file name
  83.123 +     * @param     append      if <code>true</code>, then bytes will be written
  83.124 +     *                   to the end of the file rather than the beginning
  83.125 +     * @exception  FileNotFoundException  if the file exists but is a directory
  83.126 +     *                   rather than a regular file, does not exist but cannot
  83.127 +     *                   be created, or cannot be opened for any other reason.
  83.128 +     * @exception  SecurityException  if a security manager exists and its
  83.129 +     *               <code>checkWrite</code> method denies write access
  83.130 +     *               to the file.
  83.131 +     * @see        java.lang.SecurityManager#checkWrite(java.lang.String)
  83.132 +     * @since     JDK1.1
  83.133 +     */
  83.134 +    public FileOutputStream(String name, boolean append)
  83.135 +        throws FileNotFoundException
  83.136 +    {
  83.137 +        this(name != null ? new File(name) : null, append);
  83.138 +    }
  83.139 +
  83.140 +    /**
  83.141 +     * Creates a file output stream to write to the file represented by
  83.142 +     * the specified <code>File</code> object. A new
  83.143 +     * <code>FileDescriptor</code> object is created to represent this
  83.144 +     * file connection.
  83.145 +     * <p>
  83.146 +     * First, if there is a security manager, its <code>checkWrite</code>
  83.147 +     * method is called with the path represented by the <code>file</code>
  83.148 +     * argument as its argument.
  83.149 +     * <p>
  83.150 +     * If the file exists but is a directory rather than a regular file, does
  83.151 +     * not exist but cannot be created, or cannot be opened for any other
  83.152 +     * reason then a <code>FileNotFoundException</code> is thrown.
  83.153 +     *
  83.154 +     * @param      file               the file to be opened for writing.
  83.155 +     * @exception  FileNotFoundException  if the file exists but is a directory
  83.156 +     *                   rather than a regular file, does not exist but cannot
  83.157 +     *                   be created, or cannot be opened for any other reason
  83.158 +     * @exception  SecurityException  if a security manager exists and its
  83.159 +     *               <code>checkWrite</code> method denies write access
  83.160 +     *               to the file.
  83.161 +     * @see        java.io.File#getPath()
  83.162 +     * @see        java.lang.SecurityException
  83.163 +     * @see        java.lang.SecurityManager#checkWrite(java.lang.String)
  83.164 +     */
  83.165 +    public FileOutputStream(File file) throws FileNotFoundException {
  83.166 +        this(file, false);
  83.167 +    }
  83.168 +
  83.169 +    /**
  83.170 +     * Creates a file output stream to write to the file represented by
  83.171 +     * the specified <code>File</code> object. If the second argument is
  83.172 +     * <code>true</code>, then bytes will be written to the end of the file
  83.173 +     * rather than the beginning. A new <code>FileDescriptor</code> object is
  83.174 +     * created to represent this file connection.
  83.175 +     * <p>
  83.176 +     * First, if there is a security manager, its <code>checkWrite</code>
  83.177 +     * method is called with the path represented by the <code>file</code>
  83.178 +     * argument as its argument.
  83.179 +     * <p>
  83.180 +     * If the file exists but is a directory rather than a regular file, does
  83.181 +     * not exist but cannot be created, or cannot be opened for any other
  83.182 +     * reason then a <code>FileNotFoundException</code> is thrown.
  83.183 +     *
  83.184 +     * @param      file               the file to be opened for writing.
  83.185 +     * @param     append      if <code>true</code>, then bytes will be written
  83.186 +     *                   to the end of the file rather than the beginning
  83.187 +     * @exception  FileNotFoundException  if the file exists but is a directory
  83.188 +     *                   rather than a regular file, does not exist but cannot
  83.189 +     *                   be created, or cannot be opened for any other reason
  83.190 +     * @exception  SecurityException  if a security manager exists and its
  83.191 +     *               <code>checkWrite</code> method denies write access
  83.192 +     *               to the file.
  83.193 +     * @see        java.io.File#getPath()
  83.194 +     * @see        java.lang.SecurityException
  83.195 +     * @see        java.lang.SecurityManager#checkWrite(java.lang.String)
  83.196 +     * @since 1.4
  83.197 +     */
  83.198 +    public FileOutputStream(File file, boolean append)
  83.199 +        throws FileNotFoundException
  83.200 +    {
  83.201 +        throw new SecurityException();
  83.202 +    }
  83.203 +
  83.204 +    /**
  83.205 +     * Creates a file output stream to write to the specified file
  83.206 +     * descriptor, which represents an existing connection to an actual
  83.207 +     * file in the file system.
  83.208 +     * <p>
  83.209 +     * First, if there is a security manager, its <code>checkWrite</code>
  83.210 +     * method is called with the file descriptor <code>fdObj</code>
  83.211 +     * argument as its argument.
  83.212 +     * <p>
  83.213 +     * If <code>fdObj</code> is null then a <code>NullPointerException</code>
  83.214 +     * is thrown.
  83.215 +     * <p>
  83.216 +     * This constructor does not throw an exception if <code>fdObj</code>
  83.217 +     * is {@link java.io.FileDescriptor#valid() invalid}.
  83.218 +     * However, if the methods are invoked on the resulting stream to attempt
  83.219 +     * I/O on the stream, an <code>IOException</code> is thrown.
  83.220 +     *
  83.221 +     * @param      fdObj   the file descriptor to be opened for writing
  83.222 +     * @exception  SecurityException  if a security manager exists and its
  83.223 +     *               <code>checkWrite</code> method denies
  83.224 +     *               write access to the file descriptor
  83.225 +     * @see        java.lang.SecurityManager#checkWrite(java.io.FileDescriptor)
  83.226 +     */
  83.227 +    public FileOutputStream(FileDescriptor fdObj) {
  83.228 +        throw new SecurityException();
  83.229 +    }
  83.230 +
  83.231 +    /**
  83.232 +     * Opens a file, with the specified name, for overwriting or appending.
  83.233 +     * @param name name of file to be opened
  83.234 +     * @param append whether the file is to be opened in append mode
  83.235 +     */
  83.236 +    private native void open(String name, boolean append)
  83.237 +        throws FileNotFoundException;
  83.238 +
  83.239 +    /**
  83.240 +     * Writes the specified byte to this file output stream.
  83.241 +     *
  83.242 +     * @param   b   the byte to be written.
  83.243 +     * @param   append   {@code true} if the write operation first
  83.244 +     *     advances the position to the end of file
  83.245 +     */
  83.246 +    private native void write(int b, boolean append) throws IOException;
  83.247 +
  83.248 +    /**
  83.249 +     * Writes the specified byte to this file output stream. Implements
  83.250 +     * the <code>write</code> method of <code>OutputStream</code>.
  83.251 +     *
  83.252 +     * @param      b   the byte to be written.
  83.253 +     * @exception  IOException  if an I/O error occurs.
  83.254 +     */
  83.255 +    public void write(int b) throws IOException {
  83.256 +        write(b, append);
  83.257 +    }
  83.258 +
  83.259 +    /**
  83.260 +     * Writes a sub array as a sequence of bytes.
  83.261 +     * @param b the data to be written
  83.262 +     * @param off the start offset in the data
  83.263 +     * @param len the number of bytes that are written
  83.264 +     * @param append {@code true} to first advance the position to the
  83.265 +     *     end of file
  83.266 +     * @exception IOException If an I/O error has occurred.
  83.267 +     */
  83.268 +    private native void writeBytes(byte b[], int off, int len, boolean append)
  83.269 +        throws IOException;
  83.270 +
  83.271 +    /**
  83.272 +     * Writes <code>b.length</code> bytes from the specified byte array
  83.273 +     * to this file output stream.
  83.274 +     *
  83.275 +     * @param      b   the data.
  83.276 +     * @exception  IOException  if an I/O error occurs.
  83.277 +     */
  83.278 +    public void write(byte b[]) throws IOException {
  83.279 +        writeBytes(b, 0, b.length, append);
  83.280 +    }
  83.281 +
  83.282 +    /**
  83.283 +     * Writes <code>len</code> bytes from the specified byte array
  83.284 +     * starting at offset <code>off</code> to this file output stream.
  83.285 +     *
  83.286 +     * @param      b     the data.
  83.287 +     * @param      off   the start offset in the data.
  83.288 +     * @param      len   the number of bytes to write.
  83.289 +     * @exception  IOException  if an I/O error occurs.
  83.290 +     */
  83.291 +    public void write(byte b[], int off, int len) throws IOException {
  83.292 +        writeBytes(b, off, len, append);
  83.293 +    }
  83.294 +
  83.295 +    /**
  83.296 +     * Closes this file output stream and releases any system resources
  83.297 +     * associated with this stream. This file output stream may no longer
  83.298 +     * be used for writing bytes.
  83.299 +     *
  83.300 +     * <p> If this stream has an associated channel then the channel is closed
  83.301 +     * as well.
  83.302 +     *
  83.303 +     * @exception  IOException  if an I/O error occurs.
  83.304 +     *
  83.305 +     * @revised 1.4
  83.306 +     * @spec JSR-51
  83.307 +     */
  83.308 +    public void close() throws IOException {
  83.309 +        synchronized (closeLock) {
  83.310 +            if (closed) {
  83.311 +                return;
  83.312 +            }
  83.313 +            closed = true;
  83.314 +        }
  83.315 +//
  83.316 +//        if (channel != null) {
  83.317 +//            /*
  83.318 +//             * Decrement FD use count associated with the channel
  83.319 +//             * The use count is incremented whenever a new channel
  83.320 +//             * is obtained from this stream.
  83.321 +//             */
  83.322 +//            fd.decrementAndGetUseCount();
  83.323 +//            channel.close();
  83.324 +//        }
  83.325 +
  83.326 +        /*
  83.327 +         * Decrement FD use count associated with this stream
  83.328 +         */
  83.329 +        int useCount = fd.decrementAndGetUseCount();
  83.330 +
  83.331 +        /*
  83.332 +         * If FileDescriptor is still in use by another stream, the finalizer
  83.333 +         * will not close it.
  83.334 +         */
  83.335 +        if ((useCount <= 0) || !isRunningFinalize()) {
  83.336 +            close0();
  83.337 +        }
  83.338 +    }
  83.339 +
  83.340 +    /**
  83.341 +     * Returns the file descriptor associated with this stream.
  83.342 +     *
  83.343 +     * @return  the <code>FileDescriptor</code> object that represents
  83.344 +     *          the connection to the file in the file system being used
  83.345 +     *          by this <code>FileOutputStream</code> object.
  83.346 +     *
  83.347 +     * @exception  IOException  if an I/O error occurs.
  83.348 +     * @see        java.io.FileDescriptor
  83.349 +     */
  83.350 +     public final FileDescriptor getFD()  throws IOException {
  83.351 +        if (fd != null) return fd;
  83.352 +        throw new IOException();
  83.353 +     }
  83.354 +
  83.355 +    /**
  83.356 +     * Returns the unique {@link java.nio.channels.FileChannel FileChannel}
  83.357 +     * object associated with this file output stream. </p>
  83.358 +     *
  83.359 +     * <p> The initial {@link java.nio.channels.FileChannel#position()
  83.360 +     * </code>position<code>} of the returned channel will be equal to the
  83.361 +     * number of bytes written to the file so far unless this stream is in
  83.362 +     * append mode, in which case it will be equal to the size of the file.
  83.363 +     * Writing bytes to this stream will increment the channel's position
  83.364 +     * accordingly.  Changing the channel's position, either explicitly or by
  83.365 +     * writing, will change this stream's file position.
  83.366 +     *
  83.367 +     * @return  the file channel associated with this file output stream
  83.368 +     *
  83.369 +     * @since 1.4
  83.370 +     * @spec JSR-51
  83.371 +     */
  83.372 +//    public FileChannel getChannel() {
  83.373 +//        synchronized (this) {
  83.374 +//            if (channel == null) {
  83.375 +//                channel = FileChannelImpl.open(fd, false, true, append, this);
  83.376 +//
  83.377 +//                /*
  83.378 +//                 * Increment fd's use count. Invoking the channel's close()
  83.379 +//                 * method will result in decrementing the use count set for
  83.380 +//                 * the channel.
  83.381 +//                 */
  83.382 +//                fd.incrementAndGetUseCount();
  83.383 +//            }
  83.384 +//            return channel;
  83.385 +//        }
  83.386 +//    }
  83.387 +
  83.388 +    /**
  83.389 +     * Cleans up the connection to the file, and ensures that the
  83.390 +     * <code>close</code> method of this file output stream is
  83.391 +     * called when there are no more references to this stream.
  83.392 +     *
  83.393 +     * @exception  IOException  if an I/O error occurs.
  83.394 +     * @see        java.io.FileInputStream#close()
  83.395 +     */
  83.396 +    protected void finalize() throws IOException {
  83.397 +        if (fd != null) {
  83.398 +            if (fd == FileDescriptor.out || fd == FileDescriptor.err) {
  83.399 +                flush();
  83.400 +            } else {
  83.401 +
  83.402 +                /*
  83.403 +                 * Finalizer should not release the FileDescriptor if another
  83.404 +                 * stream is still using it. If the user directly invokes
  83.405 +                 * close() then the FileDescriptor is also released.
  83.406 +                 */
  83.407 +                runningFinalize.set(Boolean.TRUE);
  83.408 +                try {
  83.409 +                    close();
  83.410 +                } finally {
  83.411 +                    runningFinalize.set(Boolean.FALSE);
  83.412 +                }
  83.413 +            }
  83.414 +        }
  83.415 +    }
  83.416 +
  83.417 +    private native void close0() throws IOException;
  83.418 +
  83.419 +    private static native void initIDs();
  83.420 +
  83.421 +    static {
  83.422 +        initIDs();
  83.423 +    }
  83.424 +
  83.425 +}
    84.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    84.2 +++ b/rt/emul/compact/src/main/java/java/io/FileReader.java	Tue Feb 11 13:31:42 2014 +0100
    84.3 @@ -0,0 +1,85 @@
    84.4 +/*
    84.5 + * Copyright (c) 1996, 2001, Oracle and/or its affiliates. All rights reserved.
    84.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    84.7 + *
    84.8 + * This code is free software; you can redistribute it and/or modify it
    84.9 + * under the terms of the GNU General Public License version 2 only, as
   84.10 + * published by the Free Software Foundation.  Oracle designates this
   84.11 + * particular file as subject to the "Classpath" exception as provided
   84.12 + * by Oracle in the LICENSE file that accompanied this code.
   84.13 + *
   84.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   84.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   84.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   84.17 + * version 2 for more details (a copy is included in the LICENSE file that
   84.18 + * accompanied this code).
   84.19 + *
   84.20 + * You should have received a copy of the GNU General Public License version
   84.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   84.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   84.23 + *
   84.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   84.25 + * or visit www.oracle.com if you need additional information or have any
   84.26 + * questions.
   84.27 + */
   84.28 +
   84.29 +package java.io;
   84.30 +
   84.31 +
   84.32 +/**
   84.33 + * Convenience class for reading character files.  The constructors of this
   84.34 + * class assume that the default character encoding and the default byte-buffer
   84.35 + * size are appropriate.  To specify these values yourself, construct an
   84.36 + * InputStreamReader on a FileInputStream.
   84.37 + *
   84.38 + * <p><code>FileReader</code> is meant for reading streams of characters.
   84.39 + * For reading streams of raw bytes, consider using a
   84.40 + * <code>FileInputStream</code>.
   84.41 + *
   84.42 + * @see InputStreamReader
   84.43 + * @see FileInputStream
   84.44 + *
   84.45 + * @author      Mark Reinhold
   84.46 + * @since       JDK1.1
   84.47 + */
   84.48 +public class FileReader extends InputStreamReader {
   84.49 +
   84.50 +   /**
   84.51 +    * Creates a new <tt>FileReader</tt>, given the name of the
   84.52 +    * file to read from.
   84.53 +    *
   84.54 +    * @param fileName the name of the file to read from
   84.55 +    * @exception  FileNotFoundException  if the named file does not exist,
   84.56 +    *                   is a directory rather than a regular file,
   84.57 +    *                   or for some other reason cannot be opened for
   84.58 +    *                   reading.
   84.59 +    */
   84.60 +    public FileReader(String fileName) throws FileNotFoundException {
   84.61 +        super(new FileInputStream(fileName));
   84.62 +    }
   84.63 +
   84.64 +   /**
   84.65 +    * Creates a new <tt>FileReader</tt>, given the <tt>File</tt>
   84.66 +    * to read from.
   84.67 +    *
   84.68 +    * @param file the <tt>File</tt> to read from
   84.69 +    * @exception  FileNotFoundException  if the file does not exist,
   84.70 +    *                   is a directory rather than a regular file,
   84.71 +    *                   or for some other reason cannot be opened for
   84.72 +    *                   reading.
   84.73 +    */
   84.74 +    public FileReader(File file) throws FileNotFoundException {
   84.75 +        super(new FileInputStream(file));
   84.76 +    }
   84.77 +
   84.78 +   /**
   84.79 +    * Creates a new <tt>FileReader</tt>, given the
   84.80 +    * <tt>FileDescriptor</tt> to read from.
   84.81 +    *
   84.82 +    * @param fd the FileDescriptor to read from
   84.83 +    */
   84.84 +    public FileReader(FileDescriptor fd) {
   84.85 +        super(new FileInputStream(fd));
   84.86 +    }
   84.87 +
   84.88 +}
    85.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    85.2 +++ b/rt/emul/compact/src/main/java/java/io/FileWriter.java	Tue Feb 11 13:31:42 2014 +0100
    85.3 @@ -0,0 +1,119 @@
    85.4 +/*
    85.5 + * Copyright (c) 1996, 2001, Oracle and/or its affiliates. All rights reserved.
    85.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    85.7 + *
    85.8 + * This code is free software; you can redistribute it and/or modify it
    85.9 + * under the terms of the GNU General Public License version 2 only, as
   85.10 + * published by the Free Software Foundation.  Oracle designates this
   85.11 + * particular file as subject to the "Classpath" exception as provided
   85.12 + * by Oracle in the LICENSE file that accompanied this code.
   85.13 + *
   85.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   85.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   85.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   85.17 + * version 2 for more details (a copy is included in the LICENSE file that
   85.18 + * accompanied this code).
   85.19 + *
   85.20 + * You should have received a copy of the GNU General Public License version
   85.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   85.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   85.23 + *
   85.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   85.25 + * or visit www.oracle.com if you need additional information or have any
   85.26 + * questions.
   85.27 + */
   85.28 +
   85.29 +package java.io;
   85.30 +
   85.31 +
   85.32 +/**
   85.33 + * Convenience class for writing character files.  The constructors of this
   85.34 + * class assume that the default character encoding and the default byte-buffer
   85.35 + * size are acceptable.  To specify these values yourself, construct an
   85.36 + * OutputStreamWriter on a FileOutputStream.
   85.37 + *
   85.38 + * <p>Whether or not a file is available or may be created depends upon the
   85.39 + * underlying platform.  Some platforms, in particular, allow a file to be
   85.40 + * opened for writing by only one <tt>FileWriter</tt> (or other file-writing
   85.41 + * object) at a time.  In such situations the constructors in this class
   85.42 + * will fail if the file involved is already open.
   85.43 + *
   85.44 + * <p><code>FileWriter</code> is meant for writing streams of characters.
   85.45 + * For writing streams of raw bytes, consider using a
   85.46 + * <code>FileOutputStream</code>.
   85.47 + *
   85.48 + * @see OutputStreamWriter
   85.49 + * @see FileOutputStream
   85.50 + *
   85.51 + * @author      Mark Reinhold
   85.52 + * @since       JDK1.1
   85.53 + */
   85.54 +
   85.55 +public class FileWriter extends OutputStreamWriter {
   85.56 +
   85.57 +    /**
   85.58 +     * Constructs a FileWriter object given a file name.
   85.59 +     *
   85.60 +     * @param fileName  String The system-dependent filename.
   85.61 +     * @throws IOException  if the named file exists but is a directory rather
   85.62 +     *                  than a regular file, does not exist but cannot be
   85.63 +     *                  created, or cannot be opened for any other reason
   85.64 +     */
   85.65 +    public FileWriter(String fileName) throws IOException {
   85.66 +        super(new FileOutputStream(fileName));
   85.67 +    }
   85.68 +
   85.69 +    /**
   85.70 +     * Constructs a FileWriter object given a file name with a boolean
   85.71 +     * indicating whether or not to append the data written.
   85.72 +     *
   85.73 +     * @param fileName  String The system-dependent filename.
   85.74 +     * @param append    boolean if <code>true</code>, then data will be written
   85.75 +     *                  to the end of the file rather than the beginning.
   85.76 +     * @throws IOException  if the named file exists but is a directory rather
   85.77 +     *                  than a regular file, does not exist but cannot be
   85.78 +     *                  created, or cannot be opened for any other reason
   85.79 +     */
   85.80 +    public FileWriter(String fileName, boolean append) throws IOException {
   85.81 +        super(new FileOutputStream(fileName, append));
   85.82 +    }
   85.83 +
   85.84 +    /**
   85.85 +     * Constructs a FileWriter object given a File object.
   85.86 +     *
   85.87 +     * @param file  a File object to write to.
   85.88 +     * @throws IOException  if the file exists but is a directory rather than
   85.89 +     *                  a regular file, does not exist but cannot be created,
   85.90 +     *                  or cannot be opened for any other reason
   85.91 +     */
   85.92 +    public FileWriter(File file) throws IOException {
   85.93 +        super(new FileOutputStream(file));
   85.94 +    }
   85.95 +
   85.96 +    /**
   85.97 +     * Constructs a FileWriter object given a File object. If the second
   85.98 +     * argument is <code>true</code>, then bytes will be written to the end
   85.99 +     * of the file rather than the beginning.
  85.100 +     *
  85.101 +     * @param file  a File object to write to
  85.102 +     * @param     append    if <code>true</code>, then bytes will be written
  85.103 +     *                      to the end of the file rather than the beginning
  85.104 +     * @throws IOException  if the file exists but is a directory rather than
  85.105 +     *                  a regular file, does not exist but cannot be created,
  85.106 +     *                  or cannot be opened for any other reason
  85.107 +     * @since 1.4
  85.108 +     */
  85.109 +    public FileWriter(File file, boolean append) throws IOException {
  85.110 +        super(new FileOutputStream(file, append));
  85.111 +    }
  85.112 +
  85.113 +    /**
  85.114 +     * Constructs a FileWriter object associated with a file descriptor.
  85.115 +     *
  85.116 +     * @param fd  FileDescriptor object to write to.
  85.117 +     */
  85.118 +    public FileWriter(FileDescriptor fd) {
  85.119 +        super(new FileOutputStream(fd));
  85.120 +    }
  85.121 +
  85.122 +}
    86.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    86.2 +++ b/rt/emul/compact/src/main/java/java/io/FilterReader.java	Tue Feb 11 13:31:42 2014 +0100
    86.3 @@ -0,0 +1,124 @@
    86.4 +/*
    86.5 + * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
    86.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    86.7 + *
    86.8 + * This code is free software; you can redistribute it and/or modify it
    86.9 + * under the terms of the GNU General Public License version 2 only, as
   86.10 + * published by the Free Software Foundation.  Oracle designates this
   86.11 + * particular file as subject to the "Classpath" exception as provided
   86.12 + * by Oracle in the LICENSE file that accompanied this code.
   86.13 + *
   86.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   86.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   86.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   86.17 + * version 2 for more details (a copy is included in the LICENSE file that
   86.18 + * accompanied this code).
   86.19 + *
   86.20 + * You should have received a copy of the GNU General Public License version
   86.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   86.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   86.23 + *
   86.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   86.25 + * or visit www.oracle.com if you need additional information or have any
   86.26 + * questions.
   86.27 + */
   86.28 +
   86.29 +package java.io;
   86.30 +
   86.31 +
   86.32 +/**
   86.33 + * Abstract class for reading filtered character streams.
   86.34 + * The abstract class <code>FilterReader</code> itself
   86.35 + * provides default methods that pass all requests to
   86.36 + * the contained stream. Subclasses of <code>FilterReader</code>
   86.37 + * should override some of these methods and may also provide
   86.38 + * additional methods and fields.
   86.39 + *
   86.40 + * @author      Mark Reinhold
   86.41 + * @since       JDK1.1
   86.42 + */
   86.43 +
   86.44 +public abstract class FilterReader extends Reader {
   86.45 +
   86.46 +    /**
   86.47 +     * The underlying character-input stream.
   86.48 +     */
   86.49 +    protected Reader in;
   86.50 +
   86.51 +    /**
   86.52 +     * Creates a new filtered reader.
   86.53 +     *
   86.54 +     * @param in  a Reader object providing the underlying stream.
   86.55 +     * @throws NullPointerException if <code>in</code> is <code>null</code>
   86.56 +     */
   86.57 +    protected FilterReader(Reader in) {
   86.58 +        super(in);
   86.59 +        this.in = in;
   86.60 +    }
   86.61 +
   86.62 +    /**
   86.63 +     * Reads a single character.
   86.64 +     *
   86.65 +     * @exception  IOException  If an I/O error occurs
   86.66 +     */
   86.67 +    public int read() throws IOException {
   86.68 +        return in.read();
   86.69 +    }
   86.70 +
   86.71 +    /**
   86.72 +     * Reads characters into a portion of an array.
   86.73 +     *
   86.74 +     * @exception  IOException  If an I/O error occurs
   86.75 +     */
   86.76 +    public int read(char cbuf[], int off, int len) throws IOException {
   86.77 +        return in.read(cbuf, off, len);
   86.78 +    }
   86.79 +
   86.80 +    /**
   86.81 +     * Skips characters.
   86.82 +     *
   86.83 +     * @exception  IOException  If an I/O error occurs
   86.84 +     */
   86.85 +    public long skip(long n) throws IOException {
   86.86 +        return in.skip(n);
   86.87 +    }
   86.88 +
   86.89 +    /**
   86.90 +     * Tells whether this stream is ready to be read.
   86.91 +     *
   86.92 +     * @exception  IOException  If an I/O error occurs
   86.93 +     */
   86.94 +    public boolean ready() throws IOException {
   86.95 +        return in.ready();
   86.96 +    }
   86.97 +
   86.98 +    /**
   86.99 +     * Tells whether this stream supports the mark() operation.
  86.100 +     */
  86.101 +    public boolean markSupported() {
  86.102 +        return in.markSupported();
  86.103 +    }
  86.104 +
  86.105 +    /**
  86.106 +     * Marks the present position in the stream.
  86.107 +     *
  86.108 +     * @exception  IOException  If an I/O error occurs
  86.109 +     */
  86.110 +    public void mark(int readAheadLimit) throws IOException {
  86.111 +        in.mark(readAheadLimit);
  86.112 +    }
  86.113 +
  86.114 +    /**
  86.115 +     * Resets the stream.
  86.116 +     *
  86.117 +     * @exception  IOException  If an I/O error occurs
  86.118 +     */
  86.119 +    public void reset() throws IOException {
  86.120 +        in.reset();
  86.121 +    }
  86.122 +
  86.123 +    public void close() throws IOException {
  86.124 +        in.close();
  86.125 +    }
  86.126 +
  86.127 +}
    87.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    87.2 +++ b/rt/emul/compact/src/main/java/java/io/FilterWriter.java	Tue Feb 11 13:31:42 2014 +0100
    87.3 @@ -0,0 +1,107 @@
    87.4 +/*
    87.5 + * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
    87.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    87.7 + *
    87.8 + * This code is free software; you can redistribute it and/or modify it
    87.9 + * under the terms of the GNU General Public License version 2 only, as
   87.10 + * published by the Free Software Foundation.  Oracle designates this
   87.11 + * particular file as subject to the "Classpath" exception as provided
   87.12 + * by Oracle in the LICENSE file that accompanied this code.
   87.13 + *
   87.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   87.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   87.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   87.17 + * version 2 for more details (a copy is included in the LICENSE file that
   87.18 + * accompanied this code).
   87.19 + *
   87.20 + * You should have received a copy of the GNU General Public License version
   87.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   87.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   87.23 + *
   87.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   87.25 + * or visit www.oracle.com if you need additional information or have any
   87.26 + * questions.
   87.27 + */
   87.28 +
   87.29 +package java.io;
   87.30 +
   87.31 +
   87.32 +/**
   87.33 + * Abstract class for writing filtered character streams.
   87.34 + * The abstract class <code>FilterWriter</code> itself
   87.35 + * provides default methods that pass all requests to the
   87.36 + * contained stream. Subclasses of <code>FilterWriter</code>
   87.37 + * should override some of these methods and may also
   87.38 + * provide additional methods and fields.
   87.39 + *
   87.40 + * @author      Mark Reinhold
   87.41 + * @since       JDK1.1
   87.42 + */
   87.43 +
   87.44 +public abstract class FilterWriter extends Writer {
   87.45 +
   87.46 +    /**
   87.47 +     * The underlying character-output stream.
   87.48 +     */
   87.49 +    protected Writer out;
   87.50 +
   87.51 +    /**
   87.52 +     * Create a new filtered writer.
   87.53 +     *
   87.54 +     * @param out  a Writer object to provide the underlying stream.
   87.55 +     * @throws NullPointerException if <code>out</code> is <code>null</code>
   87.56 +     */
   87.57 +    protected FilterWriter(Writer out) {
   87.58 +        super(out);
   87.59 +        this.out = out;
   87.60 +    }
   87.61 +
   87.62 +    /**
   87.63 +     * Writes a single character.
   87.64 +     *
   87.65 +     * @exception  IOException  If an I/O error occurs
   87.66 +     */
   87.67 +    public void write(int c) throws IOException {
   87.68 +        out.write(c);
   87.69 +    }
   87.70 +
   87.71 +    /**
   87.72 +     * Writes a portion of an array of characters.
   87.73 +     *
   87.74 +     * @param  cbuf  Buffer of characters to be written
   87.75 +     * @param  off   Offset from which to start reading characters
   87.76 +     * @param  len   Number of characters to be written
   87.77 +     *
   87.78 +     * @exception  IOException  If an I/O error occurs
   87.79 +     */
   87.80 +    public void write(char cbuf[], int off, int len) throws IOException {
   87.81 +        out.write(cbuf, off, len);
   87.82 +    }
   87.83 +
   87.84 +    /**
   87.85 +     * Writes a portion of a string.
   87.86 +     *
   87.87 +     * @param  str  String to be written
   87.88 +     * @param  off  Offset from which to start reading characters
   87.89 +     * @param  len  Number of characters to be written
   87.90 +     *
   87.91 +     * @exception  IOException  If an I/O error occurs
   87.92 +     */
   87.93 +    public void write(String str, int off, int len) throws IOException {
   87.94 +        out.write(str, off, len);
   87.95 +    }
   87.96 +
   87.97 +    /**
   87.98 +     * Flushes the stream.
   87.99 +     *
  87.100 +     * @exception  IOException  If an I/O error occurs
  87.101 +     */
  87.102 +    public void flush() throws IOException {
  87.103 +        out.flush();
  87.104 +    }
  87.105 +
  87.106 +    public void close() throws IOException {
  87.107 +        out.close();
  87.108 +    }
  87.109 +
  87.110 +}
    88.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    88.2 +++ b/rt/emul/compact/src/main/java/java/io/LineNumberInputStream.java	Tue Feb 11 13:31:42 2014 +0100
    88.3 @@ -0,0 +1,292 @@
    88.4 +/*
    88.5 + * Copyright (c) 1995, 2004, Oracle and/or its affiliates. All rights reserved.
    88.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    88.7 + *
    88.8 + * This code is free software; you can redistribute it and/or modify it
    88.9 + * under the terms of the GNU General Public License version 2 only, as
   88.10 + * published by the Free Software Foundation.  Oracle designates this
   88.11 + * particular file as subject to the "Classpath" exception as provided
   88.12 + * by Oracle in the LICENSE file that accompanied this code.
   88.13 + *
   88.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   88.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   88.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   88.17 + * version 2 for more details (a copy is included in the LICENSE file that
   88.18 + * accompanied this code).
   88.19 + *
   88.20 + * You should have received a copy of the GNU General Public License version
   88.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   88.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   88.23 + *
   88.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   88.25 + * or visit www.oracle.com if you need additional information or have any
   88.26 + * questions.
   88.27 + */
   88.28 +
   88.29 +package java.io;
   88.30 +
   88.31 +/**
   88.32 + * This class is an input stream filter that provides the added
   88.33 + * functionality of keeping track of the current line number.
   88.34 + * <p>
   88.35 + * A line is a sequence of bytes ending with a carriage return
   88.36 + * character (<code>'&#92;r'</code>), a newline character
   88.37 + * (<code>'&#92;n'</code>), or a carriage return character followed
   88.38 + * immediately by a linefeed character. In all three cases, the line
   88.39 + * terminating character(s) are returned as a single newline character.
   88.40 + * <p>
   88.41 + * The line number begins at <code>0</code>, and is incremented by
   88.42 + * <code>1</code> when a <code>read</code> returns a newline character.
   88.43 + *
   88.44 + * @author     Arthur van Hoff
   88.45 + * @see        java.io.LineNumberReader
   88.46 + * @since      JDK1.0
   88.47 + * @deprecated This class incorrectly assumes that bytes adequately represent
   88.48 + *             characters.  As of JDK&nbsp;1.1, the preferred way to operate on
   88.49 + *             character streams is via the new character-stream classes, which
   88.50 + *             include a class for counting line numbers.
   88.51 + */
   88.52 +@Deprecated
   88.53 +public
   88.54 +class LineNumberInputStream extends FilterInputStream {
   88.55 +    int pushBack = -1;
   88.56 +    int lineNumber;
   88.57 +    int markLineNumber;
   88.58 +    int markPushBack = -1;
   88.59 +
   88.60 +    /**
   88.61 +     * Constructs a newline number input stream that reads its input
   88.62 +     * from the specified input stream.
   88.63 +     *
   88.64 +     * @param      in   the underlying input stream.
   88.65 +     */
   88.66 +    public LineNumberInputStream(InputStream in) {
   88.67 +        super(in);
   88.68 +    }
   88.69 +
   88.70 +    /**
   88.71 +     * Reads the next byte of data from this input stream. The value
   88.72 +     * byte is returned as an <code>int</code> in the range
   88.73 +     * <code>0</code> to <code>255</code>. If no byte is available
   88.74 +     * because the end of the stream has been reached, the value
   88.75 +     * <code>-1</code> is returned. This method blocks until input data
   88.76 +     * is available, the end of the stream is detected, or an exception
   88.77 +     * is thrown.
   88.78 +     * <p>
   88.79 +     * The <code>read</code> method of
   88.80 +     * <code>LineNumberInputStream</code> calls the <code>read</code>
   88.81 +     * method of the underlying input stream. It checks for carriage
   88.82 +     * returns and newline characters in the input, and modifies the
   88.83 +     * current line number as appropriate. A carriage-return character or
   88.84 +     * a carriage return followed by a newline character are both
   88.85 +     * converted into a single newline character.
   88.86 +     *
   88.87 +     * @return     the next byte of data, or <code>-1</code> if the end of this
   88.88 +     *             stream is reached.
   88.89 +     * @exception  IOException  if an I/O error occurs.
   88.90 +     * @see        java.io.FilterInputStream#in
   88.91 +     * @see        java.io.LineNumberInputStream#getLineNumber()
   88.92 +     */
   88.93 +    public int read() throws IOException {
   88.94 +        int c = pushBack;
   88.95 +
   88.96 +        if (c != -1) {
   88.97 +            pushBack = -1;
   88.98 +        } else {
   88.99 +            c = in.read();
  88.100 +        }
  88.101 +
  88.102 +        switch (c) {
  88.103 +          case '\r':
  88.104 +            pushBack = in.read();
  88.105 +            if (pushBack == '\n') {
  88.106 +                pushBack = -1;
  88.107 +            }
  88.108 +          case '\n':
  88.109 +            lineNumber++;
  88.110 +            return '\n';
  88.111 +        }
  88.112 +        return c;
  88.113 +    }
  88.114 +
  88.115 +    /**
  88.116 +     * Reads up to <code>len</code> bytes of data from this input stream
  88.117 +     * into an array of bytes. This method blocks until some input is available.
  88.118 +     * <p>
  88.119 +     * The <code>read</code> method of
  88.120 +     * <code>LineNumberInputStream</code> repeatedly calls the
  88.121 +     * <code>read</code> method of zero arguments to fill in the byte array.
  88.122 +     *
  88.123 +     * @param      b     the buffer into which the data is read.
  88.124 +     * @param      off   the start offset of the data.
  88.125 +     * @param      len   the maximum number of bytes read.
  88.126 +     * @return     the total number of bytes read into the buffer, or
  88.127 +     *             <code>-1</code> if there is no more data because the end of
  88.128 +     *             this stream has been reached.
  88.129 +     * @exception  IOException  if an I/O error occurs.
  88.130 +     * @see        java.io.LineNumberInputStream#read()
  88.131 +     */
  88.132 +    public int read(byte b[], int off, int len) throws IOException {
  88.133 +        if (b == null) {
  88.134 +            throw new NullPointerException();
  88.135 +        } else if ((off < 0) || (off > b.length) || (len < 0) ||
  88.136 +                   ((off + len) > b.length) || ((off + len) < 0)) {
  88.137 +            throw new IndexOutOfBoundsException();
  88.138 +        } else if (len == 0) {
  88.139 +            return 0;
  88.140 +        }
  88.141 +
  88.142 +        int c = read();
  88.143 +        if (c == -1) {
  88.144 +            return -1;
  88.145 +        }
  88.146 +        b[off] = (byte)c;
  88.147 +
  88.148 +        int i = 1;
  88.149 +        try {
  88.150 +            for (; i < len ; i++) {
  88.151 +                c = read();
  88.152 +                if (c == -1) {
  88.153 +                    break;
  88.154 +                }
  88.155 +                if (b != null) {
  88.156 +                    b[off + i] = (byte)c;
  88.157 +                }
  88.158 +            }
  88.159 +        } catch (IOException ee) {
  88.160 +        }
  88.161 +        return i;
  88.162 +    }
  88.163 +
  88.164 +    /**
  88.165 +     * Skips over and discards <code>n</code> bytes of data from this
  88.166 +     * input stream. The <code>skip</code> method may, for a variety of
  88.167 +     * reasons, end up skipping over some smaller number of bytes,
  88.168 +     * possibly <code>0</code>. The actual number of bytes skipped is
  88.169 +     * returned.  If <code>n</code> is negative, no bytes are skipped.
  88.170 +     * <p>
  88.171 +     * The <code>skip</code> method of <code>LineNumberInputStream</code> creates
  88.172 +     * a byte array and then repeatedly reads into it until
  88.173 +     * <code>n</code> bytes have been read or the end of the stream has
  88.174 +     * been reached.
  88.175 +     *
  88.176 +     * @param      n   the number of bytes to be skipped.
  88.177 +     * @return     the actual number of bytes skipped.
  88.178 +     * @exception  IOException  if an I/O error occurs.
  88.179 +     * @see        java.io.FilterInputStream#in
  88.180 +     */
  88.181 +    public long skip(long n) throws IOException {
  88.182 +        int chunk = 2048;
  88.183 +        long remaining = n;
  88.184 +        byte data[];
  88.185 +        int nr;
  88.186 +
  88.187 +        if (n <= 0) {
  88.188 +            return 0;
  88.189 +        }
  88.190 +
  88.191 +        data = new byte[chunk];
  88.192 +        while (remaining > 0) {
  88.193 +            nr = read(data, 0, (int) Math.min(chunk, remaining));
  88.194 +            if (nr < 0) {
  88.195 +                break;
  88.196 +            }
  88.197 +            remaining -= nr;
  88.198 +        }
  88.199 +
  88.200 +        return n - remaining;
  88.201 +    }
  88.202 +
  88.203 +    /**
  88.204 +     * Sets the line number to the specified argument.
  88.205 +     *
  88.206 +     * @param      lineNumber   the new line number.
  88.207 +     * @see #getLineNumber
  88.208 +     */
  88.209 +    public void setLineNumber(int lineNumber) {
  88.210 +        this.lineNumber = lineNumber;
  88.211 +    }
  88.212 +
  88.213 +    /**
  88.214 +     * Returns the current line number.
  88.215 +     *
  88.216 +     * @return     the current line number.
  88.217 +     * @see #setLineNumber
  88.218 +     */
  88.219 +    public int getLineNumber() {
  88.220 +        return lineNumber;
  88.221 +    }
  88.222 +
  88.223 +
  88.224 +    /**
  88.225 +     * Returns the number of bytes that can be read from this input
  88.226 +     * stream without blocking.
  88.227 +     * <p>
  88.228 +     * Note that if the underlying input stream is able to supply
  88.229 +     * <i>k</i> input characters without blocking, the
  88.230 +     * <code>LineNumberInputStream</code> can guarantee only to provide
  88.231 +     * <i>k</i>/2 characters without blocking, because the
  88.232 +     * <i>k</i> characters from the underlying input stream might
  88.233 +     * consist of <i>k</i>/2 pairs of <code>'&#92;r'</code> and
  88.234 +     * <code>'&#92;n'</code>, which are converted to just
  88.235 +     * <i>k</i>/2 <code>'&#92;n'</code> characters.
  88.236 +     *
  88.237 +     * @return     the number of bytes that can be read from this input stream
  88.238 +     *             without blocking.
  88.239 +     * @exception  IOException  if an I/O error occurs.
  88.240 +     * @see        java.io.FilterInputStream#in
  88.241 +     */
  88.242 +    public int available() throws IOException {
  88.243 +        return (pushBack == -1) ? super.available()/2 : super.available()/2 + 1;
  88.244 +    }
  88.245 +
  88.246 +    /**
  88.247 +     * Marks the current position in this input stream. A subsequent
  88.248 +     * call to the <code>reset</code> method repositions this stream at
  88.249 +     * the last marked position so that subsequent reads re-read the same bytes.
  88.250 +     * <p>
  88.251 +     * The <code>mark</code> method of
  88.252 +     * <code>LineNumberInputStream</code> remembers the current line
  88.253 +     * number in a private variable, and then calls the <code>mark</code>
  88.254 +     * method of the underlying input stream.
  88.255 +     *
  88.256 +     * @param   readlimit   the maximum limit of bytes that can be read before
  88.257 +     *                      the mark position becomes invalid.
  88.258 +     * @see     java.io.FilterInputStream#in
  88.259 +     * @see     java.io.LineNumberInputStream#reset()
  88.260 +     */
  88.261 +    public void mark(int readlimit) {
  88.262 +        markLineNumber = lineNumber;
  88.263 +        markPushBack   = pushBack;
  88.264 +        in.mark(readlimit);
  88.265 +    }
  88.266 +
  88.267 +    /**
  88.268 +     * Repositions this stream to the position at the time the
  88.269 +     * <code>mark</code> method was last called on this input stream.
  88.270 +     * <p>
  88.271 +     * The <code>reset</code> method of
  88.272 +     * <code>LineNumberInputStream</code> resets the line number to be
  88.273 +     * the line number at the time the <code>mark</code> method was
  88.274 +     * called, and then calls the <code>reset</code> method of the
  88.275 +     * underlying input stream.
  88.276 +     * <p>
  88.277 +     * Stream marks are intended to be used in
  88.278 +     * situations where you need to read ahead a little to see what's in
  88.279 +     * the stream. Often this is most easily done by invoking some
  88.280 +     * general parser. If the stream is of the type handled by the
  88.281 +     * parser, it just chugs along happily. If the stream is not of
  88.282 +     * that type, the parser should toss an exception when it fails,
  88.283 +     * which, if it happens within readlimit bytes, allows the outer
  88.284 +     * code to reset the stream and try another parser.
  88.285 +     *
  88.286 +     * @exception  IOException  if an I/O error occurs.
  88.287 +     * @see        java.io.FilterInputStream#in
  88.288 +     * @see        java.io.LineNumberInputStream#mark(int)
  88.289 +     */
  88.290 +    public void reset() throws IOException {
  88.291 +        lineNumber = markLineNumber;
  88.292 +        pushBack   = markPushBack;
  88.293 +        in.reset();
  88.294 +    }
  88.295 +}
    89.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    89.2 +++ b/rt/emul/compact/src/main/java/java/io/LineNumberReader.java	Tue Feb 11 13:31:42 2014 +0100
    89.3 @@ -0,0 +1,281 @@
    89.4 +/*
    89.5 + * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
    89.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    89.7 + *
    89.8 + * This code is free software; you can redistribute it and/or modify it
    89.9 + * under the terms of the GNU General Public License version 2 only, as
   89.10 + * published by the Free Software Foundation.  Oracle designates this
   89.11 + * particular file as subject to the "Classpath" exception as provided
   89.12 + * by Oracle in the LICENSE file that accompanied this code.
   89.13 + *
   89.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   89.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   89.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   89.17 + * version 2 for more details (a copy is included in the LICENSE file that
   89.18 + * accompanied this code).
   89.19 + *
   89.20 + * You should have received a copy of the GNU General Public License version
   89.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   89.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   89.23 + *
   89.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   89.25 + * or visit www.oracle.com if you need additional information or have any
   89.26 + * questions.
   89.27 + */
   89.28 +
   89.29 +package java.io;
   89.30 +
   89.31 +
   89.32 +/**
   89.33 + * A buffered character-input stream that keeps track of line numbers.  This
   89.34 + * class defines methods {@link #setLineNumber(int)} and {@link
   89.35 + * #getLineNumber()} for setting and getting the current line number
   89.36 + * respectively.
   89.37 + *
   89.38 + * <p> By default, line numbering begins at 0. This number increments at every
   89.39 + * <a href="#lt">line terminator</a> as the data is read, and can be changed
   89.40 + * with a call to <tt>setLineNumber(int)</tt>.  Note however, that
   89.41 + * <tt>setLineNumber(int)</tt> does not actually change the current position in
   89.42 + * the stream; it only changes the value that will be returned by
   89.43 + * <tt>getLineNumber()</tt>.
   89.44 + *
   89.45 + * <p> A line is considered to be <a name="lt">terminated</a> by any one of a
   89.46 + * line feed ('\n'), a carriage return ('\r'), or a carriage return followed
   89.47 + * immediately by a linefeed.
   89.48 + *
   89.49 + * @author      Mark Reinhold
   89.50 + * @since       JDK1.1
   89.51 + */
   89.52 +
   89.53 +public class LineNumberReader extends BufferedReader {
   89.54 +
   89.55 +    /** The current line number */
   89.56 +    private int lineNumber = 0;
   89.57 +
   89.58 +    /** The line number of the mark, if any */
   89.59 +    private int markedLineNumber; // Defaults to 0
   89.60 +
   89.61 +    /** If the next character is a line feed, skip it */
   89.62 +    private boolean skipLF;
   89.63 +
   89.64 +    /** The skipLF flag when the mark was set */
   89.65 +    private boolean markedSkipLF;
   89.66 +
   89.67 +    /**
   89.68 +     * Create a new line-numbering reader, using the default input-buffer
   89.69 +     * size.
   89.70 +     *
   89.71 +     * @param  in
   89.72 +     *         A Reader object to provide the underlying stream
   89.73 +     */
   89.74 +    public LineNumberReader(Reader in) {
   89.75 +        super(in);
   89.76 +    }
   89.77 +
   89.78 +    /**
   89.79 +     * Create a new line-numbering reader, reading characters into a buffer of
   89.80 +     * the given size.
   89.81 +     *
   89.82 +     * @param  in
   89.83 +     *         A Reader object to provide the underlying stream
   89.84 +     *
   89.85 +     * @param  sz
   89.86 +     *         An int specifying the size of the buffer
   89.87 +     */
   89.88 +    public LineNumberReader(Reader in, int sz) {
   89.89 +        super(in, sz);
   89.90 +    }
   89.91 +
   89.92 +    /**
   89.93 +     * Set the current line number.
   89.94 +     *
   89.95 +     * @param  lineNumber
   89.96 +     *         An int specifying the line number
   89.97 +     *
   89.98 +     * @see #getLineNumber
   89.99 +     */
  89.100 +    public void setLineNumber(int lineNumber) {
  89.101 +        this.lineNumber = lineNumber;
  89.102 +    }
  89.103 +
  89.104 +    /**
  89.105 +     * Get the current line number.
  89.106 +     *
  89.107 +     * @return  The current line number
  89.108 +     *
  89.109 +     * @see #setLineNumber
  89.110 +     */
  89.111 +    public int getLineNumber() {
  89.112 +        return lineNumber;
  89.113 +    }
  89.114 +
  89.115 +    /**
  89.116 +     * Read a single character.  <a href="#lt">Line terminators</a> are
  89.117 +     * compressed into single newline ('\n') characters.  Whenever a line
  89.118 +     * terminator is read the current line number is incremented.
  89.119 +     *
  89.120 +     * @return  The character read, or -1 if the end of the stream has been
  89.121 +     *          reached
  89.122 +     *
  89.123 +     * @throws  IOException
  89.124 +     *          If an I/O error occurs
  89.125 +     */
  89.126 +    public int read() throws IOException {
  89.127 +        synchronized (lock) {
  89.128 +            int c = super.read();
  89.129 +            if (skipLF) {
  89.130 +                if (c == '\n')
  89.131 +                    c = super.read();
  89.132 +                skipLF = false;
  89.133 +            }
  89.134 +            switch (c) {
  89.135 +            case '\r':
  89.136 +                skipLF = true;
  89.137 +            case '\n':          /* Fall through */
  89.138 +                lineNumber++;
  89.139 +                return '\n';
  89.140 +            }
  89.141 +            return c;
  89.142 +        }
  89.143 +    }
  89.144 +
  89.145 +    /**
  89.146 +     * Read characters into a portion of an array.  Whenever a <a
  89.147 +     * href="#lt">line terminator</a> is read the current line number is
  89.148 +     * incremented.
  89.149 +     *
  89.150 +     * @param  cbuf
  89.151 +     *         Destination buffer
  89.152 +     *
  89.153 +     * @param  off
  89.154 +     *         Offset at which to start storing characters
  89.155 +     *
  89.156 +     * @param  len
  89.157 +     *         Maximum number of characters to read
  89.158 +     *
  89.159 +     * @return  The number of bytes read, or -1 if the end of the stream has
  89.160 +     *          already been reached
  89.161 +     *
  89.162 +     * @throws  IOException
  89.163 +     *          If an I/O error occurs
  89.164 +     */
  89.165 +    public int read(char cbuf[], int off, int len) throws IOException {
  89.166 +        synchronized (lock) {
  89.167 +            int n = super.read(cbuf, off, len);
  89.168 +
  89.169 +            for (int i = off; i < off + n; i++) {
  89.170 +                int c = cbuf[i];
  89.171 +                if (skipLF) {
  89.172 +                    skipLF = false;
  89.173 +                    if (c == '\n')
  89.174 +                        continue;
  89.175 +                }
  89.176 +                switch (c) {
  89.177 +                case '\r':
  89.178 +                    skipLF = true;
  89.179 +                case '\n':      /* Fall through */
  89.180 +                    lineNumber++;
  89.181 +                    break;
  89.182 +                }
  89.183 +            }
  89.184 +
  89.185 +            return n;
  89.186 +        }
  89.187 +    }
  89.188 +
  89.189 +    /**
  89.190 +     * Read a line of text.  Whenever a <a href="#lt">line terminator</a> is
  89.191 +     * read the current line number is incremented.
  89.192 +     *
  89.193 +     * @return  A String containing the contents of the line, not including
  89.194 +     *          any <a href="#lt">line termination characters</a>, or
  89.195 +     *          <tt>null</tt> if the end of the stream has been reached
  89.196 +     *
  89.197 +     * @throws  IOException
  89.198 +     *          If an I/O error occurs
  89.199 +     */
  89.200 +    public String readLine() throws IOException {
  89.201 +        synchronized (lock) {
  89.202 +            String l = super.readLine(skipLF);
  89.203 +            skipLF = false;
  89.204 +            if (l != null)
  89.205 +                lineNumber++;
  89.206 +            return l;
  89.207 +        }
  89.208 +    }
  89.209 +
  89.210 +    /** Maximum skip-buffer size */
  89.211 +    private static final int maxSkipBufferSize = 8192;
  89.212 +
  89.213 +    /** Skip buffer, null until allocated */
  89.214 +    private char skipBuffer[] = null;
  89.215 +
  89.216 +    /**
  89.217 +     * Skip characters.
  89.218 +     *
  89.219 +     * @param  n
  89.220 +     *         The number of characters to skip
  89.221 +     *
  89.222 +     * @return  The number of characters actually skipped
  89.223 +     *
  89.224 +     * @throws  IOException
  89.225 +     *          If an I/O error occurs
  89.226 +     *
  89.227 +     * @throws  IllegalArgumentException
  89.228 +     *          If <tt>n</tt> is negative
  89.229 +     */
  89.230 +    public long skip(long n) throws IOException {
  89.231 +        if (n < 0)
  89.232 +            throw new IllegalArgumentException("skip() value is negative");
  89.233 +        int nn = (int) Math.min(n, maxSkipBufferSize);
  89.234 +        synchronized (lock) {
  89.235 +            if ((skipBuffer == null) || (skipBuffer.length < nn))
  89.236 +                skipBuffer = new char[nn];
  89.237 +            long r = n;
  89.238 +            while (r > 0) {
  89.239 +                int nc = read(skipBuffer, 0, (int) Math.min(r, nn));
  89.240 +                if (nc == -1)
  89.241 +                    break;
  89.242 +                r -= nc;
  89.243 +            }
  89.244 +            return n - r;
  89.245 +        }
  89.246 +    }
  89.247 +
  89.248 +    /**
  89.249 +     * Mark the present position in the stream.  Subsequent calls to reset()
  89.250 +     * will attempt to reposition the stream to this point, and will also reset
  89.251 +     * the line number appropriately.
  89.252 +     *
  89.253 +     * @param  readAheadLimit
  89.254 +     *         Limit on the number of characters that may be read while still
  89.255 +     *         preserving the mark.  After reading this many characters,
  89.256 +     *         attempting to reset the stream may fail.
  89.257 +     *
  89.258 +     * @throws  IOException
  89.259 +     *          If an I/O error occurs
  89.260 +     */
  89.261 +    public void mark(int readAheadLimit) throws IOException {
  89.262 +        synchronized (lock) {
  89.263 +            super.mark(readAheadLimit);
  89.264 +            markedLineNumber = lineNumber;
  89.265 +            markedSkipLF     = skipLF;
  89.266 +        }
  89.267 +    }
  89.268 +
  89.269 +    /**
  89.270 +     * Reset the stream to the most recent mark.
  89.271 +     *
  89.272 +     * @throws  IOException
  89.273 +     *          If the stream has not been marked, or if the mark has been
  89.274 +     *          invalidated
  89.275 +     */
  89.276 +    public void reset() throws IOException {
  89.277 +        synchronized (lock) {
  89.278 +            super.reset();
  89.279 +            lineNumber = markedLineNumber;
  89.280 +            skipLF     = markedSkipLF;
  89.281 +        }
  89.282 +    }
  89.283 +
  89.284 +}
    90.1 --- a/rt/emul/compact/src/main/java/java/io/OutputStreamWriter.java	Tue Feb 11 10:48:24 2014 +0100
    90.2 +++ b/rt/emul/compact/src/main/java/java/io/OutputStreamWriter.java	Tue Feb 11 13:31:42 2014 +0100
    90.3 @@ -25,6 +25,8 @@
    90.4  
    90.5  package java.io;
    90.6  
    90.7 +import java.nio.charset.Charset;
    90.8 +
    90.9  /**
   90.10   * An OutputStreamWriter is a bridge from character streams to byte streams:
   90.11   * Characters written to it are encoded into bytes using a specified {@link
   90.12 @@ -116,12 +118,9 @@
   90.13       * @since 1.4
   90.14       * @spec JSR-51
   90.15       */
   90.16 -//    public OutputStreamWriter(OutputStream out, Charset cs) {
   90.17 -//        super(out);
   90.18 -//        if (cs == null)
   90.19 -//            throw new NullPointerException("charset");
   90.20 -//        se = StreamEncoder.forOutputStreamWriter(out, this, cs);
   90.21 -//    }
   90.22 +    public OutputStreamWriter(OutputStream out, Charset cs) {
   90.23 +        this(out);
   90.24 +    }
   90.25  
   90.26      /**
   90.27       * Creates an OutputStreamWriter that uses the given charset encoder.  </p>
    91.1 --- a/rt/emul/compact/src/main/java/java/io/PrintStream.java	Tue Feb 11 10:48:24 2014 +0100
    91.2 +++ b/rt/emul/compact/src/main/java/java/io/PrintStream.java	Tue Feb 11 13:31:42 2014 +0100
    91.3 @@ -25,6 +25,7 @@
    91.4  
    91.5  package java.io;
    91.6  
    91.7 +import java.nio.charset.Charset;
    91.8  import java.util.Arrays;
    91.9  
   91.10  
   91.11 @@ -88,9 +89,6 @@
   91.12      static final class Formatter {
   91.13      }
   91.14      
   91.15 -    static final class Charset {
   91.16 -    }
   91.17 -    
   91.18      static Charset toCharset(String ch) throws UnsupportedEncodingException {
   91.19          if (!"UTF-8".equals(ch)) {
   91.20              throw new UnsupportedEncodingException();
    92.1 --- a/rt/emul/compact/src/main/java/java/io/PrintWriter.java	Tue Feb 11 10:48:24 2014 +0100
    92.2 +++ b/rt/emul/compact/src/main/java/java/io/PrintWriter.java	Tue Feb 11 13:31:42 2014 +0100
    92.3 @@ -25,10 +25,9 @@
    92.4  
    92.5  package java.io;
    92.6  
    92.7 -import java.io.PrintStream.Charset;
    92.8  import java.io.PrintStream.Formatter;
    92.9 +import java.nio.charset.Charset;
   92.10  import java.util.Arrays;
   92.11 -import java.util.Objects;
   92.12  
   92.13  /**
   92.14   * Prints formatted representations of objects to a text-output stream.  This
    93.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    93.2 +++ b/rt/emul/compact/src/main/java/java/io/StringReader.java	Tue Feb 11 13:31:42 2014 +0100
    93.3 @@ -0,0 +1,201 @@
    93.4 +/*
    93.5 + * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
    93.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    93.7 + *
    93.8 + * This code is free software; you can redistribute it and/or modify it
    93.9 + * under the terms of the GNU General Public License version 2 only, as
   93.10 + * published by the Free Software Foundation.  Oracle designates this
   93.11 + * particular file as subject to the "Classpath" exception as provided
   93.12 + * by Oracle in the LICENSE file that accompanied this code.
   93.13 + *
   93.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   93.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   93.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   93.17 + * version 2 for more details (a copy is included in the LICENSE file that
   93.18 + * accompanied this code).
   93.19 + *
   93.20 + * You should have received a copy of the GNU General Public License version
   93.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   93.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   93.23 + *
   93.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   93.25 + * or visit www.oracle.com if you need additional information or have any
   93.26 + * questions.
   93.27 + */
   93.28 +
   93.29 +package java.io;
   93.30 +
   93.31 +
   93.32 +/**
   93.33 + * A character stream whose source is a string.
   93.34 + *
   93.35 + * @author      Mark Reinhold
   93.36 + * @since       JDK1.1
   93.37 + */
   93.38 +
   93.39 +public class StringReader extends Reader {
   93.40 +
   93.41 +    private String str;
   93.42 +    private int length;
   93.43 +    private int next = 0;
   93.44 +    private int mark = 0;
   93.45 +
   93.46 +    /**
   93.47 +     * Creates a new string reader.
   93.48 +     *
   93.49 +     * @param s  String providing the character stream.
   93.50 +     */
   93.51 +    public StringReader(String s) {
   93.52 +        this.str = s;
   93.53 +        this.length = s.length();
   93.54 +    }
   93.55 +
   93.56 +    /** Check to make sure that the stream has not been closed */
   93.57 +    private void ensureOpen() throws IOException {
   93.58 +        if (str == null)
   93.59 +            throw new IOException("Stream closed");
   93.60 +    }
   93.61 +
   93.62 +    /**
   93.63 +     * Reads a single character.
   93.64 +     *
   93.65 +     * @return     The character read, or -1 if the end of the stream has been
   93.66 +     *             reached
   93.67 +     *
   93.68 +     * @exception  IOException  If an I/O error occurs
   93.69 +     */
   93.70 +    public int read() throws IOException {
   93.71 +        synchronized (lock) {
   93.72 +            ensureOpen();
   93.73 +            if (next >= length)
   93.74 +                return -1;
   93.75 +            return str.charAt(next++);
   93.76 +        }
   93.77 +    }
   93.78 +
   93.79 +    /**
   93.80 +     * Reads characters into a portion of an array.
   93.81 +     *
   93.82 +     * @param      cbuf  Destination buffer
   93.83 +     * @param      off   Offset at which to start writing characters
   93.84 +     * @param      len   Maximum number of characters to read
   93.85 +     *
   93.86 +     * @return     The number of characters read, or -1 if the end of the
   93.87 +     *             stream has been reached
   93.88 +     *
   93.89 +     * @exception  IOException  If an I/O error occurs
   93.90 +     */
   93.91 +    public int read(char cbuf[], int off, int len) throws IOException {
   93.92 +        synchronized (lock) {
   93.93 +            ensureOpen();
   93.94 +            if ((off < 0) || (off > cbuf.length) || (len < 0) ||
   93.95 +                ((off + len) > cbuf.length) || ((off + len) < 0)) {
   93.96 +                throw new IndexOutOfBoundsException();
   93.97 +            } else if (len == 0) {
   93.98 +                return 0;
   93.99 +            }
  93.100 +            if (next >= length)
  93.101 +                return -1;
  93.102 +            int n = Math.min(length - next, len);
  93.103 +            str.getChars(next, next + n, cbuf, off);
  93.104 +            next += n;
  93.105 +            return n;
  93.106 +        }
  93.107 +    }
  93.108 +
  93.109 +    /**
  93.110 +     * Skips the specified number of characters in the stream. Returns
  93.111 +     * the number of characters that were skipped.
  93.112 +     *
  93.113 +     * <p>The <code>ns</code> parameter may be negative, even though the
  93.114 +     * <code>skip</code> method of the {@link Reader} superclass throws
  93.115 +     * an exception in this case. Negative values of <code>ns</code> cause the
  93.116 +     * stream to skip backwards. Negative return values indicate a skip
  93.117 +     * backwards. It is not possible to skip backwards past the beginning of
  93.118 +     * the string.
  93.119 +     *
  93.120 +     * <p>If the entire string has been read or skipped, then this method has
  93.121 +     * no effect and always returns 0.
  93.122 +     *
  93.123 +     * @exception  IOException  If an I/O error occurs
  93.124 +     */
  93.125 +    public long skip(long ns) throws IOException {
  93.126 +        synchronized (lock) {
  93.127 +            ensureOpen();
  93.128 +            if (next >= length)
  93.129 +                return 0;
  93.130 +            // Bound skip by beginning and end of the source
  93.131 +            long n = Math.min(length - next, ns);
  93.132 +            n = Math.max(-next, n);
  93.133 +            next += n;
  93.134 +            return n;
  93.135 +        }
  93.136 +    }
  93.137 +
  93.138 +    /**
  93.139 +     * Tells whether this stream is ready to be read.
  93.140 +     *
  93.141 +     * @return True if the next read() is guaranteed not to block for input
  93.142 +     *
  93.143 +     * @exception  IOException  If the stream is closed
  93.144 +     */
  93.145 +    public boolean ready() throws IOException {
  93.146 +        synchronized (lock) {
  93.147 +        ensureOpen();
  93.148 +        return true;
  93.149 +        }
  93.150 +    }
  93.151 +
  93.152 +    /**
  93.153 +     * Tells whether this stream supports the mark() operation, which it does.
  93.154 +     */
  93.155 +    public boolean markSupported() {
  93.156 +        return true;
  93.157 +    }
  93.158 +
  93.159 +    /**
  93.160 +     * Marks the present position in the stream.  Subsequent calls to reset()
  93.161 +     * will reposition the stream to this point.
  93.162 +     *
  93.163 +     * @param  readAheadLimit  Limit on the number of characters that may be
  93.164 +     *                         read while still preserving the mark.  Because
  93.165 +     *                         the stream's input comes from a string, there
  93.166 +     *                         is no actual limit, so this argument must not
  93.167 +     *                         be negative, but is otherwise ignored.
  93.168 +     *
  93.169 +     * @exception  IllegalArgumentException  If readAheadLimit is < 0
  93.170 +     * @exception  IOException  If an I/O error occurs
  93.171 +     */
  93.172 +    public void mark(int readAheadLimit) throws IOException {
  93.173 +        if (readAheadLimit < 0){
  93.174 +            throw new IllegalArgumentException("Read-ahead limit < 0");
  93.175 +        }
  93.176 +        synchronized (lock) {
  93.177 +            ensureOpen();
  93.178 +            mark = next;
  93.179 +        }
  93.180 +    }
  93.181 +
  93.182 +    /**
  93.183 +     * Resets the stream to the most recent mark, or to the beginning of the
  93.184 +     * string if it has never been marked.
  93.185 +     *
  93.186 +     * @exception  IOException  If an I/O error occurs
  93.187 +     */
  93.188 +    public void reset() throws IOException {
  93.189 +        synchronized (lock) {
  93.190 +            ensureOpen();
  93.191 +            next = mark;
  93.192 +        }
  93.193 +    }
  93.194 +
  93.195 +    /**
  93.196 +     * Closes the stream and releases any system resources associated with
  93.197 +     * it. Once the stream has been closed, further read(),
  93.198 +     * ready(), mark(), or reset() invocations will throw an IOException.
  93.199 +     * Closing a previously closed stream has no effect.
  93.200 +     */
  93.201 +    public void close() {
  93.202 +        str = null;
  93.203 +    }
  93.204 +}
    94.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    94.2 +++ b/rt/emul/compact/src/main/java/java/io/StringWriter.java	Tue Feb 11 13:31:42 2014 +0100
    94.3 @@ -0,0 +1,236 @@
    94.4 +/*
    94.5 + * Copyright (c) 1996, 2004, Oracle and/or its affiliates. All rights reserved.
    94.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    94.7 + *
    94.8 + * This code is free software; you can redistribute it and/or modify it
    94.9 + * under the terms of the GNU General Public License version 2 only, as
   94.10 + * published by the Free Software Foundation.  Oracle designates this
   94.11 + * particular file as subject to the "Classpath" exception as provided
   94.12 + * by Oracle in the LICENSE file that accompanied this code.
   94.13 + *
   94.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   94.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   94.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   94.17 + * version 2 for more details (a copy is included in the LICENSE file that
   94.18 + * accompanied this code).
   94.19 + *
   94.20 + * You should have received a copy of the GNU General Public License version
   94.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   94.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   94.23 + *
   94.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   94.25 + * or visit www.oracle.com if you need additional information or have any
   94.26 + * questions.
   94.27 + */
   94.28 +
   94.29 +package java.io;
   94.30 +
   94.31 +
   94.32 +/**
   94.33 + * A character stream that collects its output in a string buffer, which can
   94.34 + * then be used to construct a string.
   94.35 + * <p>
   94.36 + * Closing a <tt>StringWriter</tt> has no effect. The methods in this class
   94.37 + * can be called after the stream has been closed without generating an
   94.38 + * <tt>IOException</tt>.
   94.39 + *
   94.40 + * @author      Mark Reinhold
   94.41 + * @since       JDK1.1
   94.42 + */
   94.43 +
   94.44 +public class StringWriter extends Writer {
   94.45 +
   94.46 +    private StringBuffer buf;
   94.47 +
   94.48 +    /**
   94.49 +     * Create a new string writer using the default initial string-buffer
   94.50 +     * size.
   94.51 +     */
   94.52 +    public StringWriter() {
   94.53 +        buf = new StringBuffer();
   94.54 +        lock = buf;
   94.55 +    }
   94.56 +
   94.57 +    /**
   94.58 +     * Create a new string writer using the specified initial string-buffer
   94.59 +     * size.
   94.60 +     *
   94.61 +     * @param initialSize
   94.62 +     *        The number of <tt>char</tt> values that will fit into this buffer
   94.63 +     *        before it is automatically expanded
   94.64 +     *
   94.65 +     * @throws IllegalArgumentException
   94.66 +     *         If <tt>initialSize</tt> is negative
   94.67 +     */
   94.68 +    public StringWriter(int initialSize) {
   94.69 +        if (initialSize < 0) {
   94.70 +            throw new IllegalArgumentException("Negative buffer size");
   94.71 +        }
   94.72 +        buf = new StringBuffer(initialSize);
   94.73 +        lock = buf;
   94.74 +    }
   94.75 +
   94.76 +    /**
   94.77 +     * Write a single character.
   94.78 +     */
   94.79 +    public void write(int c) {
   94.80 +        buf.append((char) c);
   94.81 +    }
   94.82 +
   94.83 +    /**
   94.84 +     * Write a portion of an array of characters.
   94.85 +     *
   94.86 +     * @param  cbuf  Array of characters
   94.87 +     * @param  off   Offset from which to start writing characters
   94.88 +     * @param  len   Number of characters to write
   94.89 +     */
   94.90 +    public void write(char cbuf[], int off, int len) {
   94.91 +        if ((off < 0) || (off > cbuf.length) || (len < 0) ||
   94.92 +            ((off + len) > cbuf.length) || ((off + len) < 0)) {
   94.93 +            throw new IndexOutOfBoundsException();
   94.94 +        } else if (len == 0) {
   94.95 +            return;
   94.96 +        }
   94.97 +        buf.append(cbuf, off, len);
   94.98 +    }
   94.99 +
  94.100 +    /**
  94.101 +     * Write a string.
  94.102 +     */
  94.103 +    public void write(String str) {
  94.104 +        buf.append(str);
  94.105 +    }
  94.106 +
  94.107 +    /**
  94.108 +     * Write a portion of a string.
  94.109 +     *
  94.110 +     * @param  str  String to be written
  94.111 +     * @param  off  Offset from which to start writing characters
  94.112 +     * @param  len  Number of characters to write
  94.113 +     */
  94.114 +    public void write(String str, int off, int len)  {
  94.115 +        buf.append(str.substring(off, off + len));
  94.116 +    }
  94.117 +
  94.118 +    /**
  94.119 +     * Appends the specified character sequence to this writer.
  94.120 +     *
  94.121 +     * <p> An invocation of this method of the form <tt>out.append(csq)</tt>
  94.122 +     * behaves in exactly the same way as the invocation
  94.123 +     *
  94.124 +     * <pre>
  94.125 +     *     out.write(csq.toString()) </pre>
  94.126 +     *
  94.127 +     * <p> Depending on the specification of <tt>toString</tt> for the
  94.128 +     * character sequence <tt>csq</tt>, the entire sequence may not be
  94.129 +     * appended. For instance, invoking the <tt>toString</tt> method of a
  94.130 +     * character buffer will return a subsequence whose content depends upon
  94.131 +     * the buffer's position and limit.
  94.132 +     *
  94.133 +     * @param  csq
  94.134 +     *         The character sequence to append.  If <tt>csq</tt> is
  94.135 +     *         <tt>null</tt>, then the four characters <tt>"null"</tt> are
  94.136 +     *         appended to this writer.
  94.137 +     *
  94.138 +     * @return  This writer
  94.139 +     *
  94.140 +     * @since  1.5
  94.141 +     */
  94.142 +    public StringWriter append(CharSequence csq) {
  94.143 +        if (csq == null)
  94.144 +            write("null");
  94.145 +        else
  94.146 +            write(csq.toString());
  94.147 +        return this;
  94.148 +    }
  94.149 +
  94.150 +    /**
  94.151 +     * Appends a subsequence of the specified character sequence to this writer.
  94.152 +     *
  94.153 +     * <p> An invocation of this method of the form <tt>out.append(csq, start,
  94.154 +     * end)</tt> when <tt>csq</tt> is not <tt>null</tt>, behaves in
  94.155 +     * exactly the same way as the invocation
  94.156 +     *
  94.157 +     * <pre>
  94.158 +     *     out.write(csq.subSequence(start, end).toString()) </pre>
  94.159 +     *
  94.160 +     * @param  csq
  94.161 +     *         The character sequence from which a subsequence will be
  94.162 +     *         appended.  If <tt>csq</tt> is <tt>null</tt>, then characters
  94.163 +     *         will be appended as if <tt>csq</tt> contained the four
  94.164 +     *         characters <tt>"null"</tt>.
  94.165 +     *
  94.166 +     * @param  start
  94.167 +     *         The index of the first character in the subsequence
  94.168 +     *
  94.169 +     * @param  end
  94.170 +     *         The index of the character following the last character in the
  94.171 +     *         subsequence
  94.172 +     *
  94.173 +     * @return  This writer
  94.174 +     *
  94.175 +     * @throws  IndexOutOfBoundsException
  94.176 +     *          If <tt>start</tt> or <tt>end</tt> are negative, <tt>start</tt>
  94.177 +     *          is greater than <tt>end</tt>, or <tt>end</tt> is greater than
  94.178 +     *          <tt>csq.length()</tt>
  94.179 +     *
  94.180 +     * @since  1.5
  94.181 +     */
  94.182 +    public StringWriter append(CharSequence csq, int start, int end) {
  94.183 +        CharSequence cs = (csq == null ? "null" : csq);
  94.184 +        write(cs.subSequence(start, end).toString());
  94.185 +        return this;
  94.186 +    }
  94.187 +
  94.188 +    /**
  94.189 +     * Appends the specified character to this writer.
  94.190 +     *
  94.191 +     * <p> An invocation of this method of the form <tt>out.append(c)</tt>
  94.192 +     * behaves in exactly the same way as the invocation
  94.193 +     *
  94.194 +     * <pre>
  94.195 +     *     out.write(c) </pre>
  94.196 +     *
  94.197 +     * @param  c
  94.198 +     *         The 16-bit character to append
  94.199 +     *
  94.200 +     * @return  This writer
  94.201 +     *
  94.202 +     * @since 1.5
  94.203 +     */
  94.204 +    public StringWriter append(char c) {
  94.205 +        write(c);
  94.206 +        return this;
  94.207 +    }
  94.208 +
  94.209 +    /**
  94.210 +     * Return the buffer's current value as a string.
  94.211 +     */
  94.212 +    public String toString() {
  94.213 +        return buf.toString();
  94.214 +    }
  94.215 +
  94.216 +    /**
  94.217 +     * Return the string buffer itself.
  94.218 +     *
  94.219 +     * @return StringBuffer holding the current buffer value.
  94.220 +     */
  94.221 +    public StringBuffer getBuffer() {
  94.222 +        return buf;
  94.223 +    }
  94.224 +
  94.225 +    /**
  94.226 +     * Flush the stream.
  94.227 +     */
  94.228 +    public void flush() {
  94.229 +    }
  94.230 +
  94.231 +    /**
  94.232 +     * Closing a <tt>StringWriter</tt> has no effect. The methods in this
  94.233 +     * class can be called after the stream has been closed without generating
  94.234 +     * an <tt>IOException</tt>.
  94.235 +     */
  94.236 +    public void close() throws IOException {
  94.237 +    }
  94.238 +
  94.239 +}
    95.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    95.2 +++ b/rt/emul/compact/src/main/java/java/io/SyncFailedException.java	Tue Feb 11 13:31:42 2014 +0100
    95.3 @@ -0,0 +1,48 @@
    95.4 +/*
    95.5 + * Copyright (c) 1996, 2008, Oracle and/or its affiliates. All rights reserved.
    95.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    95.7 + *
    95.8 + * This code is free software; you can redistribute it and/or modify it
    95.9 + * under the terms of the GNU General Public License version 2 only, as
   95.10 + * published by the Free Software Foundation.  Oracle designates this
   95.11 + * particular file as subject to the "Classpath" exception as provided
   95.12 + * by Oracle in the LICENSE file that accompanied this code.
   95.13 + *
   95.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   95.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   95.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   95.17 + * version 2 for more details (a copy is included in the LICENSE file that
   95.18 + * accompanied this code).
   95.19 + *
   95.20 + * You should have received a copy of the GNU General Public License version
   95.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   95.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   95.23 + *
   95.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   95.25 + * or visit www.oracle.com if you need additional information or have any
   95.26 + * questions.
   95.27 + */
   95.28 +
   95.29 +package java.io;
   95.30 +
   95.31 +/**
   95.32 + * Signals that a sync operation has failed.
   95.33 + *
   95.34 + * @author  Ken Arnold
   95.35 + * @see     java.io.FileDescriptor#sync
   95.36 + * @see     java.io.IOException
   95.37 + * @since   JDK1.1
   95.38 + */
   95.39 +public class SyncFailedException extends IOException {
   95.40 +    private static final long serialVersionUID = -2353342684412443330L;
   95.41 +
   95.42 +    /**
   95.43 +     * Constructs an SyncFailedException with a detail message.
   95.44 +     * A detail message is a String that describes this particular exception.
   95.45 +     *
   95.46 +     * @param desc  a String describing the exception.
   95.47 +     */
   95.48 +    public SyncFailedException(String desc) {
   95.49 +        super(desc);
   95.50 +    }
   95.51 +}
    96.1 --- a/rt/emul/compact/src/main/java/java/lang/System.java	Tue Feb 11 10:48:24 2014 +0100
    96.2 +++ b/rt/emul/compact/src/main/java/java/lang/System.java	Tue Feb 11 13:31:42 2014 +0100
    96.3 @@ -17,6 +17,13 @@
    96.4   */
    96.5  package java.lang;
    96.6  
    96.7 +import java.io.BufferedOutputStream;
    96.8 +import java.io.ByteArrayInputStream;
    96.9 +import java.io.IOException;
   96.10 +import java.io.InputStream;
   96.11 +import java.io.OutputStream;
   96.12 +import java.io.PrintStream;
   96.13 +import java.util.Properties;
   96.14  import org.apidesign.bck2brwsr.core.JavaScriptBody;
   96.15  
   96.16  /** Poor man's re-implementation of most important System methods.
   96.17 @@ -45,13 +52,27 @@
   96.18      }
   96.19  
   96.20      public static String getProperty(String name) {
   96.21 +        if ("os.name".equals(name)) {
   96.22 +            return userAgent();
   96.23 +        }
   96.24          return null;
   96.25      }
   96.26      
   96.27 +    @JavaScriptBody(args = {}, body = "return (typeof navigator !== 'undefined') ? navigator.userAgent : 'unknown';")
   96.28 +    private static native String userAgent();
   96.29 +    
   96.30      public static String getProperty(String key, String def) {
   96.31          return def;
   96.32      }
   96.33      
   96.34 +    public static Properties getProperties() {
   96.35 +        throw new SecurityException();
   96.36 +    }
   96.37 +    
   96.38 +    public static void setProperties(Properties p) {
   96.39 +        throw new SecurityException();
   96.40 +    }
   96.41 +    
   96.42      /**
   96.43       * Returns the system-dependent line separator string.  It always
   96.44       * returns the same value - the initial value of the {@linkplain
   96.45 @@ -67,4 +88,49 @@
   96.46      @JavaScriptBody(args = { "exitCode" }, body = "window.close();")
   96.47      public static void exit(int exitCode) {
   96.48      }
   96.49 +    
   96.50 +    public final static InputStream in;
   96.51 +
   96.52 +    public final static PrintStream out;
   96.53 +
   96.54 +    public final static PrintStream err;
   96.55 +    
   96.56 +    public static void setOut(PrintStream out) {
   96.57 +        throw new SecurityException();
   96.58 +    }
   96.59 +
   96.60 +    public static void setIn(InputStream in) {
   96.61 +        throw new SecurityException();
   96.62 +    }
   96.63 +
   96.64 +    public static void setErr(PrintStream err) {
   96.65 +        throw new SecurityException();
   96.66 +    }
   96.67 +    
   96.68 +    static {
   96.69 +        in = new ByteArrayInputStream(new byte[0]);
   96.70 +        out = new PrintStream(new BufferedOutputStream(new SystemStream("log")));
   96.71 +        err = new PrintStream(new BufferedOutputStream(new SystemStream("warn")));
   96.72 +    }
   96.73 +
   96.74 +    private static final class SystemStream extends OutputStream {
   96.75 +        private final String method;
   96.76 +
   96.77 +        public SystemStream(String method) {
   96.78 +            this.method = method;
   96.79 +        }
   96.80 +
   96.81 +        @Override
   96.82 +        public void write(byte b[], int off, int len) throws IOException {
   96.83 +            write(method, new String(b, off, len, "UTF-8"));
   96.84 +        }
   96.85 +
   96.86 +        @JavaScriptBody(args = { "method", "b" }, body = "if (typeof console !== 'undefined') console[method](b.toString());")
   96.87 +        private static native void write(String method, String b);
   96.88 +
   96.89 +        @Override
   96.90 +        public void write(int b) throws IOException {
   96.91 +            write(new byte[] { (byte)b });
   96.92 +        }
   96.93 +    } // end of SystemStream
   96.94  }
    97.1 --- a/rt/emul/compact/src/main/java/java/lang/Thread.java	Tue Feb 11 10:48:24 2014 +0100
    97.2 +++ b/rt/emul/compact/src/main/java/java/lang/Thread.java	Tue Feb 11 13:31:42 2014 +0100
    97.3 @@ -1165,7 +1165,7 @@
    97.4       * @since 1.2
    97.5       */
    97.6      public ClassLoader getContextClassLoader() {
    97.7 -        return null;
    97.8 +        return ClassLoader.getSystemClassLoader();
    97.9      }
   97.10  
   97.11      /**
   97.12 @@ -1191,6 +1191,9 @@
   97.13       * @since 1.2
   97.14       */
   97.15      public void setContextClassLoader(ClassLoader cl) {
   97.16 +        if (cl == ClassLoader.getSystemClassLoader()) {
   97.17 +            return;
   97.18 +        }
   97.19          throw new SecurityException();
   97.20      }
   97.21  
    98.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    98.2 +++ b/rt/emul/compact/src/main/java/java/lang/annotation/Annotation.java	Tue Feb 11 13:31:42 2014 +0100
    98.3 @@ -0,0 +1,131 @@
    98.4 +/*
    98.5 + * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved.
    98.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    98.7 + *
    98.8 + * This code is free software; you can redistribute it and/or modify it
    98.9 + * under the terms of the GNU General Public License version 2 only, as
   98.10 + * published by the Free Software Foundation.  Oracle designates this
   98.11 + * particular file as subject to the "Classpath" exception as provided
   98.12 + * by Oracle in the LICENSE file that accompanied this code.
   98.13 + *
   98.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   98.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   98.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   98.17 + * version 2 for more details (a copy is included in the LICENSE file that
   98.18 + * accompanied this code).
   98.19 + *
   98.20 + * You should have received a copy of the GNU General Public License version
   98.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   98.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   98.23 + *
   98.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   98.25 + * or visit www.oracle.com if you need additional information or have any
   98.26 + * questions.
   98.27 + */
   98.28 +
   98.29 +package java.lang.annotation;
   98.30 +
   98.31 +/**
   98.32 + * The common interface extended by all annotation types.  Note that an
   98.33 + * interface that manually extends this one does <i>not</i> define
   98.34 + * an annotation type.  Also note that this interface does not itself
   98.35 + * define an annotation type.
   98.36 + *
   98.37 + * More information about annotation types can be found in section 9.6 of
   98.38 + * <cite>The Java&trade; Language Specification</cite>.
   98.39 + *
   98.40 + * @author  Josh Bloch
   98.41 + * @since   1.5
   98.42 + */
   98.43 +public interface Annotation {
   98.44 +    /**
   98.45 +     * Returns true if the specified object represents an annotation
   98.46 +     * that is logically equivalent to this one.  In other words,
   98.47 +     * returns true if the specified object is an instance of the same
   98.48 +     * annotation type as this instance, all of whose members are equal
   98.49 +     * to the corresponding member of this annotation, as defined below:
   98.50 +     * <ul>
   98.51 +     *    <li>Two corresponding primitive typed members whose values are
   98.52 +     *    <tt>x</tt> and <tt>y</tt> are considered equal if <tt>x == y</tt>,
   98.53 +     *    unless their type is <tt>float</tt> or <tt>double</tt>.
   98.54 +     *
   98.55 +     *    <li>Two corresponding <tt>float</tt> members whose values
   98.56 +     *    are <tt>x</tt> and <tt>y</tt> are considered equal if
   98.57 +     *    <tt>Float.valueOf(x).equals(Float.valueOf(y))</tt>.
   98.58 +     *    (Unlike the <tt>==</tt> operator, NaN is considered equal
   98.59 +     *    to itself, and <tt>0.0f</tt> unequal to <tt>-0.0f</tt>.)
   98.60 +     *
   98.61 +     *    <li>Two corresponding <tt>double</tt> members whose values
   98.62 +     *    are <tt>x</tt> and <tt>y</tt> are considered equal if
   98.63 +     *    <tt>Double.valueOf(x).equals(Double.valueOf(y))</tt>.
   98.64 +     *    (Unlike the <tt>==</tt> operator, NaN is considered equal
   98.65 +     *    to itself, and <tt>0.0</tt> unequal to <tt>-0.0</tt>.)
   98.66 +     *
   98.67 +     *    <li>Two corresponding <tt>String</tt>, <tt>Class</tt>, enum, or
   98.68 +     *    annotation typed members whose values are <tt>x</tt> and <tt>y</tt>
   98.69 +     *    are considered equal if <tt>x.equals(y)</tt>.  (Note that this
   98.70 +     *    definition is recursive for annotation typed members.)
   98.71 +     *
   98.72 +     *    <li>Two corresponding array typed members <tt>x</tt> and <tt>y</tt>
   98.73 +     *    are considered equal if <tt>Arrays.equals(x, y)</tt>, for the
   98.74 +     *    appropriate overloading of {@link java.util.Arrays#equals}.
   98.75 +     * </ul>
   98.76 +     *
   98.77 +     * @return true if the specified object represents an annotation
   98.78 +     *     that is logically equivalent to this one, otherwise false
   98.79 +     */
   98.80 +    boolean equals(Object obj);
   98.81 +
   98.82 +    /**
   98.83 +     * Returns the hash code of this annotation, as defined below:
   98.84 +     *
   98.85 +     * <p>The hash code of an annotation is the sum of the hash codes
   98.86 +     * of its members (including those with default values), as defined
   98.87 +     * below:
   98.88 +     *
   98.89 +     * The hash code of an annotation member is (127 times the hash code
   98.90 +     * of the member-name as computed by {@link String#hashCode()}) XOR
   98.91 +     * the hash code of the member-value, as defined below:
   98.92 +     *
   98.93 +     * <p>The hash code of a member-value depends on its type:
   98.94 +     * <ul>
   98.95 +     * <li>The hash code of a primitive value <tt><i>v</i></tt> is equal to
   98.96 +     *     <tt><i>WrapperType</i>.valueOf(<i>v</i>).hashCode()</tt>, where
   98.97 +     *     <tt><i>WrapperType</i></tt> is the wrapper type corresponding
   98.98 +     *     to the primitive type of <tt><i>v</i></tt> ({@link Byte},
   98.99 +     *     {@link Character}, {@link Double}, {@link Float}, {@link Integer},
  98.100 +     *     {@link Long}, {@link Short}, or {@link Boolean}).
  98.101 +     *
  98.102 +     * <li>The hash code of a string, enum, class, or annotation member-value
  98.103 +     I     <tt><i>v</i></tt> is computed as by calling
  98.104 +     *     <tt><i>v</i>.hashCode()</tt>.  (In the case of annotation
  98.105 +     *     member values, this is a recursive definition.)
  98.106 +     *
  98.107 +     * <li>The hash code of an array member-value is computed by calling
  98.108 +     *     the appropriate overloading of
  98.109 +     *     {@link java.util.Arrays#hashCode(long[]) Arrays.hashCode}
  98.110 +     *     on the value.  (There is one overloading for each primitive
  98.111 +     *     type, and one for object reference types.)
  98.112 +     * </ul>
  98.113 +     *
  98.114 +     * @return the hash code of this annotation
  98.115 +     */
  98.116 +    int hashCode();
  98.117 +
  98.118 +    /**
  98.119 +     * Returns a string representation of this annotation.  The details
  98.120 +     * of the representation are implementation-dependent, but the following
  98.121 +     * may be regarded as typical:
  98.122 +     * <pre>
  98.123 +     *   &#064;com.acme.util.Name(first=Alfred, middle=E., last=Neuman)
  98.124 +     * </pre>
  98.125 +     *
  98.126 +     * @return a string representation of this annotation
  98.127 +     */
  98.128 +    String toString();
  98.129 +
  98.130 +    /**
  98.131 +     * Returns the annotation type of this annotation.
  98.132 +     */
  98.133 +    Class<? extends Annotation> annotationType();
  98.134 +}
    99.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    99.2 +++ b/rt/emul/compact/src/main/java/java/lang/annotation/AnnotationFormatError.java	Tue Feb 11 13:31:42 2014 +0100
    99.3 @@ -0,0 +1,79 @@
    99.4 +/*
    99.5 + * Copyright (c) 2004, 2008, Oracle and/or its affiliates. All rights reserved.
    99.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    99.7 + *
    99.8 + * This code is free software; you can redistribute it and/or modify it
    99.9 + * under the terms of the GNU General Public License version 2 only, as
   99.10 + * published by the Free Software Foundation.  Oracle designates this
   99.11 + * particular file as subject to the "Classpath" exception as provided
   99.12 + * by Oracle in the LICENSE file that accompanied this code.
   99.13 + *
   99.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   99.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   99.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   99.17 + * version 2 for more details (a copy is included in the LICENSE file that
   99.18 + * accompanied this code).
   99.19 + *
   99.20 + * You should have received a copy of the GNU General Public License version
   99.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   99.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   99.23 + *
   99.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   99.25 + * or visit www.oracle.com if you need additional information or have any
   99.26 + * questions.
   99.27 + */
   99.28 +
   99.29 +package java.lang.annotation;
   99.30 +
   99.31 +/**
   99.32 + * Thrown when the annotation parser attempts to read an annotation
   99.33 + * from a class file and determines that the annotation is malformed.
   99.34 + * This error can be thrown by the {@linkplain
   99.35 + * java.lang.reflect.AnnotatedElement API used to read annotations
   99.36 + * reflectively}.
   99.37 + *
   99.38 + * @author  Josh Bloch
   99.39 + * @see     java.lang.reflect.AnnotatedElement
   99.40 + * @since   1.5
   99.41 + */
   99.42 +public class AnnotationFormatError extends Error {
   99.43 +    private static final long serialVersionUID = -4256701562333669892L;
   99.44 +
   99.45 +    /**
   99.46 +     * Constructs a new <tt>AnnotationFormatError</tt> with the specified
   99.47 +     * detail message.
   99.48 +     *
   99.49 +     * @param   message   the detail message.
   99.50 +     */
   99.51 +    public AnnotationFormatError(String message) {
   99.52 +        super(message);
   99.53 +    }
   99.54 +
   99.55 +    /**
   99.56 +     * Constructs a new <tt>AnnotationFormatError</tt> with the specified
   99.57 +     * detail message and cause.  Note that the detail message associated
   99.58 +     * with <code>cause</code> is <i>not</i> automatically incorporated in
   99.59 +     * this error's detail message.
   99.60 +     *
   99.61 +     * @param  message the detail message
   99.62 +     * @param  cause the cause (A <tt>null</tt> value is permitted, and
   99.63 +     *     indicates that the cause is nonexistent or unknown.)
   99.64 +     */
   99.65 +    public AnnotationFormatError(String message, Throwable cause) {
   99.66 +        super(message, cause);
   99.67 +    }
   99.68 +
   99.69 +
   99.70 +    /**
   99.71 +     * Constructs a new <tt>AnnotationFormatError</tt> with the specified
   99.72 +     * cause and a detail message of
   99.73 +     * <tt>(cause == null ? null : cause.toString())</tt> (which
   99.74 +     * typically contains the class and detail message of <tt>cause</tt>).
   99.75 +     *
   99.76 +     * @param  cause the cause (A <tt>null</tt> value is permitted, and
   99.77 +     *     indicates that the cause is nonexistent or unknown.)
   99.78 +     */
   99.79 +    public AnnotationFormatError(Throwable cause) {
   99.80 +        super(cause);
   99.81 +    }
   99.82 +}
   100.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   100.2 +++ b/rt/emul/compact/src/main/java/java/lang/annotation/AnnotationTypeMismatchException.java	Tue Feb 11 13:31:42 2014 +0100
   100.3 @@ -0,0 +1,91 @@
   100.4 +/*
   100.5 + * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved.
   100.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   100.7 + *
   100.8 + * This code is free software; you can redistribute it and/or modify it
   100.9 + * under the terms of the GNU General Public License version 2 only, as
  100.10 + * published by the Free Software Foundation.  Oracle designates this
  100.11 + * particular file as subject to the "Classpath" exception as provided
  100.12 + * by Oracle in the LICENSE file that accompanied this code.
  100.13 + *
  100.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  100.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  100.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  100.17 + * version 2 for more details (a copy is included in the LICENSE file that
  100.18 + * accompanied this code).
  100.19 + *
  100.20 + * You should have received a copy of the GNU General Public License version
  100.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  100.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  100.23 + *
  100.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  100.25 + * or visit www.oracle.com if you need additional information or have any
  100.26 + * questions.
  100.27 + */
  100.28 +
  100.29 +package java.lang.annotation;
  100.30 +import java.lang.reflect.Method;
  100.31 +
  100.32 +/**
  100.33 + * Thrown to indicate that a program has attempted to access an element of
  100.34 + * an annotation whose type has changed after the annotation was compiled
  100.35 + * (or serialized).
  100.36 + * This exception can be thrown by the {@linkplain
  100.37 + * java.lang.reflect.AnnotatedElement API used to read annotations
  100.38 + * reflectively}.
  100.39 + *
  100.40 + * @author  Josh Bloch
  100.41 + * @see     java.lang.reflect.AnnotatedElement
  100.42 + * @since 1.5
  100.43 + */
  100.44 +public class AnnotationTypeMismatchException extends RuntimeException {
  100.45 +    private static final long serialVersionUID = 8125925355765570191L;
  100.46 +
  100.47 +    /**
  100.48 +     * The <tt>Method</tt> object for the annotation element.
  100.49 +     */
  100.50 +    private final Method element;
  100.51 +
  100.52 +    /**
  100.53 +     * The (erroneous) type of data found in the annotation.  This string
  100.54 +     * may, but is not required to, contain the value as well.  The exact
  100.55 +     * format of the string is unspecified.
  100.56 +     */
  100.57 +    private final String foundType;
  100.58 +
  100.59 +    /**
  100.60 +     * Constructs an AnnotationTypeMismatchException for the specified
  100.61 +     * annotation type element and found data type.
  100.62 +     *
  100.63 +     * @param element the <tt>Method</tt> object for the annotation element
  100.64 +     * @param foundType the (erroneous) type of data found in the annotation.
  100.65 +     *        This string may, but is not required to, contain the value
  100.66 +     *        as well.  The exact format of the string is unspecified.
  100.67 +     */
  100.68 +    public AnnotationTypeMismatchException(Method element, String foundType) {
  100.69 +        super("Incorrectly typed data found for annotation element " + element
  100.70 +              + " (Found data of type " + foundType + ")");
  100.71 +        this.element = element;
  100.72 +        this.foundType = foundType;
  100.73 +    }
  100.74 +
  100.75 +    /**
  100.76 +     * Returns the <tt>Method</tt> object for the incorrectly typed element.
  100.77 +     *
  100.78 +     * @return the <tt>Method</tt> object for the incorrectly typed element
  100.79 +     */
  100.80 +    public Method element() {
  100.81 +        return this.element;
  100.82 +    }
  100.83 +
  100.84 +    /**
  100.85 +     * Returns the type of data found in the incorrectly typed element.
  100.86 +     * The returned string may, but is not required to, contain the value
  100.87 +     * as well.  The exact format of the string is unspecified.
  100.88 +     *
  100.89 +     * @return the type of data found in the incorrectly typed element
  100.90 +     */
  100.91 +    public String foundType() {
  100.92 +        return this.foundType;
  100.93 +    }
  100.94 +}
   101.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   101.2 +++ b/rt/emul/compact/src/main/java/java/lang/annotation/Documented.java	Tue Feb 11 13:31:42 2014 +0100
   101.3 @@ -0,0 +1,43 @@
   101.4 +/*
   101.5 + * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
   101.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   101.7 + *
   101.8 + * This code is free software; you can redistribute it and/or modify it
   101.9 + * under the terms of the GNU General Public License version 2 only, as
  101.10 + * published by the Free Software Foundation.  Oracle designates this
  101.11 + * particular file as subject to the "Classpath" exception as provided
  101.12 + * by Oracle in the LICENSE file that accompanied this code.
  101.13 + *
  101.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  101.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  101.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  101.17 + * version 2 for more details (a copy is included in the LICENSE file that
  101.18 + * accompanied this code).
  101.19 + *
  101.20 + * You should have received a copy of the GNU General Public License version
  101.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  101.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  101.23 + *
  101.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  101.25 + * or visit www.oracle.com if you need additional information or have any
  101.26 + * questions.
  101.27 + */
  101.28 +
  101.29 +package java.lang.annotation;
  101.30 +
  101.31 +/**
  101.32 + * Indicates that annotations with a type are to be documented by javadoc
  101.33 + * and similar tools by default.  This type should be used to annotate the
  101.34 + * declarations of types whose annotations affect the use of annotated
  101.35 + * elements by their clients.  If a type declaration is annotated with
  101.36 + * Documented, its annotations become part of the public API
  101.37 + * of the annotated elements.
  101.38 + *
  101.39 + * @author  Joshua Bloch
  101.40 + * @since 1.5
  101.41 + */
  101.42 +@Documented
  101.43 +@Retention(RetentionPolicy.RUNTIME)
  101.44 +@Target(ElementType.ANNOTATION_TYPE)
  101.45 +public @interface Documented {
  101.46 +}
   102.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   102.2 +++ b/rt/emul/compact/src/main/java/java/lang/annotation/ElementType.java	Tue Feb 11 13:31:42 2014 +0100
   102.3 @@ -0,0 +1,63 @@
   102.4 +/*
   102.5 + * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
   102.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   102.7 + *
   102.8 + * This code is free software; you can redistribute it and/or modify it
   102.9 + * under the terms of the GNU General Public License version 2 only, as
  102.10 + * published by the Free Software Foundation.  Oracle designates this
  102.11 + * particular file as subject to the "Classpath" exception as provided
  102.12 + * by Oracle in the LICENSE file that accompanied this code.
  102.13 + *
  102.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  102.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  102.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  102.17 + * version 2 for more details (a copy is included in the LICENSE file that
  102.18 + * accompanied this code).
  102.19 + *
  102.20 + * You should have received a copy of the GNU General Public License version
  102.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  102.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  102.23 + *
  102.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  102.25 + * or visit www.oracle.com if you need additional information or have any
  102.26 + * questions.
  102.27 + */
  102.28 +
  102.29 +package java.lang.annotation;
  102.30 +
  102.31 +/**
  102.32 + * A program element type.  The constants of this enumerated type
  102.33 + * provide a simple classification of the declared elements in a
  102.34 + * Java program.
  102.35 + *
  102.36 + * <p>These constants are used with the {@link Target} meta-annotation type
  102.37 + * to specify where it is legal to use an annotation type.
  102.38 + *
  102.39 + * @author  Joshua Bloch
  102.40 + * @since 1.5
  102.41 + */
  102.42 +public enum ElementType {
  102.43 +    /** Class, interface (including annotation type), or enum declaration */
  102.44 +    TYPE,
  102.45 +
  102.46 +    /** Field declaration (includes enum constants) */
  102.47 +    FIELD,
  102.48 +
  102.49 +    /** Method declaration */
  102.50 +    METHOD,
  102.51 +
  102.52 +    /** Parameter declaration */
  102.53 +    PARAMETER,
  102.54 +
  102.55 +    /** Constructor declaration */
  102.56 +    CONSTRUCTOR,
  102.57 +
  102.58 +    /** Local variable declaration */
  102.59 +    LOCAL_VARIABLE,
  102.60 +
  102.61 +    /** Annotation type declaration */
  102.62 +    ANNOTATION_TYPE,
  102.63 +
  102.64 +    /** Package declaration */
  102.65 +    PACKAGE
  102.66 +}
   103.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   103.2 +++ b/rt/emul/compact/src/main/java/java/lang/annotation/IncompleteAnnotationException.java	Tue Feb 11 13:31:42 2014 +0100
   103.3 @@ -0,0 +1,83 @@
   103.4 +/*
   103.5 + * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved.
   103.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   103.7 + *
   103.8 + * This code is free software; you can redistribute it and/or modify it
   103.9 + * under the terms of the GNU General Public License version 2 only, as
  103.10 + * published by the Free Software Foundation.  Oracle designates this
  103.11 + * particular file as subject to the "Classpath" exception as provided
  103.12 + * by Oracle in the LICENSE file that accompanied this code.
  103.13 + *
  103.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  103.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  103.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  103.17 + * version 2 for more details (a copy is included in the LICENSE file that
  103.18 + * accompanied this code).
  103.19 + *
  103.20 + * You should have received a copy of the GNU General Public License version
  103.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  103.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  103.23 + *
  103.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  103.25 + * or visit www.oracle.com if you need additional information or have any
  103.26 + * questions.
  103.27 + */
  103.28 +
  103.29 +package java.lang.annotation;
  103.30 +
  103.31 +/**
  103.32 + * Thrown to indicate that a program has attempted to access an element of
  103.33 + * an annotation type that was added to the annotation type definition after
  103.34 + * the annotation was compiled (or serialized).  This exception will not be
  103.35 + * thrown if the new element has a default value.
  103.36 + * This exception can be thrown by the {@linkplain
  103.37 + * java.lang.reflect.AnnotatedElement API used to read annotations
  103.38 + * reflectively}.
  103.39 + *
  103.40 + * @author  Josh Bloch
  103.41 + * @see     java.lang.reflect.AnnotatedElement
  103.42 + * @since 1.5
  103.43 + */
  103.44 +public class IncompleteAnnotationException extends RuntimeException {
  103.45 +    private static final long serialVersionUID = 8445097402741811912L;
  103.46 +
  103.47 +    private Class annotationType;
  103.48 +    private String elementName;
  103.49 +
  103.50 +
  103.51 +    /**
  103.52 +     * Constructs an IncompleteAnnotationException to indicate that
  103.53 +     * the named element was missing from the specified annotation type.
  103.54 +     *
  103.55 +     * @param annotationType the Class object for the annotation type
  103.56 +     * @param elementName the name of the missing element
  103.57 +     */
  103.58 +    public IncompleteAnnotationException(
  103.59 +            Class<? extends Annotation> annotationType,
  103.60 +            String elementName) {
  103.61 +        super(annotationType.getName() + " missing element " + elementName);
  103.62 +
  103.63 +        this.annotationType = annotationType;
  103.64 +        this.elementName = elementName;
  103.65 +    }
  103.66 +
  103.67 +    /**
  103.68 +     * Returns the Class object for the annotation type with the
  103.69 +     * missing element.
  103.70 +     *
  103.71 +     * @return the Class object for the annotation type with the
  103.72 +     *     missing element
  103.73 +     */
  103.74 +    public Class<? extends Annotation> annotationType() {
  103.75 +        return annotationType;
  103.76 +    }
  103.77 +
  103.78 +    /**
  103.79 +     * Returns the name of the missing element.
  103.80 +     *
  103.81 +     * @return the name of the missing element
  103.82 +     */
  103.83 +    public String elementName() {
  103.84 +        return elementName;
  103.85 +    }
  103.86 +}
   104.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   104.2 +++ b/rt/emul/compact/src/main/java/java/lang/annotation/Inherited.java	Tue Feb 11 13:31:42 2014 +0100
   104.3 @@ -0,0 +1,52 @@
   104.4 +/*
   104.5 + * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
   104.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   104.7 + *
   104.8 + * This code is free software; you can redistribute it and/or modify it
   104.9 + * under the terms of the GNU General Public License version 2 only, as
  104.10 + * published by the Free Software Foundation.  Oracle designates this
  104.11 + * particular file as subject to the "Classpath" exception as provided
  104.12 + * by Oracle in the LICENSE file that accompanied this code.
  104.13 + *
  104.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  104.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  104.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  104.17 + * version 2 for more details (a copy is included in the LICENSE file that
  104.18 + * accompanied this code).
  104.19 + *
  104.20 + * You should have received a copy of the GNU General Public License version
  104.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  104.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  104.23 + *
  104.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  104.25 + * or visit www.oracle.com if you need additional information or have any
  104.26 + * questions.
  104.27 + */
  104.28 +
  104.29 +package java.lang.annotation;
  104.30 +
  104.31 +/**
  104.32 + * Indicates that an annotation type is automatically inherited.  If
  104.33 + * an Inherited meta-annotation is present on an annotation type
  104.34 + * declaration, and the user queries the annotation type on a class
  104.35 + * declaration, and the class declaration has no annotation for this type,
  104.36 + * then the class's superclass will automatically be queried for the
  104.37 + * annotation type.  This process will be repeated until an annotation for this
  104.38 + * type is found, or the top of the class hierarchy (Object)
  104.39 + * is reached.  If no superclass has an annotation for this type, then
  104.40 + * the query will indicate that the class in question has no such annotation.
  104.41 + *
  104.42 + * <p>Note that this meta-annotation type has no effect if the annotated
  104.43 + * type is used to annotate anything other than a class.  Note also
  104.44 + * that this meta-annotation only causes annotations to be inherited
  104.45 + * from superclasses; annotations on implemented interfaces have no
  104.46 + * effect.
  104.47 + *
  104.48 + * @author  Joshua Bloch
  104.49 + * @since 1.5
  104.50 + */
  104.51 +@Documented
  104.52 +@Retention(RetentionPolicy.RUNTIME)
  104.53 +@Target(ElementType.ANNOTATION_TYPE)
  104.54 +public @interface Inherited {
  104.55 +}
   105.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   105.2 +++ b/rt/emul/compact/src/main/java/java/lang/annotation/Retention.java	Tue Feb 11 13:31:42 2014 +0100
   105.3 @@ -0,0 +1,47 @@
   105.4 +/*
   105.5 + * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
   105.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   105.7 + *
   105.8 + * This code is free software; you can redistribute it and/or modify it
   105.9 + * under the terms of the GNU General Public License version 2 only, as
  105.10 + * published by the Free Software Foundation.  Oracle designates this
  105.11 + * particular file as subject to the "Classpath" exception as provided
  105.12 + * by Oracle in the LICENSE file that accompanied this code.
  105.13 + *
  105.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  105.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  105.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  105.17 + * version 2 for more details (a copy is included in the LICENSE file that
  105.18 + * accompanied this code).
  105.19 + *
  105.20 + * You should have received a copy of the GNU General Public License version
  105.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  105.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  105.23 + *
  105.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  105.25 + * or visit www.oracle.com if you need additional information or have any
  105.26 + * questions.
  105.27 + */
  105.28 +
  105.29 +package java.lang.annotation;
  105.30 +
  105.31 +/**
  105.32 + * Indicates how long annotations with the annotated type are to
  105.33 + * be retained.  If no Retention annotation is present on
  105.34 + * an annotation type declaration, the retention policy defaults to
  105.35 + * {@code RetentionPolicy.CLASS}.
  105.36 + *
  105.37 + * <p>A Retention meta-annotation has effect only if the
  105.38 + * meta-annotated type is used directly for annotation.  It has no
  105.39 + * effect if the meta-annotated type is used as a member type in
  105.40 + * another annotation type.
  105.41 + *
  105.42 + * @author  Joshua Bloch
  105.43 + * @since 1.5
  105.44 + */
  105.45 +@Documented
  105.46 +@Retention(RetentionPolicy.RUNTIME)
  105.47 +@Target(ElementType.ANNOTATION_TYPE)
  105.48 +public @interface Retention {
  105.49 +    RetentionPolicy value();
  105.50 +}
   106.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   106.2 +++ b/rt/emul/compact/src/main/java/java/lang/annotation/RetentionPolicy.java	Tue Feb 11 13:31:42 2014 +0100
   106.3 @@ -0,0 +1,57 @@
   106.4 +/*
   106.5 + * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
   106.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   106.7 + *
   106.8 + * This code is free software; you can redistribute it and/or modify it
   106.9 + * under the terms of the GNU General Public License version 2 only, as
  106.10 + * published by the Free Software Foundation.  Oracle designates this
  106.11 + * particular file as subject to the "Classpath" exception as provided
  106.12 + * by Oracle in the LICENSE file that accompanied this code.
  106.13 + *
  106.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  106.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  106.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  106.17 + * version 2 for more details (a copy is included in the LICENSE file that
  106.18 + * accompanied this code).
  106.19 + *
  106.20 + * You should have received a copy of the GNU General Public License version
  106.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  106.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  106.23 + *
  106.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  106.25 + * or visit www.oracle.com if you need additional information or have any
  106.26 + * questions.
  106.27 + */
  106.28 +
  106.29 +package java.lang.annotation;
  106.30 +
  106.31 +/**
  106.32 + * Annotation retention policy.  The constants of this enumerated type
  106.33 + * describe the various policies for retaining annotations.  They are used
  106.34 + * in conjunction with the {@link Retention} meta-annotation type to specify
  106.35 + * how long annotations are to be retained.
  106.36 + *
  106.37 + * @author  Joshua Bloch
  106.38 + * @since 1.5
  106.39 + */
  106.40 +public enum RetentionPolicy {
  106.41 +    /**
  106.42 +     * Annotations are to be discarded by the compiler.
  106.43 +     */
  106.44 +    SOURCE,
  106.45 +
  106.46 +    /**
  106.47 +     * Annotations are to be recorded in the class file by the compiler
  106.48 +     * but need not be retained by the VM at run time.  This is the default
  106.49 +     * behavior.
  106.50 +     */
  106.51 +    CLASS,
  106.52 +
  106.53 +    /**
  106.54 +     * Annotations are to be recorded in the class file by the compiler and
  106.55 +     * retained by the VM at run time, so they may be read reflectively.
  106.56 +     *
  106.57 +     * @see java.lang.reflect.AnnotatedElement
  106.58 +     */
  106.59 +    RUNTIME
  106.60 +}
   107.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   107.2 +++ b/rt/emul/compact/src/main/java/java/lang/annotation/Target.java	Tue Feb 11 13:31:42 2014 +0100
   107.3 @@ -0,0 +1,68 @@
   107.4 +/*
   107.5 + * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
   107.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   107.7 + *
   107.8 + * This code is free software; you can redistribute it and/or modify it
   107.9 + * under the terms of the GNU General Public License version 2 only, as
  107.10 + * published by the Free Software Foundation.  Oracle designates this
  107.11 + * particular file as subject to the "Classpath" exception as provided
  107.12 + * by Oracle in the LICENSE file that accompanied this code.
  107.13 + *
  107.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  107.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  107.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  107.17 + * version 2 for more details (a copy is included in the LICENSE file that
  107.18 + * accompanied this code).
  107.19 + *
  107.20 + * You should have received a copy of the GNU General Public License version
  107.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  107.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  107.23 + *
  107.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  107.25 + * or visit www.oracle.com if you need additional information or have any
  107.26 + * questions.
  107.27 + */
  107.28 +
  107.29 +package java.lang.annotation;
  107.30 +
  107.31 +/**
  107.32 + * Indicates the kinds of program element to which an annotation type
  107.33 + * is applicable.  If a Target meta-annotation is not present on an
  107.34 + * annotation type declaration, the declared type may be used on any
  107.35 + * program element.  If such a meta-annotation is present, the compiler
  107.36 + * will enforce the specified usage restriction.
  107.37 + *
  107.38 + * For example, this meta-annotation indicates that the declared type is
  107.39 + * itself a meta-annotation type.  It can only be used on annotation type
  107.40 + * declarations:
  107.41 + * <pre>
  107.42 + *    &#064;Target(ElementType.ANNOTATION_TYPE)
  107.43 + *    public &#064;interface MetaAnnotationType {
  107.44 + *        ...
  107.45 + *    }
  107.46 + * </pre>
  107.47 + * This meta-annotation indicates that the declared type is intended solely
  107.48 + * for use as a member type in complex annotation type declarations.  It
  107.49 + * cannot be used to annotate anything directly:
  107.50 + * <pre>
  107.51 + *    &#064;Target({})
  107.52 + *    public &#064;interface MemberType {
  107.53 + *        ...
  107.54 + *    }
  107.55 + * </pre>
  107.56 + * It is a compile-time error for a single ElementType constant to
  107.57 + * appear more than once in a Target annotation.  For example, the
  107.58 + * following meta-annotation is illegal:
  107.59 + * <pre>
  107.60 + *    &#064;Target({ElementType.FIELD, ElementType.METHOD, ElementType.FIELD})
  107.61 + *    public &#064;interface Bogus {
  107.62 + *        ...
  107.63 + *    }
  107.64 + * </pre>
  107.65 + */
  107.66 +@Documented
  107.67 +@Retention(RetentionPolicy.RUNTIME)
  107.68 +@Target(ElementType.ANNOTATION_TYPE)
  107.69 +public @interface Target {
  107.70 +    ElementType[] value();
  107.71 +}
   108.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   108.2 +++ b/rt/emul/compact/src/main/java/java/lang/annotation/package-info.java	Tue Feb 11 13:31:42 2014 +0100
   108.3 @@ -0,0 +1,33 @@
   108.4 +/*
   108.5 + * Copyright (c) 2004, 2006, Oracle and/or its affiliates. All rights reserved.
   108.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   108.7 + *
   108.8 + * This code is free software; you can redistribute it and/or modify it
   108.9 + * under the terms of the GNU General Public License version 2 only, as
  108.10 + * published by the Free Software Foundation.  Oracle designates this
  108.11 + * particular file as subject to the "Classpath" exception as provided
  108.12 + * by Oracle in the LICENSE file that accompanied this code.
  108.13 + *
  108.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  108.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  108.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  108.17 + * version 2 for more details (a copy is included in the LICENSE file that
  108.18 + * accompanied this code).
  108.19 + *
  108.20 + * You should have received a copy of the GNU General Public License version
  108.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  108.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  108.23 + *
  108.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  108.25 + * or visit www.oracle.com if you need additional information or have any
  108.26 + * questions.
  108.27 + */
  108.28 +
  108.29 +/**
  108.30 + * Provides library support for the Java programming language
  108.31 + * annotation facility.
  108.32 + *
  108.33 + * @author Josh Bloch
  108.34 + * @since 1.5
  108.35 + */
  108.36 +package java.lang.annotation;
   109.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   109.2 +++ b/rt/emul/compact/src/main/java/java/net/URLConnection.java	Tue Feb 11 13:31:42 2014 +0100
   109.3 @@ -0,0 +1,2314 @@
   109.4 +/*
   109.5 + * Copyright (c) 1995, 2011, Oracle and/or its affiliates. All rights reserved.
   109.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   109.7 + *
   109.8 + * This code is free software; you can redistribute it and/or modify it
   109.9 + * under the terms of the GNU General Public License version 2 only, as
  109.10 + * published by the Free Software Foundation.  Oracle designates this
  109.11 + * particular file as subject to the "Classpath" exception as provided
  109.12 + * by Oracle in the LICENSE file that accompanied this code.
  109.13 + *
  109.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  109.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  109.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  109.17 + * version 2 for more details (a copy is included in the LICENSE file that
  109.18 + * accompanied this code).
  109.19 + *
  109.20 + * You should have received a copy of the GNU General Public License version
  109.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  109.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  109.23 + *
  109.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  109.25 + * or visit www.oracle.com if you need additional information or have any
  109.26 + * questions.
  109.27 + */
  109.28 +
  109.29 +package java.net;
  109.30 +
  109.31 +import java.io.IOException;
  109.32 +import java.io.InputStream;
  109.33 +import java.io.OutputStream;
  109.34 +import java.io.PrintStream;
  109.35 +import java.util.ArrayList;
  109.36 +import java.util.Date;
  109.37 +import java.util.StringTokenizer;
  109.38 +import java.util.Collections;
  109.39 +import java.util.HashMap;
  109.40 +import java.util.Hashtable;
  109.41 +import java.util.Iterator;
  109.42 +import java.util.Map;
  109.43 +import java.util.List;
  109.44 +import java.util.NoSuchElementException;
  109.45 +
  109.46 +/**
  109.47 + * The abstract class <code>URLConnection</code> is the superclass
  109.48 + * of all classes that represent a communications link between the
  109.49 + * application and a URL. Instances of this class can be used both to
  109.50 + * read from and to write to the resource referenced by the URL. In
  109.51 + * general, creating a connection to a URL is a multistep process:
  109.52 + * <p>
  109.53 + * <center><table border=2 summary="Describes the process of creating a connection to a URL: openConnection() and connect() over time.">
  109.54 + * <tr><th><code>openConnection()</code></th>
  109.55 + *     <th><code>connect()</code></th></tr>
  109.56 + * <tr><td>Manipulate parameters that affect the connection to the remote
  109.57 + *         resource.</td>
  109.58 + *     <td>Interact with the resource; query header fields and
  109.59 + *         contents.</td></tr>
  109.60 + * </table>
  109.61 + * ----------------------------&gt;
  109.62 + * <br>time</center>
  109.63 + *
  109.64 + * <ol>
  109.65 + * <li>The connection object is created by invoking the
  109.66 + *     <code>openConnection</code> method on a URL.
  109.67 + * <li>The setup parameters and general request properties are manipulated.
  109.68 + * <li>The actual connection to the remote object is made, using the
  109.69 + *    <code>connect</code> method.
  109.70 + * <li>The remote object becomes available. The header fields and the contents
  109.71 + *     of the remote object can be accessed.
  109.72 + * </ol>
  109.73 + * <p>
  109.74 + * The setup parameters are modified using the following methods:
  109.75 + * <ul>
  109.76 + *   <li><code>setAllowUserInteraction</code>
  109.77 + *   <li><code>setDoInput</code>
  109.78 + *   <li><code>setDoOutput</code>
  109.79 + *   <li><code>setIfModifiedSince</code>
  109.80 + *   <li><code>setUseCaches</code>
  109.81 + * </ul>
  109.82 + * <p>
  109.83 + * and the general request properties are modified using the method:
  109.84 + * <ul>
  109.85 + *   <li><code>setRequestProperty</code>
  109.86 + * </ul>
  109.87 + * <p>
  109.88 + * Default values for the <code>AllowUserInteraction</code> and
  109.89 + * <code>UseCaches</code> parameters can be set using the methods
  109.90 + * <code>setDefaultAllowUserInteraction</code> and
  109.91 + * <code>setDefaultUseCaches</code>.
  109.92 + * <p>
  109.93 + * Each of the above <code>set</code> methods has a corresponding
  109.94 + * <code>get</code> method to retrieve the value of the parameter or
  109.95 + * general request property. The specific parameters and general
  109.96 + * request properties that are applicable are protocol specific.
  109.97 + * <p>
  109.98 + * The following methods are used to access the header fields and
  109.99 + * the contents after the connection is made to the remote object:
 109.100 + * <ul>
 109.101 + *   <li><code>getContent</code>
 109.102 + *   <li><code>getHeaderField</code>
 109.103 + *   <li><code>getInputStream</code>
 109.104 + *   <li><code>getOutputStream</code>
 109.105 + * </ul>
 109.106 + * <p>
 109.107 + * Certain header fields are accessed frequently. The methods:
 109.108 + * <ul>
 109.109 + *   <li><code>getContentEncoding</code>
 109.110 + *   <li><code>getContentLength</code>
 109.111 + *   <li><code>getContentType</code>
 109.112 + *   <li><code>getDate</code>
 109.113 + *   <li><code>getExpiration</code>
 109.114 + *   <li><code>getLastModifed</code>
 109.115 + * </ul>
 109.116 + * <p>
 109.117 + * provide convenient access to these fields. The
 109.118 + * <code>getContentType</code> method is used by the
 109.119 + * <code>getContent</code> method to determine the type of the remote
 109.120 + * object; subclasses may find it convenient to override the
 109.121 + * <code>getContentType</code> method.
 109.122 + * <p>
 109.123 + * In the common case, all of the pre-connection parameters and
 109.124 + * general request properties can be ignored: the pre-connection
 109.125 + * parameters and request properties default to sensible values. For
 109.126 + * most clients of this interface, there are only two interesting
 109.127 + * methods: <code>getInputStream</code> and <code>getContent</code>,
 109.128 + * which are mirrored in the <code>URL</code> class by convenience methods.
 109.129 + * <p>
 109.130 + * More information on the request properties and header fields of
 109.131 + * an <code>http</code> connection can be found at:
 109.132 + * <blockquote><pre>
 109.133 + * <a href="http://www.ietf.org/rfc/rfc2616.txt">http://www.ietf.org/rfc/rfc2616.txt</a>
 109.134 + * </pre></blockquote>
 109.135 + *
 109.136 + * Note about <code>fileNameMap</code>: In versions prior to JDK 1.1.6,
 109.137 + * field <code>fileNameMap</code> of <code>URLConnection</code> was public.
 109.138 + * In JDK 1.1.6 and later, <code>fileNameMap</code> is private; accessor
 109.139 + * and mutator methods {@link #getFileNameMap() getFileNameMap} and
 109.140 + * {@link #setFileNameMap(java.net.FileNameMap) setFileNameMap} are added
 109.141 + * to access it.  This change is also described on the <a href=
 109.142 + * "http://java.sun.com/products/jdk/1.2/compatibility.html">
 109.143 + * Compatibility</a> page.
 109.144 + *
 109.145 + * Invoking the <tt>close()</tt> methods on the <tt>InputStream</tt> or <tt>OutputStream</tt> of an
 109.146 + * <tt>URLConnection</tt> after a request may free network resources associated with this
 109.147 + * instance, unless particular protocol specifications specify different behaviours
 109.148 + * for it.
 109.149 + *
 109.150 + * @author  James Gosling
 109.151 + * @see     java.net.URL#openConnection()
 109.152 + * @see     java.net.URLConnection#connect()
 109.153 + * @see     java.net.URLConnection#getContent()
 109.154 + * @see     java.net.URLConnection#getContentEncoding()
 109.155 + * @see     java.net.URLConnection#getContentLength()
 109.156 + * @see     java.net.URLConnection#getContentType()
 109.157 + * @see     java.net.URLConnection#getDate()
 109.158 + * @see     java.net.URLConnection#getExpiration()
 109.159 + * @see     java.net.URLConnection#getHeaderField(int)
 109.160 + * @see     java.net.URLConnection#getHeaderField(java.lang.String)
 109.161 + * @see     java.net.URLConnection#getInputStream()
 109.162 + * @see     java.net.URLConnection#getLastModified()
 109.163 + * @see     java.net.URLConnection#getOutputStream()
 109.164 + * @see     java.net.URLConnection#setAllowUserInteraction(boolean)
 109.165 + * @see     java.net.URLConnection#setDefaultUseCaches(boolean)
 109.166 + * @see     java.net.URLConnection#setDoInput(boolean)
 109.167 + * @see     java.net.URLConnection#setDoOutput(boolean)
 109.168 + * @see     java.net.URLConnection#setIfModifiedSince(long)
 109.169 + * @see     java.net.URLConnection#setRequestProperty(java.lang.String, java.lang.String)
 109.170 + * @see     java.net.URLConnection#setUseCaches(boolean)
 109.171 + * @since   JDK1.0
 109.172 + */
 109.173 +public abstract class URLConnection {
 109.174 +
 109.175 +   /**
 109.176 +     * The URL represents the remote object on the World Wide Web to
 109.177 +     * which this connection is opened.
 109.178 +     * <p>
 109.179 +     * The value of this field can be accessed by the
 109.180 +     * <code>getURL</code> method.
 109.181 +     * <p>
 109.182 +     * The default value of this variable is the value of the URL
 109.183 +     * argument in the <code>URLConnection</code> constructor.
 109.184 +     *
 109.185 +     * @see     java.net.URLConnection#getURL()
 109.186 +     * @see     java.net.URLConnection#url
 109.187 +     */
 109.188 +    protected URL url;
 109.189 +
 109.190 +   /**
 109.191 +     * This variable is set by the <code>setDoInput</code> method. Its
 109.192 +     * value is returned by the <code>getDoInput</code> method.
 109.193 +     * <p>
 109.194 +     * A URL connection can be used for input and/or output. Setting the
 109.195 +     * <code>doInput</code> flag to <code>true</code> indicates that
 109.196 +     * the application intends to read data from the URL connection.
 109.197 +     * <p>
 109.198 +     * The default value of this field is <code>true</code>.
 109.199 +     *
 109.200 +     * @see     java.net.URLConnection#getDoInput()
 109.201 +     * @see     java.net.URLConnection#setDoInput(boolean)
 109.202 +     */
 109.203 +    protected boolean doInput = true;
 109.204 +
 109.205 +   /**
 109.206 +     * This variable is set by the <code>setDoOutput</code> method. Its
 109.207 +     * value is returned by the <code>getDoOutput</code> method.
 109.208 +     * <p>
 109.209 +     * A URL connection can be used for input and/or output. Setting the
 109.210 +     * <code>doOutput</code> flag to <code>true</code> indicates
 109.211 +     * that the application intends to write data to the URL connection.
 109.212 +     * <p>
 109.213 +     * The default value of this field is <code>false</code>.
 109.214 +     *
 109.215 +     * @see     java.net.URLConnection#getDoOutput()
 109.216 +     * @see     java.net.URLConnection#setDoOutput(boolean)
 109.217 +     */
 109.218 +    protected boolean doOutput = false;
 109.219 +
 109.220 +    private static boolean defaultAllowUserInteraction = false;
 109.221 +
 109.222 +   /**
 109.223 +     * If <code>true</code>, this <code>URL</code> is being examined in
 109.224 +     * a context in which it makes sense to allow user interactions such
 109.225 +     * as popping up an authentication dialog. If <code>false</code>,
 109.226 +     * then no user interaction is allowed.
 109.227 +     * <p>
 109.228 +     * The value of this field can be set by the
 109.229 +     * <code>setAllowUserInteraction</code> method.
 109.230 +     * Its value is returned by the
 109.231 +     * <code>getAllowUserInteraction</code> method.
 109.232 +     * Its default value is the value of the argument in the last invocation
 109.233 +     * of the <code>setDefaultAllowUserInteraction</code> method.
 109.234 +     *
 109.235 +     * @see     java.net.URLConnection#getAllowUserInteraction()
 109.236 +     * @see     java.net.URLConnection#setAllowUserInteraction(boolean)
 109.237 +     * @see     java.net.URLConnection#setDefaultAllowUserInteraction(boolean)
 109.238 +     */
 109.239 +    protected boolean allowUserInteraction = defaultAllowUserInteraction;
 109.240 +
 109.241 +    private static boolean defaultUseCaches = true;
 109.242 +
 109.243 +   /**
 109.244 +     * If <code>true</code>, the protocol is allowed to use caching
 109.245 +     * whenever it can. If <code>false</code>, the protocol must always
 109.246 +     * try to get a fresh copy of the object.
 109.247 +     * <p>
 109.248 +     * This field is set by the <code>setUseCaches</code> method. Its
 109.249 +     * value is returned by the <code>getUseCaches</code> method.
 109.250 +     * <p>
 109.251 +     * Its default value is the value given in the last invocation of the
 109.252 +     * <code>setDefaultUseCaches</code> method.
 109.253 +     *
 109.254 +     * @see     java.net.URLConnection#setUseCaches(boolean)
 109.255 +     * @see     java.net.URLConnection#getUseCaches()
 109.256 +     * @see     java.net.URLConnection#setDefaultUseCaches(boolean)
 109.257 +     */
 109.258 +    protected boolean useCaches = defaultUseCaches;
 109.259 +
 109.260 +   /**
 109.261 +     * Some protocols support skipping the fetching of the object unless
 109.262 +     * the object has been modified more recently than a certain time.
 109.263 +     * <p>
 109.264 +     * A nonzero value gives a time as the number of milliseconds since
 109.265 +     * January 1, 1970, GMT. The object is fetched only if it has been
 109.266 +     * modified more recently than that time.
 109.267 +     * <p>
 109.268 +     * This variable is set by the <code>setIfModifiedSince</code>
 109.269 +     * method. Its value is returned by the
 109.270 +     * <code>getIfModifiedSince</code> method.
 109.271 +     * <p>
 109.272 +     * The default value of this field is <code>0</code>, indicating
 109.273 +     * that the fetching must always occur.
 109.274 +     *
 109.275 +     * @see     java.net.URLConnection#getIfModifiedSince()
 109.276 +     * @see     java.net.URLConnection#setIfModifiedSince(long)
 109.277 +     */
 109.278 +    protected long ifModifiedSince = 0;
 109.279 +
 109.280 +   /**
 109.281 +     * If <code>false</code>, this connection object has not created a
 109.282 +     * communications link to the specified URL. If <code>true</code>,
 109.283 +     * the communications link has been established.
 109.284 +     */
 109.285 +    protected boolean connected = false;
 109.286 +
 109.287 +    /**
 109.288 +     * @since 1.5
 109.289 +     */
 109.290 +    private int connectTimeout;
 109.291 +    private int readTimeout;
 109.292 +
 109.293 +    /**
 109.294 +     * @since 1.6
 109.295 +     */
 109.296 +    private MessageHeader requests;
 109.297 +
 109.298 +   /**
 109.299 +    * @since   JDK1.1
 109.300 +    */
 109.301 +    private static FileNameMap fileNameMap;
 109.302 +
 109.303 +    /**
 109.304 +     * @since 1.2.2
 109.305 +     */
 109.306 +    private static boolean fileNameMapLoaded = false;
 109.307 +
 109.308 +    /**
 109.309 +     * Loads filename map (a mimetable) from a data file. It will
 109.310 +     * first try to load the user-specific table, defined
 109.311 +     * by &quot;content.types.user.table&quot; property. If that fails,
 109.312 +     * it tries to load the default built-in table at
 109.313 +     * lib/content-types.properties under java home.
 109.314 +     *
 109.315 +     * @return the FileNameMap
 109.316 +     * @since 1.2
 109.317 +     * @see #setFileNameMap(java.net.FileNameMap)
 109.318 +     */
 109.319 +    public static synchronized FileNameMap getFileNameMap() {
 109.320 +        if ((fileNameMap == null) && !fileNameMapLoaded) {
 109.321 +            fileNameMap = new FileNameMap() {
 109.322 +                @Override
 109.323 +                public String getContentTypeFor(String fileName) {
 109.324 +                    return "text/plain";
 109.325 +                }
 109.326 +            };
 109.327 +            fileNameMapLoaded = true;
 109.328 +        }
 109.329 +
 109.330 +        return new FileNameMap() {
 109.331 +            private FileNameMap map = fileNameMap;
 109.332 +            public String getContentTypeFor(String fileName) {
 109.333 +                return map.getContentTypeFor(fileName);
 109.334 +            }
 109.335 +        };
 109.336 +    }
 109.337 +
 109.338 +    /**
 109.339 +     * Sets the FileNameMap.
 109.340 +     * <p>
 109.341 +     * If there is a security manager, this method first calls
 109.342 +     * the security manager's <code>checkSetFactory</code> method
 109.343 +     * to ensure the operation is allowed.
 109.344 +     * This could result in a SecurityException.
 109.345 +     *
 109.346 +     * @param map the FileNameMap to be set
 109.347 +     * @exception  SecurityException  if a security manager exists and its
 109.348 +     *             <code>checkSetFactory</code> method doesn't allow the operation.
 109.349 +     * @see        SecurityManager#checkSetFactory
 109.350 +     * @see #getFileNameMap()
 109.351 +     * @since 1.2
 109.352 +     */
 109.353 +    public static void setFileNameMap(FileNameMap map) {
 109.354 +        throw new SecurityException();
 109.355 +    }
 109.356 +
 109.357 +    /**
 109.358 +     * Opens a communications link to the resource referenced by this
 109.359 +     * URL, if such a connection has not already been established.
 109.360 +     * <p>
 109.361 +     * If the <code>connect</code> method is called when the connection
 109.362 +     * has already been opened (indicated by the <code>connected</code>
 109.363 +     * field having the value <code>true</code>), the call is ignored.
 109.364 +     * <p>
 109.365 +     * URLConnection objects go through two phases: first they are
 109.366 +     * created, then they are connected.  After being created, and
 109.367 +     * before being connected, various options can be specified
 109.368 +     * (e.g., doInput and UseCaches).  After connecting, it is an
 109.369 +     * error to try to set them.  Operations that depend on being
 109.370 +     * connected, like getContentLength, will implicitly perform the
 109.371 +     * connection, if necessary.
 109.372 +     *
 109.373 +     * @throws SocketTimeoutException if the timeout expires before
 109.374 +     *               the connection can be established
 109.375 +     * @exception  IOException  if an I/O error occurs while opening the
 109.376 +     *               connection.
 109.377 +     * @see java.net.URLConnection#connected
 109.378 +     * @see #getConnectTimeout()
 109.379 +     * @see #setConnectTimeout(int)
 109.380 +     */
 109.381 +    abstract public void connect() throws IOException;
 109.382 +
 109.383 +    /**
 109.384 +     * Sets a specified timeout value, in milliseconds, to be used
 109.385 +     * when opening a communications link to the resource referenced
 109.386 +     * by this URLConnection.  If the timeout expires before the
 109.387 +     * connection can be established, a
 109.388 +     * java.net.SocketTimeoutException is raised. A timeout of zero is
 109.389 +     * interpreted as an infinite timeout.
 109.390 +
 109.391 +     * <p> Some non-standard implmentation of this method may ignore
 109.392 +     * the specified timeout. To see the connect timeout set, please
 109.393 +     * call getConnectTimeout().
 109.394 +     *
 109.395 +     * @param timeout an <code>int</code> that specifies the connect
 109.396 +     *               timeout value in milliseconds
 109.397 +     * @throws IllegalArgumentException if the timeout parameter is negative
 109.398 +     *
 109.399 +     * @see #getConnectTimeout()
 109.400 +     * @see #connect()
 109.401 +     * @since 1.5
 109.402 +     */
 109.403 +    public void setConnectTimeout(int timeout) {
 109.404 +        if (timeout < 0) {
 109.405 +            throw new IllegalArgumentException("timeout can not be negative");
 109.406 +        }
 109.407 +        connectTimeout = timeout;
 109.408 +    }
 109.409 +
 109.410 +    /**
 109.411 +     * Returns setting for connect timeout.
 109.412 +     * <p>
 109.413 +     * 0 return implies that the option is disabled
 109.414 +     * (i.e., timeout of infinity).
 109.415 +     *
 109.416 +     * @return an <code>int</code> that indicates the connect timeout
 109.417 +     *         value in milliseconds
 109.418 +     * @see #setConnectTimeout(int)
 109.419 +     * @see #connect()
 109.420 +     * @since 1.5
 109.421 +     */
 109.422 +    public int getConnectTimeout() {
 109.423 +        return connectTimeout;
 109.424 +    }
 109.425 +
 109.426 +    /**
 109.427 +     * Sets the read timeout to a specified timeout, in
 109.428 +     * milliseconds. A non-zero value specifies the timeout when
 109.429 +     * reading from Input stream when a connection is established to a
 109.430 +     * resource. If the timeout expires before there is data available
 109.431 +     * for read, a java.net.SocketTimeoutException is raised. A
 109.432 +     * timeout of zero is interpreted as an infinite timeout.
 109.433 +     *
 109.434 +     *<p> Some non-standard implementation of this method ignores the
 109.435 +     * specified timeout. To see the read timeout set, please call
 109.436 +     * getReadTimeout().
 109.437 +     *
 109.438 +     * @param timeout an <code>int</code> that specifies the timeout
 109.439 +     * value to be used in milliseconds
 109.440 +     * @throws IllegalArgumentException if the timeout parameter is negative
 109.441 +     *
 109.442 +     * @see #getReadTimeout()
 109.443 +     * @see InputStream#read()
 109.444 +     * @since 1.5
 109.445 +     */
 109.446 +    public void setReadTimeout(int timeout) {
 109.447 +        if (timeout < 0) {
 109.448 +            throw new IllegalArgumentException("timeout can not be negative");
 109.449 +        }
 109.450 +        readTimeout = timeout;
 109.451 +    }
 109.452 +
 109.453 +    /**
 109.454 +     * Returns setting for read timeout. 0 return implies that the
 109.455 +     * option is disabled (i.e., timeout of infinity).
 109.456 +     *
 109.457 +     * @return an <code>int</code> that indicates the read timeout
 109.458 +     *         value in milliseconds
 109.459 +     *
 109.460 +     * @see #setReadTimeout(int)
 109.461 +     * @see InputStream#read()
 109.462 +     * @since 1.5
 109.463 +     */
 109.464 +    public int getReadTimeout() {
 109.465 +        return readTimeout;
 109.466 +    }
 109.467 +
 109.468 +    /**
 109.469 +     * Constructs a URL connection to the specified URL. A connection to
 109.470 +     * the object referenced by the URL is not created.
 109.471 +     *
 109.472 +     * @param   url   the specified URL.
 109.473 +     */
 109.474 +    protected URLConnection(URL url) {
 109.475 +        this.url = url;
 109.476 +    }
 109.477 +
 109.478 +    /**
 109.479 +     * Returns the value of this <code>URLConnection</code>'s <code>URL</code>
 109.480 +     * field.
 109.481 +     *
 109.482 +     * @return  the value of this <code>URLConnection</code>'s <code>URL</code>
 109.483 +     *          field.
 109.484 +     * @see     java.net.URLConnection#url
 109.485 +     */
 109.486 +    public URL getURL() {
 109.487 +        return url;
 109.488 +    }
 109.489 +
 109.490 +    /**
 109.491 +     * Returns the value of the <code>content-length</code> header field.
 109.492 +     * <P>
 109.493 +     * <B>Note</B>: {@link #getContentLengthLong() getContentLengthLong()}
 109.494 +     * should be preferred over this method, since it returns a {@code long}
 109.495 +     * instead and is therefore more portable.</P>
 109.496 +     *
 109.497 +     * @return  the content length of the resource that this connection's URL
 109.498 +     *          references, {@code -1} if the content length is not known,
 109.499 +     *          or if the content length is greater than Integer.MAX_VALUE.
 109.500 +     */
 109.501 +    public int getContentLength() {
 109.502 +        long l = getContentLengthLong();
 109.503 +        if (l > Integer.MAX_VALUE)
 109.504 +            return -1;
 109.505 +        return (int) l;
 109.506 +    }
 109.507 +
 109.508 +    /**
 109.509 +     * Returns the value of the <code>content-length</code> header field as a
 109.510 +     * long.
 109.511 +     *
 109.512 +     * @return  the content length of the resource that this connection's URL
 109.513 +     *          references, or <code>-1</code> if the content length is
 109.514 +     *          not known.
 109.515 +     * @since 7.0
 109.516 +     */
 109.517 +    public long getContentLengthLong() {
 109.518 +        return getHeaderFieldLong("content-length", -1);
 109.519 +    }
 109.520 +
 109.521 +    /**
 109.522 +     * Returns the value of the <code>content-type</code> header field.
 109.523 +     *
 109.524 +     * @return  the content type of the resource that the URL references,
 109.525 +     *          or <code>null</code> if not known.
 109.526 +     * @see     java.net.URLConnection#getHeaderField(java.lang.String)
 109.527 +     */
 109.528 +    public String getContentType() {
 109.529 +        return getHeaderField("content-type");
 109.530 +    }
 109.531 +
 109.532 +    /**
 109.533 +     * Returns the value of the <code>content-encoding</code> header field.
 109.534 +     *
 109.535 +     * @return  the content encoding of the resource that the URL references,
 109.536 +     *          or <code>null</code> if not known.
 109.537 +     * @see     java.net.URLConnection#getHeaderField(java.lang.String)
 109.538 +     */
 109.539 +    public String getContentEncoding() {
 109.540 +        return getHeaderField("content-encoding");
 109.541 +    }
 109.542 +
 109.543 +    /**
 109.544 +     * Returns the value of the <code>expires</code> header field.
 109.545 +     *
 109.546 +     * @return  the expiration date of the resource that this URL references,
 109.547 +     *          or 0 if not known. The value is the number of milliseconds since
 109.548 +     *          January 1, 1970 GMT.
 109.549 +     * @see     java.net.URLConnection#getHeaderField(java.lang.String)
 109.550 +     */
 109.551 +    public long getExpiration() {
 109.552 +        return getHeaderFieldDate("expires", 0);
 109.553 +    }
 109.554 +
 109.555 +    /**
 109.556 +     * Returns the value of the <code>date</code> header field.
 109.557 +     *
 109.558 +     * @return  the sending date of the resource that the URL references,
 109.559 +     *          or <code>0</code> if not known. The value returned is the
 109.560 +     *          number of milliseconds since January 1, 1970 GMT.
 109.561 +     * @see     java.net.URLConnection#getHeaderField(java.lang.String)
 109.562 +     */
 109.563 +    public long getDate() {
 109.564 +        return getHeaderFieldDate("date", 0);
 109.565 +    }
 109.566 +
 109.567 +    /**
 109.568 +     * Returns the value of the <code>last-modified</code> header field.
 109.569 +     * The result is the number of milliseconds since January 1, 1970 GMT.
 109.570 +     *
 109.571 +     * @return  the date the resource referenced by this
 109.572 +     *          <code>URLConnection</code> was last modified, or 0 if not known.
 109.573 +     * @see     java.net.URLConnection#getHeaderField(java.lang.String)
 109.574 +     */
 109.575 +    public long getLastModified() {
 109.576 +        return getHeaderFieldDate("last-modified", 0);
 109.577 +    }
 109.578 +
 109.579 +    /**
 109.580 +     * Returns the value of the named header field.
 109.581 +     * <p>
 109.582 +     * If called on a connection that sets the same header multiple times
 109.583 +     * with possibly different values, only the last value is returned.
 109.584 +     *
 109.585 +     *
 109.586 +     * @param   name   the name of a header field.
 109.587 +     * @return  the value of the named header field, or <code>null</code>
 109.588 +     *          if there is no such field in the header.
 109.589 +     */
 109.590 +    public String getHeaderField(String name) {
 109.591 +        return null;
 109.592 +    }
 109.593 +
 109.594 +    /**
 109.595 +     * Returns an unmodifiable Map of the header fields.
 109.596 +     * The Map keys are Strings that represent the
 109.597 +     * response-header field names. Each Map value is an
 109.598 +     * unmodifiable List of Strings that represents
 109.599 +     * the corresponding field values.
 109.600 +     *
 109.601 +     * @return a Map of header fields
 109.602 +     * @since 1.4
 109.603 +     */
 109.604 +    public Map<String,List<String>> getHeaderFields() {
 109.605 +        return Collections.EMPTY_MAP;
 109.606 +    }
 109.607 +
 109.608 +    /**
 109.609 +     * Returns the value of the named field parsed as a number.
 109.610 +     * <p>
 109.611 +     * This form of <code>getHeaderField</code> exists because some
 109.612 +     * connection types (e.g., <code>http-ng</code>) have pre-parsed
 109.613 +     * headers. Classes for that connection type can override this method
 109.614 +     * and short-circuit the parsing.
 109.615 +     *
 109.616 +     * @param   name      the name of the header field.
 109.617 +     * @param   Default   the default value.
 109.618 +     * @return  the value of the named field, parsed as an integer. The
 109.619 +     *          <code>Default</code> value is returned if the field is
 109.620 +     *          missing or malformed.
 109.621 +     */
 109.622 +    public int getHeaderFieldInt(String name, int Default) {
 109.623 +        String value = getHeaderField(name);
 109.624 +        try {
 109.625 +            return Integer.parseInt(value);
 109.626 +        } catch (Exception e) { }
 109.627 +        return Default;
 109.628 +    }
 109.629 +
 109.630 +    /**
 109.631 +     * Returns the value of the named field parsed as a number.
 109.632 +     * <p>
 109.633 +     * This form of <code>getHeaderField</code> exists because some
 109.634 +     * connection types (e.g., <code>http-ng</code>) have pre-parsed
 109.635 +     * headers. Classes for that connection type can override this method
 109.636 +     * and short-circuit the parsing.
 109.637 +     *
 109.638 +     * @param   name      the name of the header field.
 109.639 +     * @param   Default   the default value.
 109.640 +     * @return  the value of the named field, parsed as a long. The
 109.641 +     *          <code>Default</code> value is returned if the field is
 109.642 +     *          missing or malformed.
 109.643 +     * @since 7.0
 109.644 +     */
 109.645 +    public long getHeaderFieldLong(String name, long Default) {
 109.646 +        String value = getHeaderField(name);
 109.647 +        try {
 109.648 +            return Long.parseLong(value);
 109.649 +        } catch (Exception e) { }
 109.650 +        return Default;
 109.651 +    }
 109.652 +
 109.653 +    /**
 109.654 +     * Returns the value of the named field parsed as date.
 109.655 +     * The result is the number of milliseconds since January 1, 1970 GMT
 109.656 +     * represented by the named field.
 109.657 +     * <p>
 109.658 +     * This form of <code>getHeaderField</code> exists because some
 109.659 +     * connection types (e.g., <code>http-ng</code>) have pre-parsed
 109.660 +     * headers. Classes for that connection type can override this method
 109.661 +     * and short-circuit the parsing.
 109.662 +     *
 109.663 +     * @param   name     the name of the header field.
 109.664 +     * @param   Default   a default value.
 109.665 +     * @return  the value of the field, parsed as a date. The value of the
 109.666 +     *          <code>Default</code> argument is returned if the field is
 109.667 +     *          missing or malformed.
 109.668 +     */
 109.669 +    public long getHeaderFieldDate(String name, long Default) {
 109.670 +        String value = getHeaderField(name);
 109.671 +        try {
 109.672 +            return Date.parse(value);
 109.673 +        } catch (Exception e) { }
 109.674 +        return Default;
 109.675 +    }
 109.676 +
 109.677 +    /**
 109.678 +     * Returns the key for the <code>n</code><sup>th</sup> header field.
 109.679 +     * It returns <code>null</code> if there are fewer than <code>n+1</code> fields.
 109.680 +     *
 109.681 +     * @param   n   an index, where n>=0
 109.682 +     * @return  the key for the <code>n</code><sup>th</sup> header field,
 109.683 +     *          or <code>null</code> if there are fewer than <code>n+1</code>
 109.684 +     *          fields.
 109.685 +     */
 109.686 +    public String getHeaderFieldKey(int n) {
 109.687 +        return null;
 109.688 +    }
 109.689 +
 109.690 +    /**
 109.691 +     * Returns the value for the <code>n</code><sup>th</sup> header field.
 109.692 +     * It returns <code>null</code> if there are fewer than
 109.693 +     * <code>n+1</code>fields.
 109.694 +     * <p>
 109.695 +     * This method can be used in conjunction with the
 109.696 +     * {@link #getHeaderFieldKey(int) getHeaderFieldKey} method to iterate through all
 109.697 +     * the headers in the message.
 109.698 +     *
 109.699 +     * @param   n   an index, where n>=0
 109.700 +     * @return  the value of the <code>n</code><sup>th</sup> header field
 109.701 +     *          or <code>null</code> if there are fewer than <code>n+1</code> fields
 109.702 +     * @see     java.net.URLConnection#getHeaderFieldKey(int)
 109.703 +     */
 109.704 +    public String getHeaderField(int n) {
 109.705 +        return null;
 109.706 +    }
 109.707 +
 109.708 +    /**
 109.709 +     * Retrieves the contents of this URL connection.
 109.710 +     * <p>
 109.711 +     * This method first determines the content type of the object by
 109.712 +     * calling the <code>getContentType</code> method. If this is
 109.713 +     * the first time that the application has seen that specific content
 109.714 +     * type, a content handler for that content type is created:
 109.715 +     * <ol>
 109.716 +     * <li>If the application has set up a content handler factory instance
 109.717 +     *     using the <code>setContentHandlerFactory</code> method, the
 109.718 +     *     <code>createContentHandler</code> method of that instance is called
 109.719 +     *     with the content type as an argument; the result is a content
 109.720 +     *     handler for that content type.
 109.721 +     * <li>If no content handler factory has yet been set up, or if the
 109.722 +     *     factory's <code>createContentHandler</code> method returns
 109.723 +     *     <code>null</code>, then the application loads the class named:
 109.724 +     *     <blockquote><pre>
 109.725 +     *         sun.net.www.content.&lt;<i>contentType</i>&gt;
 109.726 +     *     </pre></blockquote>
 109.727 +     *     where &lt;<i>contentType</i>&gt; is formed by taking the
 109.728 +     *     content-type string, replacing all slash characters with a
 109.729 +     *     <code>period</code> ('.'), and all other non-alphanumeric characters
 109.730 +     *     with the underscore character '<code>_</code>'. The alphanumeric
 109.731 +     *     characters are specifically the 26 uppercase ASCII letters
 109.732 +     *     '<code>A</code>' through '<code>Z</code>', the 26 lowercase ASCII
 109.733 +     *     letters '<code>a</code>' through '<code>z</code>', and the 10 ASCII
 109.734 +     *     digits '<code>0</code>' through '<code>9</code>'. If the specified
 109.735 +     *     class does not exist, or is not a subclass of
 109.736 +     *     <code>ContentHandler</code>, then an
 109.737 +     *     <code>UnknownServiceException</code> is thrown.
 109.738 +     * </ol>
 109.739 +     *
 109.740 +     * @return     the object fetched. The <code>instanceof</code> operator
 109.741 +     *               should be used to determine the specific kind of object
 109.742 +     *               returned.
 109.743 +     * @exception  IOException              if an I/O error occurs while
 109.744 +     *               getting the content.
 109.745 +     * @exception  UnknownServiceException  if the protocol does not support
 109.746 +     *               the content type.
 109.747 +     * @see        java.net.ContentHandlerFactory#createContentHandler(java.lang.String)
 109.748 +     * @see        java.net.URLConnection#getContentType()
 109.749 +     * @see        java.net.URLConnection#setContentHandlerFactory(java.net.ContentHandlerFactory)
 109.750 +     */
 109.751 +    public Object getContent() throws IOException {
 109.752 +        // Must call getInputStream before GetHeaderField gets called
 109.753 +        // so that FileNotFoundException has a chance to be thrown up
 109.754 +        // from here without being caught.
 109.755 +        getInputStream();
 109.756 +        return getContentHandler().getContent(this);
 109.757 +    }
 109.758 +
 109.759 +    /**
 109.760 +     * Retrieves the contents of this URL connection.
 109.761 +     *
 109.762 +     * @param classes the <code>Class</code> array
 109.763 +     * indicating the requested types
 109.764 +     * @return     the object fetched that is the first match of the type
 109.765 +     *               specified in the classes array. null if none of
 109.766 +     *               the requested types are supported.
 109.767 +     *               The <code>instanceof</code> operator should be used to
 109.768 +     *               determine the specific kind of object returned.
 109.769 +     * @exception  IOException              if an I/O error occurs while
 109.770 +     *               getting the content.
 109.771 +     * @exception  UnknownServiceException  if the protocol does not support
 109.772 +     *               the content type.
 109.773 +     * @see        java.net.URLConnection#getContent()
 109.774 +     * @see        java.net.ContentHandlerFactory#createContentHandler(java.lang.String)
 109.775 +     * @see        java.net.URLConnection#getContent(java.lang.Class[])
 109.776 +     * @see        java.net.URLConnection#setContentHandlerFactory(java.net.ContentHandlerFactory)
 109.777 +     * @since 1.3
 109.778 +     */
 109.779 +    public Object getContent(Class[] classes) throws IOException {
 109.780 +        // Must call getInputStream before GetHeaderField gets called
 109.781 +        // so that FileNotFoundException has a chance to be thrown up
 109.782 +        // from here without being caught.
 109.783 +        getInputStream();
 109.784 +        return getContentHandler().getContent(this, classes);
 109.785 +    }
 109.786 +
 109.787 +    /**
 109.788 +     * Returns a permission object representing the permission
 109.789 +     * necessary to make the connection represented by this
 109.790 +     * object. This method returns null if no permission is
 109.791 +     * required to make the connection. By default, this method
 109.792 +     * returns <code>java.security.AllPermission</code>. Subclasses
 109.793 +     * should override this method and return the permission
 109.794 +     * that best represents the permission required to make a
 109.795 +     * a connection to the URL. For example, a <code>URLConnection</code>
 109.796 +     * representing a <code>file:</code> URL would return a
 109.797 +     * <code>java.io.FilePermission</code> object.
 109.798 +     *
 109.799 +     * <p>The permission returned may dependent upon the state of the
 109.800 +     * connection. For example, the permission before connecting may be
 109.801 +     * different from that after connecting. For example, an HTTP
 109.802 +     * sever, say foo.com, may redirect the connection to a different
 109.803 +     * host, say bar.com. Before connecting the permission returned by
 109.804 +     * the connection will represent the permission needed to connect
 109.805 +     * to foo.com, while the permission returned after connecting will
 109.806 +     * be to bar.com.
 109.807 +     *
 109.808 +     * <p>Permissions are generally used for two purposes: to protect
 109.809 +     * caches of objects obtained through URLConnections, and to check
 109.810 +     * the right of a recipient to learn about a particular URL. In
 109.811 +     * the first case, the permission should be obtained
 109.812 +     * <em>after</em> the object has been obtained. For example, in an
 109.813 +     * HTTP connection, this will represent the permission to connect
 109.814 +     * to the host from which the data was ultimately fetched. In the
 109.815 +     * second case, the permission should be obtained and tested
 109.816 +     * <em>before</em> connecting.
 109.817 +     *
 109.818 +     * @return the permission object representing the permission
 109.819 +     * necessary to make the connection represented by this
 109.820 +     * URLConnection.
 109.821 +     *
 109.822 +     * @exception IOException if the computation of the permission
 109.823 +     * requires network or file I/O and an exception occurs while
 109.824 +     * computing it.
 109.825 +     */
 109.826 +//    public Permission getPermission() throws IOException {
 109.827 +//        return SecurityConstants.ALL_PERMISSION;
 109.828 +//    }
 109.829 +
 109.830 +    /**
 109.831 +     * Returns an input stream that reads from this open connection.
 109.832 +     *
 109.833 +     * A SocketTimeoutException can be thrown when reading from the
 109.834 +     * returned input stream if the read timeout expires before data
 109.835 +     * is available for read.
 109.836 +     *
 109.837 +     * @return     an input stream that reads from this open connection.
 109.838 +     * @exception  IOException              if an I/O error occurs while
 109.839 +     *               creating the input stream.
 109.840 +     * @exception  UnknownServiceException  if the protocol does not support
 109.841 +     *               input.
 109.842 +     * @see #setReadTimeout(int)
 109.843 +     * @see #getReadTimeout()
 109.844 +     */
 109.845 +    public InputStream getInputStream() throws IOException {
 109.846 +        throw new UnknownServiceException("protocol doesn't support input");
 109.847 +    }
 109.848 +
 109.849 +    /**
 109.850 +     * Returns an output stream that writes to this connection.
 109.851 +     *
 109.852 +     * @return     an output stream that writes to this connection.
 109.853 +     * @exception  IOException              if an I/O error occurs while
 109.854 +     *               creating the output stream.
 109.855 +     * @exception  UnknownServiceException  if the protocol does not support
 109.856 +     *               output.
 109.857 +     */
 109.858 +    public OutputStream getOutputStream() throws IOException {
 109.859 +        throw new UnknownServiceException("protocol doesn't support output");
 109.860 +    }
 109.861 +
 109.862 +    /**
 109.863 +     * Returns a <code>String</code> representation of this URL connection.
 109.864 +     *
 109.865 +     * @return  a string representation of this <code>URLConnection</code>.
 109.866 +     */
 109.867 +    public String toString() {
 109.868 +        return this.getClass().getName() + ":" + url;
 109.869 +    }
 109.870 +
 109.871 +    /**
 109.872 +     * Sets the value of the <code>doInput</code> field for this
 109.873 +     * <code>URLConnection</code> to the specified value.
 109.874 +     * <p>
 109.875 +     * A URL connection can be used for input and/or output.  Set the DoInput
 109.876 +     * flag to true if you intend to use the URL connection for input,
 109.877 +     * false if not.  The default is true.
 109.878 +     *
 109.879 +     * @param   doinput   the new value.
 109.880 +     * @throws IllegalStateException if already connected
 109.881 +     * @see     java.net.URLConnection#doInput
 109.882 +     * @see #getDoInput()
 109.883 +     */
 109.884 +    public void setDoInput(boolean doinput) {
 109.885 +        if (connected)
 109.886 +            throw new IllegalStateException("Already connected");
 109.887 +        doInput = doinput;
 109.888 +    }
 109.889 +
 109.890 +    /**
 109.891 +     * Returns the value of this <code>URLConnection</code>'s
 109.892 +     * <code>doInput</code> flag.
 109.893 +     *
 109.894 +     * @return  the value of this <code>URLConnection</code>'s
 109.895 +     *          <code>doInput</code> flag.
 109.896 +     * @see     #setDoInput(boolean)
 109.897 +     */
 109.898 +    public boolean getDoInput() {
 109.899 +        return doInput;
 109.900 +    }
 109.901 +
 109.902 +    /**
 109.903 +     * Sets the value of the <code>doOutput</code> field for this
 109.904 +     * <code>URLConnection</code> to the specified value.
 109.905 +     * <p>
 109.906 +     * A URL connection can be used for input and/or output.  Set the DoOutput
 109.907 +     * flag to true if you intend to use the URL connection for output,
 109.908 +     * false if not.  The default is false.
 109.909 +     *
 109.910 +     * @param   dooutput   the new value.
 109.911 +     * @throws IllegalStateException if already connected
 109.912 +     * @see #getDoOutput()
 109.913 +     */
 109.914 +    public void setDoOutput(boolean dooutput) {
 109.915 +        if (connected)
 109.916 +            throw new IllegalStateException("Already connected");
 109.917 +        doOutput = dooutput;
 109.918 +    }
 109.919 +
 109.920 +    /**
 109.921 +     * Returns the value of this <code>URLConnection</code>'s
 109.922 +     * <code>doOutput</code> flag.
 109.923 +     *
 109.924 +     * @return  the value of this <code>URLConnection</code>'s
 109.925 +     *          <code>doOutput</code> flag.
 109.926 +     * @see     #setDoOutput(boolean)
 109.927 +     */
 109.928 +    public boolean getDoOutput() {
 109.929 +        return doOutput;
 109.930 +    }
 109.931 +
 109.932 +    /**
 109.933 +     * Set the value of the <code>allowUserInteraction</code> field of
 109.934 +     * this <code>URLConnection</code>.
 109.935 +     *
 109.936 +     * @param   allowuserinteraction   the new value.
 109.937 +     * @throws IllegalStateException if already connected
 109.938 +     * @see     #getAllowUserInteraction()
 109.939 +     */
 109.940 +    public void setAllowUserInteraction(boolean allowuserinteraction) {
 109.941 +        if (connected)
 109.942 +            throw new IllegalStateException("Already connected");
 109.943 +        allowUserInteraction = allowuserinteraction;
 109.944 +    }
 109.945 +
 109.946 +    /**
 109.947 +     * Returns the value of the <code>allowUserInteraction</code> field for
 109.948 +     * this object.
 109.949 +     *
 109.950 +     * @return  the value of the <code>allowUserInteraction</code> field for
 109.951 +     *          this object.
 109.952 +     * @see     #setAllowUserInteraction(boolean)
 109.953 +     */
 109.954 +    public boolean getAllowUserInteraction() {
 109.955 +        return allowUserInteraction;
 109.956 +    }
 109.957 +
 109.958 +    /**
 109.959 +     * Sets the default value of the
 109.960 +     * <code>allowUserInteraction</code> field for all future
 109.961 +     * <code>URLConnection</code> objects to the specified value.
 109.962 +     *
 109.963 +     * @param   defaultallowuserinteraction   the new value.
 109.964 +     * @see     #getDefaultAllowUserInteraction()
 109.965 +     */
 109.966 +    public static void setDefaultAllowUserInteraction(boolean defaultallowuserinteraction) {
 109.967 +        defaultAllowUserInteraction = defaultallowuserinteraction;
 109.968 +    }
 109.969 +
 109.970 +    /**
 109.971 +     * Returns the default value of the <code>allowUserInteraction</code>
 109.972 +     * field.
 109.973 +     * <p>
 109.974 +     * Ths default is "sticky", being a part of the static state of all
 109.975 +     * URLConnections.  This flag applies to the next, and all following
 109.976 +     * URLConnections that are created.
 109.977 +     *
 109.978 +     * @return  the default value of the <code>allowUserInteraction</code>
 109.979 +     *          field.
 109.980 +     * @see     #setDefaultAllowUserInteraction(boolean)
 109.981 +     */
 109.982 +    public static boolean getDefaultAllowUserInteraction() {
 109.983 +        return defaultAllowUserInteraction;
 109.984 +    }
 109.985 +
 109.986 +    /**
 109.987 +     * Sets the value of the <code>useCaches</code> field of this
 109.988 +     * <code>URLConnection</code> to the specified value.
 109.989 +     * <p>
 109.990 +     * Some protocols do caching of documents.  Occasionally, it is important
 109.991 +     * to be able to "tunnel through" and ignore the caches (e.g., the
 109.992 +     * "reload" button in a browser).  If the UseCaches flag on a connection
 109.993 +     * is true, the connection is allowed to use whatever caches it can.
 109.994 +     *  If false, caches are to be ignored.
 109.995 +     *  The default value comes from DefaultUseCaches, which defaults to
 109.996 +     * true.
 109.997 +     *
 109.998 +     * @param usecaches a <code>boolean</code> indicating whether
 109.999 +     * or not to allow caching
109.1000 +     * @throws IllegalStateException if already connected
109.1001 +     * @see #getUseCaches()
109.1002 +     */
109.1003 +    public void setUseCaches(boolean usecaches) {
109.1004 +        if (connected)
109.1005 +            throw new IllegalStateException("Already connected");
109.1006 +        useCaches = usecaches;
109.1007 +    }
109.1008 +
109.1009 +    /**
109.1010 +     * Returns the value of this <code>URLConnection</code>'s
109.1011 +     * <code>useCaches</code> field.
109.1012 +     *
109.1013 +     * @return  the value of this <code>URLConnection</code>'s
109.1014 +     *          <code>useCaches</code> field.
109.1015 +     * @see #setUseCaches(boolean)
109.1016 +     */
109.1017 +    public boolean getUseCaches() {
109.1018 +        return useCaches;
109.1019 +    }
109.1020 +
109.1021 +    /**
109.1022 +     * Sets the value of the <code>ifModifiedSince</code> field of
109.1023 +     * this <code>URLConnection</code> to the specified value.
109.1024 +     *
109.1025 +     * @param   ifmodifiedsince   the new value.
109.1026 +     * @throws IllegalStateException if already connected
109.1027 +     * @see     #getIfModifiedSince()
109.1028 +     */
109.1029 +    public void setIfModifiedSince(long ifmodifiedsince) {
109.1030 +        if (connected)
109.1031 +            throw new IllegalStateException("Already connected");
109.1032 +        ifModifiedSince = ifmodifiedsince;
109.1033 +    }
109.1034 +
109.1035 +    /**
109.1036 +     * Returns the value of this object's <code>ifModifiedSince</code> field.
109.1037 +     *
109.1038 +     * @return  the value of this object's <code>ifModifiedSince</code> field.
109.1039 +     * @see #setIfModifiedSince(long)
109.1040 +     */
109.1041 +    public long getIfModifiedSince() {
109.1042 +        return ifModifiedSince;
109.1043 +    }
109.1044 +
109.1045 +   /**
109.1046 +     * Returns the default value of a <code>URLConnection</code>'s
109.1047 +     * <code>useCaches</code> flag.
109.1048 +     * <p>
109.1049 +     * Ths default is "sticky", being a part of the static state of all
109.1050 +     * URLConnections.  This flag applies to the next, and all following
109.1051 +     * URLConnections that are created.
109.1052 +     *
109.1053 +     * @return  the default value of a <code>URLConnection</code>'s
109.1054 +     *          <code>useCaches</code> flag.
109.1055 +     * @see     #setDefaultUseCaches(boolean)
109.1056 +     */
109.1057 +    public boolean getDefaultUseCaches() {
109.1058 +        return defaultUseCaches;
109.1059 +    }
109.1060 +
109.1061 +   /**
109.1062 +     * Sets the default value of the <code>useCaches</code> field to the
109.1063 +     * specified value.
109.1064 +     *
109.1065 +     * @param   defaultusecaches   the new value.
109.1066 +     * @see     #getDefaultUseCaches()
109.1067 +     */
109.1068 +    public void setDefaultUseCaches(boolean defaultusecaches) {
109.1069 +        defaultUseCaches = defaultusecaches;
109.1070 +    }
109.1071 +
109.1072 +    /**
109.1073 +     * Sets the general request property. If a property with the key already
109.1074 +     * exists, overwrite its value with the new value.
109.1075 +     *
109.1076 +     * <p> NOTE: HTTP requires all request properties which can
109.1077 +     * legally have multiple instances with the same key
109.1078 +     * to use a comma-seperated list syntax which enables multiple
109.1079 +     * properties to be appended into a single property.
109.1080 +     *
109.1081 +     * @param   key     the keyword by which the request is known
109.1082 +     *                  (e.g., "<code>Accept</code>").
109.1083 +     * @param   value   the value associated with it.
109.1084 +     * @throws IllegalStateException if already connected
109.1085 +     * @throws NullPointerException if key is <CODE>null</CODE>
109.1086 +     * @see #getRequestProperty(java.lang.String)
109.1087 +     */
109.1088 +    public void setRequestProperty(String key, String value) {
109.1089 +        if (connected)
109.1090 +            throw new IllegalStateException("Already connected");
109.1091 +        if (key == null)
109.1092 +            throw new NullPointerException ("key is null");
109.1093 +
109.1094 +        if (requests == null)
109.1095 +            requests = new MessageHeader();
109.1096 +
109.1097 +        requests.set(key, value);
109.1098 +    }
109.1099 +
109.1100 +    /**
109.1101 +     * Adds a general request property specified by a
109.1102 +     * key-value pair.  This method will not overwrite
109.1103 +     * existing values associated with the same key.
109.1104 +     *
109.1105 +     * @param   key     the keyword by which the request is known
109.1106 +     *                  (e.g., "<code>Accept</code>").
109.1107 +     * @param   value  the value associated with it.
109.1108 +     * @throws IllegalStateException if already connected
109.1109 +     * @throws NullPointerException if key is null
109.1110 +     * @see #getRequestProperties()
109.1111 +     * @since 1.4
109.1112 +     */
109.1113 +    public void addRequestProperty(String key, String value) {
109.1114 +        if (connected)
109.1115 +            throw new IllegalStateException("Already connected");
109.1116 +        if (key == null)
109.1117 +            throw new NullPointerException ("key is null");
109.1118 +
109.1119 +        if (requests == null)
109.1120 +            requests = new MessageHeader();
109.1121 +
109.1122 +        requests.add(key, value);
109.1123 +    }
109.1124 +
109.1125 +
109.1126 +    /**
109.1127 +     * Returns the value of the named general request property for this
109.1128 +     * connection.
109.1129 +     *
109.1130 +     * @param key the keyword by which the request is known (e.g., "Accept").
109.1131 +     * @return  the value of the named general request property for this
109.1132 +     *           connection. If key is null, then null is returned.
109.1133 +     * @throws IllegalStateException if already connected
109.1134 +     * @see #setRequestProperty(java.lang.String, java.lang.String)
109.1135 +     */
109.1136 +    public String getRequestProperty(String key) {
109.1137 +        if (connected)
109.1138 +            throw new IllegalStateException("Already connected");
109.1139 +
109.1140 +        if (requests == null)
109.1141 +            return null;
109.1142 +
109.1143 +        return requests.findValue(key);
109.1144 +    }
109.1145 +
109.1146 +    /**
109.1147 +     * Returns an unmodifiable Map of general request
109.1148 +     * properties for this connection. The Map keys
109.1149 +     * are Strings that represent the request-header
109.1150 +     * field names. Each Map value is a unmodifiable List
109.1151 +     * of Strings that represents the corresponding
109.1152 +     * field values.
109.1153 +     *
109.1154 +     * @return  a Map of the general request properties for this connection.
109.1155 +     * @throws IllegalStateException if already connected
109.1156 +     * @since 1.4
109.1157 +     */
109.1158 +    public Map<String,List<String>> getRequestProperties() {
109.1159 +        if (connected)
109.1160 +            throw new IllegalStateException("Already connected");
109.1161 +
109.1162 +        if (requests == null)
109.1163 +            return Collections.EMPTY_MAP;
109.1164 +
109.1165 +        return requests.getHeaders(null);
109.1166 +    }
109.1167 +
109.1168 +    /**
109.1169 +     * Sets the default value of a general request property. When a
109.1170 +     * <code>URLConnection</code> is created, it is initialized with
109.1171 +     * these properties.
109.1172 +     *
109.1173 +     * @param   key     the keyword by which the request is known
109.1174 +     *                  (e.g., "<code>Accept</code>").
109.1175 +     * @param   value   the value associated with the key.
109.1176 +     *
109.1177 +     * @see java.net.URLConnection#setRequestProperty(java.lang.String,java.lang.String)
109.1178 +     *
109.1179 +     * @deprecated The instance specific setRequestProperty method
109.1180 +     * should be used after an appropriate instance of URLConnection
109.1181 +     * is obtained. Invoking this method will have no effect.
109.1182 +     *
109.1183 +     * @see #getDefaultRequestProperty(java.lang.String)
109.1184 +     */
109.1185 +    @Deprecated
109.1186 +    public static void setDefaultRequestProperty(String key, String value) {
109.1187 +    }
109.1188 +
109.1189 +    /**
109.1190 +     * Returns the value of the default request property. Default request
109.1191 +     * properties are set for every connection.
109.1192 +     *
109.1193 +     * @param key the keyword by which the request is known (e.g., "Accept").
109.1194 +     * @return  the value of the default request property
109.1195 +     * for the specified key.
109.1196 +     *
109.1197 +     * @see java.net.URLConnection#getRequestProperty(java.lang.String)
109.1198 +     *
109.1199 +     * @deprecated The instance specific getRequestProperty method
109.1200 +     * should be used after an appropriate instance of URLConnection
109.1201 +     * is obtained.
109.1202 +     *
109.1203 +     * @see #setDefaultRequestProperty(java.lang.String, java.lang.String)
109.1204 +     */
109.1205 +    @Deprecated
109.1206 +    public static String getDefaultRequestProperty(String key) {
109.1207 +        return null;
109.1208 +    }
109.1209 +
109.1210 +    /**
109.1211 +     * The ContentHandler factory.
109.1212 +     */
109.1213 +    static ContentHandlerFactory factory;
109.1214 +
109.1215 +    /**
109.1216 +     * Sets the <code>ContentHandlerFactory</code> of an
109.1217 +     * application. It can be called at most once by an application.
109.1218 +     * <p>
109.1219 +     * The <code>ContentHandlerFactory</code> instance is used to
109.1220 +     * construct a content handler from a content type
109.1221 +     * <p>
109.1222 +     * If there is a security manager, this method first calls
109.1223 +     * the security manager's <code>checkSetFactory</code> method
109.1224 +     * to ensure the operation is allowed.
109.1225 +     * This could result in a SecurityException.
109.1226 +     *
109.1227 +     * @param      fac   the desired factory.
109.1228 +     * @exception  Error  if the factory has already been defined.
109.1229 +     * @exception  SecurityException  if a security manager exists and its
109.1230 +     *             <code>checkSetFactory</code> method doesn't allow the operation.
109.1231 +     * @see        java.net.ContentHandlerFactory
109.1232 +     * @see        java.net.URLConnection#getContent()
109.1233 +     * @see        SecurityManager#checkSetFactory
109.1234 +     */
109.1235 +    public static synchronized void setContentHandlerFactory(ContentHandlerFactory fac) {
109.1236 +        throw new SecurityException();
109.1237 +    }
109.1238 +
109.1239 +    private static Hashtable handlers = new Hashtable();
109.1240 +
109.1241 +    /**
109.1242 +     * Gets the Content Handler appropriate for this connection.
109.1243 +     * @param connection the connection to use.
109.1244 +     */
109.1245 +    synchronized ContentHandler getContentHandler()
109.1246 +    throws UnknownServiceException
109.1247 +    {
109.1248 +        String contentType = stripOffParameters(getContentType());
109.1249 +        ContentHandler handler = null;
109.1250 +        if (contentType == null)
109.1251 +            throw new UnknownServiceException("no content-type");
109.1252 +        try {
109.1253 +            handler = (ContentHandler) handlers.get(contentType);
109.1254 +            if (handler != null)
109.1255 +                return handler;
109.1256 +        } catch(Exception e) {
109.1257 +        }
109.1258 +
109.1259 +        if (factory != null)
109.1260 +            handler = factory.createContentHandler(contentType);
109.1261 +        if (handler == null) {
109.1262 +            try {
109.1263 +                handler = lookupContentHandlerClassFor(contentType);
109.1264 +            } catch(Exception e) {
109.1265 +                e.printStackTrace();
109.1266 +                handler = UnknownContentHandler.INSTANCE;
109.1267 +            }
109.1268 +            handlers.put(contentType, handler);
109.1269 +        }
109.1270 +        return handler;
109.1271 +    }
109.1272 +
109.1273 +    /*
109.1274 +     * Media types are in the format: type/subtype*(; parameter).
109.1275 +     * For looking up the content handler, we should ignore those
109.1276 +     * parameters.
109.1277 +     */
109.1278 +    private String stripOffParameters(String contentType)
109.1279 +    {
109.1280 +        if (contentType == null)
109.1281 +            return null;
109.1282 +        int index = contentType.indexOf(';');
109.1283 +
109.1284 +        if (index > 0)
109.1285 +            return contentType.substring(0, index);
109.1286 +        else
109.1287 +            return contentType;
109.1288 +    }
109.1289 +
109.1290 +    private static final String contentClassPrefix = "sun.net.www.content";
109.1291 +    private static final String contentPathProp = "java.content.handler.pkgs";
109.1292 +
109.1293 +    /**
109.1294 +     * Looks for a content handler in a user-defineable set of places.
109.1295 +     * By default it looks in sun.net.www.content, but users can define a
109.1296 +     * vertical-bar delimited set of class prefixes to search through in
109.1297 +     * addition by defining the java.content.handler.pkgs property.
109.1298 +     * The class name must be of the form:
109.1299 +     * <pre>
109.1300 +     *     {package-prefix}.{major}.{minor}
109.1301 +     * e.g.
109.1302 +     *     YoyoDyne.experimental.text.plain
109.1303 +     * </pre>
109.1304 +     */
109.1305 +    private ContentHandler lookupContentHandlerClassFor(String contentType)
109.1306 +        throws InstantiationException, IllegalAccessException, ClassNotFoundException {
109.1307 +        String contentHandlerClassName = typeToPackageName(contentType);
109.1308 +
109.1309 +        String contentHandlerPkgPrefixes =getContentHandlerPkgPrefixes();
109.1310 +
109.1311 +        StringTokenizer packagePrefixIter =
109.1312 +            new StringTokenizer(contentHandlerPkgPrefixes, "|");
109.1313 +
109.1314 +        while (packagePrefixIter.hasMoreTokens()) {
109.1315 +            String packagePrefix = packagePrefixIter.nextToken().trim();
109.1316 +
109.1317 +            try {
109.1318 +                String clsName = packagePrefix + "." + contentHandlerClassName;
109.1319 +                Class cls = null;
109.1320 +                try {
109.1321 +                    cls = Class.forName(clsName);
109.1322 +                } catch (ClassNotFoundException e) {
109.1323 +                    ClassLoader cl = ClassLoader.getSystemClassLoader();
109.1324 +                    if (cl != null) {
109.1325 +                        cls = cl.loadClass(clsName);
109.1326 +                    }
109.1327 +                }
109.1328 +                if (cls != null) {
109.1329 +                    ContentHandler handler =
109.1330 +                        (ContentHandler)cls.newInstance();
109.1331 +                    return handler;
109.1332 +                }
109.1333 +            } catch(Exception e) {
109.1334 +            }
109.1335 +        }
109.1336 +
109.1337 +        return UnknownContentHandler.INSTANCE;
109.1338 +    }
109.1339 +
109.1340 +    /**
109.1341 +     * Utility function to map a MIME content type into an equivalent
109.1342 +     * pair of class name components.  For example: "text/html" would
109.1343 +     * be returned as "text.html"
109.1344 +     */
109.1345 +    private String typeToPackageName(String contentType) {
109.1346 +        // make sure we canonicalize the class name: all lower case
109.1347 +        contentType = contentType.toLowerCase();
109.1348 +        int len = contentType.length();
109.1349 +        char nm[] = new char[len];
109.1350 +        contentType.getChars(0, len, nm, 0);
109.1351 +        for (int i = 0; i < len; i++) {
109.1352 +            char c = nm[i];
109.1353 +            if (c == '/') {
109.1354 +                nm[i] = '.';
109.1355 +            } else if (!('A' <= c && c <= 'Z' ||
109.1356 +                       'a' <= c && c <= 'z' ||
109.1357 +                       '0' <= c && c <= '9')) {
109.1358 +                nm[i] = '_';
109.1359 +            }
109.1360 +        }
109.1361 +        return new String(nm);
109.1362 +    }
109.1363 +
109.1364 +
109.1365 +    /**
109.1366 +     * Returns a vertical bar separated list of package prefixes for potential
109.1367 +     * content handlers.  Tries to get the java.content.handler.pkgs property
109.1368 +     * to use as a set of package prefixes to search.  Whether or not
109.1369 +     * that property has been defined, the sun.net.www.content is always
109.1370 +     * the last one on the returned package list.
109.1371 +     */
109.1372 +    private String getContentHandlerPkgPrefixes() {
109.1373 +        String packagePrefixList = "";
109.1374 +        
109.1375 +        if (packagePrefixList != "") {
109.1376 +            packagePrefixList += "|";
109.1377 +        }
109.1378 +
109.1379 +        return packagePrefixList + contentClassPrefix;
109.1380 +    }
109.1381 +
109.1382 +    /**
109.1383 +     * Tries to determine the content type of an object, based
109.1384 +     * on the specified "file" component of a URL.
109.1385 +     * This is a convenience method that can be used by
109.1386 +     * subclasses that override the <code>getContentType</code> method.
109.1387 +     *
109.1388 +     * @param   fname   a filename.
109.1389 +     * @return  a guess as to what the content type of the object is,
109.1390 +     *          based upon its file name.
109.1391 +     * @see     java.net.URLConnection#getContentType()
109.1392 +     */
109.1393 +    public static String guessContentTypeFromName(String fname) {
109.1394 +        return getFileNameMap().getContentTypeFor(fname);
109.1395 +    }
109.1396 +
109.1397 +    /**
109.1398 +     * Tries to determine the type of an input stream based on the
109.1399 +     * characters at the beginning of the input stream. This method can
109.1400 +     * be used by subclasses that override the
109.1401 +     * <code>getContentType</code> method.
109.1402 +     * <p>
109.1403 +     * Ideally, this routine would not be needed. But many
109.1404 +     * <code>http</code> servers return the incorrect content type; in
109.1405 +     * addition, there are many nonstandard extensions. Direct inspection
109.1406 +     * of the bytes to determine the content type is often more accurate
109.1407 +     * than believing the content type claimed by the <code>http</code> server.
109.1408 +     *
109.1409 +     * @param      is   an input stream that supports marks.
109.1410 +     * @return     a guess at the content type, or <code>null</code> if none
109.1411 +     *             can be determined.
109.1412 +     * @exception  IOException  if an I/O error occurs while reading the
109.1413 +     *               input stream.
109.1414 +     * @see        java.io.InputStream#mark(int)
109.1415 +     * @see        java.io.InputStream#markSupported()
109.1416 +     * @see        java.net.URLConnection#getContentType()
109.1417 +     */
109.1418 +    static public String guessContentTypeFromStream(InputStream is)
109.1419 +                        throws IOException {
109.1420 +        // If we can't read ahead safely, just give up on guessing
109.1421 +        if (!is.markSupported())
109.1422 +            return null;
109.1423 +
109.1424 +        is.mark(16);
109.1425 +        int c1 = is.read();
109.1426 +        int c2 = is.read();
109.1427 +        int c3 = is.read();
109.1428 +        int c4 = is.read();
109.1429 +        int c5 = is.read();
109.1430 +        int c6 = is.read();
109.1431 +        int c7 = is.read();
109.1432 +        int c8 = is.read();
109.1433 +        int c9 = is.read();
109.1434 +        int c10 = is.read();
109.1435 +        int c11 = is.read();
109.1436 +        int c12 = is.read();
109.1437 +        int c13 = is.read();
109.1438 +        int c14 = is.read();
109.1439 +        int c15 = is.read();
109.1440 +        int c16 = is.read();
109.1441 +        is.reset();
109.1442 +
109.1443 +        if (c1 == 0xCA && c2 == 0xFE && c3 == 0xBA && c4 == 0xBE) {
109.1444 +            return "application/java-vm";
109.1445 +        }
109.1446 +
109.1447 +        if (c1 == 0xAC && c2 == 0xED) {
109.1448 +            // next two bytes are version number, currently 0x00 0x05
109.1449 +            return "application/x-java-serialized-object";
109.1450 +        }
109.1451 +
109.1452 +        if (c1 == '<') {
109.1453 +            if (c2 == '!'
109.1454 +                || ((c2 == 'h' && (c3 == 't' && c4 == 'm' && c5 == 'l' ||
109.1455 +                                   c3 == 'e' && c4 == 'a' && c5 == 'd') ||
109.1456 +                (c2 == 'b' && c3 == 'o' && c4 == 'd' && c5 == 'y'))) ||
109.1457 +                ((c2 == 'H' && (c3 == 'T' && c4 == 'M' && c5 == 'L' ||
109.1458 +                                c3 == 'E' && c4 == 'A' && c5 == 'D') ||
109.1459 +                (c2 == 'B' && c3 == 'O' && c4 == 'D' && c5 == 'Y')))) {
109.1460 +                return "text/html";
109.1461 +            }
109.1462 +
109.1463 +            if (c2 == '?' && c3 == 'x' && c4 == 'm' && c5 == 'l' && c6 == ' ') {
109.1464 +                return "application/xml";
109.1465 +            }
109.1466 +        }
109.1467 +
109.1468 +        // big and little (identical) endian UTF-8 encodings, with BOM
109.1469 +        if (c1 == 0xef &&  c2 == 0xbb &&  c3 == 0xbf) {
109.1470 +            if (c4 == '<' &&  c5 == '?' &&  c6 == 'x') {
109.1471 +                return "application/xml";
109.1472 +            }
109.1473 +        }
109.1474 +
109.1475 +        // big and little endian UTF-16 encodings, with byte order mark
109.1476 +        if (c1 == 0xfe && c2 == 0xff) {
109.1477 +            if (c3 == 0 && c4 == '<' && c5 == 0 && c6 == '?' &&
109.1478 +                c7 == 0 && c8 == 'x') {
109.1479 +                return "application/xml";
109.1480 +            }
109.1481 +        }
109.1482 +
109.1483 +        if (c1 == 0xff && c2 == 0xfe) {
109.1484 +            if (c3 == '<' && c4 == 0 && c5 == '?' && c6 == 0 &&
109.1485 +                c7 == 'x' && c8 == 0) {
109.1486 +                return "application/xml";
109.1487 +            }
109.1488 +        }
109.1489 +
109.1490 +        // big and little endian UTF-32 encodings, with BOM
109.1491 +        if (c1 == 0x00 &&  c2 == 0x00 &&  c3 == 0xfe &&  c4 == 0xff) {
109.1492 +            if (c5  == 0 && c6  == 0 && c7  == 0 && c8  == '<' &&
109.1493 +                c9  == 0 && c10 == 0 && c11 == 0 && c12 == '?' &&
109.1494 +                c13 == 0 && c14 == 0 && c15 == 0 && c16 == 'x') {
109.1495 +                return "application/xml";
109.1496 +            }
109.1497 +        }
109.1498 +
109.1499 +        if (c1 == 0xff &&  c2 == 0xfe &&  c3 == 0x00 &&  c4 == 0x00) {
109.1500 +            if (c5  == '<' && c6  == 0 && c7  == 0 && c8  == 0 &&
109.1501 +                c9  == '?' && c10 == 0 && c11 == 0 && c12 == 0 &&
109.1502 +                c13 == 'x' && c14 == 0 && c15 == 0 && c16 == 0) {
109.1503 +                return "application/xml";
109.1504 +            }
109.1505 +        }
109.1506 +
109.1507 +        if (c1 == 'G' && c2 == 'I' && c3 == 'F' && c4 == '8') {
109.1508 +            return "image/gif";
109.1509 +        }
109.1510 +
109.1511 +        if (c1 == '#' && c2 == 'd' && c3 == 'e' && c4 == 'f') {
109.1512 +            return "image/x-bitmap";
109.1513 +        }
109.1514 +
109.1515 +        if (c1 == '!' && c2 == ' ' && c3 == 'X' && c4 == 'P' &&
109.1516 +                        c5 == 'M' && c6 == '2') {
109.1517 +            return "image/x-pixmap";
109.1518 +        }
109.1519 +
109.1520 +        if (c1 == 137 && c2 == 80 && c3 == 78 &&
109.1521 +                c4 == 71 && c5 == 13 && c6 == 10 &&
109.1522 +                c7 == 26 && c8 == 10) {
109.1523 +            return "image/png";
109.1524 +        }
109.1525 +
109.1526 +        if (c1 == 0xFF && c2 == 0xD8 && c3 == 0xFF) {
109.1527 +            if (c4 == 0xE0) {
109.1528 +                return "image/jpeg";
109.1529 +            }
109.1530 +
109.1531 +            /**
109.1532 +             * File format used by digital cameras to store images.
109.1533 +             * Exif Format can be read by any application supporting
109.1534 +             * JPEG. Exif Spec can be found at:
109.1535 +             * http://www.pima.net/standards/it10/PIMA15740/Exif_2-1.PDF
109.1536 +             */
109.1537 +            if ((c4 == 0xE1) &&
109.1538 +                (c7 == 'E' && c8 == 'x' && c9 == 'i' && c10 =='f' &&
109.1539 +                 c11 == 0)) {
109.1540 +                return "image/jpeg";
109.1541 +            }
109.1542 +
109.1543 +            if (c4 == 0xEE) {
109.1544 +                return "image/jpg";
109.1545 +            }
109.1546 +        }
109.1547 +
109.1548 +        if (c1 == 0xD0 && c2 == 0xCF && c3 == 0x11 && c4 == 0xE0 &&
109.1549 +            c5 == 0xA1 && c6 == 0xB1 && c7 == 0x1A && c8 == 0xE1) {
109.1550 +
109.1551 +            /* Above is signature of Microsoft Structured Storage.
109.1552 +             * Below this, could have tests for various SS entities.
109.1553 +             * For now, just test for FlashPix.
109.1554 +             */
109.1555 +            if (checkfpx(is)) {
109.1556 +                return "image/vnd.fpx";
109.1557 +            }
109.1558 +        }
109.1559 +
109.1560 +        if (c1 == 0x2E && c2 == 0x73 && c3 == 0x6E && c4 == 0x64) {
109.1561 +            return "audio/basic";  // .au format, big endian
109.1562 +        }
109.1563 +
109.1564 +        if (c1 == 0x64 && c2 == 0x6E && c3 == 0x73 && c4 == 0x2E) {
109.1565 +            return "audio/basic";  // .au format, little endian
109.1566 +        }
109.1567 +
109.1568 +        if (c1 == 'R' && c2 == 'I' && c3 == 'F' && c4 == 'F') {
109.1569 +            /* I don't know if this is official but evidence
109.1570 +             * suggests that .wav files start with "RIFF" - brown
109.1571 +             */
109.1572 +            return "audio/x-wav";
109.1573 +        }
109.1574 +        return null;
109.1575 +    }
109.1576 +
109.1577 +    /**
109.1578 +     * Check for FlashPix image data in InputStream is.  Return true if
109.1579 +     * the stream has FlashPix data, false otherwise.  Before calling this
109.1580 +     * method, the stream should have already been checked to be sure it
109.1581 +     * contains Microsoft Structured Storage data.
109.1582 +     */
109.1583 +    static private boolean checkfpx(InputStream is) throws IOException {
109.1584 +
109.1585 +        /* Test for FlashPix image data in Microsoft Structured Storage format.
109.1586 +         * In general, should do this with calls to an SS implementation.
109.1587 +         * Lacking that, need to dig via offsets to get to the FlashPix
109.1588 +         * ClassID.  Details:
109.1589 +         *
109.1590 +         * Offset to Fpx ClsID from beginning of stream should be:
109.1591 +         *
109.1592 +         * FpxClsidOffset = rootEntryOffset + clsidOffset
109.1593 +         *
109.1594 +         * where: clsidOffset = 0x50.
109.1595 +         *        rootEntryOffset = headerSize + sectorSize*sectDirStart
109.1596 +         *                          + 128*rootEntryDirectory
109.1597 +         *
109.1598 +         *        where:  headerSize = 0x200 (always)
109.1599 +         *                sectorSize = 2 raised to power of uSectorShift,
109.1600 +         *                             which is found in the header at
109.1601 +         *                             offset 0x1E.
109.1602 +         *                sectDirStart = found in the header at offset 0x30.
109.1603 +         *                rootEntryDirectory = in general, should search for
109.1604 +         *                                     directory labelled as root.
109.1605 +         *                                     We will assume value of 0 (i.e.,
109.1606 +         *                                     rootEntry is in first directory)
109.1607 +         */
109.1608 +
109.1609 +        // Mark the stream so we can reset it. 0x100 is enough for the first
109.1610 +        // few reads, but the mark will have to be reset and set again once
109.1611 +        // the offset to the root directory entry is computed. That offset
109.1612 +        // can be very large and isn't know until the stream has been read from
109.1613 +        is.mark(0x100);
109.1614 +
109.1615 +        // Get the byte ordering located at 0x1E. 0xFE is Intel,
109.1616 +        // 0xFF is other
109.1617 +        long toSkip = (long)0x1C;
109.1618 +        long posn;
109.1619 +
109.1620 +        if ((posn = skipForward(is, toSkip)) < toSkip) {
109.1621 +          is.reset();
109.1622 +          return false;
109.1623 +        }
109.1624 +
109.1625 +        int c[] = new int[16];
109.1626 +        if (readBytes(c, 2, is) < 0) {
109.1627 +            is.reset();
109.1628 +            return false;
109.1629 +        }
109.1630 +
109.1631 +        int byteOrder = c[0];
109.1632 +
109.1633 +        posn+=2;
109.1634 +        int uSectorShift;
109.1635 +        if (readBytes(c, 2, is) < 0) {
109.1636 +            is.reset();
109.1637 +            return false;
109.1638 +        }
109.1639 +
109.1640 +        if(byteOrder == 0xFE) {
109.1641 +            uSectorShift = c[0];
109.1642 +            uSectorShift += c[1] << 8;
109.1643 +        }
109.1644 +        else {
109.1645 +            uSectorShift = c[0] << 8;
109.1646 +            uSectorShift += c[1];
109.1647 +        }
109.1648 +
109.1649 +        posn += 2;
109.1650 +        toSkip = (long)0x30 - posn;
109.1651 +        long skipped = 0;
109.1652 +        if ((skipped = skipForward(is, toSkip)) < toSkip) {
109.1653 +          is.reset();
109.1654 +          return false;
109.1655 +        }
109.1656 +        posn += skipped;
109.1657 +
109.1658 +        if (readBytes(c, 4, is) < 0) {
109.1659 +            is.reset();
109.1660 +            return false;
109.1661 +        }
109.1662 +
109.1663 +        int sectDirStart;
109.1664 +        if(byteOrder == 0xFE) {
109.1665 +            sectDirStart = c[0];
109.1666 +            sectDirStart += c[1] << 8;
109.1667 +            sectDirStart += c[2] << 16;
109.1668 +            sectDirStart += c[3] << 24;
109.1669 +        } else {
109.1670 +            sectDirStart =  c[0] << 24;
109.1671 +            sectDirStart += c[1] << 16;
109.1672 +            sectDirStart += c[2] << 8;
109.1673 +            sectDirStart += c[3];
109.1674 +        }
109.1675 +        posn += 4;
109.1676 +        is.reset(); // Reset back to the beginning
109.1677 +
109.1678 +        toSkip = 0x200L + (long)(1<<uSectorShift)*sectDirStart + 0x50L;
109.1679 +
109.1680 +        // Sanity check!
109.1681 +        if (toSkip < 0) {
109.1682 +            return false;
109.1683 +        }
109.1684 +
109.1685 +        /*
109.1686 +         * How far can we skip? Is there any performance problem here?
109.1687 +         * This skip can be fairly long, at least 0x4c650 in at least
109.1688 +         * one case. Have to assume that the skip will fit in an int.
109.1689 +         * Leave room to read whole root dir
109.1690 +         */
109.1691 +        is.mark((int)toSkip+0x30);
109.1692 +
109.1693 +        if ((skipForward(is, toSkip)) < toSkip) {
109.1694 +            is.reset();
109.1695 +            return false;
109.1696 +        }
109.1697 +
109.1698 +        /* should be at beginning of ClassID, which is as follows
109.1699 +         * (in Intel byte order):
109.1700 +         *    00 67 61 56 54 C1 CE 11 85 53 00 AA 00 A1 F9 5B
109.1701 +         *
109.1702 +         * This is stored from Windows as long,short,short,char[8]
109.1703 +         * so for byte order changes, the order only changes for
109.1704 +         * the first 8 bytes in the ClassID.
109.1705 +         *
109.1706 +         * Test against this, ignoring second byte (Intel) since
109.1707 +         * this could change depending on part of Fpx file we have.
109.1708 +         */
109.1709 +
109.1710 +        if (readBytes(c, 16, is) < 0) {
109.1711 +            is.reset();
109.1712 +            return false;
109.1713 +        }
109.1714 +
109.1715 +        // intel byte order
109.1716 +        if (byteOrder == 0xFE &&
109.1717 +            c[0] == 0x00 && c[2] == 0x61 && c[3] == 0x56 &&
109.1718 +            c[4] == 0x54 && c[5] == 0xC1 && c[6] == 0xCE &&
109.1719 +            c[7] == 0x11 && c[8] == 0x85 && c[9] == 0x53 &&
109.1720 +            c[10]== 0x00 && c[11]== 0xAA && c[12]== 0x00 &&
109.1721 +            c[13]== 0xA1 && c[14]== 0xF9 && c[15]== 0x5B) {
109.1722 +            is.reset();
109.1723 +            return true;
109.1724 +        }
109.1725 +
109.1726 +        // non-intel byte order
109.1727 +        else if (c[3] == 0x00 && c[1] == 0x61 && c[0] == 0x56 &&
109.1728 +            c[5] == 0x54 && c[4] == 0xC1 && c[7] == 0xCE &&
109.1729 +            c[6] == 0x11 && c[8] == 0x85 && c[9] == 0x53 &&
109.1730 +            c[10]== 0x00 && c[11]== 0xAA && c[12]== 0x00 &&
109.1731 +            c[13]== 0xA1 && c[14]== 0xF9 && c[15]== 0x5B) {
109.1732 +            is.reset();
109.1733 +            return true;
109.1734 +        }
109.1735 +        is.reset();
109.1736 +        return false;
109.1737 +    }
109.1738 +
109.1739 +    /**
109.1740 +     * Tries to read the specified number of bytes from the stream
109.1741 +     * Returns -1, If EOF is reached before len bytes are read, returns 0
109.1742 +     * otherwise
109.1743 +     */
109.1744 +    static private int readBytes(int c[], int len, InputStream is)
109.1745 +                throws IOException {
109.1746 +
109.1747 +        byte buf[] = new byte[len];
109.1748 +        if (is.read(buf, 0, len) < len) {
109.1749 +            return -1;
109.1750 +        }
109.1751 +
109.1752 +        // fill the passed in int array
109.1753 +        for (int i = 0; i < len; i++) {
109.1754 +             c[i] = buf[i] & 0xff;
109.1755 +        }
109.1756 +        return 0;
109.1757 +    }
109.1758 +
109.1759 +
109.1760 +    /**
109.1761 +     * Skips through the specified number of bytes from the stream
109.1762 +     * until either EOF is reached, or the specified
109.1763 +     * number of bytes have been skipped
109.1764 +     */
109.1765 +    static private long skipForward(InputStream is, long toSkip)
109.1766 +                throws IOException {
109.1767 +
109.1768 +        long eachSkip = 0;
109.1769 +        long skipped = 0;
109.1770 +
109.1771 +        while (skipped != toSkip) {
109.1772 +            eachSkip = is.skip(toSkip - skipped);
109.1773 +
109.1774 +            // check if EOF is reached
109.1775 +            if (eachSkip <= 0) {
109.1776 +                if (is.read() == -1) {
109.1777 +                    return skipped ;
109.1778 +                } else {
109.1779 +                    skipped++;
109.1780 +                }
109.1781 +            }
109.1782 +            skipped += eachSkip;
109.1783 +        }
109.1784 +        return skipped;
109.1785 +    }
109.1786 +
109.1787 +}
109.1788 +
109.1789 +
109.1790 +class UnknownContentHandler extends ContentHandler {
109.1791 +    static final ContentHandler INSTANCE = new UnknownContentHandler();
109.1792 +
109.1793 +    public Object getContent(URLConnection uc) throws IOException {
109.1794 +        return uc.getInputStream();
109.1795 +    }
109.1796 +}
109.1797 +
109.1798 +/** An RFC 844 or MIME message header.  Includes methods
109.1799 +    for parsing headers from incoming streams, fetching
109.1800 +    values, setting values, and printing headers.
109.1801 +    Key values of null are legal: they indicate lines in
109.1802 +    the header that don't have a valid key, but do have
109.1803 +    a value (this isn't legal according to the standard,
109.1804 +    but lines like this are everywhere). */
109.1805 +class MessageHeader {
109.1806 +    private String keys[];
109.1807 +    private String values[];
109.1808 +    private int nkeys;
109.1809 +
109.1810 +    public MessageHeader () {
109.1811 +        grow();
109.1812 +    }
109.1813 +
109.1814 +    public MessageHeader (InputStream is) throws java.io.IOException {
109.1815 +        parseHeader(is);
109.1816 +    }
109.1817 +
109.1818 +    /**
109.1819 +     * Reset a message header (all key/values removed)
109.1820 +     */
109.1821 +    public synchronized void reset() {
109.1822 +        keys = null;
109.1823 +        values = null;
109.1824 +        nkeys = 0;
109.1825 +        grow();
109.1826 +    }
109.1827 +
109.1828 +    /**
109.1829 +     * Find the value that corresponds to this key.
109.1830 +     * It finds only the first occurrence of the key.
109.1831 +     * @param k the key to find.
109.1832 +     * @return null if not found.
109.1833 +     */
109.1834 +    public synchronized String findValue(String k) {
109.1835 +        if (k == null) {
109.1836 +            for (int i = nkeys; --i >= 0;)
109.1837 +                if (keys[i] == null)
109.1838 +                    return values[i];
109.1839 +        } else
109.1840 +            for (int i = nkeys; --i >= 0;) {
109.1841 +                if (k.equalsIgnoreCase(keys[i]))
109.1842 +                    return values[i];
109.1843 +            }
109.1844 +        return null;
109.1845 +    }
109.1846 +
109.1847 +    // return the location of the key
109.1848 +    public synchronized int getKey(String k) {
109.1849 +        for (int i = nkeys; --i >= 0;)
109.1850 +            if ((keys[i] == k) ||
109.1851 +                (k != null && k.equalsIgnoreCase(keys[i])))
109.1852 +                return i;
109.1853 +        return -1;
109.1854 +    }
109.1855 +
109.1856 +    public synchronized String getKey(int n) {
109.1857 +        if (n < 0 || n >= nkeys) return null;
109.1858 +        return keys[n];
109.1859 +    }
109.1860 +
109.1861 +    public synchronized String getValue(int n) {
109.1862 +        if (n < 0 || n >= nkeys) return null;
109.1863 +        return values[n];
109.1864 +    }
109.1865 +
109.1866 +    /** Deprecated: Use multiValueIterator() instead.
109.1867 +     *
109.1868 +     *  Find the next value that corresponds to this key.
109.1869 +     *  It finds the first value that follows v. To iterate
109.1870 +     *  over all the values of a key use:
109.1871 +     *  <pre>
109.1872 +     *          for(String v=h.findValue(k); v!=null; v=h.findNextValue(k, v)) {
109.1873 +     *              ...
109.1874 +     *          }
109.1875 +     *  </pre>
109.1876 +     */
109.1877 +    public synchronized String findNextValue(String k, String v) {
109.1878 +        boolean foundV = false;
109.1879 +        if (k == null) {
109.1880 +            for (int i = nkeys; --i >= 0;)
109.1881 +                if (keys[i] == null)
109.1882 +                    if (foundV)
109.1883 +                        return values[i];
109.1884 +                    else if (values[i] == v)
109.1885 +                        foundV = true;
109.1886 +        } else
109.1887 +            for (int i = nkeys; --i >= 0;)
109.1888 +                if (k.equalsIgnoreCase(keys[i]))
109.1889 +                    if (foundV)
109.1890 +                        return values[i];
109.1891 +                    else if (values[i] == v)
109.1892 +                        foundV = true;
109.1893 +        return null;
109.1894 +    }
109.1895 +
109.1896 +    class HeaderIterator implements Iterator<String> {
109.1897 +        int index = 0;
109.1898 +        int next = -1;
109.1899 +        String key;
109.1900 +        boolean haveNext = false;
109.1901 +        Object lock;
109.1902 +
109.1903 +        public HeaderIterator (String k, Object lock) {
109.1904 +            key = k;
109.1905 +            this.lock = lock;
109.1906 +        }
109.1907 +        public boolean hasNext () {
109.1908 +            synchronized (lock) {
109.1909 +                if (haveNext) {
109.1910 +                    return true;
109.1911 +                }
109.1912 +                while (index < nkeys) {
109.1913 +                    if (key.equalsIgnoreCase (keys[index])) {
109.1914 +                        haveNext = true;
109.1915 +                        next = index++;
109.1916 +                        return true;
109.1917 +                    }
109.1918 +                    index ++;
109.1919 +                }
109.1920 +                return false;
109.1921 +            }
109.1922 +        }
109.1923 +        public String next() {
109.1924 +            synchronized (lock) {
109.1925 +                if (haveNext) {
109.1926 +                    haveNext = false;
109.1927 +                    return values [next];
109.1928 +                }
109.1929 +                if (hasNext()) {
109.1930 +                    return next();
109.1931 +                } else {
109.1932 +                    throw new NoSuchElementException ("No more elements");
109.1933 +                }
109.1934 +            }
109.1935 +        }
109.1936 +        public void remove () {
109.1937 +            throw new UnsupportedOperationException ("remove not allowed");
109.1938 +        }
109.1939 +    }
109.1940 +
109.1941 +    /**
109.1942 +     * return an Iterator that returns all values of a particular
109.1943 +     * key in sequence
109.1944 +     */
109.1945 +    public Iterator<String> multiValueIterator (String k) {
109.1946 +        return new HeaderIterator (k, this);
109.1947 +    }
109.1948 +
109.1949 +    public synchronized Map<String, List<String>> getHeaders() {
109.1950 +        return getHeaders(null);
109.1951 +    }
109.1952 +
109.1953 +    public synchronized Map<String, List<String>> getHeaders(String[] excludeList) {
109.1954 +        return filterAndAddHeaders(excludeList, null);
109.1955 +    }
109.1956 +
109.1957 +    public synchronized Map<String, List<String>> filterAndAddHeaders(String[] excludeList, Map<String, List<String>>  include) {
109.1958 +        boolean skipIt = false;
109.1959 +        Map<String, List<String>> m = new HashMap<String, List<String>>();
109.1960 +        for (int i = nkeys; --i >= 0;) {
109.1961 +            if (excludeList != null) {
109.1962 +                // check if the key is in the excludeList.
109.1963 +                // if so, don't include it in the Map.
109.1964 +                for (int j = 0; j < excludeList.length; j++) {
109.1965 +                    if ((excludeList[j] != null) &&
109.1966 +                        (excludeList[j].equalsIgnoreCase(keys[i]))) {
109.1967 +                        skipIt = true;
109.1968 +                        break;
109.1969 +                    }
109.1970 +                }
109.1971 +            }
109.1972 +            if (!skipIt) {
109.1973 +                List<String> l = m.get(keys[i]);
109.1974 +                if (l == null) {
109.1975 +                    l = new ArrayList<String>();
109.1976 +                    m.put(keys[i], l);
109.1977 +                }
109.1978 +                l.add(values[i]);
109.1979 +            } else {
109.1980 +                // reset the flag
109.1981 +                skipIt = false;
109.1982 +            }
109.1983 +        }
109.1984 +
109.1985 +        if (include != null) {
109.1986 +            Iterator entries = include.entrySet().iterator();
109.1987 +            while (entries.hasNext()) {
109.1988 +                Map.Entry entry = (Map.Entry)entries.next();
109.1989 +                List l = (List)m.get(entry.getKey());
109.1990 +                if (l == null) {
109.1991 +                    l = new ArrayList();
109.1992 +                    m.put((String)entry.getKey(), l);
109.1993 +                }
109.1994 +                l.add(entry.getValue());
109.1995 +            }
109.1996 +        }
109.1997 +
109.1998 +        for (String key : m.keySet()) {
109.1999 +            m.put(key, Collections.unmodifiableList(m.get(key)));
109.2000 +        }
109.2001 +
109.2002 +        return Collections.unmodifiableMap(m);
109.2003 +    }
109.2004 +
109.2005 +    /** Prints the key-value pairs represented by this
109.2006 +        header.  Also prints the RFC required blank line
109.2007 +        at the end. Omits pairs with a null key. */
109.2008 +    public synchronized void print(PrintStream p) {
109.2009 +        for (int i = 0; i < nkeys; i++)
109.2010 +            if (keys[i] != null) {
109.2011 +                p.print(keys[i] +
109.2012 +                    (values[i] != null ? ": "+values[i]: "") + "\r\n");
109.2013 +            }
109.2014 +        p.print("\r\n");
109.2015 +        p.flush();
109.2016 +    }
109.2017 +
109.2018 +    /** Adds a key value pair to the end of the
109.2019 +        header.  Duplicates are allowed */
109.2020 +    public synchronized void add(String k, String v) {
109.2021 +        grow();
109.2022 +        keys[nkeys] = k;
109.2023 +        values[nkeys] = v;
109.2024 +        nkeys++;
109.2025 +    }
109.2026 +
109.2027 +    /** Prepends a key value pair to the beginning of the
109.2028 +        header.  Duplicates are allowed */
109.2029 +    public synchronized void prepend(String k, String v) {
109.2030 +        grow();
109.2031 +        for (int i = nkeys; i > 0; i--) {
109.2032 +            keys[i] = keys[i-1];
109.2033 +            values[i] = values[i-1];
109.2034 +        }
109.2035 +        keys[0] = k;
109.2036 +        values[0] = v;
109.2037 +        nkeys++;
109.2038 +    }
109.2039 +
109.2040 +    /** Overwrite the previous key/val pair at location 'i'
109.2041 +     * with the new k/v.  If the index didn't exist before
109.2042 +     * the key/val is simply tacked onto the end.
109.2043 +     */
109.2044 +
109.2045 +    public synchronized void set(int i, String k, String v) {
109.2046 +        grow();
109.2047 +        if (i < 0) {
109.2048 +            return;
109.2049 +        } else if (i >= nkeys) {
109.2050 +            add(k, v);
109.2051 +        } else {
109.2052 +            keys[i] = k;
109.2053 +            values[i] = v;
109.2054 +        }
109.2055 +    }
109.2056 +
109.2057 +
109.2058 +    /** grow the key/value arrays as needed */
109.2059 +
109.2060 +    private void grow() {
109.2061 +        if (keys == null || nkeys >= keys.length) {
109.2062 +            String[] nk = new String[nkeys + 4];
109.2063 +            String[] nv = new String[nkeys + 4];
109.2064 +            if (keys != null)
109.2065 +                System.arraycopy(keys, 0, nk, 0, nkeys);
109.2066 +            if (values != null)
109.2067 +                System.arraycopy(values, 0, nv, 0, nkeys);
109.2068 +            keys = nk;
109.2069 +            values = nv;
109.2070 +        }
109.2071 +    }
109.2072 +
109.2073 +    /**
109.2074 +     * Remove the key from the header. If there are multiple values under
109.2075 +     * the same key, they are all removed.
109.2076 +     * Nothing is done if the key doesn't exist.
109.2077 +     * After a remove, the other pairs' order are not changed.
109.2078 +     * @param k the key to remove
109.2079 +     */
109.2080 +    public synchronized void remove(String k) {
109.2081 +        if(k == null) {
109.2082 +            for (int i = 0; i < nkeys; i++) {
109.2083 +                while (keys[i] == null && i < nkeys) {
109.2084 +                    for(int j=i; j<nkeys-1; j++) {
109.2085 +                        keys[j] = keys[j+1];
109.2086 +                        values[j] = values[j+1];
109.2087 +                    }
109.2088 +                    nkeys--;
109.2089 +                }
109.2090 +            }
109.2091 +        } else {
109.2092 +            for (int i = 0; i < nkeys; i++) {
109.2093 +                while (k.equalsIgnoreCase(keys[i]) && i < nkeys) {
109.2094 +                    for(int j=i; j<nkeys-1; j++) {
109.2095 +                        keys[j] = keys[j+1];
109.2096 +                        values[j] = values[j+1];
109.2097 +                    }
109.2098 +                    nkeys--;
109.2099 +                }
109.2100 +            }
109.2101 +        }
109.2102 +    }
109.2103 +
109.2104 +    /** Sets the value of a key.  If the key already
109.2105 +        exists in the header, it's value will be
109.2106 +        changed.  Otherwise a new key/value pair will
109.2107 +        be added to the end of the header. */
109.2108 +    public synchronized void set(String k, String v) {
109.2109 +        for (int i = nkeys; --i >= 0;)
109.2110 +            if (k.equalsIgnoreCase(keys[i])) {
109.2111 +                values[i] = v;
109.2112 +                return;
109.2113 +            }
109.2114 +        add(k, v);
109.2115 +    }
109.2116 +
109.2117 +    /** Set's the value of a key only if there is no
109.2118 +     *  key with that value already.
109.2119 +     */
109.2120 +
109.2121 +    public synchronized void setIfNotSet(String k, String v) {
109.2122 +        if (findValue(k) == null) {
109.2123 +            add(k, v);
109.2124 +        }
109.2125 +    }
109.2126 +
109.2127 +    /** Convert a message-id string to canonical form (strips off
109.2128 +        leading and trailing <>s) */
109.2129 +    public static String canonicalID(String id) {
109.2130 +        if (id == null)
109.2131 +            return "";
109.2132 +        int st = 0;
109.2133 +        int len = id.length();
109.2134 +        boolean substr = false;
109.2135 +        int c;
109.2136 +        while (st < len && ((c = id.charAt(st)) == '<' ||
109.2137 +                            c <= ' ')) {
109.2138 +            st++;
109.2139 +            substr = true;
109.2140 +        }
109.2141 +        while (st < len && ((c = id.charAt(len - 1)) == '>' ||
109.2142 +                            c <= ' ')) {
109.2143 +            len--;
109.2144 +            substr = true;
109.2145 +        }
109.2146 +        return substr ? id.substring(st, len) : id;
109.2147 +    }
109.2148 +
109.2149 +    /** Parse a MIME header from an input stream. */
109.2150 +    public void parseHeader(InputStream is) throws java.io.IOException {
109.2151 +        synchronized (this) {
109.2152 +            nkeys = 0;
109.2153 +        }
109.2154 +        mergeHeader(is);
109.2155 +    }
109.2156 +
109.2157 +    /** Parse and merge a MIME header from an input stream. */
109.2158 +    public void mergeHeader(InputStream is) throws java.io.IOException {
109.2159 +        if (is == null)
109.2160 +            return;
109.2161 +        char s[] = new char[10];
109.2162 +        int firstc = is.read();
109.2163 +        while (firstc != '\n' && firstc != '\r' && firstc >= 0) {
109.2164 +            int len = 0;
109.2165 +            int keyend = -1;
109.2166 +            int c;
109.2167 +            boolean inKey = firstc > ' ';
109.2168 +            s[len++] = (char) firstc;
109.2169 +    parseloop:{
109.2170 +                while ((c = is.read()) >= 0) {
109.2171 +                    switch (c) {
109.2172 +                      case ':':
109.2173 +                        if (inKey && len > 0)
109.2174 +                            keyend = len;
109.2175 +                        inKey = false;
109.2176 +                        break;
109.2177 +                      case '\t':
109.2178 +                        c = ' ';
109.2179 +                      case ' ':
109.2180 +                        inKey = false;
109.2181 +                        break;
109.2182 +                      case '\r':
109.2183 +                      case '\n':
109.2184 +                        firstc = is.read();
109.2185 +                        if (c == '\r' && firstc == '\n') {
109.2186 +                            firstc = is.read();
109.2187 +                            if (firstc == '\r')
109.2188 +                                firstc = is.read();
109.2189 +                        }
109.2190 +                        if (firstc == '\n' || firstc == '\r' || firstc > ' ')
109.2191 +                            break parseloop;
109.2192 +                        /* continuation */
109.2193 +                        c = ' ';
109.2194 +                        break;
109.2195 +                    }
109.2196 +                    if (len >= s.length) {
109.2197 +                        char ns[] = new char[s.length * 2];
109.2198 +                        System.arraycopy(s, 0, ns, 0, len);
109.2199 +                        s = ns;
109.2200 +                    }
109.2201 +                    s[len++] = (char) c;
109.2202 +                }
109.2203 +                firstc = -1;
109.2204 +            }
109.2205 +            while (len > 0 && s[len - 1] <= ' ')
109.2206 +                len--;
109.2207 +            String k;
109.2208 +            if (keyend <= 0) {
109.2209 +                k = null;
109.2210 +                keyend = 0;
109.2211 +            } else {
109.2212 +                k = String.copyValueOf(s, 0, keyend);
109.2213 +                if (keyend < len && s[keyend] == ':')
109.2214 +                    keyend++;
109.2215 +                while (keyend < len && s[keyend] <= ' ')
109.2216 +                    keyend++;
109.2217 +            }
109.2218 +            String v;
109.2219 +            if (keyend >= len)
109.2220 +                v = new String();
109.2221 +            else
109.2222 +                v = String.copyValueOf(s, keyend, len - keyend);
109.2223 +            add(k, v);
109.2224 +        }
109.2225 +    }
109.2226 +
109.2227 +    public synchronized String toString() {
109.2228 +        String result = super.toString() + nkeys + " pairs: ";
109.2229 +        for (int i = 0; i < keys.length && i < nkeys; i++) {
109.2230 +            result += "{"+keys[i]+": "+values[i]+"}";
109.2231 +        }
109.2232 +        return result;
109.2233 +    }
109.2234 +}
109.2235 +
109.2236 +interface ContentHandlerFactory {
109.2237 +
109.2238 +    public ContentHandler createContentHandler(String contentType);
109.2239 +}
109.2240 +
109.2241 +abstract class ContentHandler {
109.2242 +    /**
109.2243 +     * Given a URL connect stream positioned at the beginning of the
109.2244 +     * representation of an object, this method reads that stream and
109.2245 +     * creates an object from it.
109.2246 +     *
109.2247 +     * @param      urlc   a URL connection.
109.2248 +     * @return     the object read by the <code>ContentHandler</code>.
109.2249 +     * @exception  IOException  if an I/O error occurs while reading the object.
109.2250 +     */
109.2251 +    abstract public Object getContent(URLConnection urlc) throws IOException;
109.2252 +
109.2253 +    /**
109.2254 +     * Given a URL connect stream positioned at the beginning of the
109.2255 +     * representation of an object, this method reads that stream and
109.2256 +     * creates an object that matches one of the types specified.
109.2257 +     *
109.2258 +     * The default implementation of this method should call getContent()
109.2259 +     * and screen the return type for a match of the suggested types.
109.2260 +     *
109.2261 +     * @param      urlc   a URL connection.
109.2262 +     * @param      classes      an array of types requested
109.2263 +     * @return     the object read by the <code>ContentHandler</code> that is
109.2264 +     *                 the first match of the suggested types.
109.2265 +     *                 null if none of the requested  are supported.
109.2266 +     * @exception  IOException  if an I/O error occurs while reading the object.
109.2267 +     * @since 1.3
109.2268 +     */
109.2269 +    public Object getContent(URLConnection urlc, Class[] classes) throws IOException {
109.2270 +        Object obj = getContent(urlc);
109.2271 +
109.2272 +        for (int i = 0; i < classes.length; i++) {
109.2273 +          if (classes[i].isInstance(obj)) {
109.2274 +                return obj;
109.2275 +          }
109.2276 +        }
109.2277 +        return null;
109.2278 +    }
109.2279 +
109.2280 +}
109.2281 +class UnknownServiceException extends IOException {
109.2282 +    private static final long serialVersionUID = -4169033248853639508L;
109.2283 +
109.2284 +    /**
109.2285 +     * Constructs a new <code>UnknownServiceException</code> with no
109.2286 +     * detail message.
109.2287 +     */
109.2288 +    public UnknownServiceException() {
109.2289 +    }
109.2290 +
109.2291 +    /**
109.2292 +     * Constructs a new <code>UnknownServiceException</code> with the
109.2293 +     * specified detail message.
109.2294 +     *
109.2295 +     * @param   msg   the detail message.
109.2296 +     */
109.2297 +    public UnknownServiceException(String msg) {
109.2298 +        super(msg);
109.2299 +    }
109.2300 +}
109.2301 +/**
109.2302 + * A simple interface which provides a mechanism to map
109.2303 + * between a file name and a MIME type string.
109.2304 + *
109.2305 + * @author  Steven B. Byrne
109.2306 + * @since   JDK1.1
109.2307 + */
109.2308 +interface FileNameMap {
109.2309 +
109.2310 +    /**
109.2311 +     * Gets the MIME type for the specified file name.
109.2312 +     * @param fileName the specified file name
109.2313 +     * @return a <code>String</code> indicating the MIME
109.2314 +     * type for the specified file name.
109.2315 +     */
109.2316 +    public String getContentTypeFor(String fileName);
109.2317 +}
   110.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   110.2 +++ b/rt/emul/compact/src/main/java/java/nio/charset/Charset.java	Tue Feb 11 13:31:42 2014 +0100
   110.3 @@ -0,0 +1,765 @@
   110.4 +/*
   110.5 + * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
   110.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   110.7 + *
   110.8 + * This code is free software; you can redistribute it and/or modify it
   110.9 + * under the terms of the GNU General Public License version 2 only, as
  110.10 + * published by the Free Software Foundation.  Oracle designates this
  110.11 + * particular file as subject to the "Classpath" exception as provided
  110.12 + * by Oracle in the LICENSE file that accompanied this code.
  110.13 + *
  110.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  110.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  110.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  110.17 + * version 2 for more details (a copy is included in the LICENSE file that
  110.18 + * accompanied this code).
  110.19 + *
  110.20 + * You should have received a copy of the GNU General Public License version
  110.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  110.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  110.23 + *
  110.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  110.25 + * or visit www.oracle.com if you need additional information or have any
  110.26 + * questions.
  110.27 + */
  110.28 +
  110.29 +package java.nio.charset;
  110.30 +
  110.31 +//import java.nio.ByteBuffer;
  110.32 +//import java.nio.CharBuffer;
  110.33 +import java.util.Collections;
  110.34 +import java.util.HashSet;
  110.35 +import java.util.Iterator;
  110.36 +import java.util.Locale;
  110.37 +import java.util.Map;
  110.38 +import java.util.Set;
  110.39 +import java.util.SortedMap;
  110.40 +import java.util.TreeMap;
  110.41 +
  110.42 +
  110.43 +/**
  110.44 + * A named mapping between sequences of sixteen-bit Unicode <a
  110.45 + * href="../../lang/Character.html#unicode">code units</a> and sequences of
  110.46 + * bytes.  This class defines methods for creating decoders and encoders and
  110.47 + * for retrieving the various names associated with a charset.  Instances of
  110.48 + * this class are immutable.
  110.49 + *
  110.50 + * <p> This class also defines static methods for testing whether a particular
  110.51 + * charset is supported, for locating charset instances by name, and for
  110.52 + * constructing a map that contains every charset for which support is
  110.53 + * available in the current Java virtual machine.  Support for new charsets can
  110.54 + * be added via the service-provider interface defined in the {@link
  110.55 + * java.nio.charset.spi.CharsetProvider} class.
  110.56 + *
  110.57 + * <p> All of the methods defined in this class are safe for use by multiple
  110.58 + * concurrent threads.
  110.59 + *
  110.60 + *
  110.61 + * <a name="names"><a name="charenc">
  110.62 + * <h4>Charset names</h4>
  110.63 + *
  110.64 + * <p> Charsets are named by strings composed of the following characters:
  110.65 + *
  110.66 + * <ul>
  110.67 + *
  110.68 + *   <li> The uppercase letters <tt>'A'</tt> through <tt>'Z'</tt>
  110.69 + *        (<tt>'&#92;u0041'</tt>&nbsp;through&nbsp;<tt>'&#92;u005a'</tt>),
  110.70 + *
  110.71 + *   <li> The lowercase letters <tt>'a'</tt> through <tt>'z'</tt>
  110.72 + *        (<tt>'&#92;u0061'</tt>&nbsp;through&nbsp;<tt>'&#92;u007a'</tt>),
  110.73 + *
  110.74 + *   <li> The digits <tt>'0'</tt> through <tt>'9'</tt>
  110.75 + *        (<tt>'&#92;u0030'</tt>&nbsp;through&nbsp;<tt>'&#92;u0039'</tt>),
  110.76 + *
  110.77 + *   <li> The dash character <tt>'-'</tt>
  110.78 + *        (<tt>'&#92;u002d'</tt>,&nbsp;<small>HYPHEN-MINUS</small>),
  110.79 + *
  110.80 + *   <li> The plus character <tt>'+'</tt>
  110.81 + *        (<tt>'&#92;u002b'</tt>,&nbsp;<small>PLUS SIGN</small>),
  110.82 + *
  110.83 + *   <li> The period character <tt>'.'</tt>
  110.84 + *        (<tt>'&#92;u002e'</tt>,&nbsp;<small>FULL STOP</small>),
  110.85 + *
  110.86 + *   <li> The colon character <tt>':'</tt>
  110.87 + *        (<tt>'&#92;u003a'</tt>,&nbsp;<small>COLON</small>), and
  110.88 + *
  110.89 + *   <li> The underscore character <tt>'_'</tt>
  110.90 + *        (<tt>'&#92;u005f'</tt>,&nbsp;<small>LOW&nbsp;LINE</small>).
  110.91 + *
  110.92 + * </ul>
  110.93 + *
  110.94 + * A charset name must begin with either a letter or a digit.  The empty string
  110.95 + * is not a legal charset name.  Charset names are not case-sensitive; that is,
  110.96 + * case is always ignored when comparing charset names.  Charset names
  110.97 + * generally follow the conventions documented in <a
  110.98 + * href="http://www.ietf.org/rfc/rfc2278.txt"><i>RFC&nbsp;2278:&nbsp;IANA Charset
  110.99 + * Registration Procedures</i></a>.
 110.100 + *
 110.101 + * <p> Every charset has a <i>canonical name</i> and may also have one or more
 110.102 + * <i>aliases</i>.  The canonical name is returned by the {@link #name() name} method
 110.103 + * of this class.  Canonical names are, by convention, usually in upper case.
 110.104 + * The aliases of a charset are returned by the {@link #aliases() aliases}
 110.105 + * method.
 110.106 + *
 110.107 + * <a name="hn">
 110.108 + *
 110.109 + * <p> Some charsets have an <i>historical name</i> that is defined for
 110.110 + * compatibility with previous versions of the Java platform.  A charset's
 110.111 + * historical name is either its canonical name or one of its aliases.  The
 110.112 + * historical name is returned by the <tt>getEncoding()</tt> methods of the
 110.113 + * {@link java.io.InputStreamReader#getEncoding InputStreamReader} and {@link
 110.114 + * java.io.OutputStreamWriter#getEncoding OutputStreamWriter} classes.
 110.115 + *
 110.116 + * <a name="iana">
 110.117 + *
 110.118 + * <p> If a charset listed in the <a
 110.119 + * href="http://www.iana.org/assignments/character-sets"><i>IANA Charset
 110.120 + * Registry</i></a> is supported by an implementation of the Java platform then
 110.121 + * its canonical name must be the name listed in the registry.  Many charsets
 110.122 + * are given more than one name in the registry, in which case the registry
 110.123 + * identifies one of the names as <i>MIME-preferred</i>.  If a charset has more
 110.124 + * than one registry name then its canonical name must be the MIME-preferred
 110.125 + * name and the other names in the registry must be valid aliases.  If a
 110.126 + * supported charset is not listed in the IANA registry then its canonical name
 110.127 + * must begin with one of the strings <tt>"X-"</tt> or <tt>"x-"</tt>.
 110.128 + *
 110.129 + * <p> The IANA charset registry does change over time, and so the canonical
 110.130 + * name and the aliases of a particular charset may also change over time.  To
 110.131 + * ensure compatibility it is recommended that no alias ever be removed from a
 110.132 + * charset, and that if the canonical name of a charset is changed then its
 110.133 + * previous canonical name be made into an alias.
 110.134 + *
 110.135 + *
 110.136 + * <h4>Standard charsets</h4>
 110.137 + *
 110.138 + * <a name="standard">
 110.139 + *
 110.140 + * <p> Every implementation of the Java platform is required to support the
 110.141 + * following standard charsets.  Consult the release documentation for your
 110.142 + * implementation to see if any other charsets are supported.  The behavior
 110.143 + * of such optional charsets may differ between implementations.
 110.144 + *
 110.145 + * <blockquote><table width="80%" summary="Description of standard charsets">
 110.146 + * <tr><th><p align="left">Charset</p></th><th><p align="left">Description</p></th></tr>
 110.147 + * <tr><td valign=top><tt>US-ASCII</tt></td>
 110.148 + *     <td>Seven-bit ASCII, a.k.a. <tt>ISO646-US</tt>,
 110.149 + *         a.k.a. the Basic Latin block of the Unicode character set</td></tr>
 110.150 + * <tr><td valign=top><tt>ISO-8859-1&nbsp;&nbsp;</tt></td>
 110.151 + *     <td>ISO Latin Alphabet No. 1, a.k.a. <tt>ISO-LATIN-1</tt></td></tr>
 110.152 + * <tr><td valign=top><tt>UTF-8</tt></td>
 110.153 + *     <td>Eight-bit UCS Transformation Format</td></tr>
 110.154 + * <tr><td valign=top><tt>UTF-16BE</tt></td>
 110.155 + *     <td>Sixteen-bit UCS Transformation Format,
 110.156 + *         big-endian byte&nbsp;order</td></tr>
 110.157 + * <tr><td valign=top><tt>UTF-16LE</tt></td>
 110.158 + *     <td>Sixteen-bit UCS Transformation Format,
 110.159 + *         little-endian byte&nbsp;order</td></tr>
 110.160 + * <tr><td valign=top><tt>UTF-16</tt></td>
 110.161 + *     <td>Sixteen-bit UCS Transformation Format,
 110.162 + *         byte&nbsp;order identified by an optional byte-order mark</td></tr>
 110.163 + * </table></blockquote>
 110.164 + *
 110.165 + * <p> The <tt>UTF-8</tt> charset is specified by <a
 110.166 + * href="http://www.ietf.org/rfc/rfc2279.txt"><i>RFC&nbsp;2279</i></a>; the
 110.167 + * transformation format upon which it is based is specified in
 110.168 + * Amendment&nbsp;2 of ISO&nbsp;10646-1 and is also described in the <a
 110.169 + * href="http://www.unicode.org/unicode/standard/standard.html"><i>Unicode
 110.170 + * Standard</i></a>.
 110.171 + *
 110.172 + * <p> The <tt>UTF-16</tt> charsets are specified by <a
 110.173 + * href="http://www.ietf.org/rfc/rfc2781.txt"><i>RFC&nbsp;2781</i></a>; the
 110.174 + * transformation formats upon which they are based are specified in
 110.175 + * Amendment&nbsp;1 of ISO&nbsp;10646-1 and are also described in the <a
 110.176 + * href="http://www.unicode.org/unicode/standard/standard.html"><i>Unicode
 110.177 + * Standard</i></a>.
 110.178 + *
 110.179 + * <p> The <tt>UTF-16</tt> charsets use sixteen-bit quantities and are
 110.180 + * therefore sensitive to byte order.  In these encodings the byte order of a
 110.181 + * stream may be indicated by an initial <i>byte-order mark</i> represented by
 110.182 + * the Unicode character <tt>'&#92;uFEFF'</tt>.  Byte-order marks are handled
 110.183 + * as follows:
 110.184 + *
 110.185 + * <ul>
 110.186 + *
 110.187 + *   <li><p> When decoding, the <tt>UTF-16BE</tt> and <tt>UTF-16LE</tt>
 110.188 + *   charsets interpret the initial byte-order marks as a <small>ZERO-WIDTH
 110.189 + *   NON-BREAKING SPACE</small>; when encoding, they do not write
 110.190 + *   byte-order marks. </p></li>
 110.191 +
 110.192 + *
 110.193 + *   <li><p> When decoding, the <tt>UTF-16</tt> charset interprets the
 110.194 + *   byte-order mark at the beginning of the input stream to indicate the
 110.195 + *   byte-order of the stream but defaults to big-endian if there is no
 110.196 + *   byte-order mark; when encoding, it uses big-endian byte order and writes
 110.197 + *   a big-endian byte-order mark. </p></li>
 110.198 + *
 110.199 + * </ul>
 110.200 + *
 110.201 + * In any case, byte order marks occuring after the first element of an
 110.202 + * input sequence are not omitted since the same code is used to represent
 110.203 + * <small>ZERO-WIDTH NON-BREAKING SPACE</small>.
 110.204 + *
 110.205 + * <p> Every instance of the Java virtual machine has a default charset, which
 110.206 + * may or may not be one of the standard charsets.  The default charset is
 110.207 + * determined during virtual-machine startup and typically depends upon the
 110.208 + * locale and charset being used by the underlying operating system. </p>
 110.209 + *
 110.210 + * <p>The {@link StandardCharsets} class defines constants for each of the
 110.211 + * standard charsets.
 110.212 + *
 110.213 + * <h4>Terminology</h4>
 110.214 + *
 110.215 + * <p> The name of this class is taken from the terms used in
 110.216 + * <a href="http://www.ietf.org/rfc/rfc2278.txt"><i>RFC&nbsp;2278</i></a>.
 110.217 + * In that document a <i>charset</i> is defined as the combination of
 110.218 + * one or more coded character sets and a character-encoding scheme.
 110.219 + * (This definition is confusing; some other software systems define
 110.220 + * <i>charset</i> as a synonym for <i>coded character set</i>.)
 110.221 + *
 110.222 + * <p> A <i>coded character set</i> is a mapping between a set of abstract
 110.223 + * characters and a set of integers.  US-ASCII, ISO&nbsp;8859-1,
 110.224 + * JIS&nbsp;X&nbsp;0201, and Unicode are examples of coded character sets.
 110.225 + *
 110.226 + * <p> Some standards have defined a <i>character set</i> to be simply a
 110.227 + * set of abstract characters without an associated assigned numbering.
 110.228 + * An alphabet is an example of such a character set.  However, the subtle
 110.229 + * distinction between <i>character set</i> and <i>coded character set</i>
 110.230 + * is rarely used in practice; the former has become a short form for the
 110.231 + * latter, including in the Java API specification.
 110.232 + *
 110.233 + * <p> A <i>character-encoding scheme</i> is a mapping between one or more
 110.234 + * coded character sets and a set of octet (eight-bit byte) sequences.
 110.235 + * UTF-8, UTF-16, ISO&nbsp;2022, and EUC are examples of
 110.236 + * character-encoding schemes.  Encoding schemes are often associated with
 110.237 + * a particular coded character set; UTF-8, for example, is used only to
 110.238 + * encode Unicode.  Some schemes, however, are associated with multiple
 110.239 + * coded character sets; EUC, for example, can be used to encode
 110.240 + * characters in a variety of Asian coded character sets.
 110.241 + *
 110.242 + * <p> When a coded character set is used exclusively with a single
 110.243 + * character-encoding scheme then the corresponding charset is usually
 110.244 + * named for the coded character set; otherwise a charset is usually named
 110.245 + * for the encoding scheme and, possibly, the locale of the coded
 110.246 + * character sets that it supports.  Hence <tt>US-ASCII</tt> is both the
 110.247 + * name of a coded character set and of the charset that encodes it, while
 110.248 + * <tt>EUC-JP</tt> is the name of the charset that encodes the
 110.249 + * JIS&nbsp;X&nbsp;0201, JIS&nbsp;X&nbsp;0208, and JIS&nbsp;X&nbsp;0212
 110.250 + * coded character sets for the Japanese language.
 110.251 + *
 110.252 + * <p> The native character encoding of the Java programming language is
 110.253 + * UTF-16.  A charset in the Java platform therefore defines a mapping
 110.254 + * between sequences of sixteen-bit UTF-16 code units (that is, sequences
 110.255 + * of chars) and sequences of bytes. </p>
 110.256 + *
 110.257 + *
 110.258 + * @author Mark Reinhold
 110.259 + * @author JSR-51 Expert Group
 110.260 + * @since 1.4
 110.261 + *
 110.262 + * @see CharsetDecoder
 110.263 + * @see CharsetEncoder
 110.264 + * @see java.nio.charset.spi.CharsetProvider
 110.265 + * @see java.lang.Character
 110.266 + */
 110.267 +
 110.268 +public abstract class Charset
 110.269 +    implements Comparable<Charset>
 110.270 +{
 110.271 +
 110.272 +    /* -- Static methods -- */
 110.273 +
 110.274 +    private static volatile String bugLevel = null;
 110.275 +
 110.276 +    /**
 110.277 +     * Checks that the given string is a legal charset name. </p>
 110.278 +     *
 110.279 +     * @param  s
 110.280 +     *         A purported charset name
 110.281 +     *
 110.282 +     * @throws  IllegalCharsetNameException
 110.283 +     *          If the given name is not a legal charset name
 110.284 +     */
 110.285 +    private static void checkName(String s) {
 110.286 +        int n = s.length();
 110.287 +            if (n == 0)
 110.288 +                throw new IllegalCharsetNameException(s);
 110.289 +        for (int i = 0; i < n; i++) {
 110.290 +            char c = s.charAt(i);
 110.291 +            if (c >= 'A' && c <= 'Z') continue;
 110.292 +            if (c >= 'a' && c <= 'z') continue;
 110.293 +            if (c >= '0' && c <= '9') continue;
 110.294 +            if (c == '-' && i != 0) continue;
 110.295 +            if (c == '+' && i != 0) continue;
 110.296 +            if (c == ':' && i != 0) continue;
 110.297 +            if (c == '_' && i != 0) continue;
 110.298 +            if (c == '.' && i != 0) continue;
 110.299 +            throw new IllegalCharsetNameException(s);
 110.300 +        }
 110.301 +    }
 110.302 +
 110.303 +    // Cache of the most-recently-returned charsets,
 110.304 +    // along with the names that were used to find them
 110.305 +    //
 110.306 +    private static volatile Object[] cache1 = null; // "Level 1" cache
 110.307 +    private static volatile Object[] cache2 = null; // "Level 2" cache
 110.308 +
 110.309 +    private static void cache(String charsetName, Charset cs) {
 110.310 +        cache2 = cache1;
 110.311 +        cache1 = new Object[] { charsetName, cs };
 110.312 +    }
 110.313 +
 110.314 +    // Creates an iterator that walks over the available providers, ignoring
 110.315 +    // those whose lookup or instantiation causes a security exception to be
 110.316 +    // thrown.  Should be invoked with full privileges.
 110.317 +    //
 110.318 +    private static Iterator providers() {
 110.319 +        return Collections.emptyIterator();
 110.320 +    }
 110.321 +
 110.322 +    // Thread-local gate to prevent recursive provider lookups
 110.323 +    private static ThreadLocal<ThreadLocal> gate = new ThreadLocal<ThreadLocal>();
 110.324 +
 110.325 +    private static Charset lookupViaProviders(final String charsetName) {
 110.326 +        return null;
 110.327 +    }
 110.328 +
 110.329 +    /* The extended set of charsets */
 110.330 +    private static Object extendedProviderLock = new Object();
 110.331 +    private static boolean extendedProviderProbed = false;
 110.332 +
 110.333 +
 110.334 +    private static Charset lookupExtendedCharset(String charsetName) {
 110.335 +        return null;
 110.336 +    }
 110.337 +
 110.338 +    private static Charset lookup(String charsetName) {
 110.339 +        if (charsetName == null)
 110.340 +            throw new IllegalArgumentException("Null charset name");
 110.341 +
 110.342 +        Object[] a;
 110.343 +        if ((a = cache1) != null && charsetName.equals(a[0]))
 110.344 +            return (Charset)a[1];
 110.345 +        // We expect most programs to use one Charset repeatedly.
 110.346 +        // We convey a hint to this effect to the VM by putting the
 110.347 +        // level 1 cache miss code in a separate method.
 110.348 +        return lookup2(charsetName);
 110.349 +    }
 110.350 +
 110.351 +    private static Charset lookup2(String charsetName) {
 110.352 +        Object[] a;
 110.353 +        if ((a = cache2) != null && charsetName.equals(a[0])) {
 110.354 +            cache2 = cache1;
 110.355 +            cache1 = a;
 110.356 +            return (Charset)a[1];
 110.357 +        }
 110.358 +
 110.359 +        /* Only need to check the name if we didn't find a charset for it */
 110.360 +        checkName(charsetName);
 110.361 +        return null;
 110.362 +    }
 110.363 +
 110.364 +    /**
 110.365 +     * Tells whether the named charset is supported. </p>
 110.366 +     *
 110.367 +     * @param  charsetName
 110.368 +     *         The name of the requested charset; may be either
 110.369 +     *         a canonical name or an alias
 110.370 +     *
 110.371 +     * @return  <tt>true</tt> if, and only if, support for the named charset
 110.372 +     *          is available in the current Java virtual machine
 110.373 +     *
 110.374 +     * @throws IllegalCharsetNameException
 110.375 +     *         If the given charset name is illegal
 110.376 +     *
 110.377 +     * @throws  IllegalArgumentException
 110.378 +     *          If the given <tt>charsetName</tt> is null
 110.379 +     */
 110.380 +    public static boolean isSupported(String charsetName) {
 110.381 +        return (lookup(charsetName) != null);
 110.382 +    }
 110.383 +
 110.384 +    /**
 110.385 +     * Returns a charset object for the named charset. </p>
 110.386 +     *
 110.387 +     * @param  charsetName
 110.388 +     *         The name of the requested charset; may be either
 110.389 +     *         a canonical name or an alias
 110.390 +     *
 110.391 +     * @return  A charset object for the named charset
 110.392 +     *
 110.393 +     * @throws  IllegalCharsetNameException
 110.394 +     *          If the given charset name is illegal
 110.395 +     *
 110.396 +     * @throws  IllegalArgumentException
 110.397 +     *          If the given <tt>charsetName</tt> is null
 110.398 +     *
 110.399 +     * @throws  UnsupportedCharsetException
 110.400 +     *          If no support for the named charset is available
 110.401 +     *          in this instance of the Java virtual machine
 110.402 +     */
 110.403 +    public static Charset forName(String charsetName) {
 110.404 +        Charset cs = lookup(charsetName);
 110.405 +        if (cs != null)
 110.406 +            return cs;
 110.407 +        throw new UnsupportedCharsetException(charsetName);
 110.408 +    }
 110.409 +
 110.410 +    // Fold charsets from the given iterator into the given map, ignoring
 110.411 +    // charsets whose names already have entries in the map.
 110.412 +    //
 110.413 +    private static void put(Iterator<Charset> i, Map<String,Charset> m) {
 110.414 +        while (i.hasNext()) {
 110.415 +            Charset cs = i.next();
 110.416 +            if (!m.containsKey(cs.name()))
 110.417 +                m.put(cs.name(), cs);
 110.418 +        }
 110.419 +    }
 110.420 +
 110.421 +    /**
 110.422 +     * Constructs a sorted map from canonical charset names to charset objects.
 110.423 +     *
 110.424 +     * <p> The map returned by this method will have one entry for each charset
 110.425 +     * for which support is available in the current Java virtual machine.  If
 110.426 +     * two or more supported charsets have the same canonical name then the
 110.427 +     * resulting map will contain just one of them; which one it will contain
 110.428 +     * is not specified. </p>
 110.429 +     *
 110.430 +     * <p> The invocation of this method, and the subsequent use of the
 110.431 +     * resulting map, may cause time-consuming disk or network I/O operations
 110.432 +     * to occur.  This method is provided for applications that need to
 110.433 +     * enumerate all of the available charsets, for example to allow user
 110.434 +     * charset selection.  This method is not used by the {@link #forName
 110.435 +     * forName} method, which instead employs an efficient incremental lookup
 110.436 +     * algorithm.
 110.437 +     *
 110.438 +     * <p> This method may return different results at different times if new
 110.439 +     * charset providers are dynamically made available to the current Java
 110.440 +     * virtual machine.  In the absence of such changes, the charsets returned
 110.441 +     * by this method are exactly those that can be retrieved via the {@link
 110.442 +     * #forName forName} method.  </p>
 110.443 +     *
 110.444 +     * @return An immutable, case-insensitive map from canonical charset names
 110.445 +     *         to charset objects
 110.446 +     */
 110.447 +    public static SortedMap<String,Charset> availableCharsets() {
 110.448 +        TreeMap<String, Charset> tm = new TreeMap<String,Charset>();
 110.449 +        tm.put("UTF-8", Charset.defaultCharset());
 110.450 +        return tm;
 110.451 +    }
 110.452 +
 110.453 +    private static volatile Charset defaultCharset;
 110.454 +
 110.455 +    /**
 110.456 +     * Returns the default charset of this Java virtual machine.
 110.457 +     *
 110.458 +     * <p> The default charset is determined during virtual-machine startup and
 110.459 +     * typically depends upon the locale and charset of the underlying
 110.460 +     * operating system.
 110.461 +     *
 110.462 +     * @return  A charset object for the default charset
 110.463 +     *
 110.464 +     * @since 1.5
 110.465 +     */
 110.466 +    public static Charset defaultCharset() {
 110.467 +        if (defaultCharset == null) {
 110.468 +            defaultCharset = forName("UTF-8");
 110.469 +        }
 110.470 +        return defaultCharset;
 110.471 +    }
 110.472 +
 110.473 +
 110.474 +    /* -- Instance fields and methods -- */
 110.475 +
 110.476 +    private final String name;          // tickles a bug in oldjavac
 110.477 +    private final String[] aliases;     // tickles a bug in oldjavac
 110.478 +    private Set<String> aliasSet = null;
 110.479 +
 110.480 +    /**
 110.481 +     * Initializes a new charset with the given canonical name and alias
 110.482 +     * set. </p>
 110.483 +     *
 110.484 +     * @param  canonicalName
 110.485 +     *         The canonical name of this charset
 110.486 +     *
 110.487 +     * @param  aliases
 110.488 +     *         An array of this charset's aliases, or null if it has no aliases
 110.489 +     *
 110.490 +     * @throws IllegalCharsetNameException
 110.491 +     *         If the canonical name or any of the aliases are illegal
 110.492 +     */
 110.493 +    protected Charset(String canonicalName, String[] aliases) {
 110.494 +        checkName(canonicalName);
 110.495 +        String[] as = (aliases == null) ? new String[0] : aliases;
 110.496 +        for (int i = 0; i < as.length; i++)
 110.497 +            checkName(as[i]);
 110.498 +        this.name = canonicalName;
 110.499 +        this.aliases = as;
 110.500 +    }
 110.501 +
 110.502 +    /**
 110.503 +     * Returns this charset's canonical name. </p>
 110.504 +     *
 110.505 +     * @return  The canonical name of this charset
 110.506 +     */
 110.507 +    public final String name() {
 110.508 +        return name;
 110.509 +    }
 110.510 +
 110.511 +    /**
 110.512 +     * Returns a set containing this charset's aliases. </p>
 110.513 +     *
 110.514 +     * @return  An immutable set of this charset's aliases
 110.515 +     */
 110.516 +    public final Set<String> aliases() {
 110.517 +        if (aliasSet != null)
 110.518 +            return aliasSet;
 110.519 +        int n = aliases.length;
 110.520 +        HashSet<String> hs = new HashSet<String>(n);
 110.521 +        for (int i = 0; i < n; i++)
 110.522 +            hs.add(aliases[i]);
 110.523 +        aliasSet = Collections.unmodifiableSet(hs);
 110.524 +        return aliasSet;
 110.525 +    }
 110.526 +
 110.527 +    /**
 110.528 +     * Returns this charset's human-readable name for the default locale.
 110.529 +     *
 110.530 +     * <p> The default implementation of this method simply returns this
 110.531 +     * charset's canonical name.  Concrete subclasses of this class may
 110.532 +     * override this method in order to provide a localized display name. </p>
 110.533 +     *
 110.534 +     * @return  The display name of this charset in the default locale
 110.535 +     */
 110.536 +    public String displayName() {
 110.537 +        return name;
 110.538 +    }
 110.539 +
 110.540 +    /**
 110.541 +     * Tells whether or not this charset is registered in the <a
 110.542 +     * href="http://www.iana.org/assignments/character-sets">IANA Charset
 110.543 +     * Registry</a>.  </p>
 110.544 +     *
 110.545 +     * @return  <tt>true</tt> if, and only if, this charset is known by its
 110.546 +     *          implementor to be registered with the IANA
 110.547 +     */
 110.548 +    public final boolean isRegistered() {
 110.549 +        return !name.startsWith("X-") && !name.startsWith("x-");
 110.550 +    }
 110.551 +
 110.552 +    /**
 110.553 +     * Returns this charset's human-readable name for the given locale.
 110.554 +     *
 110.555 +     * <p> The default implementation of this method simply returns this
 110.556 +     * charset's canonical name.  Concrete subclasses of this class may
 110.557 +     * override this method in order to provide a localized display name. </p>
 110.558 +     *
 110.559 +     * @param  locale
 110.560 +     *         The locale for which the display name is to be retrieved
 110.561 +     *
 110.562 +     * @return  The display name of this charset in the given locale
 110.563 +     */
 110.564 +    public String displayName(Locale locale) {
 110.565 +        return name;
 110.566 +    }
 110.567 +
 110.568 +    /**
 110.569 +     * Tells whether or not this charset contains the given charset.
 110.570 +     *
 110.571 +     * <p> A charset <i>C</i> is said to <i>contain</i> a charset <i>D</i> if,
 110.572 +     * and only if, every character representable in <i>D</i> is also
 110.573 +     * representable in <i>C</i>.  If this relationship holds then it is
 110.574 +     * guaranteed that every string that can be encoded in <i>D</i> can also be
 110.575 +     * encoded in <i>C</i> without performing any replacements.
 110.576 +     *
 110.577 +     * <p> That <i>C</i> contains <i>D</i> does not imply that each character
 110.578 +     * representable in <i>C</i> by a particular byte sequence is represented
 110.579 +     * in <i>D</i> by the same byte sequence, although sometimes this is the
 110.580 +     * case.
 110.581 +     *
 110.582 +     * <p> Every charset contains itself.
 110.583 +     *
 110.584 +     * <p> This method computes an approximation of the containment relation:
 110.585 +     * If it returns <tt>true</tt> then the given charset is known to be
 110.586 +     * contained by this charset; if it returns <tt>false</tt>, however, then
 110.587 +     * it is not necessarily the case that the given charset is not contained
 110.588 +     * in this charset.
 110.589 +     *
 110.590 +     * @return  <tt>true</tt> if the given charset is contained in this charset
 110.591 +     */
 110.592 +    public abstract boolean contains(Charset cs);
 110.593 +
 110.594 +    /**
 110.595 +     * Constructs a new decoder for this charset. </p>
 110.596 +     *
 110.597 +     * @return  A new decoder for this charset
 110.598 +     */
 110.599 +    public abstract CharsetDecoder newDecoder();
 110.600 +
 110.601 +    /**
 110.602 +     * Constructs a new encoder for this charset. </p>
 110.603 +     *
 110.604 +     * @return  A new encoder for this charset
 110.605 +     *
 110.606 +     * @throws  UnsupportedOperationException
 110.607 +     *          If this charset does not support encoding
 110.608 +     */
 110.609 +    public abstract CharsetEncoder newEncoder();
 110.610 +
 110.611 +    /**
 110.612 +     * Tells whether or not this charset supports encoding.
 110.613 +     *
 110.614 +     * <p> Nearly all charsets support encoding.  The primary exceptions are
 110.615 +     * special-purpose <i>auto-detect</i> charsets whose decoders can determine
 110.616 +     * which of several possible encoding schemes is in use by examining the
 110.617 +     * input byte sequence.  Such charsets do not support encoding because
 110.618 +     * there is no way to determine which encoding should be used on output.
 110.619 +     * Implementations of such charsets should override this method to return
 110.620 +     * <tt>false</tt>. </p>
 110.621 +     *
 110.622 +     * @return  <tt>true</tt> if, and only if, this charset supports encoding
 110.623 +     */
 110.624 +    public boolean canEncode() {
 110.625 +        return true;
 110.626 +    }
 110.627 +
 110.628 +    /**
 110.629 +     * Convenience method that decodes bytes in this charset into Unicode
 110.630 +     * characters.
 110.631 +     *
 110.632 +     * <p> An invocation of this method upon a charset <tt>cs</tt> returns the
 110.633 +     * same result as the expression
 110.634 +     *
 110.635 +     * <pre>
 110.636 +     *     cs.newDecoder()
 110.637 +     *       .onMalformedInput(CodingErrorAction.REPLACE)
 110.638 +     *       .onUnmappableCharacter(CodingErrorAction.REPLACE)
 110.639 +     *       .decode(bb); </pre>
 110.640 +     *
 110.641 +     * except that it is potentially more efficient because it can cache
 110.642 +     * decoders between successive invocations.
 110.643 +     *
 110.644 +     * <p> This method always replaces malformed-input and unmappable-character
 110.645 +     * sequences with this charset's default replacement byte array.  In order
 110.646 +     * to detect such sequences, use the {@link
 110.647 +     * CharsetDecoder#decode(java.nio.ByteBuffer)} method directly.  </p>
 110.648 +     *
 110.649 +     * @param  bb  The byte buffer to be decoded
 110.650 +     *
 110.651 +     * @return  A char buffer containing the decoded characters
 110.652 +     */
 110.653 +//    public final CharBuffer decode(ByteBuffer bb) {
 110.654 +//        try {
 110.655 +//            return ThreadLocalCoders.decoderFor(this)
 110.656 +//                .onMalformedInput(CodingErrorAction.REPLACE)
 110.657 +//                .onUnmappableCharacter(CodingErrorAction.REPLACE)
 110.658 +//                .decode(bb);
 110.659 +//        } catch (CharacterCodingException x) {
 110.660 +//            throw new Error(x);         // Can't happen
 110.661 +//        }
 110.662 +//    }
 110.663 +
 110.664 +    /**
 110.665 +     * Convenience method that encodes Unicode characters into bytes in this
 110.666 +     * charset.
 110.667 +     *
 110.668 +     * <p> An invocation of this method upon a charset <tt>cs</tt> returns the
 110.669 +     * same result as the expression
 110.670 +     *
 110.671 +     * <pre>
 110.672 +     *     cs.newEncoder()
 110.673 +     *       .onMalformedInput(CodingErrorAction.REPLACE)
 110.674 +     *       .onUnmappableCharacter(CodingErrorAction.REPLACE)
 110.675 +     *       .encode(bb); </pre>
 110.676 +     *
 110.677 +     * except that it is potentially more efficient because it can cache
 110.678 +     * encoders between successive invocations.
 110.679 +     *
 110.680 +     * <p> This method always replaces malformed-input and unmappable-character
 110.681 +     * sequences with this charset's default replacement string.  In order to
 110.682 +     * detect such sequences, use the {@link
 110.683 +     * CharsetEncoder#encode(java.nio.CharBuffer)} method directly.  </p>
 110.684 +     *
 110.685 +     * @param  cb  The char buffer to be encoded
 110.686 +     *
 110.687 +     * @return  A byte buffer containing the encoded characters
 110.688 +     */
 110.689 +//    public final ByteBuffer encode(CharBuffer cb) {
 110.690 +//        try {
 110.691 +//            return ThreadLocalCoders.encoderFor(this)
 110.692 +//                .onMalformedInput(CodingErrorAction.REPLACE)
 110.693 +//                .onUnmappableCharacter(CodingErrorAction.REPLACE)
 110.694 +//                .encode(cb);
 110.695 +//        } catch (CharacterCodingException x) {
 110.696 +//            throw new Error(x);         // Can't happen
 110.697 +//        }
 110.698 +//    }
 110.699 +
 110.700 +    /**
 110.701 +     * Convenience method that encodes a string into bytes in this charset.
 110.702 +     *
 110.703 +     * <p> An invocation of this method upon a charset <tt>cs</tt> returns the
 110.704 +     * same result as the expression
 110.705 +     *
 110.706 +     * <pre>
 110.707 +     *     cs.encode(CharBuffer.wrap(s)); </pre>
 110.708 +     *
 110.709 +     * @param  str  The string to be encoded
 110.710 +     *
 110.711 +     * @return  A byte buffer containing the encoded characters
 110.712 +     */
 110.713 +//    public final ByteBuffer encode(String str) {
 110.714 +//        return encode(CharBuffer.wrap(str));
 110.715 +//    }
 110.716 +
 110.717 +    /**
 110.718 +     * Compares this charset to another.
 110.719 +     *
 110.720 +     * <p> Charsets are ordered by their canonical names, without regard to
 110.721 +     * case. </p>
 110.722 +     *
 110.723 +     * @param  that
 110.724 +     *         The charset to which this charset is to be compared
 110.725 +     *
 110.726 +     * @return A negative integer, zero, or a positive integer as this charset
 110.727 +     *         is less than, equal to, or greater than the specified charset
 110.728 +     */
 110.729 +    public final int compareTo(Charset that) {
 110.730 +        return (name().compareToIgnoreCase(that.name()));
 110.731 +    }
 110.732 +
 110.733 +    /**
 110.734 +     * Computes a hashcode for this charset. </p>
 110.735 +     *
 110.736 +     * @return  An integer hashcode
 110.737 +     */
 110.738 +    public final int hashCode() {
 110.739 +        return name().hashCode();
 110.740 +    }
 110.741 +
 110.742 +    /**
 110.743 +     * Tells whether or not this object is equal to another.
 110.744 +     *
 110.745 +     * <p> Two charsets are equal if, and only if, they have the same canonical
 110.746 +     * names.  A charset is never equal to any other type of object.  </p>
 110.747 +     *
 110.748 +     * @return  <tt>true</tt> if, and only if, this charset is equal to the
 110.749 +     *          given object
 110.750 +     */
 110.751 +    public final boolean equals(Object ob) {
 110.752 +        if (!(ob instanceof Charset))
 110.753 +            return false;
 110.754 +        if (this == ob)
 110.755 +            return true;
 110.756 +        return name.equals(((Charset)ob).name());
 110.757 +    }
 110.758 +
 110.759 +    /**
 110.760 +     * Returns a string describing this charset. </p>
 110.761 +     *
 110.762 +     * @return  A string describing this charset
 110.763 +     */
 110.764 +    public final String toString() {
 110.765 +        return name();
 110.766 +    }
 110.767 +
 110.768 +}
   111.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   111.2 +++ b/rt/emul/compact/src/main/java/java/nio/charset/CharsetDecoder.java	Tue Feb 11 13:31:42 2014 +0100
   111.3 @@ -0,0 +1,970 @@
   111.4 +/*
   111.5 + * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
   111.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   111.7 + *
   111.8 + * This code is free software; you can redistribute it and/or modify it
   111.9 + * under the terms of the GNU General Public License version 2 only, as
  111.10 + * published by the Free Software Foundation.  Oracle designates this
  111.11 + * particular file as subject to the "Classpath" exception as provided
  111.12 + * by Oracle in the LICENSE file that accompanied this code.
  111.13 + *
  111.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  111.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  111.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  111.17 + * version 2 for more details (a copy is included in the LICENSE file that
  111.18 + * accompanied this code).
  111.19 + *
  111.20 + * You should have received a copy of the GNU General Public License version
  111.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  111.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  111.23 + *
  111.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  111.25 + * or visit www.oracle.com if you need additional information or have any
  111.26 + * questions.
  111.27 + */
  111.28 +
  111.29 +// -- This file was mechanically generated: Do not edit! -- //
  111.30 +
  111.31 +package java.nio.charset;
  111.32 +
  111.33 +//import java.nio.Buffer;
  111.34 +//import java.nio.ByteBuffer;
  111.35 +//import java.nio.CharBuffer;
  111.36 +//import java.nio.BufferOverflowException;
  111.37 +//import java.nio.BufferUnderflowException;
  111.38 +import java.lang.ref.WeakReference;
  111.39 +//import java.nio.charset.CoderMalfunctionError;                  // javadoc
  111.40 +
  111.41 +
  111.42 +/**
  111.43 + * An engine that can transform a sequence of bytes in a specific charset into a sequence of
  111.44 + * sixteen-bit Unicode characters.
  111.45 + *
  111.46 + * <a name="steps">
  111.47 + *
  111.48 + * <p> The input byte sequence is provided in a byte buffer or a series
  111.49 + * of such buffers.  The output character sequence is written to a character buffer
  111.50 + * or a series of such buffers.  A decoder should always be used by making
  111.51 + * the following sequence of method invocations, hereinafter referred to as a
  111.52 + * <i>decoding operation</i>:
  111.53 + *
  111.54 + * <ol>
  111.55 + *
  111.56 + *   <li><p> Reset the decoder via the {@link #reset reset} method, unless it
  111.57 + *   has not been used before; </p></li>
  111.58 + *
  111.59 + *   <li><p> Invoke the {@link #decode decode} method zero or more times, as
  111.60 + *   long as additional input may be available, passing <tt>false</tt> for the
  111.61 + *   <tt>endOfInput</tt> argument and filling the input buffer and flushing the
  111.62 + *   output buffer between invocations; </p></li>
  111.63 + *
  111.64 + *   <li><p> Invoke the {@link #decode decode} method one final time, passing
  111.65 + *   <tt>true</tt> for the <tt>endOfInput</tt> argument; and then </p></li>
  111.66 + *
  111.67 + *   <li><p> Invoke the {@link #flush flush} method so that the decoder can
  111.68 + *   flush any internal state to the output buffer. </p></li>
  111.69 + *
  111.70 + * </ol>
  111.71 + *
  111.72 + * Each invocation of the {@link #decode decode} method will decode as many
  111.73 + * bytes as possible from the input buffer, writing the resulting characters
  111.74 + * to the output buffer.  The {@link #decode decode} method returns when more
  111.75 + * input is required, when there is not enough room in the output buffer, or
  111.76 + * when a decoding error has occurred.  In each case a {@link CoderResult}
  111.77 + * object is returned to describe the reason for termination.  An invoker can
  111.78 + * examine this object and fill the input buffer, flush the output buffer, or
  111.79 + * attempt to recover from a decoding error, as appropriate, and try again.
  111.80 + *
  111.81 + * <a name="ce">
  111.82 + *
  111.83 + * <p> There are two general types of decoding errors.  If the input byte
  111.84 + * sequence is not legal for this charset then the input is considered <i>malformed</i>.  If
  111.85 + * the input byte sequence is legal but cannot be mapped to a valid
  111.86 + * Unicode character then an <i>unmappable character</i> has been encountered.
  111.87 + *
  111.88 + * <a name="cae">
  111.89 + *
  111.90 + * <p> How a decoding error is handled depends upon the action requested for
  111.91 + * that type of error, which is described by an instance of the {@link
  111.92 + * CodingErrorAction} class.  The possible error actions are to {@link
  111.93 + * CodingErrorAction#IGNORE </code>ignore<code>} the erroneous input, {@link
  111.94 + * CodingErrorAction#REPORT </code>report<code>} the error to the invoker via
  111.95 + * the returned {@link CoderResult} object, or {@link CodingErrorAction#REPLACE
  111.96 + * </code>replace<code>} the erroneous input with the current value of the
  111.97 + * replacement string.  The replacement
  111.98 + *
  111.99 +
 111.100 +
 111.101 +
 111.102 +
 111.103 +
 111.104 + * has the initial value <tt>"&#92;uFFFD"</tt>;
 111.105 +
 111.106 + *
 111.107 + * its value may be changed via the {@link #replaceWith(java.lang.String)
 111.108 + * replaceWith} method.
 111.109 + *
 111.110 + * <p> The default action for malformed-input and unmappable-character errors
 111.111 + * is to {@link CodingErrorAction#REPORT </code>report<code>} them.  The
 111.112 + * malformed-input error action may be changed via the {@link
 111.113 + * #onMalformedInput(CodingErrorAction) onMalformedInput} method; the
 111.114 + * unmappable-character action may be changed via the {@link
 111.115 + * #onUnmappableCharacter(CodingErrorAction) onUnmappableCharacter} method.
 111.116 + *
 111.117 + * <p> This class is designed to handle many of the details of the decoding
 111.118 + * process, including the implementation of error actions.  A decoder for a
 111.119 + * specific charset, which is a concrete subclass of this class, need only
 111.120 + * implement the abstract {@link #decodeLoop decodeLoop} method, which
 111.121 + * encapsulates the basic decoding loop.  A subclass that maintains internal
 111.122 + * state should, additionally, override the {@link #implFlush implFlush} and
 111.123 + * {@link #implReset implReset} methods.
 111.124 + *
 111.125 + * <p> Instances of this class are not safe for use by multiple concurrent
 111.126 + * threads.  </p>
 111.127 + *
 111.128 + *
 111.129 + * @author Mark Reinhold
 111.130 + * @author JSR-51 Expert Group
 111.131 + * @since 1.4
 111.132 + *
 111.133 + * @see ByteBuffer
 111.134 + * @see CharBuffer
 111.135 + * @see Charset
 111.136 + * @see CharsetEncoder
 111.137 + */
 111.138 +
 111.139 +public abstract class CharsetDecoder {
 111.140 +
 111.141 +    private final Charset charset;
 111.142 +    private final float averageCharsPerByte;
 111.143 +    private final float maxCharsPerByte;
 111.144 +
 111.145 +    private String replacement;
 111.146 +//    private CodingErrorAction malformedInputAction
 111.147 +//        = CodingErrorAction.REPORT;
 111.148 +//    private CodingErrorAction unmappableCharacterAction
 111.149 +//        = CodingErrorAction.REPORT;
 111.150 +
 111.151 +    // Internal states
 111.152 +    //
 111.153 +    private static final int ST_RESET   = 0;
 111.154 +    private static final int ST_CODING  = 1;
 111.155 +    private static final int ST_END     = 2;
 111.156 +    private static final int ST_FLUSHED = 3;
 111.157 +
 111.158 +    private int state = ST_RESET;
 111.159 +
 111.160 +    private static String stateNames[]
 111.161 +        = { "RESET", "CODING", "CODING_END", "FLUSHED" };
 111.162 +
 111.163 +
 111.164 +    /**
 111.165 +     * Initializes a new decoder.  The new decoder will have the given
 111.166 +     * chars-per-byte and replacement values. </p>
 111.167 +     *
 111.168 +     * @param  averageCharsPerByte
 111.169 +     *         A positive float value indicating the expected number of
 111.170 +     *         characters that will be produced for each input byte
 111.171 +     *
 111.172 +     * @param  maxCharsPerByte
 111.173 +     *         A positive float value indicating the maximum number of
 111.174 +     *         characters that will be produced for each input byte
 111.175 +     *
 111.176 +     * @param  replacement
 111.177 +     *         The initial replacement; must not be <tt>null</tt>, must have
 111.178 +     *         non-zero length, must not be longer than maxCharsPerByte,
 111.179 +     *         and must be {@link #isLegalReplacement </code>legal<code>}
 111.180 +     *
 111.181 +     * @throws  IllegalArgumentException
 111.182 +     *          If the preconditions on the parameters do not hold
 111.183 +     */
 111.184 +    private
 111.185 +    CharsetDecoder(Charset cs,
 111.186 +                   float averageCharsPerByte,
 111.187 +                   float maxCharsPerByte,
 111.188 +                   String replacement)
 111.189 +    {
 111.190 +        this.charset = cs;
 111.191 +        if (averageCharsPerByte <= 0.0f)
 111.192 +            throw new IllegalArgumentException("Non-positive "
 111.193 +                                               + "averageCharsPerByte");
 111.194 +        if (maxCharsPerByte <= 0.0f)
 111.195 +            throw new IllegalArgumentException("Non-positive "
 111.196 +                                               + "maxCharsPerByte");
 111.197 +        if (averageCharsPerByte > maxCharsPerByte)
 111.198 +            throw new IllegalArgumentException("averageCharsPerByte"
 111.199 +                                               + " exceeds "
 111.200 +                                               + "maxCharsPerByte");
 111.201 +        this.replacement = replacement;
 111.202 +        this.averageCharsPerByte = averageCharsPerByte;
 111.203 +        this.maxCharsPerByte = maxCharsPerByte;
 111.204 +        replaceWith(replacement);
 111.205 +    }
 111.206 +
 111.207 +    /**
 111.208 +     * Initializes a new decoder.  The new decoder will have the given
 111.209 +     * chars-per-byte values and its replacement will be the
 111.210 +     * string <tt>"&#92;uFFFD"</tt>. </p>
 111.211 +     *
 111.212 +     * @param  averageCharsPerByte
 111.213 +     *         A positive float value indicating the expected number of
 111.214 +     *         characters that will be produced for each input byte
 111.215 +     *
 111.216 +     * @param  maxCharsPerByte
 111.217 +     *         A positive float value indicating the maximum number of
 111.218 +     *         characters that will be produced for each input byte
 111.219 +     *
 111.220 +     * @throws  IllegalArgumentException
 111.221 +     *          If the preconditions on the parameters do not hold
 111.222 +     */
 111.223 +    protected CharsetDecoder(Charset cs,
 111.224 +                             float averageCharsPerByte,
 111.225 +                             float maxCharsPerByte)
 111.226 +    {
 111.227 +        this(cs,
 111.228 +             averageCharsPerByte, maxCharsPerByte,
 111.229 +             "\uFFFD");
 111.230 +    }
 111.231 +
 111.232 +    /**
 111.233 +     * Returns the charset that created this decoder.  </p>
 111.234 +     *
 111.235 +     * @return  This decoder's charset
 111.236 +     */
 111.237 +    public final Charset charset() {
 111.238 +        return charset;
 111.239 +    }
 111.240 +
 111.241 +    /**
 111.242 +     * Returns this decoder's replacement value. </p>
 111.243 +     *
 111.244 +     * @return  This decoder's current replacement,
 111.245 +     *          which is never <tt>null</tt> and is never empty
 111.246 +     */
 111.247 +    public final String replacement() {
 111.248 +        return replacement;
 111.249 +    }
 111.250 +
 111.251 +    /**
 111.252 +     * Changes this decoder's replacement value.
 111.253 +     *
 111.254 +     * <p> This method invokes the {@link #implReplaceWith implReplaceWith}
 111.255 +     * method, passing the new replacement, after checking that the new
 111.256 +     * replacement is acceptable.  </p>
 111.257 +     *
 111.258 +     * @param  newReplacement
 111.259 +     *
 111.260 +
 111.261 +     *         The new replacement; must not be <tt>null</tt>
 111.262 +     *         and must have non-zero length
 111.263 +
 111.264 +
 111.265 +
 111.266 +
 111.267 +
 111.268 +
 111.269 +
 111.270 +     *
 111.271 +     * @return  This decoder
 111.272 +     *
 111.273 +     * @throws  IllegalArgumentException
 111.274 +     *          If the preconditions on the parameter do not hold
 111.275 +     */
 111.276 +    public final CharsetDecoder replaceWith(String newReplacement) {
 111.277 +        if (newReplacement == null)
 111.278 +            throw new IllegalArgumentException("Null replacement");
 111.279 +        int len = newReplacement.length();
 111.280 +        if (len == 0)
 111.281 +            throw new IllegalArgumentException("Empty replacement");
 111.282 +        if (len > maxCharsPerByte)
 111.283 +            throw new IllegalArgumentException("Replacement too long");
 111.284 +
 111.285 +
 111.286 +
 111.287 +
 111.288 +        this.replacement = newReplacement;
 111.289 +        implReplaceWith(newReplacement);
 111.290 +        return this;
 111.291 +    }
 111.292 +
 111.293 +    /**
 111.294 +     * Reports a change to this decoder's replacement value.
 111.295 +     *
 111.296 +     * <p> The default implementation of this method does nothing.  This method
 111.297 +     * should be overridden by decoders that require notification of changes to
 111.298 +     * the replacement.  </p>
 111.299 +     *
 111.300 +     * @param  newReplacement
 111.301 +     */
 111.302 +    protected void implReplaceWith(String newReplacement) {
 111.303 +    }
 111.304 +
 111.305 +
 111.306 +
 111.307 +
 111.308 +
 111.309 +
 111.310 +
 111.311 +
 111.312 +
 111.313 +
 111.314 +
 111.315 +
 111.316 +
 111.317 +
 111.318 +
 111.319 +
 111.320 +
 111.321 +
 111.322 +
 111.323 +
 111.324 +
 111.325 +
 111.326 +
 111.327 +
 111.328 +
 111.329 +
 111.330 +
 111.331 +
 111.332 +
 111.333 +
 111.334 +
 111.335 +
 111.336 +
 111.337 +
 111.338 +
 111.339 +
 111.340 +
 111.341 +
 111.342 +
 111.343 +
 111.344 +
 111.345 +    /**
 111.346 +     * Returns this decoder's current action for malformed-input errors.  </p>
 111.347 +     *
 111.348 +     * @return The current malformed-input action, which is never <tt>null</tt>
 111.349 +     */
 111.350 +//    public CodingErrorAction malformedInputAction() {
 111.351 +//        return malformedInputAction;
 111.352 +//    }
 111.353 +
 111.354 +    /**
 111.355 +     * Changes this decoder's action for malformed-input errors.  </p>
 111.356 +     *
 111.357 +     * <p> This method invokes the {@link #implOnMalformedInput
 111.358 +     * implOnMalformedInput} method, passing the new action.  </p>
 111.359 +     *
 111.360 +     * @param  newAction  The new action; must not be <tt>null</tt>
 111.361 +     *
 111.362 +     * @return  This decoder
 111.363 +     *
 111.364 +     * @throws IllegalArgumentException
 111.365 +     *         If the precondition on the parameter does not hold
 111.366 +     */
 111.367 +//    public final CharsetDecoder onMalformedInput(CodingErrorAction newAction) {
 111.368 +//        if (newAction == null)
 111.369 +//            throw new IllegalArgumentException("Null action");
 111.370 +//        malformedInputAction = newAction;
 111.371 +//        implOnMalformedInput(newAction);
 111.372 +//        return this;
 111.373 +//    }
 111.374 +
 111.375 +    /**
 111.376 +     * Reports a change to this decoder's malformed-input action.
 111.377 +     *
 111.378 +     * <p> The default implementation of this method does nothing.  This method
 111.379 +     * should be overridden by decoders that require notification of changes to
 111.380 +     * the malformed-input action.  </p>
 111.381 +     */
 111.382 +//    protected void implOnMalformedInput(CodingErrorAction newAction) { }
 111.383 +
 111.384 +    /**
 111.385 +     * Returns this decoder's current action for unmappable-character errors.
 111.386 +     * </p>
 111.387 +     *
 111.388 +     * @return The current unmappable-character action, which is never
 111.389 +     *         <tt>null</tt>
 111.390 +     */
 111.391 +//    public CodingErrorAction unmappableCharacterAction() {
 111.392 +//        return unmappableCharacterAction;
 111.393 +//    }
 111.394 +
 111.395 +    /**
 111.396 +     * Changes this decoder's action for unmappable-character errors.
 111.397 +     *
 111.398 +     * <p> This method invokes the {@link #implOnUnmappableCharacter
 111.399 +     * implOnUnmappableCharacter} method, passing the new action.  </p>
 111.400 +     *
 111.401 +     * @param  newAction  The new action; must not be <tt>null</tt>
 111.402 +     *
 111.403 +     * @return  This decoder
 111.404 +     *
 111.405 +     * @throws IllegalArgumentException
 111.406 +     *         If the precondition on the parameter does not hold
 111.407 +     */
 111.408 +//    public final CharsetDecoder onUnmappableCharacter(CodingErrorAction
 111.409 +//                                                      newAction)
 111.410 +//    {
 111.411 +//        if (newAction == null)
 111.412 +//            throw new IllegalArgumentException("Null action");
 111.413 +//        unmappableCharacterAction = newAction;
 111.414 +//        implOnUnmappableCharacter(newAction);
 111.415 +//        return this;
 111.416 +//    }
 111.417 +
 111.418 +    /**
 111.419 +     * Reports a change to this decoder's unmappable-character action.
 111.420 +     *
 111.421 +     * <p> The default implementation of this method does nothing.  This method
 111.422 +     * should be overridden by decoders that require notification of changes to
 111.423 +     * the unmappable-character action.  </p>
 111.424 +     */
 111.425 +//    protected void implOnUnmappableCharacter(CodingErrorAction newAction) { }
 111.426 +
 111.427 +    /**
 111.428 +     * Returns the average number of characters that will be produced for each
 111.429 +     * byte of input.  This heuristic value may be used to estimate the size
 111.430 +     * of the output buffer required for a given input sequence. </p>
 111.431 +     *
 111.432 +     * @return  The average number of characters produced
 111.433 +     *          per byte of input
 111.434 +     */
 111.435 +    public final float averageCharsPerByte() {
 111.436 +        return averageCharsPerByte;
 111.437 +    }
 111.438 +
 111.439 +    /**
 111.440 +     * Returns the maximum number of characters that will be produced for each
 111.441 +     * byte of input.  This value may be used to compute the worst-case size
 111.442 +     * of the output buffer required for a given input sequence. </p>
 111.443 +     *
 111.444 +     * @return  The maximum number of characters that will be produced per
 111.445 +     *          byte of input
 111.446 +     */
 111.447 +    public final float maxCharsPerByte() {
 111.448 +        return maxCharsPerByte;
 111.449 +    }
 111.450 +
 111.451 +    /**
 111.452 +     * Decodes as many bytes as possible from the given input buffer,
 111.453 +     * writing the results to the given output buffer.
 111.454 +     *
 111.455 +     * <p> The buffers are read from, and written to, starting at their current
 111.456 +     * positions.  At most {@link Buffer#remaining in.remaining()} bytes
 111.457 +     * will be read and at most {@link Buffer#remaining out.remaining()}
 111.458 +     * characters will be written.  The buffers' positions will be advanced to
 111.459 +     * reflect the bytes read and the characters written, but their marks and
 111.460 +     * limits will not be modified.
 111.461 +     *
 111.462 +     * <p> In addition to reading bytes from the input buffer and writing
 111.463 +     * characters to the output buffer, this method returns a {@link CoderResult}
 111.464 +     * object to describe its reason for termination:
 111.465 +     *
 111.466 +     * <ul>
 111.467 +     *
 111.468 +     *   <li><p> {@link CoderResult#UNDERFLOW} indicates that as much of the
 111.469 +     *   input buffer as possible has been decoded.  If there is no further
 111.470 +     *   input then the invoker can proceed to the next step of the
 111.471 +     *   <a href="#steps">decoding operation</a>.  Otherwise this method
 111.472 +     *   should be invoked again with further input.  </p></li>
 111.473 +     *
 111.474 +     *   <li><p> {@link CoderResult#OVERFLOW} indicates that there is
 111.475 +     *   insufficient space in the output buffer to decode any more bytes.
 111.476 +     *   This method should be invoked again with an output buffer that has
 111.477 +     *   more {@linkplain Buffer#remaining remaining} characters. This is
 111.478 +     *   typically done by draining any decoded characters from the output
 111.479 +     *   buffer.  </p></li>
 111.480 +     *
 111.481 +     *   <li><p> A {@link CoderResult#malformedForLength
 111.482 +     *   </code>malformed-input<code>} result indicates that a malformed-input
 111.483 +     *   error has been detected.  The malformed bytes begin at the input
 111.484 +     *   buffer's (possibly incremented) position; the number of malformed
 111.485 +     *   bytes may be determined by invoking the result object's {@link
 111.486 +     *   CoderResult#length() length} method.  This case applies only if the
 111.487 +     *   {@link #onMalformedInput </code>malformed action<code>} of this decoder
 111.488 +     *   is {@link CodingErrorAction#REPORT}; otherwise the malformed input
 111.489 +     *   will be ignored or replaced, as requested.  </p></li>
 111.490 +     *
 111.491 +     *   <li><p> An {@link CoderResult#unmappableForLength
 111.492 +     *   </code>unmappable-character<code>} result indicates that an
 111.493 +     *   unmappable-character error has been detected.  The bytes that
 111.494 +     *   decode the unmappable character begin at the input buffer's (possibly
 111.495 +     *   incremented) position; the number of such bytes may be determined
 111.496 +     *   by invoking the result object's {@link CoderResult#length() length}
 111.497 +     *   method.  This case applies only if the {@link #onUnmappableCharacter
 111.498 +     *   </code>unmappable action<code>} of this decoder is {@link
 111.499 +     *   CodingErrorAction#REPORT}; otherwise the unmappable character will be
 111.500 +     *   ignored or replaced, as requested.  </p></li>
 111.501 +     *
 111.502 +     * </ul>
 111.503 +     *
 111.504 +     * In any case, if this method is to be reinvoked in the same decoding
 111.505 +     * operation then care should be taken to preserve any bytes remaining
 111.506 +     * in the input buffer so that they are available to the next invocation.
 111.507 +     *
 111.508 +     * <p> The <tt>endOfInput</tt> parameter advises this method as to whether
 111.509 +     * the invoker can provide further input beyond that contained in the given
 111.510 +     * input buffer.  If there is a possibility of providing additional input
 111.511 +     * then the invoker should pass <tt>false</tt> for this parameter; if there
 111.512 +     * is no possibility of providing further input then the invoker should
 111.513 +     * pass <tt>true</tt>.  It is not erroneous, and in fact it is quite
 111.514 +     * common, to pass <tt>false</tt> in one invocation and later discover that
 111.515 +     * no further input was actually available.  It is critical, however, that
 111.516 +     * the final invocation of this method in a sequence of invocations always
 111.517 +     * pass <tt>true</tt> so that any remaining undecoded input will be treated
 111.518 +     * as being malformed.
 111.519 +     *
 111.520 +     * <p> This method works by invoking the {@link #decodeLoop decodeLoop}
 111.521 +     * method, interpreting its results, handling error conditions, and
 111.522 +     * reinvoking it as necessary.  </p>
 111.523 +     *
 111.524 +     *
 111.525 +     * @param  in
 111.526 +     *         The input byte buffer
 111.527 +     *
 111.528 +     * @param  out
 111.529 +     *         The output character buffer
 111.530 +     *
 111.531 +     * @param  endOfInput
 111.532 +     *         <tt>true</tt> if, and only if, the invoker can provide no
 111.533 +     *         additional input bytes beyond those in the given buffer
 111.534 +     *
 111.535 +     * @return  A coder-result object describing the reason for termination
 111.536 +     *
 111.537 +     * @throws  IllegalStateException
 111.538 +     *          If a decoding operation is already in progress and the previous
 111.539 +     *          step was an invocation neither of the {@link #reset reset}
 111.540 +     *          method, nor of this method with a value of <tt>false</tt> for
 111.541 +     *          the <tt>endOfInput</tt> parameter, nor of this method with a
 111.542 +     *          value of <tt>true</tt> for the <tt>endOfInput</tt> parameter
 111.543 +     *          but a return value indicating an incomplete decoding operation
 111.544 +     *
 111.545 +     * @throws  CoderMalfunctionError
 111.546 +     *          If an invocation of the decodeLoop method threw
 111.547 +     *          an unexpected exception
 111.548 +     */
 111.549 +//    public final CoderResult decode(ByteBuffer in, CharBuffer out,
 111.550 +//                                    boolean endOfInput)
 111.551 +//    {
 111.552 +//        int newState = endOfInput ? ST_END : ST_CODING;
 111.553 +//        if ((state != ST_RESET) && (state != ST_CODING)
 111.554 +//            && !(endOfInput && (state == ST_END)))
 111.555 +//            throwIllegalStateException(state, newState);
 111.556 +//        state = newState;
 111.557 +//
 111.558 +//        for (;;) {
 111.559 +//
 111.560 +//            CoderResult cr;
 111.561 +//            try {
 111.562 +//                cr = decodeLoop(in, out);
 111.563 +//            } catch (BufferUnderflowException x) {
 111.564 +//                throw new CoderMalfunctionError(x);
 111.565 +//            } catch (BufferOverflowException x) {
 111.566 +//                throw new CoderMalfunctionError(x);
 111.567 +//            }
 111.568 +//
 111.569 +//            if (cr.isOverflow())
 111.570 +//                return cr;
 111.571 +//
 111.572 +//            if (cr.isUnderflow()) {
 111.573 +//                if (endOfInput && in.hasRemaining()) {
 111.574 +//                    cr = CoderResult.malformedForLength(in.remaining());
 111.575 +//                    // Fall through to malformed-input case
 111.576 +//                } else {
 111.577 +//                    return cr;
 111.578 +//                }
 111.579 +//            }
 111.580 +//
 111.581 +//            CodingErrorAction action = null;
 111.582 +//            if (cr.isMalformed())
 111.583 +//                action = malformedInputAction;
 111.584 +//            else if (cr.isUnmappable())
 111.585 +//                action = unmappableCharacterAction;
 111.586 +//            else
 111.587 +//                assert false : cr.toString();
 111.588 +//
 111.589 +//            if (action == CodingErrorAction.REPORT)
 111.590 +//                return cr;
 111.591 +//
 111.592 +//            if (action == CodingErrorAction.REPLACE) {
 111.593 +//                if (out.remaining() < replacement.length())
 111.594 +//                    return CoderResult.OVERFLOW;
 111.595 +//                out.put(replacement);
 111.596 +//            }
 111.597 +//
 111.598 +//            if ((action == CodingErrorAction.IGNORE)
 111.599 +//                || (action == CodingErrorAction.REPLACE)) {
 111.600 +//                // Skip erroneous input either way
 111.601 +//                in.position(in.position() + cr.length());
 111.602 +//                continue;
 111.603 +//            }
 111.604 +//
 111.605 +//            assert false;
 111.606 +//        }
 111.607 +//
 111.608 +//    }
 111.609 +
 111.610 +    /**
 111.611 +     * Flushes this decoder.
 111.612 +     *
 111.613 +     * <p> Some decoders maintain internal state and may need to write some
 111.614 +     * final characters to the output buffer once the overall input sequence has
 111.615 +     * been read.
 111.616 +     *
 111.617 +     * <p> Any additional output is written to the output buffer beginning at
 111.618 +     * its current position.  At most {@link Buffer#remaining out.remaining()}
 111.619 +     * characters will be written.  The buffer's position will be advanced
 111.620 +     * appropriately, but its mark and limit will not be modified.
 111.621 +     *
 111.622 +     * <p> If this method completes successfully then it returns {@link
 111.623 +     * CoderResult#UNDERFLOW}.  If there is insufficient room in the output
 111.624 +     * buffer then it returns {@link CoderResult#OVERFLOW}.  If this happens
 111.625 +     * then this method must be invoked again, with an output buffer that has
 111.626 +     * more room, in order to complete the current <a href="#steps">decoding
 111.627 +     * operation</a>.
 111.628 +     *
 111.629 +     * <p> If this decoder has already been flushed then invoking this method
 111.630 +     * has no effect.
 111.631 +     *
 111.632 +     * <p> This method invokes the {@link #implFlush implFlush} method to
 111.633 +     * perform the actual flushing operation.  </p>
 111.634 +     *
 111.635 +     * @param  out
 111.636 +     *         The output character buffer
 111.637 +     *
 111.638 +     * @return  A coder-result object, either {@link CoderResult#UNDERFLOW} or
 111.639 +     *          {@link CoderResult#OVERFLOW}
 111.640 +     *
 111.641 +     * @throws  IllegalStateException
 111.642 +     *          If the previous step of the current decoding operation was an
 111.643 +     *          invocation neither of the {@link #flush flush} method nor of
 111.644 +     *          the three-argument {@link
 111.645 +     *          #decode(ByteBuffer,CharBuffer,boolean) decode} method
 111.646 +     *          with a value of <tt>true</tt> for the <tt>endOfInput</tt>
 111.647 +     *          parameter
 111.648 +     */
 111.649 +//    public final CoderResult flush(CharBuffer out) {
 111.650 +//        if (state == ST_END) {
 111.651 +//            CoderResult cr = implFlush(out);
 111.652 +//            if (cr.isUnderflow())
 111.653 +//                state = ST_FLUSHED;
 111.654 +//            return cr;
 111.655 +//        }
 111.656 +//
 111.657 +//        if (state != ST_FLUSHED)
 111.658 +//            throwIllegalStateException(state, ST_FLUSHED);
 111.659 +//
 111.660 +//        return CoderResult.UNDERFLOW; // Already flushed
 111.661 +//    }
 111.662 +
 111.663 +    /**
 111.664 +     * Flushes this decoder.
 111.665 +     *
 111.666 +     * <p> The default implementation of this method does nothing, and always
 111.667 +     * returns {@link CoderResult#UNDERFLOW}.  This method should be overridden
 111.668 +     * by decoders that may need to write final characters to the output buffer
 111.669 +     * once the entire input sequence has been read. </p>
 111.670 +     *
 111.671 +     * @param  out
 111.672 +     *         The output character buffer
 111.673 +     *
 111.674 +     * @return  A coder-result object, either {@link CoderResult#UNDERFLOW} or
 111.675 +     *          {@link CoderResult#OVERFLOW}
 111.676 +     */
 111.677 +//    protected CoderResult implFlush(CharBuffer out) {
 111.678 +//        return CoderResult.UNDERFLOW;
 111.679 +//    }
 111.680 +
 111.681 +    /**
 111.682 +     * Resets this decoder, clearing any internal state.
 111.683 +     *
 111.684 +     * <p> This method resets charset-independent state and also invokes the
 111.685 +     * {@link #implReset() implReset} method in order to perform any
 111.686 +     * charset-specific reset actions.  </p>
 111.687 +     *
 111.688 +     * @return  This decoder
 111.689 +     *
 111.690 +     */
 111.691 +    public final CharsetDecoder reset() {
 111.692 +        implReset();
 111.693 +        state = ST_RESET;
 111.694 +        return this;
 111.695 +    }
 111.696 +
 111.697 +    /**
 111.698 +     * Resets this decoder, clearing any charset-specific internal state.
 111.699 +     *
 111.700 +     * <p> The default implementation of this method does nothing.  This method
 111.701 +     * should be overridden by decoders that maintain internal state.  </p>
 111.702 +     */
 111.703 +    protected void implReset() { }
 111.704 +
 111.705 +    /**
 111.706 +     * Decodes one or more bytes into one or more characters.
 111.707 +     *
 111.708 +     * <p> This method encapsulates the basic decoding loop, decoding as many
 111.709 +     * bytes as possible until it either runs out of input, runs out of room
 111.710 +     * in the output buffer, or encounters a decoding error.  This method is
 111.711 +     * invoked by the {@link #decode decode} method, which handles result
 111.712 +     * interpretation and error recovery.
 111.713 +     *
 111.714 +     * <p> The buffers are read from, and written to, starting at their current
 111.715 +     * positions.  At most {@link Buffer#remaining in.remaining()} bytes
 111.716 +     * will be read, and at most {@link Buffer#remaining out.remaining()}
 111.717 +     * characters will be written.  The buffers' positions will be advanced to
 111.718 +     * reflect the bytes read and the characters written, but their marks and
 111.719 +     * limits will not be modified.
 111.720 +     *
 111.721 +     * <p> This method returns a {@link CoderResult} object to describe its
 111.722 +     * reason for termination, in the same manner as the {@link #decode decode}
 111.723 +     * method.  Most implementations of this method will handle decoding errors
 111.724 +     * by returning an appropriate result object for interpretation by the
 111.725 +     * {@link #decode decode} method.  An optimized implementation may instead
 111.726 +     * examine the relevant error action and implement that action itself.
 111.727 +     *
 111.728 +     * <p> An implementation of this method may perform arbitrary lookahead by
 111.729 +     * returning {@link CoderResult#UNDERFLOW} until it receives sufficient
 111.730 +     * input.  </p>
 111.731 +     *
 111.732 +     * @param  in
 111.733 +     *         The input byte buffer
 111.734 +     *
 111.735 +     * @param  out
 111.736 +     *         The output character buffer
 111.737 +     *
 111.738 +     * @return  A coder-result object describing the reason for termination
 111.739 +     */
 111.740 +//    protected abstract CoderResult decodeLoop(ByteBuffer in,
 111.741 +//                                              CharBuffer out);
 111.742 +
 111.743 +    /**
 111.744 +     * Convenience method that decodes the remaining content of a single input
 111.745 +     * byte buffer into a newly-allocated character buffer.
 111.746 +     *
 111.747 +     * <p> This method implements an entire <a href="#steps">decoding
 111.748 +     * operation</a>; that is, it resets this decoder, then it decodes the
 111.749 +     * bytes in the given byte buffer, and finally it flushes this
 111.750 +     * decoder.  This method should therefore not be invoked if a decoding
 111.751 +     * operation is already in progress.  </p>
 111.752 +     *
 111.753 +     * @param  in
 111.754 +     *         The input byte buffer
 111.755 +     *
 111.756 +     * @return A newly-allocated character buffer containing the result of the
 111.757 +     *         decoding operation.  The buffer's position will be zero and its
 111.758 +     *         limit will follow the last character written.
 111.759 +     *
 111.760 +     * @throws  IllegalStateException
 111.761 +     *          If a decoding operation is already in progress
 111.762 +     *
 111.763 +     * @throws  MalformedInputException
 111.764 +     *          If the byte sequence starting at the input buffer's current
 111.765 +     *          position is not legal for this charset and the current malformed-input action
 111.766 +     *          is {@link CodingErrorAction#REPORT}
 111.767 +     *
 111.768 +     * @throws  UnmappableCharacterException
 111.769 +     *          If the byte sequence starting at the input buffer's current
 111.770 +     *          position cannot be mapped to an equivalent character sequence and
 111.771 +     *          the current unmappable-character action is {@link
 111.772 +     *          CodingErrorAction#REPORT}
 111.773 +     */
 111.774 +//    public final CharBuffer decode(ByteBuffer in)
 111.775 +//        throws CharacterCodingException
 111.776 +//    {
 111.777 +//        int n = (int)(in.remaining() * averageCharsPerByte());
 111.778 +//        CharBuffer out = CharBuffer.allocate(n);
 111.779 +//
 111.780 +//        if ((n == 0) && (in.remaining() == 0))
 111.781 +//            return out;
 111.782 +//        reset();
 111.783 +//        for (;;) {
 111.784 +//            CoderResult cr = in.hasRemaining() ?
 111.785 +//                decode(in, out, true) : CoderResult.UNDERFLOW;
 111.786 +//            if (cr.isUnderflow())
 111.787 +//                cr = flush(out);
 111.788 +//
 111.789 +//            if (cr.isUnderflow())
 111.790 +//                break;
 111.791 +//            if (cr.isOverflow()) {
 111.792 +//                n = 2*n + 1;    // Ensure progress; n might be 0!
 111.793 +//                CharBuffer o = CharBuffer.allocate(n);
 111.794 +//                out.flip();
 111.795 +//                o.put(out);
 111.796 +//                out = o;
 111.797 +//                continue;
 111.798 +//            }
 111.799 +//            cr.throwException();
 111.800 +//        }
 111.801 +//        out.flip();
 111.802 +//        return out;
 111.803 +//    }
 111.804 +
 111.805 +
 111.806 +
 111.807 +    /**
 111.808 +     * Tells whether or not this decoder implements an auto-detecting charset.
 111.809 +     *
 111.810 +     * <p> The default implementation of this method always returns
 111.811 +     * <tt>false</tt>; it should be overridden by auto-detecting decoders to
 111.812 +     * return <tt>true</tt>.  </p>
 111.813 +     *
 111.814 +     * @return  <tt>true</tt> if, and only if, this decoder implements an
 111.815 +     *          auto-detecting charset
 111.816 +     */
 111.817 +    public boolean isAutoDetecting() {
 111.818 +        return false;
 111.819 +    }
 111.820 +
 111.821 +    /**
 111.822 +     * Tells whether or not this decoder has yet detected a
 111.823 +     * charset&nbsp;&nbsp;<i>(optional operation)</i>.
 111.824 +     *
 111.825 +     * <p> If this decoder implements an auto-detecting charset then at a
 111.826 +     * single point during a decoding operation this method may start returning
 111.827 +     * <tt>true</tt> to indicate that a specific charset has been detected in
 111.828 +     * the input byte sequence.  Once this occurs, the {@link #detectedCharset
 111.829 +     * detectedCharset} method may be invoked to retrieve the detected charset.
 111.830 +     *
 111.831 +     * <p> That this method returns <tt>false</tt> does not imply that no bytes
 111.832 +     * have yet been decoded.  Some auto-detecting decoders are capable of
 111.833 +     * decoding some, or even all, of an input byte sequence without fixing on
 111.834 +     * a particular charset.
 111.835 +     *
 111.836 +     * <p> The default implementation of this method always throws an {@link
 111.837 +     * UnsupportedOperationException}; it should be overridden by
 111.838 +     * auto-detecting decoders to return <tt>true</tt> once the input charset
 111.839 +     * has been determined.  </p>
 111.840 +     *
 111.841 +     * @return  <tt>true</tt> if, and only if, this decoder has detected a
 111.842 +     *          specific charset
 111.843 +     *
 111.844 +     * @throws  UnsupportedOperationException
 111.845 +     *          If this decoder does not implement an auto-detecting charset
 111.846 +     */
 111.847 +    public boolean isCharsetDetected() {
 111.848 +        throw new UnsupportedOperationException();
 111.849 +    }
 111.850 +
 111.851 +    /**
 111.852 +     * Retrieves the charset that was detected by this
 111.853 +     * decoder&nbsp;&nbsp;<i>(optional operation)</i>.
 111.854 +     *
 111.855 +     * <p> If this decoder implements an auto-detecting charset then this
 111.856 +     * method returns the actual charset once it has been detected.  After that
 111.857 +     * point, this method returns the same value for the duration of the
 111.858 +     * current decoding operation.  If not enough input bytes have yet been
 111.859 +     * read to determine the actual charset then this method throws an {@link
 111.860 +     * IllegalStateException}.
 111.861 +     *
 111.862 +     * <p> The default implementation of this method always throws an {@link
 111.863 +     * UnsupportedOperationException}; it should be overridden by
 111.864 +     * auto-detecting decoders to return the appropriate value.  </p>
 111.865 +     *
 111.866 +     * @return  The charset detected by this auto-detecting decoder,
 111.867 +     *          or <tt>null</tt> if the charset has not yet been determined
 111.868 +     *
 111.869 +     * @throws  IllegalStateException
 111.870 +     *          If insufficient bytes have been read to determine a charset
 111.871 +     *
 111.872 +     * @throws  UnsupportedOperationException
 111.873 +     *          If this decoder does not implement an auto-detecting charset
 111.874 +     */
 111.875 +    public Charset detectedCharset() {
 111.876 +        throw new UnsupportedOperationException();
 111.877 +    }
 111.878 +
 111.879 +
 111.880 +
 111.881 +
 111.882 +
 111.883 +
 111.884 +
 111.885 +
 111.886 +
 111.887 +
 111.888 +
 111.889 +
 111.890 +
 111.891 +
 111.892 +
 111.893 +
 111.894 +
 111.895 +
 111.896 +
 111.897 +
 111.898 +
 111.899 +
 111.900 +
 111.901 +
 111.902 +
 111.903 +
 111.904 +
 111.905 +
 111.906 +
 111.907 +
 111.908 +
 111.909 +
 111.910 +
 111.911 +
 111.912 +
 111.913 +
 111.914 +
 111.915 +
 111.916 +
 111.917 +
 111.918 +
 111.919 +
 111.920 +
 111.921 +
 111.922 +
 111.923 +
 111.924 +
 111.925 +
 111.926 +
 111.927 +
 111.928 +
 111.929 +
 111.930 +
 111.931 +
 111.932 +
 111.933 +
 111.934 +
 111.935 +
 111.936 +
 111.937 +
 111.938 +
 111.939 +
 111.940 +
 111.941 +
 111.942 +
 111.943 +
 111.944 +
 111.945 +
 111.946 +
 111.947 +
 111.948 +
 111.949 +
 111.950 +
 111.951 +
 111.952 +
 111.953 +
 111.954 +
 111.955 +
 111.956 +
 111.957 +
 111.958 +
 111.959 +
 111.960 +
 111.961 +
 111.962 +
 111.963 +
 111.964 +
 111.965 +
 111.966 +
 111.967 +
 111.968 +    private void throwIllegalStateException(int from, int to) {
 111.969 +        throw new IllegalStateException("Current state = " + stateNames[from]
 111.970 +                                        + ", new state = " + stateNames[to]);
 111.971 +    }
 111.972 +
 111.973 +}
   112.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   112.2 +++ b/rt/emul/compact/src/main/java/java/nio/charset/CharsetEncoder.java	Tue Feb 11 13:31:42 2014 +0100
   112.3 @@ -0,0 +1,970 @@
   112.4 +/*
   112.5 + * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
   112.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   112.7 + *
   112.8 + * This code is free software; you can redistribute it and/or modify it
   112.9 + * under the terms of the GNU General Public License version 2 only, as
  112.10 + * published by the Free Software Foundation.  Oracle designates this
  112.11 + * particular file as subject to the "Classpath" exception as provided
  112.12 + * by Oracle in the LICENSE file that accompanied this code.
  112.13 + *
  112.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  112.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  112.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  112.17 + * version 2 for more details (a copy is included in the LICENSE file that
  112.18 + * accompanied this code).
  112.19 + *
  112.20 + * You should have received a copy of the GNU General Public License version
  112.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  112.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  112.23 + *
  112.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  112.25 + * or visit www.oracle.com if you need additional information or have any
  112.26 + * questions.
  112.27 + */
  112.28 +
  112.29 +// -- This file was mechanically generated: Do not edit! -- //
  112.30 +
  112.31 +package java.nio.charset;
  112.32 +
  112.33 +//import java.nio.Buffer;
  112.34 +//import java.nio.ByteBuffer;
  112.35 +//import java.nio.CharBuffer;
  112.36 +//import java.nio.BufferOverflowException;
  112.37 +//import java.nio.BufferUnderflowException;
  112.38 +import java.lang.ref.WeakReference;
  112.39 +//import java.nio.charset.CoderMalfunctionError;                  // javadoc
  112.40 +
  112.41 +
  112.42 +/**
  112.43 + * An engine that can transform a sequence of sixteen-bit Unicode characters into a sequence of
  112.44 + * bytes in a specific charset.
  112.45 + *
  112.46 + * <a name="steps">
  112.47 + *
  112.48 + * <p> The input character sequence is provided in a character buffer or a series
  112.49 + * of such buffers.  The output byte sequence is written to a byte buffer
  112.50 + * or a series of such buffers.  An encoder should always be used by making
  112.51 + * the following sequence of method invocations, hereinafter referred to as an
  112.52 + * <i>encoding operation</i>:
  112.53 + *
  112.54 + * <ol>
  112.55 + *
  112.56 + *   <li><p> Reset the encoder via the {@link #reset reset} method, unless it
  112.57 + *   has not been used before; </p></li>
  112.58 + *
  112.59 + *   <li><p> Invoke the {@link #encode encode} method zero or more times, as
  112.60 + *   long as additional input may be available, passing <tt>false</tt> for the
  112.61 + *   <tt>endOfInput</tt> argument and filling the input buffer and flushing the
  112.62 + *   output buffer between invocations; </p></li>
  112.63 + *
  112.64 + *   <li><p> Invoke the {@link #encode encode} method one final time, passing
  112.65 + *   <tt>true</tt> for the <tt>endOfInput</tt> argument; and then </p></li>
  112.66 + *
  112.67 + *   <li><p> Invoke the {@link #flush flush} method so that the encoder can
  112.68 + *   flush any internal state to the output buffer. </p></li>
  112.69 + *
  112.70 + * </ol>
  112.71 + *
  112.72 + * Each invocation of the {@link #encode encode} method will encode as many
  112.73 + * characters as possible from the input buffer, writing the resulting bytes
  112.74 + * to the output buffer.  The {@link #encode encode} method returns when more
  112.75 + * input is required, when there is not enough room in the output buffer, or
  112.76 + * when an encoding error has occurred.  In each case a {@link CoderResult}
  112.77 + * object is returned to describe the reason for termination.  An invoker can
  112.78 + * examine this object and fill the input buffer, flush the output buffer, or
  112.79 + * attempt to recover from an encoding error, as appropriate, and try again.
  112.80 + *
  112.81 + * <a name="ce">
  112.82 + *
  112.83 + * <p> There are two general types of encoding errors.  If the input character
  112.84 + * sequence is not a legal sixteen-bit Unicode sequence then the input is considered <i>malformed</i>.  If
  112.85 + * the input character sequence is legal but cannot be mapped to a valid
  112.86 + * byte sequence in the given charset then an <i>unmappable character</i> has been encountered.
  112.87 + *
  112.88 + * <a name="cae">
  112.89 + *
  112.90 + * <p> How an encoding error is handled depends upon the action requested for
  112.91 + * that type of error, which is described by an instance of the {@link
  112.92 + * CodingErrorAction} class.  The possible error actions are to {@link
  112.93 + * CodingErrorAction#IGNORE </code>ignore<code>} the erroneous input, {@link
  112.94 + * CodingErrorAction#REPORT </code>report<code>} the error to the invoker via
  112.95 + * the returned {@link CoderResult} object, or {@link CodingErrorAction#REPLACE
  112.96 + * </code>replace<code>} the erroneous input with the current value of the
  112.97 + * replacement byte array.  The replacement
  112.98 + *
  112.99 +
 112.100 + * is initially set to the encoder's default replacement, which often
 112.101 + * (but not always) has the initial value&nbsp;<tt>{</tt>&nbsp;<tt>(byte)'?'</tt>&nbsp;<tt>}</tt>;
 112.102 +
 112.103 +
 112.104 +
 112.105 +
 112.106 + *
 112.107 + * its value may be changed via the {@link #replaceWith(byte[])
 112.108 + * replaceWith} method.
 112.109 + *
 112.110 + * <p> The default action for malformed-input and unmappable-character errors
 112.111 + * is to {@link CodingErrorAction#REPORT </code>report<code>} them.  The
 112.112 + * malformed-input error action may be changed via the {@link
 112.113 + * #onMalformedInput(CodingErrorAction) onMalformedInput} method; the
 112.114 + * unmappable-character action may be changed via the {@link
 112.115 + * #onUnmappableCharacter(CodingErrorAction) onUnmappableCharacter} method.
 112.116 + *
 112.117 + * <p> This class is designed to handle many of the details of the encoding
 112.118 + * process, including the implementation of error actions.  An encoder for a
 112.119 + * specific charset, which is a concrete subclass of this class, need only
 112.120 + * implement the abstract {@link #encodeLoop encodeLoop} method, which
 112.121 + * encapsulates the basic encoding loop.  A subclass that maintains internal
 112.122 + * state should, additionally, override the {@link #implFlush implFlush} and
 112.123 + * {@link #implReset implReset} methods.
 112.124 + *
 112.125 + * <p> Instances of this class are not safe for use by multiple concurrent
 112.126 + * threads.  </p>
 112.127 + *
 112.128 + *
 112.129 + * @author Mark Reinhold
 112.130 + * @author JSR-51 Expert Group
 112.131 + * @since 1.4
 112.132 + *
 112.133 + * @see ByteBuffer
 112.134 + * @see CharBuffer
 112.135 + * @see Charset
 112.136 + * @see CharsetDecoder
 112.137 + */
 112.138 +
 112.139 +public abstract class CharsetEncoder {
 112.140 +
 112.141 +    private final Charset charset;
 112.142 +    private final float averageBytesPerChar;
 112.143 +    private final float maxBytesPerChar;
 112.144 +
 112.145 +    private byte[] replacement;
 112.146 +//    private CodingErrorAction malformedInputAction
 112.147 +//        = CodingErrorAction.REPORT;
 112.148 +//    private CodingErrorAction unmappableCharacterAction
 112.149 +//        = CodingErrorAction.REPORT;
 112.150 +
 112.151 +    // Internal states
 112.152 +    //
 112.153 +    private static final int ST_RESET   = 0;
 112.154 +    private static final int ST_CODING  = 1;
 112.155 +    private static final int ST_END     = 2;
 112.156 +    private static final int ST_FLUSHED = 3;
 112.157 +
 112.158 +    private int state = ST_RESET;
 112.159 +
 112.160 +    private static String stateNames[]
 112.161 +        = { "RESET", "CODING", "CODING_END", "FLUSHED" };
 112.162 +
 112.163 +
 112.164 +    /**
 112.165 +     * Initializes a new encoder.  The new encoder will have the given
 112.166 +     * bytes-per-char and replacement values. </p>
 112.167 +     *
 112.168 +     * @param  averageBytesPerChar
 112.169 +     *         A positive float value indicating the expected number of
 112.170 +     *         bytes that will be produced for each input character
 112.171 +     *
 112.172 +     * @param  maxBytesPerChar
 112.173 +     *         A positive float value indicating the maximum number of
 112.174 +     *         bytes that will be produced for each input character
 112.175 +     *
 112.176 +     * @param  replacement
 112.177 +     *         The initial replacement; must not be <tt>null</tt>, must have
 112.178 +     *         non-zero length, must not be longer than maxBytesPerChar,
 112.179 +     *         and must be {@link #isLegalReplacement </code>legal<code>}
 112.180 +     *
 112.181 +     * @throws  IllegalArgumentException
 112.182 +     *          If the preconditions on the parameters do not hold
 112.183 +     */
 112.184 +    protected
 112.185 +    CharsetEncoder(Charset cs,
 112.186 +                   float averageBytesPerChar,
 112.187 +                   float maxBytesPerChar,
 112.188 +                   byte[] replacement)
 112.189 +    {
 112.190 +        this.charset = cs;
 112.191 +        if (averageBytesPerChar <= 0.0f)
 112.192 +            throw new IllegalArgumentException("Non-positive "
 112.193 +                                               + "averageBytesPerChar");
 112.194 +        if (maxBytesPerChar <= 0.0f)
 112.195 +            throw new IllegalArgumentException("Non-positive "
 112.196 +                                               + "maxBytesPerChar");
 112.197 +        if (averageBytesPerChar > maxBytesPerChar)
 112.198 +            throw new IllegalArgumentException("averageBytesPerChar"
 112.199 +                                               + " exceeds "
 112.200 +                                               + "maxBytesPerChar");
 112.201 +        this.replacement = replacement;
 112.202 +        this.averageBytesPerChar = averageBytesPerChar;
 112.203 +        this.maxBytesPerChar = maxBytesPerChar;
 112.204 +        replaceWith(replacement);
 112.205 +    }
 112.206 +
 112.207 +    /**
 112.208 +     * Initializes a new encoder.  The new encoder will have the given
 112.209 +     * bytes-per-char values and its replacement will be the
 112.210 +     * byte array <tt>{</tt>&nbsp;<tt>(byte)'?'</tt>&nbsp;<tt>}</tt>. </p>
 112.211 +     *
 112.212 +     * @param  averageBytesPerChar
 112.213 +     *         A positive float value indicating the expected number of
 112.214 +     *         bytes that will be produced for each input character
 112.215 +     *
 112.216 +     * @param  maxBytesPerChar
 112.217 +     *         A positive float value indicating the maximum number of
 112.218 +     *         bytes that will be produced for each input character
 112.219 +     *
 112.220 +     * @throws  IllegalArgumentException
 112.221 +     *          If the preconditions on the parameters do not hold
 112.222 +     */
 112.223 +    protected CharsetEncoder(Charset cs,
 112.224 +                             float averageBytesPerChar,
 112.225 +                             float maxBytesPerChar)
 112.226 +    {
 112.227 +        this(cs,
 112.228 +             averageBytesPerChar, maxBytesPerChar,
 112.229 +             new byte[] { (byte)'?' });
 112.230 +    }
 112.231 +
 112.232 +    /**
 112.233 +     * Returns the charset that created this encoder.  </p>
 112.234 +     *
 112.235 +     * @return  This encoder's charset
 112.236 +     */
 112.237 +    public final Charset charset() {
 112.238 +        return charset;
 112.239 +    }
 112.240 +
 112.241 +    /**
 112.242 +     * Returns this encoder's replacement value. </p>
 112.243 +     *
 112.244 +     * @return  This encoder's current replacement,
 112.245 +     *          which is never <tt>null</tt> and is never empty
 112.246 +     */
 112.247 +    public final byte[] replacement() {
 112.248 +        return replacement;
 112.249 +    }
 112.250 +
 112.251 +    /**
 112.252 +     * Changes this encoder's replacement value.
 112.253 +     *
 112.254 +     * <p> This method invokes the {@link #implReplaceWith implReplaceWith}
 112.255 +     * method, passing the new replacement, after checking that the new
 112.256 +     * replacement is acceptable.  </p>
 112.257 +     *
 112.258 +     * @param  newReplacement
 112.259 +     *
 112.260 +
 112.261 +
 112.262 +
 112.263 +
 112.264 +
 112.265 +     *         The new replacement; must not be <tt>null</tt>, must have
 112.266 +     *         non-zero length, must not be longer than the value returned by
 112.267 +     *         the {@link #maxBytesPerChar() maxBytesPerChar} method, and
 112.268 +     *         must be {@link #isLegalReplacement </code>legal<code>}
 112.269 +
 112.270 +     *
 112.271 +     * @return  This encoder
 112.272 +     *
 112.273 +     * @throws  IllegalArgumentException
 112.274 +     *          If the preconditions on the parameter do not hold
 112.275 +     */
 112.276 +    public final CharsetEncoder replaceWith(byte[] newReplacement) {
 112.277 +        if (newReplacement == null)
 112.278 +            throw new IllegalArgumentException("Null replacement");
 112.279 +        int len = newReplacement.length;
 112.280 +        if (len == 0)
 112.281 +            throw new IllegalArgumentException("Empty replacement");
 112.282 +        if (len > maxBytesPerChar)
 112.283 +            throw new IllegalArgumentException("Replacement too long");
 112.284 +
 112.285 +//        if (!isLegalReplacement(newReplacement))
 112.286 +//            throw new IllegalArgumentException("Illegal replacement");
 112.287 +
 112.288 +        this.replacement = newReplacement;
 112.289 +        implReplaceWith(newReplacement);
 112.290 +        return this;
 112.291 +    }
 112.292 +
 112.293 +    /**
 112.294 +     * Reports a change to this encoder's replacement value.
 112.295 +     *
 112.296 +     * <p> The default implementation of this method does nothing.  This method
 112.297 +     * should be overridden by encoders that require notification of changes to
 112.298 +     * the replacement.  </p>
 112.299 +     *
 112.300 +     * @param  newReplacement
 112.301 +     */
 112.302 +    protected void implReplaceWith(byte[] newReplacement) {
 112.303 +    }
 112.304 +
 112.305 +
 112.306 +
 112.307 +    private WeakReference<CharsetDecoder> cachedDecoder = null;
 112.308 +
 112.309 +    /**
 112.310 +     * Tells whether or not the given byte array is a legal replacement value
 112.311 +     * for this encoder.
 112.312 +     *
 112.313 +     * <p> A replacement is legal if, and only if, it is a legal sequence of
 112.314 +     * bytes in this encoder's charset; that is, it must be possible to decode
 112.315 +     * the replacement into one or more sixteen-bit Unicode characters.
 112.316 +     *
 112.317 +     * <p> The default implementation of this method is not very efficient; it
 112.318 +     * should generally be overridden to improve performance.  </p>
 112.319 +     *
 112.320 +     * @param  repl  The byte array to be tested
 112.321 +     *
 112.322 +     * @return  <tt>true</tt> if, and only if, the given byte array
 112.323 +     *          is a legal replacement value for this encoder
 112.324 +     */
 112.325 +//    public boolean isLegalReplacement(byte[] repl) {
 112.326 +//        WeakReference<CharsetDecoder> wr = cachedDecoder;
 112.327 +//        CharsetDecoder dec = null;
 112.328 +//        if ((wr == null) || ((dec = wr.get()) == null)) {
 112.329 +//            dec = charset().newDecoder();
 112.330 +//            dec.onMalformedInput(CodingErrorAction.REPORT);
 112.331 +//            dec.onUnmappableCharacter(CodingErrorAction.REPORT);
 112.332 +//            cachedDecoder = new WeakReference<CharsetDecoder>(dec);
 112.333 +//        } else {
 112.334 +//            dec.reset();
 112.335 +//        }
 112.336 +//        ByteBuffer bb = ByteBuffer.wrap(repl);
 112.337 +//        CharBuffer cb = CharBuffer.allocate((int)(bb.remaining()
 112.338 +//                                                  * dec.maxCharsPerByte()));
 112.339 +//        CoderResult cr = dec.decode(bb, cb, true);
 112.340 +//        return !cr.isError();
 112.341 +//    }
 112.342 +
 112.343 +
 112.344 +
 112.345 +    /**
 112.346 +     * Returns this encoder's current action for malformed-input errors.  </p>
 112.347 +     *
 112.348 +     * @return The current malformed-input action, which is never <tt>null</tt>
 112.349 +     */
 112.350 +//    public CodingErrorAction malformedInputAction() {
 112.351 +//        return malformedInputAction;
 112.352 +//    }
 112.353 +
 112.354 +    /**
 112.355 +     * Changes this encoder's action for malformed-input errors.  </p>
 112.356 +     *
 112.357 +     * <p> This method invokes the {@link #implOnMalformedInput
 112.358 +     * implOnMalformedInput} method, passing the new action.  </p>
 112.359 +     *
 112.360 +     * @param  newAction  The new action; must not be <tt>null</tt>
 112.361 +     *
 112.362 +     * @return  This encoder
 112.363 +     *
 112.364 +     * @throws IllegalArgumentException
 112.365 +     *         If the precondition on the parameter does not hold
 112.366 +     */
 112.367 +//    public final CharsetEncoder onMalformedInput(CodingErrorAction newAction) {
 112.368 +//        if (newAction == null)
 112.369 +//            throw new IllegalArgumentException("Null action");
 112.370 +//        malformedInputAction = newAction;
 112.371 +//        implOnMalformedInput(newAction);
 112.372 +//        return this;
 112.373 +//    }
 112.374 +
 112.375 +    /**
 112.376 +     * Reports a change to this encoder's malformed-input action.
 112.377 +     *
 112.378 +     * <p> The default implementation of this method does nothing.  This method
 112.379 +     * should be overridden by encoders that require notification of changes to
 112.380 +     * the malformed-input action.  </p>
 112.381 +     */
 112.382 +//    protected void implOnMalformedInput(CodingErrorAction newAction) { }
 112.383 +
 112.384 +    /**
 112.385 +     * Returns this encoder's current action for unmappable-character errors.
 112.386 +     * </p>
 112.387 +     *
 112.388 +     * @return The current unmappable-character action, which is never
 112.389 +     *         <tt>null</tt>
 112.390 +     */
 112.391 +//    public CodingErrorAction unmappableCharacterAction() {
 112.392 +//        return unmappableCharacterAction;
 112.393 +//    }
 112.394 +
 112.395 +    /**
 112.396 +     * Changes this encoder's action for unmappable-character errors.
 112.397 +     *
 112.398 +     * <p> This method invokes the {@link #implOnUnmappableCharacter
 112.399 +     * implOnUnmappableCharacter} method, passing the new action.  </p>
 112.400 +     *
 112.401 +     * @param  newAction  The new action; must not be <tt>null</tt>
 112.402 +     *
 112.403 +     * @return  This encoder
 112.404 +     *
 112.405 +     * @throws IllegalArgumentException
 112.406 +     *         If the precondition on the parameter does not hold
 112.407 +     */
 112.408 +//    public final CharsetEncoder onUnmappableCharacter(CodingErrorAction
 112.409 +//                                                      newAction)
 112.410 +//    {
 112.411 +//        if (newAction == null)
 112.412 +//            throw new IllegalArgumentException("Null action");
 112.413 +//        unmappableCharacterAction = newAction;
 112.414 +//        implOnUnmappableCharacter(newAction);
 112.415 +//        return this;
 112.416 +//    }
 112.417 +
 112.418 +    /**
 112.419 +     * Reports a change to this encoder's unmappable-character action.
 112.420 +     *
 112.421 +     * <p> The default implementation of this method does nothing.  This method
 112.422 +     * should be overridden by encoders that require notification of changes to
 112.423 +     * the unmappable-character action.  </p>
 112.424 +     */
 112.425 +//    protected void implOnUnmappableCharacter(CodingErrorAction newAction) { }
 112.426 +
 112.427 +    /**
 112.428 +     * Returns the average number of bytes that will be produced for each
 112.429 +     * character of input.  This heuristic value may be used to estimate the size
 112.430 +     * of the output buffer required for a given input sequence. </p>
 112.431 +     *
 112.432 +     * @return  The average number of bytes produced
 112.433 +     *          per character of input
 112.434 +     */
 112.435 +    public final float averageBytesPerChar() {
 112.436 +        return averageBytesPerChar;
 112.437 +    }
 112.438 +
 112.439 +    /**
 112.440 +     * Returns the maximum number of bytes that will be produced for each
 112.441 +     * character of input.  This value may be used to compute the worst-case size
 112.442 +     * of the output buffer required for a given input sequence. </p>
 112.443 +     *
 112.444 +     * @return  The maximum number of bytes that will be produced per
 112.445 +     *          character of input
 112.446 +     */
 112.447 +    public final float maxBytesPerChar() {
 112.448 +        return maxBytesPerChar;
 112.449 +    }
 112.450 +
 112.451 +    /**
 112.452 +     * Encodes as many characters as possible from the given input buffer,
 112.453 +     * writing the results to the given output buffer.
 112.454 +     *
 112.455 +     * <p> The buffers are read from, and written to, starting at their current
 112.456 +     * positions.  At most {@link Buffer#remaining in.remaining()} characters
 112.457 +     * will be read and at most {@link Buffer#remaining out.remaining()}
 112.458 +     * bytes will be written.  The buffers' positions will be advanced to
 112.459 +     * reflect the characters read and the bytes written, but their marks and
 112.460 +     * limits will not be modified.
 112.461 +     *
 112.462 +     * <p> In addition to reading characters from the input buffer and writing
 112.463 +     * bytes to the output buffer, this method returns a {@link CoderResult}
 112.464 +     * object to describe its reason for termination:
 112.465 +     *
 112.466 +     * <ul>
 112.467 +     *
 112.468 +     *   <li><p> {@link CoderResult#UNDERFLOW} indicates that as much of the
 112.469 +     *   input buffer as possible has been encoded.  If there is no further
 112.470 +     *   input then the invoker can proceed to the next step of the
 112.471 +     *   <a href="#steps">encoding operation</a>.  Otherwise this method
 112.472 +     *   should be invoked again with further input.  </p></li>
 112.473 +     *
 112.474 +     *   <li><p> {@link CoderResult#OVERFLOW} indicates that there is
 112.475 +     *   insufficient space in the output buffer to encode any more characters.
 112.476 +     *   This method should be invoked again with an output buffer that has
 112.477 +     *   more {@linkplain Buffer#remaining remaining} bytes. This is
 112.478 +     *   typically done by draining any encoded bytes from the output
 112.479 +     *   buffer.  </p></li>
 112.480 +     *
 112.481 +     *   <li><p> A {@link CoderResult#malformedForLength
 112.482 +     *   </code>malformed-input<code>} result indicates that a malformed-input
 112.483 +     *   error has been detected.  The malformed characters begin at the input
 112.484 +     *   buffer's (possibly incremented) position; the number of malformed
 112.485 +     *   characters may be determined by invoking the result object's {@link
 112.486 +     *   CoderResult#length() length} method.  This case applies only if the
 112.487 +     *   {@link #onMalformedInput </code>malformed action<code>} of this encoder
 112.488 +     *   is {@link CodingErrorAction#REPORT}; otherwise the malformed input
 112.489 +     *   will be ignored or replaced, as requested.  </p></li>
 112.490 +     *
 112.491 +     *   <li><p> An {@link CoderResult#unmappableForLength
 112.492 +     *   </code>unmappable-character<code>} result indicates that an
 112.493 +     *   unmappable-character error has been detected.  The characters that
 112.494 +     *   encode the unmappable character begin at the input buffer's (possibly
 112.495 +     *   incremented) position; the number of such characters may be determined
 112.496 +     *   by invoking the result object's {@link CoderResult#length() length}
 112.497 +     *   method.  This case applies only if the {@link #onUnmappableCharacter
 112.498 +     *   </code>unmappable action<code>} of this encoder is {@link
 112.499 +     *   CodingErrorAction#REPORT}; otherwise the unmappable character will be
 112.500 +     *   ignored or replaced, as requested.  </p></li>
 112.501 +     *
 112.502 +     * </ul>
 112.503 +     *
 112.504 +     * In any case, if this method is to be reinvoked in the same encoding
 112.505 +     * operation then care should be taken to preserve any characters remaining
 112.506 +     * in the input buffer so that they are available to the next invocation.
 112.507 +     *
 112.508 +     * <p> The <tt>endOfInput</tt> parameter advises this method as to whether
 112.509 +     * the invoker can provide further input beyond that contained in the given
 112.510 +     * input buffer.  If there is a possibility of providing additional input
 112.511 +     * then the invoker should pass <tt>false</tt> for this parameter; if there
 112.512 +     * is no possibility of providing further input then the invoker should
 112.513 +     * pass <tt>true</tt>.  It is not erroneous, and in fact it is quite
 112.514 +     * common, to pass <tt>false</tt> in one invocation and later discover that
 112.515 +     * no further input was actually available.  It is critical, however, that
 112.516 +     * the final invocation of this method in a sequence of invocations always
 112.517 +     * pass <tt>true</tt> so that any remaining unencoded input will be treated
 112.518 +     * as being malformed.
 112.519 +     *
 112.520 +     * <p> This method works by invoking the {@link #encodeLoop encodeLoop}
 112.521 +     * method, interpreting its results, handling error conditions, and
 112.522 +     * reinvoking it as necessary.  </p>
 112.523 +     *
 112.524 +     *
 112.525 +     * @param  in
 112.526 +     *         The input character buffer
 112.527 +     *
 112.528 +     * @param  out
 112.529 +     *         The output byte buffer
 112.530 +     *
 112.531 +     * @param  endOfInput
 112.532 +     *         <tt>true</tt> if, and only if, the invoker can provide no
 112.533 +     *         additional input characters beyond those in the given buffer
 112.534 +     *
 112.535 +     * @return  A coder-result object describing the reason for termination
 112.536 +     *
 112.537 +     * @throws  IllegalStateException
 112.538 +     *          If an encoding operation is already in progress and the previous
 112.539 +     *          step was an invocation neither of the {@link #reset reset}
 112.540 +     *          method, nor of this method with a value of <tt>false</tt> for
 112.541 +     *          the <tt>endOfInput</tt> parameter, nor of this method with a
 112.542 +     *          value of <tt>true</tt> for the <tt>endOfInput</tt> parameter
 112.543 +     *          but a return value indicating an incomplete encoding operation
 112.544 +     *
 112.545 +     * @throws  CoderMalfunctionError
 112.546 +     *          If an invocation of the encodeLoop method threw
 112.547 +     *          an unexpected exception
 112.548 +     */
 112.549 +//    public final CoderResult encode(CharBuffer in, ByteBuffer out,
 112.550 +//                                    boolean endOfInput)
 112.551 +//    {
 112.552 +//        int newState = endOfInput ? ST_END : ST_CODING;
 112.553 +//        if ((state != ST_RESET) && (state != ST_CODING)
 112.554 +//            && !(endOfInput && (state == ST_END)))
 112.555 +//            throwIllegalStateException(state, newState);
 112.556 +//        state = newState;
 112.557 +//
 112.558 +//        for (;;) {
 112.559 +//
 112.560 +//            CoderResult cr;
 112.561 +//            try {
 112.562 +//                cr = encodeLoop(in, out);
 112.563 +//            } catch (BufferUnderflowException x) {
 112.564 +//                throw new CoderMalfunctionError(x);
 112.565 +//            } catch (BufferOverflowException x) {
 112.566 +//                throw new CoderMalfunctionError(x);
 112.567 +//            }
 112.568 +//
 112.569 +//            if (cr.isOverflow())
 112.570 +//                return cr;
 112.571 +//
 112.572 +//            if (cr.isUnderflow()) {
 112.573 +//                if (endOfInput && in.hasRemaining()) {
 112.574 +//                    cr = CoderResult.malformedForLength(in.remaining());
 112.575 +//                    // Fall through to malformed-input case
 112.576 +//                } else {
 112.577 +//                    return cr;
 112.578 +//                }
 112.579 +//            }
 112.580 +//
 112.581 +//            CodingErrorAction action = null;
 112.582 +//            if (cr.isMalformed())
 112.583 +//                action = malformedInputAction;
 112.584 +//            else if (cr.isUnmappable())
 112.585 +//                action = unmappableCharacterAction;
 112.586 +//            else
 112.587 +//                assert false : cr.toString();
 112.588 +//
 112.589 +//            if (action == CodingErrorAction.REPORT)
 112.590 +//                return cr;
 112.591 +//
 112.592 +//            if (action == CodingErrorAction.REPLACE) {
 112.593 +//                if (out.remaining() < replacement.length)
 112.594 +//                    return CoderResult.OVERFLOW;
 112.595 +//                out.put(replacement);
 112.596 +//            }
 112.597 +//
 112.598 +//            if ((action == CodingErrorAction.IGNORE)
 112.599 +//                || (action == CodingErrorAction.REPLACE)) {
 112.600 +//                // Skip erroneous input either way
 112.601 +//                in.position(in.position() + cr.length());
 112.602 +//                continue;
 112.603 +//            }
 112.604 +//
 112.605 +//            assert false;
 112.606 +//        }
 112.607 +//
 112.608 +//    }
 112.609 +
 112.610 +    /**
 112.611 +     * Flushes this encoder.
 112.612 +     *
 112.613 +     * <p> Some encoders maintain internal state and may need to write some
 112.614 +     * final bytes to the output buffer once the overall input sequence has
 112.615 +     * been read.
 112.616 +     *
 112.617 +     * <p> Any additional output is written to the output buffer beginning at
 112.618 +     * its current position.  At most {@link Buffer#remaining out.remaining()}
 112.619 +     * bytes will be written.  The buffer's position will be advanced
 112.620 +     * appropriately, but its mark and limit will not be modified.
 112.621 +     *
 112.622 +     * <p> If this method completes successfully then it returns {@link
 112.623 +     * CoderResult#UNDERFLOW}.  If there is insufficient room in the output
 112.624 +     * buffer then it returns {@link CoderResult#OVERFLOW}.  If this happens
 112.625 +     * then this method must be invoked again, with an output buffer that has
 112.626 +     * more room, in order to complete the current <a href="#steps">encoding
 112.627 +     * operation</a>.
 112.628 +     *
 112.629 +     * <p> If this encoder has already been flushed then invoking this method
 112.630 +     * has no effect.
 112.631 +     *
 112.632 +     * <p> This method invokes the {@link #implFlush implFlush} method to
 112.633 +     * perform the actual flushing operation.  </p>
 112.634 +     *
 112.635 +     * @param  out
 112.636 +     *         The output byte buffer
 112.637 +     *
 112.638 +     * @return  A coder-result object, either {@link CoderResult#UNDERFLOW} or
 112.639 +     *          {@link CoderResult#OVERFLOW}
 112.640 +     *
 112.641 +     * @throws  IllegalStateException
 112.642 +     *          If the previous step of the current encoding operation was an
 112.643 +     *          invocation neither of the {@link #flush flush} method nor of
 112.644 +     *          the three-argument {@link
 112.645 +     *          #encode(CharBuffer,ByteBuffer,boolean) encode} method
 112.646 +     *          with a value of <tt>true</tt> for the <tt>endOfInput</tt>
 112.647 +     *          parameter
 112.648 +     */
 112.649 +//    public final CoderResult flush(ByteBuffer out) {
 112.650 +//        if (state == ST_END) {
 112.651 +//            CoderResult cr = implFlush(out);
 112.652 +//            if (cr.isUnderflow())
 112.653 +//                state = ST_FLUSHED;
 112.654 +//            return cr;
 112.655 +//        }
 112.656 +//
 112.657 +//        if (state != ST_FLUSHED)
 112.658 +//            throwIllegalStateException(state, ST_FLUSHED);
 112.659 +//
 112.660 +//        return CoderResult.UNDERFLOW; // Already flushed
 112.661 +//    }
 112.662 +
 112.663 +    /**
 112.664 +     * Flushes this encoder.
 112.665 +     *
 112.666 +     * <p> The default implementation of this method does nothing, and always
 112.667 +     * returns {@link CoderResult#UNDERFLOW}.  This method should be overridden
 112.668 +     * by encoders that may need to write final bytes to the output buffer
 112.669 +     * once the entire input sequence has been read. </p>
 112.670 +     *
 112.671 +     * @param  out
 112.672 +     *         The output byte buffer
 112.673 +     *
 112.674 +     * @return  A coder-result object, either {@link CoderResult#UNDERFLOW} or
 112.675 +     *          {@link CoderResult#OVERFLOW}
 112.676 +     */
 112.677 +//    protected CoderResult implFlush(ByteBuffer out) {
 112.678 +//        return CoderResult.UNDERFLOW;
 112.679 +//    }
 112.680 +
 112.681 +    /**
 112.682 +     * Resets this encoder, clearing any internal state.
 112.683 +     *
 112.684 +     * <p> This method resets charset-independent state and also invokes the
 112.685 +     * {@link #implReset() implReset} method in order to perform any
 112.686 +     * charset-specific reset actions.  </p>
 112.687 +     *
 112.688 +     * @return  This encoder
 112.689 +     *
 112.690 +     */
 112.691 +    public final CharsetEncoder reset() {
 112.692 +        implReset();
 112.693 +        state = ST_RESET;
 112.694 +        return this;
 112.695 +    }
 112.696 +
 112.697 +    /**
 112.698 +     * Resets this encoder, clearing any charset-specific internal state.
 112.699 +     *
 112.700 +     * <p> The default implementation of this method does nothing.  This method
 112.701 +     * should be overridden by encoders that maintain internal state.  </p>
 112.702 +     */
 112.703 +    protected void implReset() { }
 112.704 +
 112.705 +    /**
 112.706 +     * Encodes one or more characters into one or more bytes.
 112.707 +     *
 112.708 +     * <p> This method encapsulates the basic encoding loop, encoding as many
 112.709 +     * characters as possible until it either runs out of input, runs out of room
 112.710 +     * in the output buffer, or encounters an encoding error.  This method is
 112.711 +     * invoked by the {@link #encode encode} method, which handles result
 112.712 +     * interpretation and error recovery.
 112.713 +     *
 112.714 +     * <p> The buffers are read from, and written to, starting at their current
 112.715 +     * positions.  At most {@link Buffer#remaining in.remaining()} characters
 112.716 +     * will be read, and at most {@link Buffer#remaining out.remaining()}
 112.717 +     * bytes will be written.  The buffers' positions will be advanced to
 112.718 +     * reflect the characters read and the bytes written, but their marks and
 112.719 +     * limits will not be modified.
 112.720 +     *
 112.721 +     * <p> This method returns a {@link CoderResult} object to describe its
 112.722 +     * reason for termination, in the same manner as the {@link #encode encode}
 112.723 +     * method.  Most implementations of this method will handle encoding errors
 112.724 +     * by returning an appropriate result object for interpretation by the
 112.725 +     * {@link #encode encode} method.  An optimized implementation may instead
 112.726 +     * examine the relevant error action and implement that action itself.
 112.727 +     *
 112.728 +     * <p> An implementation of this method may perform arbitrary lookahead by
 112.729 +     * returning {@link CoderResult#UNDERFLOW} until it receives sufficient
 112.730 +     * input.  </p>
 112.731 +     *
 112.732 +     * @param  in
 112.733 +     *         The input character buffer
 112.734 +     *
 112.735 +     * @param  out
 112.736 +     *         The output byte buffer
 112.737 +     *
 112.738 +     * @return  A coder-result object describing the reason for termination
 112.739 +     */
 112.740 +//    protected abstract CoderResult encodeLoop(CharBuffer in,
 112.741 +//                                              ByteBuffer out);
 112.742 +
 112.743 +    /**
 112.744 +     * Convenience method that encodes the remaining content of a single input
 112.745 +     * character buffer into a newly-allocated byte buffer.
 112.746 +     *
 112.747 +     * <p> This method implements an entire <a href="#steps">encoding
 112.748 +     * operation</a>; that is, it resets this encoder, then it encodes the
 112.749 +     * characters in the given character buffer, and finally it flushes this
 112.750 +     * encoder.  This method should therefore not be invoked if an encoding
 112.751 +     * operation is already in progress.  </p>
 112.752 +     *
 112.753 +     * @param  in
 112.754 +     *         The input character buffer
 112.755 +     *
 112.756 +     * @return A newly-allocated byte buffer containing the result of the
 112.757 +     *         encoding operation.  The buffer's position will be zero and its
 112.758 +     *         limit will follow the last byte written.
 112.759 +     *
 112.760 +     * @throws  IllegalStateException
 112.761 +     *          If an encoding operation is already in progress
 112.762 +     *
 112.763 +     * @throws  MalformedInputException
 112.764 +     *          If the character sequence starting at the input buffer's current
 112.765 +     *          position is not a legal sixteen-bit Unicode sequence and the current malformed-input action
 112.766 +     *          is {@link CodingErrorAction#REPORT}
 112.767 +     *
 112.768 +     * @throws  UnmappableCharacterException
 112.769 +     *          If the character sequence starting at the input buffer's current
 112.770 +     *          position cannot be mapped to an equivalent byte sequence and
 112.771 +     *          the current unmappable-character action is {@link
 112.772 +     *          CodingErrorAction#REPORT}
 112.773 +     */
 112.774 +//    public final ByteBuffer encode(CharBuffer in)
 112.775 +//        throws CharacterCodingException
 112.776 +//    {
 112.777 +//        int n = (int)(in.remaining() * averageBytesPerChar());
 112.778 +//        ByteBuffer out = ByteBuffer.allocate(n);
 112.779 +//
 112.780 +//        if ((n == 0) && (in.remaining() == 0))
 112.781 +//            return out;
 112.782 +//        reset();
 112.783 +//        for (;;) {
 112.784 +//            CoderResult cr = in.hasRemaining() ?
 112.785 +//                encode(in, out, true) : CoderResult.UNDERFLOW;
 112.786 +//            if (cr.isUnderflow())
 112.787 +//                cr = flush(out);
 112.788 +//
 112.789 +//            if (cr.isUnderflow())
 112.790 +//                break;
 112.791 +//            if (cr.isOverflow()) {
 112.792 +//                n = 2*n + 1;    // Ensure progress; n might be 0!
 112.793 +//                ByteBuffer o = ByteBuffer.allocate(n);
 112.794 +//                out.flip();
 112.795 +//                o.put(out);
 112.796 +//                out = o;
 112.797 +//                continue;
 112.798 +//            }
 112.799 +//            cr.throwException();
 112.800 +//        }
 112.801 +//        out.flip();
 112.802 +//        return out;
 112.803 +//    }
 112.804 +
 112.805 +
 112.806 +
 112.807 +
 112.808 +
 112.809 +
 112.810 +
 112.811 +
 112.812 +
 112.813 +
 112.814 +
 112.815 +
 112.816 +
 112.817 +
 112.818 +
 112.819 +
 112.820 +
 112.821 +
 112.822 +
 112.823 +
 112.824 +
 112.825 +
 112.826 +
 112.827 +
 112.828 +
 112.829 +
 112.830 +
 112.831 +
 112.832 +
 112.833 +
 112.834 +
 112.835 +
 112.836 +
 112.837 +
 112.838 +
 112.839 +
 112.840 +
 112.841 +
 112.842 +
 112.843 +
 112.844 +
 112.845 +
 112.846 +
 112.847 +
 112.848 +
 112.849 +
 112.850 +
 112.851 +
 112.852 +
 112.853 +
 112.854 +
 112.855 +
 112.856 +
 112.857 +
 112.858 +
 112.859 +
 112.860 +
 112.861 +
 112.862 +
 112.863 +
 112.864 +
 112.865 +
 112.866 +
 112.867 +
 112.868 +
 112.869 +
 112.870 +
 112.871 +
 112.872 +
 112.873 +
 112.874 +
 112.875 +
 112.876 +
 112.877 +
 112.878 +
 112.879 +
 112.880 +
 112.881 +
 112.882 +
 112.883 +//    private boolean canEncode(CharBuffer cb) {
 112.884 +//        if (state == ST_FLUSHED)
 112.885 +//            reset();
 112.886 +//        else if (state != ST_RESET)
 112.887 +//            throwIllegalStateException(state, ST_CODING);
 112.888 +//        CodingErrorAction ma = malformedInputAction();
 112.889 +//        CodingErrorAction ua = unmappableCharacterAction();
 112.890 +//        try {
 112.891 +//            onMalformedInput(CodingErrorAction.REPORT);
 112.892 +//            onUnmappableCharacter(CodingErrorAction.REPORT);
 112.893 +//            encode(cb);
 112.894 +//        } catch (CharacterCodingException x) {
 112.895 +//            return false;
 112.896 +//        } finally {
 112.897 +//            onMalformedInput(ma);
 112.898 +//            onUnmappableCharacter(ua);
 112.899 +//            reset();
 112.900 +//        }
 112.901 +//        return true;
 112.902 +//    }
 112.903 +
 112.904 +    /**
 112.905 +     * Tells whether or not this encoder can encode the given character.
 112.906 +     *
 112.907 +     * <p> This method returns <tt>false</tt> if the given character is a
 112.908 +     * surrogate character; such characters can be interpreted only when they
 112.909 +     * are members of a pair consisting of a high surrogate followed by a low
 112.910 +     * surrogate.  The {@link #canEncode(java.lang.CharSequence)
 112.911 +     * canEncode(CharSequence)} method may be used to test whether or not a
 112.912 +     * character sequence can be encoded.
 112.913 +     *
 112.914 +     * <p> This method may modify this encoder's state; it should therefore not
 112.915 +     * be invoked if an <a href="#steps">encoding operation</a> is already in
 112.916 +     * progress.
 112.917 +     *
 112.918 +     * <p> The default implementation of this method is not very efficient; it
 112.919 +     * should generally be overridden to improve performance.  </p>
 112.920 +     *
 112.921 +     * @return  <tt>true</tt> if, and only if, this encoder can encode
 112.922 +     *          the given character
 112.923 +     *
 112.924 +     * @throws  IllegalStateException
 112.925 +     *          If an encoding operation is already in progress
 112.926 +     */
 112.927 +//    public boolean canEncode(char c) {
 112.928 +//        CharBuffer cb = CharBuffer.allocate(1);
 112.929 +//        cb.put(c);
 112.930 +//        cb.flip();
 112.931 +//        return canEncode(cb);
 112.932 +//    }
 112.933 +
 112.934 +    /**
 112.935 +     * Tells whether or not this encoder can encode the given character
 112.936 +     * sequence.
 112.937 +     *
 112.938 +     * <p> If this method returns <tt>false</tt> for a particular character
 112.939 +     * sequence then more information about why the sequence cannot be encoded
 112.940 +     * may be obtained by performing a full <a href="#steps">encoding
 112.941 +     * operation</a>.
 112.942 +     *
 112.943 +     * <p> This method may modify this encoder's state; it should therefore not
 112.944 +     * be invoked if an encoding operation is already in progress.
 112.945 +     *
 112.946 +     * <p> The default implementation of this method is not very efficient; it
 112.947 +     * should generally be overridden to improve performance.  </p>
 112.948 +     *
 112.949 +     * @return  <tt>true</tt> if, and only if, this encoder can encode
 112.950 +     *          the given character without throwing any exceptions and without
 112.951 +     *          performing any replacements
 112.952 +     *
 112.953 +     * @throws  IllegalStateException
 112.954 +     *          If an encoding operation is already in progress
 112.955 +     */
 112.956 +//    public boolean canEncode(CharSequence cs) {
 112.957 +//        CharBuffer cb;
 112.958 +//        if (cs instanceof CharBuffer)
 112.959 +//            cb = ((CharBuffer)cs).duplicate();
 112.960 +//        else
 112.961 +//            cb = CharBuffer.wrap(cs.toString());
 112.962 +//        return canEncode(cb);
 112.963 +//    }
 112.964 +
 112.965 +
 112.966 +
 112.967 +
 112.968 +    private void throwIllegalStateException(int from, int to) {
 112.969 +        throw new IllegalStateException("Current state = " + stateNames[from]
 112.970 +                                        + ", new state = " + stateNames[to]);
 112.971 +    }
 112.972 +
 112.973 +}
   113.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   113.2 +++ b/rt/emul/compact/src/main/java/java/nio/charset/IllegalCharsetNameException.java	Tue Feb 11 13:31:42 2014 +0100
   113.3 @@ -0,0 +1,68 @@
   113.4 +/*
   113.5 + * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
   113.6 + *
   113.7 + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
   113.8 + *
   113.9 + *
  113.10 + *
  113.11 + *
  113.12 + *
  113.13 + *
  113.14 + *
  113.15 + *
  113.16 + *
  113.17 + *
  113.18 + *
  113.19 + *
  113.20 + *
  113.21 + *
  113.22 + *
  113.23 + *
  113.24 + *
  113.25 + *
  113.26 + *
  113.27 + *
  113.28 + *
  113.29 + */
  113.30 +
  113.31 +// -- This file was mechanically generated: Do not edit! -- //
  113.32 +
  113.33 +package java.nio.charset;
  113.34 +
  113.35 +
  113.36 +/**
  113.37 + * Unchecked exception thrown when a string that is not a
  113.38 + * <a href=Charset.html#names>legal charset name</a> is used as such.
  113.39 + *
  113.40 + * @since 1.4
  113.41 + */
  113.42 +
  113.43 +public class IllegalCharsetNameException
  113.44 +    extends IllegalArgumentException
  113.45 +{
  113.46 +
  113.47 +    private static final long serialVersionUID = 1457525358470002989L;
  113.48 +
  113.49 +    private String charsetName;
  113.50 +
  113.51 +    /**
  113.52 +     * Constructs an instance of this class. </p>
  113.53 +     *
  113.54 +     * @param  charsetName
  113.55 +     *         The illegal charset name
  113.56 +     */
  113.57 +    public IllegalCharsetNameException(String charsetName) {
  113.58 +        super(String.valueOf(charsetName));
  113.59 +	this.charsetName = charsetName;
  113.60 +    }
  113.61 +
  113.62 +    /**
  113.63 +     * Retrieves the illegal charset name. </p>
  113.64 +     *
  113.65 +     * @return  The illegal charset name
  113.66 +     */
  113.67 +    public String getCharsetName() {
  113.68 +        return charsetName;
  113.69 +    }
  113.70 +
  113.71 +}
   114.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   114.2 +++ b/rt/emul/compact/src/main/java/java/nio/charset/UnsupportedCharsetException.java	Tue Feb 11 13:31:42 2014 +0100
   114.3 @@ -0,0 +1,68 @@
   114.4 +/*
   114.5 + * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
   114.6 + *
   114.7 + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
   114.8 + *
   114.9 + *
  114.10 + *
  114.11 + *
  114.12 + *
  114.13 + *
  114.14 + *
  114.15 + *
  114.16 + *
  114.17 + *
  114.18 + *
  114.19 + *
  114.20 + *
  114.21 + *
  114.22 + *
  114.23 + *
  114.24 + *
  114.25 + *
  114.26 + *
  114.27 + *
  114.28 + *
  114.29 + */
  114.30 +
  114.31 +// -- This file was mechanically generated: Do not edit! -- //
  114.32 +
  114.33 +package java.nio.charset;
  114.34 +
  114.35 +
  114.36 +/**
  114.37 + * Unchecked exception thrown when no support is available
  114.38 + * for a requested charset.
  114.39 + *
  114.40 + * @since 1.4
  114.41 + */
  114.42 +
  114.43 +public class UnsupportedCharsetException
  114.44 +    extends IllegalArgumentException
  114.45 +{
  114.46 +
  114.47 +    private static final long serialVersionUID = 1490765524727386367L;
  114.48 +
  114.49 +    private String charsetName;
  114.50 +
  114.51 +    /**
  114.52 +     * Constructs an instance of this class. </p>
  114.53 +     *
  114.54 +     * @param  charsetName
  114.55 +     *         The name of the unsupported charset
  114.56 +     */
  114.57 +    public UnsupportedCharsetException(String charsetName) {
  114.58 +        super(String.valueOf(charsetName));
  114.59 +	this.charsetName = charsetName;
  114.60 +    }
  114.61 +
  114.62 +    /**
  114.63 +     * Retrieves the name of the unsupported charset. </p>
  114.64 +     *
  114.65 +     * @return  The name of the unsupported charset
  114.66 +     */
  114.67 +    public String getCharsetName() {
  114.68 +        return charsetName;
  114.69 +    }
  114.70 +
  114.71 +}
   115.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   115.2 +++ b/rt/emul/compact/src/main/java/java/security/AccessController.java	Tue Feb 11 13:31:42 2014 +0100
   115.3 @@ -0,0 +1,504 @@
   115.4 +/*
   115.5 + * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
   115.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   115.7 + *
   115.8 + * This code is free software; you can redistribute it and/or modify it
   115.9 + * under the terms of the GNU General Public License version 2 only, as
  115.10 + * published by the Free Software Foundation.  Oracle designates this
  115.11 + * particular file as subject to the "Classpath" exception as provided
  115.12 + * by Oracle in the LICENSE file that accompanied this code.
  115.13 + *
  115.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  115.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  115.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  115.17 + * version 2 for more details (a copy is included in the LICENSE file that
  115.18 + * accompanied this code).
  115.19 + *
  115.20 + * You should have received a copy of the GNU General Public License version
  115.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  115.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  115.23 + *
  115.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  115.25 + * or visit www.oracle.com if you need additional information or have any
  115.26 + * questions.
  115.27 + */
  115.28 +
  115.29 +package java.security;
  115.30 +
  115.31 +/**
  115.32 + * <p> The AccessController class is used for access control operations
  115.33 + * and decisions.
  115.34 + *
  115.35 + * <p> More specifically, the AccessController class is used for
  115.36 + * three purposes:
  115.37 + *
  115.38 + * <ul>
  115.39 + * <li> to decide whether an access to a critical system
  115.40 + * resource is to be allowed or denied, based on the security policy
  115.41 + * currently in effect,<p>
  115.42 + * <li>to mark code as being "privileged", thus affecting subsequent
  115.43 + * access determinations, and<p>
  115.44 + * <li>to obtain a "snapshot" of the current calling context so
  115.45 + * access-control decisions from a different context can be made with
  115.46 + * respect to the saved context. </ul>
  115.47 + *
  115.48 + * <p> The {@link #checkPermission(Permission) checkPermission} method
  115.49 + * determines whether the access request indicated by a specified
  115.50 + * permission should be granted or denied. A sample call appears
  115.51 + * below. In this example, <code>checkPermission</code> will determine
  115.52 + * whether or not to grant "read" access to the file named "testFile" in
  115.53 + * the "/temp" directory.
  115.54 + *
  115.55 + * <pre>
  115.56 + *
  115.57 + * FilePermission perm = new FilePermission("/temp/testFile", "read");
  115.58 + * AccessController.checkPermission(perm);
  115.59 + *
  115.60 + * </pre>
  115.61 + *
  115.62 + * <p> If a requested access is allowed,
  115.63 + * <code>checkPermission</code> returns quietly. If denied, an
  115.64 + * AccessControlException is
  115.65 + * thrown. AccessControlException can also be thrown if the requested
  115.66 + * permission is of an incorrect type or contains an invalid value.
  115.67 + * Such information is given whenever possible.
  115.68 + *
  115.69 + * Suppose the current thread traversed m callers, in the order of caller 1
  115.70 + * to caller 2 to caller m. Then caller m invoked the
  115.71 + * <code>checkPermission</code> method.
  115.72 + * The <code>checkPermission </code>method determines whether access
  115.73 + * is granted or denied based on the following algorithm:
  115.74 + *
  115.75 + *  <pre> {@code
  115.76 + * for (int i = m; i > 0; i--) {
  115.77 + *
  115.78 + *     if (caller i's domain does not have the permission)
  115.79 + *         throw AccessControlException
  115.80 + *
  115.81 + *     else if (caller i is marked as privileged) {
  115.82 + *         if (a context was specified in the call to doPrivileged)
  115.83 + *             context.checkPermission(permission)
  115.84 + *         return;
  115.85 + *     }
  115.86 + * };
  115.87 + *
  115.88 + * // Next, check the context inherited when the thread was created.
  115.89 + * // Whenever a new thread is created, the AccessControlContext at
  115.90 + * // that time is stored and associated with the new thread, as the
  115.91 + * // "inherited" context.
  115.92 + *
  115.93 + * inheritedContext.checkPermission(permission);
  115.94 + * }</pre>
  115.95 + *
  115.96 + * <p> A caller can be marked as being "privileged"
  115.97 + * (see {@link #doPrivileged(PrivilegedAction) doPrivileged} and below).
  115.98 + * When making access control decisions, the <code>checkPermission</code>
  115.99 + * method stops checking if it reaches a caller that
 115.100 + * was marked as "privileged" via a <code>doPrivileged</code>
 115.101 + * call without a context argument (see below for information about a
 115.102 + * context argument). If that caller's domain has the
 115.103 + * specified permission, no further checking is done and
 115.104 + * <code>checkPermission</code>
 115.105 + * returns quietly, indicating that the requested access is allowed.
 115.106 + * If that domain does not have the specified permission, an exception
 115.107 + * is thrown, as usual.
 115.108 + *
 115.109 + * <p> The normal use of the "privileged" feature is as follows. If you
 115.110 + * don't need to return a value from within the "privileged" block, do
 115.111 + * the following:
 115.112 + *
 115.113 + *  <pre> {@code
 115.114 + * somemethod() {
 115.115 + *     ...normal code here...
 115.116 + *     AccessController.doPrivileged(new PrivilegedAction<Void>() {
 115.117 + *         public Void run() {
 115.118 + *             // privileged code goes here, for example:
 115.119 + *             System.loadLibrary("awt");
 115.120 + *             return null; // nothing to return
 115.121 + *         }
 115.122 + *     });
 115.123 + *     ...normal code here...
 115.124 + * }}</pre>
 115.125 + *
 115.126 + * <p>
 115.127 + * PrivilegedAction is an interface with a single method, named
 115.128 + * <code>run</code>.
 115.129 + * The above example shows creation of an implementation
 115.130 + * of that interface; a concrete implementation of the
 115.131 + * <code>run</code> method is supplied.
 115.132 + * When the call to <code>doPrivileged</code> is made, an
 115.133 + * instance of the PrivilegedAction implementation is passed
 115.134 + * to it. The <code>doPrivileged</code> method calls the
 115.135 + * <code>run</code> method from the PrivilegedAction
 115.136 + * implementation after enabling privileges, and returns the
 115.137 + * <code>run</code> method's return value as the
 115.138 + * <code>doPrivileged</code> return value (which is
 115.139 + * ignored in this example).
 115.140 + *
 115.141 + * <p> If you need to return a value, you can do something like the following:
 115.142 + *
 115.143 + *  <pre> {@code
 115.144 + * somemethod() {
 115.145 + *     ...normal code here...
 115.146 + *     String user = AccessController.doPrivileged(
 115.147 + *         new PrivilegedAction<String>() {
 115.148 + *         public String run() {
 115.149 + *             return System.getProperty("user.name");
 115.150 + *             }
 115.151 + *         });
 115.152 + *     ...normal code here...
 115.153 + * }}</pre>
 115.154 + *
 115.155 + * <p>If the action performed in your <code>run</code> method could
 115.156 + * throw a "checked" exception (those listed in the <code>throws</code> clause
 115.157 + * of a method), then you need to use the
 115.158 + * <code>PrivilegedExceptionAction</code> interface instead of the
 115.159 + * <code>PrivilegedAction</code> interface:
 115.160 + *
 115.161 + *  <pre> {@code
 115.162 + * somemethod() throws FileNotFoundException {
 115.163 + *     ...normal code here...
 115.164 + *     try {
 115.165 + *         FileInputStream fis = AccessController.doPrivileged(
 115.166 + *         new PrivilegedExceptionAction<FileInputStream>() {
 115.167 + *             public FileInputStream run() throws FileNotFoundException {
 115.168 + *                 return new FileInputStream("someFile");
 115.169 + *             }
 115.170 + *         });
 115.171 + *     } catch (PrivilegedActionException e) {
 115.172 + *         // e.getException() should be an instance of FileNotFoundException,
 115.173 + *         // as only "checked" exceptions will be "wrapped" in a
 115.174 + *         // PrivilegedActionException.
 115.175 + *         throw (FileNotFoundException) e.getException();
 115.176 + *     }
 115.177 + *     ...normal code here...
 115.178 + *  }}</pre>
 115.179 + *
 115.180 + * <p> Be *very* careful in your use of the "privileged" construct, and
 115.181 + * always remember to make the privileged code section as small as possible.
 115.182 + *
 115.183 + * <p> Note that <code>checkPermission</code> always performs security checks
 115.184 + * within the context of the currently executing thread.
 115.185 + * Sometimes a security check that should be made within a given context
 115.186 + * will actually need to be done from within a
 115.187 + * <i>different</i> context (for example, from within a worker thread).
 115.188 + * The {@link #getContext() getContext} method and
 115.189 + * AccessControlContext class are provided
 115.190 + * for this situation. The <code>getContext</code> method takes a "snapshot"
 115.191 + * of the current calling context, and places
 115.192 + * it in an AccessControlContext object, which it returns. A sample call is
 115.193 + * the following:
 115.194 + *
 115.195 + * <pre>
 115.196 + *
 115.197 + * AccessControlContext acc = AccessController.getContext()
 115.198 + *
 115.199 + * </pre>
 115.200 + *
 115.201 + * <p>
 115.202 + * AccessControlContext itself has a <code>checkPermission</code> method
 115.203 + * that makes access decisions based on the context <i>it</i> encapsulates,
 115.204 + * rather than that of the current execution thread.
 115.205 + * Code within a different context can thus call that method on the
 115.206 + * previously-saved AccessControlContext object. A sample call is the
 115.207 + * following:
 115.208 + *
 115.209 + * <pre>
 115.210 + *
 115.211 + * acc.checkPermission(permission)
 115.212 + *
 115.213 + * </pre>
 115.214 + *
 115.215 + * <p> There are also times where you don't know a priori which permissions
 115.216 + * to check the context against. In these cases you can use the
 115.217 + * doPrivileged method that takes a context:
 115.218 + *
 115.219 + *  <pre> {@code
 115.220 + * somemethod() {
 115.221 + *     AccessController.doPrivileged(new PrivilegedAction<Object>() {
 115.222 + *         public Object run() {
 115.223 + *             // Code goes here. Any permission checks within this
 115.224 + *             // run method will require that the intersection of the
 115.225 + *             // callers protection domain and the snapshot's
 115.226 + *             // context have the desired permission.
 115.227 + *         }
 115.228 + *     }, acc);
 115.229 + *     ...normal code here...
 115.230 + * }}</pre>
 115.231 + *
 115.232 + * @see AccessControlContext
 115.233 + *
 115.234 + * @author Li Gong
 115.235 + * @author Roland Schemers
 115.236 + */
 115.237 +
 115.238 +public final class AccessController {
 115.239 +
 115.240 +    /**
 115.241 +     * Don't allow anyone to instantiate an AccessController
 115.242 +     */
 115.243 +    private AccessController() { }
 115.244 +
 115.245 +    /**
 115.246 +     * Performs the specified <code>PrivilegedAction</code> with privileges
 115.247 +     * enabled. The action is performed with <i>all</i> of the permissions
 115.248 +     * possessed by the caller's protection domain.
 115.249 +     *
 115.250 +     * <p> If the action's <code>run</code> method throws an (unchecked)
 115.251 +     * exception, it will propagate through this method.
 115.252 +     *
 115.253 +     * <p> Note that any DomainCombiner associated with the current
 115.254 +     * AccessControlContext will be ignored while the action is performed.
 115.255 +     *
 115.256 +     * @param action the action to be performed.
 115.257 +     *
 115.258 +     * @return the value returned by the action's <code>run</code> method.
 115.259 +     *
 115.260 +     * @exception NullPointerException if the action is <code>null</code>
 115.261 +     *
 115.262 +     * @see #doPrivileged(PrivilegedAction,AccessControlContext)
 115.263 +     * @see #doPrivileged(PrivilegedExceptionAction)
 115.264 +     * @see #doPrivilegedWithCombiner(PrivilegedAction)
 115.265 +     * @see java.security.DomainCombiner
 115.266 +     */
 115.267 +
 115.268 +    public static <T> T doPrivileged(PrivilegedAction<T> action) {
 115.269 +        return action.run();
 115.270 +    }
 115.271 +
 115.272 +    /**
 115.273 +     * Performs the specified <code>PrivilegedAction</code> with privileges
 115.274 +     * enabled. The action is performed with <i>all</i> of the permissions
 115.275 +     * possessed by the caller's protection domain.
 115.276 +     *
 115.277 +     * <p> If the action's <code>run</code> method throws an (unchecked)
 115.278 +     * exception, it will propagate through this method.
 115.279 +     *
 115.280 +     * <p> This method preserves the current AccessControlContext's
 115.281 +     * DomainCombiner (which may be null) while the action is performed.
 115.282 +     *
 115.283 +     * @param action the action to be performed.
 115.284 +     *
 115.285 +     * @return the value returned by the action's <code>run</code> method.
 115.286 +     *
 115.287 +     * @exception NullPointerException if the action is <code>null</code>
 115.288 +     *
 115.289 +     * @see #doPrivileged(PrivilegedAction)
 115.290 +     * @see java.security.DomainCombiner
 115.291 +     *
 115.292 +     * @since 1.6
 115.293 +     */
 115.294 +    public static <T> T doPrivilegedWithCombiner(PrivilegedAction<T> action) {
 115.295 +        return action.run();
 115.296 +    }
 115.297 +
 115.298 +
 115.299 +    /**
 115.300 +     * Performs the specified <code>PrivilegedAction</code> with privileges
 115.301 +     * enabled and restricted by the specified
 115.302 +     * <code>AccessControlContext</code>.
 115.303 +     * The action is performed with the intersection of the permissions
 115.304 +     * possessed by the caller's protection domain, and those possessed
 115.305 +     * by the domains represented by the specified
 115.306 +     * <code>AccessControlContext</code>.
 115.307 +     * <p>
 115.308 +     * If the action's <code>run</code> method throws an (unchecked) exception,
 115.309 +     * it will propagate through this method.
 115.310 +     *
 115.311 +     * @param action the action to be performed.
 115.312 +     * @param context an <i>access control context</i>
 115.313 +     *                representing the restriction to be applied to the
 115.314 +     *                caller's domain's privileges before performing
 115.315 +     *                the specified action.  If the context is
 115.316 +     *                <code>null</code>,
 115.317 +     *                then no additional restriction is applied.
 115.318 +     *
 115.319 +     * @return the value returned by the action's <code>run</code> method.
 115.320 +     *
 115.321 +     * @exception NullPointerException if the action is <code>null</code>
 115.322 +     *
 115.323 +     * @see #doPrivileged(PrivilegedAction)
 115.324 +     * @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext)
 115.325 +     */
 115.326 +//    public static native <T> T doPrivileged(PrivilegedAction<T> action,
 115.327 +//                                            AccessControlContext context);
 115.328 +
 115.329 +    /**
 115.330 +     * Performs the specified <code>PrivilegedExceptionAction</code> with
 115.331 +     * privileges enabled.  The action is performed with <i>all</i> of the
 115.332 +     * permissions possessed by the caller's protection domain.
 115.333 +     *
 115.334 +     * <p> If the action's <code>run</code> method throws an <i>unchecked</i>
 115.335 +     * exception, it will propagate through this method.
 115.336 +     *
 115.337 +     * <p> Note that any DomainCombiner associated with the current
 115.338 +     * AccessControlContext will be ignored while the action is performed.
 115.339 +     *
 115.340 +     * @param action the action to be performed
 115.341 +     *
 115.342 +     * @return the value returned by the action's <code>run</code> method
 115.343 +     *
 115.344 +     * @exception PrivilegedActionException if the specified action's
 115.345 +     *         <code>run</code> method threw a <i>checked</i> exception
 115.346 +     * @exception NullPointerException if the action is <code>null</code>
 115.347 +     *
 115.348 +     * @see #doPrivileged(PrivilegedAction)
 115.349 +     * @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext)
 115.350 +     * @see #doPrivilegedWithCombiner(PrivilegedExceptionAction)
 115.351 +     * @see java.security.DomainCombiner
 115.352 +     */
 115.353 +    public static <T> T
 115.354 +        doPrivileged(PrivilegedExceptionAction<T> action)
 115.355 +        throws PrivilegedActionException {
 115.356 +        try {
 115.357 +            return action.run();
 115.358 +        } catch (Exception ex) {
 115.359 +            throw new PrivilegedActionException(ex);
 115.360 +        }
 115.361 +    }
 115.362 +
 115.363 +
 115.364 +    /**
 115.365 +     * Performs the specified <code>PrivilegedExceptionAction</code> with
 115.366 +     * privileges enabled.  The action is performed with <i>all</i> of the
 115.367 +     * permissions possessed by the caller's protection domain.
 115.368 +     *
 115.369 +     * <p> If the action's <code>run</code> method throws an <i>unchecked</i>
 115.370 +     * exception, it will propagate through this method.
 115.371 +     *
 115.372 +     * <p> This method preserves the current AccessControlContext's
 115.373 +     * DomainCombiner (which may be null) while the action is performed.
 115.374 +     *
 115.375 +     * @param action the action to be performed.
 115.376 +     *
 115.377 +     * @return the value returned by the action's <code>run</code> method
 115.378 +     *
 115.379 +     * @exception PrivilegedActionException if the specified action's
 115.380 +     *         <code>run</code> method threw a <i>checked</i> exception
 115.381 +     * @exception NullPointerException if the action is <code>null</code>
 115.382 +     *
 115.383 +     * @see #doPrivileged(PrivilegedAction)
 115.384 +     * @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext)
 115.385 +     * @see java.security.DomainCombiner
 115.386 +     *
 115.387 +     * @since 1.6
 115.388 +     */
 115.389 +    public static <T> T doPrivilegedWithCombiner
 115.390 +        (PrivilegedExceptionAction<T> action) throws PrivilegedActionException {
 115.391 +        return doPrivileged(action);
 115.392 +    }
 115.393 +
 115.394 +    /**
 115.395 +     * Performs the specified <code>PrivilegedExceptionAction</code> with
 115.396 +     * privileges enabled and restricted by the specified
 115.397 +     * <code>AccessControlContext</code>.  The action is performed with the
 115.398 +     * intersection of the permissions possessed by the caller's
 115.399 +     * protection domain, and those possessed by the domains represented by the
 115.400 +     * specified <code>AccessControlContext</code>.
 115.401 +     * <p>
 115.402 +     * If the action's <code>run</code> method throws an <i>unchecked</i>
 115.403 +     * exception, it will propagate through this method.
 115.404 +     *
 115.405 +     * @param action the action to be performed
 115.406 +     * @param context an <i>access control context</i>
 115.407 +     *                representing the restriction to be applied to the
 115.408 +     *                caller's domain's privileges before performing
 115.409 +     *                the specified action.  If the context is
 115.410 +     *                <code>null</code>,
 115.411 +     *                then no additional restriction is applied.
 115.412 +     *
 115.413 +     * @return the value returned by the action's <code>run</code> method
 115.414 +     *
 115.415 +     * @exception PrivilegedActionException if the specified action's
 115.416 +     *         <code>run</code> method
 115.417 +     *         threw a <i>checked</i> exception
 115.418 +     * @exception NullPointerException if the action is <code>null</code>
 115.419 +     *
 115.420 +     * @see #doPrivileged(PrivilegedAction)
 115.421 +     * @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext)
 115.422 +     */
 115.423 +//    public static native <T> T
 115.424 +//        doPrivileged(PrivilegedExceptionAction<T> action,
 115.425 +//                     AccessControlContext context)
 115.426 +//        throws PrivilegedActionException;
 115.427 +
 115.428 +    /**
 115.429 +     * This method takes a "snapshot" of the current calling context, which
 115.430 +     * includes the current Thread's inherited AccessControlContext,
 115.431 +     * and places it in an AccessControlContext object. This context may then
 115.432 +     * be checked at a later point, possibly in another thread.
 115.433 +     *
 115.434 +     * @see AccessControlContext
 115.435 +     *
 115.436 +     * @return the AccessControlContext based on the current context.
 115.437 +     */
 115.438 +
 115.439 +//    public static AccessControlContext getContext()
 115.440 +//    {
 115.441 +//        AccessControlContext acc = getStackAccessControlContext();
 115.442 +//        if (acc == null) {
 115.443 +//            // all we had was privileged system code. We don't want
 115.444 +//            // to return null though, so we construct a real ACC.
 115.445 +//            return new AccessControlContext(null, true);
 115.446 +//        } else {
 115.447 +//            return acc.optimize();
 115.448 +//        }
 115.449 +//    }
 115.450 +
 115.451 +    /**
 115.452 +     * Determines whether the access request indicated by the
 115.453 +     * specified permission should be allowed or denied, based on
 115.454 +     * the current AccessControlContext and security policy.
 115.455 +     * This method quietly returns if the access request
 115.456 +     * is permitted, or throws an AccessControlException otherwise. The
 115.457 +     * getPermission method of the AccessControlException returns the
 115.458 +     * <code>perm</code> Permission object instance.
 115.459 +     *
 115.460 +     * @param perm the requested permission.
 115.461 +     *
 115.462 +     * @exception AccessControlException if the specified permission
 115.463 +     *            is not permitted, based on the current security policy.
 115.464 +     * @exception NullPointerException if the specified permission
 115.465 +     *            is <code>null</code> and is checked based on the
 115.466 +     *            security policy currently in effect.
 115.467 +     */
 115.468 +
 115.469 +//    public static void checkPermission(Permission perm)
 115.470 +//                 throws AccessControlException
 115.471 +//    {
 115.472 +//        //System.err.println("checkPermission "+perm);
 115.473 +//        //Thread.currentThread().dumpStack();
 115.474 +//
 115.475 +//        if (perm == null) {
 115.476 +//            throw new NullPointerException("permission can't be null");
 115.477 +//        }
 115.478 +//
 115.479 +//        AccessControlContext stack = getStackAccessControlContext();
 115.480 +//        // if context is null, we had privileged system code on the stack.
 115.481 +//        if (stack == null) {
 115.482 +//            Debug debug = AccessControlContext.getDebug();
 115.483 +//            boolean dumpDebug = false;
 115.484 +//            if (debug != null) {
 115.485 +//                dumpDebug = !Debug.isOn("codebase=");
 115.486 +//                dumpDebug &= !Debug.isOn("permission=") ||
 115.487 +//                    Debug.isOn("permission=" + perm.getClass().getCanonicalName());
 115.488 +//            }
 115.489 +//
 115.490 +//            if (dumpDebug && Debug.isOn("stack")) {
 115.491 +//                Thread.currentThread().dumpStack();
 115.492 +//            }
 115.493 +//
 115.494 +//            if (dumpDebug && Debug.isOn("domain")) {
 115.495 +//                debug.println("domain (context is null)");
 115.496 +//            }
 115.497 +//
 115.498 +//            if (dumpDebug) {
 115.499 +//                debug.println("access allowed "+perm);
 115.500 +//            }
 115.501 +//            return;
 115.502 +//        }
 115.503 +//
 115.504 +//        AccessControlContext acc = stack.optimize();
 115.505 +//        acc.checkPermission(perm);
 115.506 +//    }
 115.507 +}
   116.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   116.2 +++ b/rt/emul/compact/src/main/java/java/security/PrivilegedAction.java	Tue Feb 11 13:31:42 2014 +0100
   116.3 @@ -0,0 +1,56 @@
   116.4 +/*
   116.5 + * Copyright (c) 1998, 2004, Oracle and/or its affiliates. All rights reserved.
   116.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   116.7 + *
   116.8 + * This code is free software; you can redistribute it and/or modify it
   116.9 + * under the terms of the GNU General Public License version 2 only, as
  116.10 + * published by the Free Software Foundation.  Oracle designates this
  116.11 + * particular file as subject to the "Classpath" exception as provided
  116.12 + * by Oracle in the LICENSE file that accompanied this code.
  116.13 + *
  116.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  116.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  116.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  116.17 + * version 2 for more details (a copy is included in the LICENSE file that
  116.18 + * accompanied this code).
  116.19 + *
  116.20 + * You should have received a copy of the GNU General Public License version
  116.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  116.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  116.23 + *
  116.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  116.25 + * or visit www.oracle.com if you need additional information or have any
  116.26 + * questions.
  116.27 + */
  116.28 +
  116.29 +package java.security;
  116.30 +
  116.31 +
  116.32 +/**
  116.33 + * A computation to be performed with privileges enabled.  The computation is
  116.34 + * performed by invoking <code>AccessController.doPrivileged</code> on the
  116.35 + * <code>PrivilegedAction</code> object.  This interface is used only for
  116.36 + * computations that do not throw checked exceptions; computations that
  116.37 + * throw checked exceptions must use <code>PrivilegedExceptionAction</code>
  116.38 + * instead.
  116.39 + *
  116.40 + * @see AccessController
  116.41 + * @see AccessController#doPrivileged(PrivilegedAction)
  116.42 + * @see PrivilegedExceptionAction
  116.43 + */
  116.44 +
  116.45 +public interface PrivilegedAction<T> {
  116.46 +    /**
  116.47 +     * Performs the computation.  This method will be called by
  116.48 +     * <code>AccessController.doPrivileged</code> after enabling privileges.
  116.49 +     *
  116.50 +     * @return a class-dependent value that may represent the results of the
  116.51 +     *         computation. Each class that implements
  116.52 +     *         <code>PrivilegedAction</code>
  116.53 +     *         should document what (if anything) this value represents.
  116.54 +     * @see AccessController#doPrivileged(PrivilegedAction)
  116.55 +     * @see AccessController#doPrivileged(PrivilegedAction,
  116.56 +     *                                     AccessControlContext)
  116.57 +     */
  116.58 +    T run();
  116.59 +}
   117.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   117.2 +++ b/rt/emul/compact/src/main/java/java/security/PrivilegedActionException.java	Tue Feb 11 13:31:42 2014 +0100
   117.3 @@ -0,0 +1,105 @@
   117.4 +/*
   117.5 + * Copyright (c) 1998, 2001, Oracle and/or its affiliates. All rights reserved.
   117.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   117.7 + *
   117.8 + * This code is free software; you can redistribute it and/or modify it
   117.9 + * under the terms of the GNU General Public License version 2 only, as
  117.10 + * published by the Free Software Foundation.  Oracle designates this
  117.11 + * particular file as subject to the "Classpath" exception as provided
  117.12 + * by Oracle in the LICENSE file that accompanied this code.
  117.13 + *
  117.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  117.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  117.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  117.17 + * version 2 for more details (a copy is included in the LICENSE file that
  117.18 + * accompanied this code).
  117.19 + *
  117.20 + * You should have received a copy of the GNU General Public License version
  117.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  117.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  117.23 + *
  117.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  117.25 + * or visit www.oracle.com if you need additional information or have any
  117.26 + * questions.
  117.27 + */
  117.28 +
  117.29 +package java.security;
  117.30 +
  117.31 +/**
  117.32 + * This exception is thrown by
  117.33 + * <code>doPrivileged(PrivilegedExceptionAction)</code> and
  117.34 + * <code>doPrivileged(PrivilegedExceptionAction,
  117.35 + * AccessControlContext context)</code> to indicate
  117.36 + * that the action being performed threw a checked exception.  The exception
  117.37 + * thrown by the action can be obtained by calling the
  117.38 + * <code>getException</code> method.  In effect, an
  117.39 + * <code>PrivilegedActionException</code> is a "wrapper"
  117.40 + * for an exception thrown by a privileged action.
  117.41 + *
  117.42 + * <p>As of release 1.4, this exception has been retrofitted to conform to
  117.43 + * the general purpose exception-chaining mechanism.  The "exception thrown
  117.44 + * by the privileged computation" that is provided at construction time and
  117.45 + * accessed via the {@link #getException()} method is now known as the
  117.46 + * <i>cause</i>, and may be accessed via the {@link Throwable#getCause()}
  117.47 + * method, as well as the aforementioned "legacy method."
  117.48 + *
  117.49 + * @see PrivilegedExceptionAction
  117.50 + * @see AccessController#doPrivileged(PrivilegedExceptionAction)
  117.51 + * @see AccessController#doPrivileged(PrivilegedExceptionAction,AccessControlContext)
  117.52 + */
  117.53 +public class PrivilegedActionException extends Exception {
  117.54 +    // use serialVersionUID from JDK 1.2.2 for interoperability
  117.55 +    private static final long serialVersionUID = 4724086851538908602L;
  117.56 +
  117.57 +    /**
  117.58 +     * @serial
  117.59 +     */
  117.60 +    private Exception exception;
  117.61 +
  117.62 +    /**
  117.63 +     * Constructs a new PrivilegedActionException &quot;wrapping&quot;
  117.64 +     * the specific Exception.
  117.65 +     *
  117.66 +     * @param exception The exception thrown
  117.67 +     */
  117.68 +    public PrivilegedActionException(Exception exception) {
  117.69 +        super((Throwable)null);  // Disallow initCause
  117.70 +        this.exception = exception;
  117.71 +    }
  117.72 +
  117.73 +    /**
  117.74 +     * Returns the exception thrown by the privileged computation that
  117.75 +     * resulted in this <code>PrivilegedActionException</code>.
  117.76 +     *
  117.77 +     * <p>This method predates the general-purpose exception chaining facility.
  117.78 +     * The {@link Throwable#getCause()} method is now the preferred means of
  117.79 +     * obtaining this information.
  117.80 +     *
  117.81 +     * @return the exception thrown by the privileged computation that
  117.82 +     *         resulted in this <code>PrivilegedActionException</code>.
  117.83 +     * @see PrivilegedExceptionAction
  117.84 +     * @see AccessController#doPrivileged(PrivilegedExceptionAction)
  117.85 +     * @see AccessController#doPrivileged(PrivilegedExceptionAction,
  117.86 +     *                                            AccessControlContext)
  117.87 +     */
  117.88 +    public Exception getException() {
  117.89 +        return exception;
  117.90 +    }
  117.91 +
  117.92 +    /**
  117.93 +     * Returns the cause of this exception (the exception thrown by
  117.94 +     * the privileged computation that resulted in this
  117.95 +     * <code>PrivilegedActionException</code>).
  117.96 +     *
  117.97 +     * @return  the cause of this exception.
  117.98 +     * @since   1.4
  117.99 +     */
 117.100 +    public Throwable getCause() {
 117.101 +        return exception;
 117.102 +    }
 117.103 +
 117.104 +    public String toString() {
 117.105 +        String s = getClass().getName();
 117.106 +        return (exception != null) ? (s + ": " + exception.toString()) : s;
 117.107 +    }
 117.108 +}
   118.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   118.2 +++ b/rt/emul/compact/src/main/java/java/security/PrivilegedExceptionAction.java	Tue Feb 11 13:31:42 2014 +0100
   118.3 @@ -0,0 +1,62 @@
   118.4 +/*
   118.5 + * Copyright (c) 1998, 2004, Oracle and/or its affiliates. All rights reserved.
   118.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   118.7 + *
   118.8 + * This code is free software; you can redistribute it and/or modify it
   118.9 + * under the terms of the GNU General Public License version 2 only, as
  118.10 + * published by the Free Software Foundation.  Oracle designates this
  118.11 + * particular file as subject to the "Classpath" exception as provided
  118.12 + * by Oracle in the LICENSE file that accompanied this code.
  118.13 + *
  118.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  118.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  118.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  118.17 + * version 2 for more details (a copy is included in the LICENSE file that
  118.18 + * accompanied this code).
  118.19 + *
  118.20 + * You should have received a copy of the GNU General Public License version
  118.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  118.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  118.23 + *
  118.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  118.25 + * or visit www.oracle.com if you need additional information or have any
  118.26 + * questions.
  118.27 + */
  118.28 +
  118.29 +package java.security;
  118.30 +
  118.31 +
  118.32 +/**
  118.33 + * A computation to be performed with privileges enabled, that throws one or
  118.34 + * more checked exceptions.  The computation is performed by invoking
  118.35 + * <code>AccessController.doPrivileged</code> on the
  118.36 + * <code>PrivilegedExceptionAction</code> object.  This interface is
  118.37 + * used only for computations that throw checked exceptions;
  118.38 + * computations that do not throw
  118.39 + * checked exceptions should use <code>PrivilegedAction</code> instead.
  118.40 + *
  118.41 + * @see AccessController
  118.42 + * @see AccessController#doPrivileged(PrivilegedExceptionAction)
  118.43 + * @see AccessController#doPrivileged(PrivilegedExceptionAction,
  118.44 + *                                              AccessControlContext)
  118.45 + * @see PrivilegedAction
  118.46 + */
  118.47 +
  118.48 +public interface PrivilegedExceptionAction<T> {
  118.49 +    /**
  118.50 +     * Performs the computation.  This method will be called by
  118.51 +     * <code>AccessController.doPrivileged</code> after enabling privileges.
  118.52 +     *
  118.53 +     * @return a class-dependent value that may represent the results of the
  118.54 +     *         computation.  Each class that implements
  118.55 +     *         <code>PrivilegedExceptionAction</code> should document what
  118.56 +     *         (if anything) this value represents.
  118.57 +     * @throws Exception an exceptional condition has occurred.  Each class
  118.58 +     *         that implements <code>PrivilegedExceptionAction</code> should
  118.59 +     *         document the exceptions that its run method can throw.
  118.60 +     * @see AccessController#doPrivileged(PrivilegedExceptionAction)
  118.61 +     * @see AccessController#doPrivileged(PrivilegedExceptionAction,AccessControlContext)
  118.62 +     */
  118.63 +
  118.64 +    T run() throws Exception;
  118.65 +}
   119.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   119.2 +++ b/rt/emul/compact/src/main/java/java/text/Annotation.java	Tue Feb 11 13:31:42 2014 +0100
   119.3 @@ -0,0 +1,84 @@
   119.4 +/*
   119.5 + * Copyright (c) 1997, 2002, Oracle and/or its affiliates. All rights reserved.
   119.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   119.7 + *
   119.8 + * This code is free software; you can redistribute it and/or modify it
   119.9 + * under the terms of the GNU General Public License version 2 only, as
  119.10 + * published by the Free Software Foundation.  Oracle designates this
  119.11 + * particular file as subject to the "Classpath" exception as provided
  119.12 + * by Oracle in the LICENSE file that accompanied this code.
  119.13 + *
  119.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  119.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  119.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  119.17 + * version 2 for more details (a copy is included in the LICENSE file that
  119.18 + * accompanied this code).
  119.19 + *
  119.20 + * You should have received a copy of the GNU General Public License version
  119.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  119.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  119.23 + *
  119.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  119.25 + * or visit www.oracle.com if you need additional information or have any
  119.26 + * questions.
  119.27 + */
  119.28 +
  119.29 +package java.text;
  119.30 +
  119.31 +/**
  119.32 +* An Annotation object is used as a wrapper for a text attribute value if
  119.33 +* the attribute has annotation characteristics. These characteristics are:
  119.34 +* <ul>
  119.35 +* <li>The text range that the attribute is applied to is critical to the
  119.36 +* semantics of the range. That means, the attribute cannot be applied to subranges
  119.37 +* of the text range that it applies to, and, if two adjacent text ranges have
  119.38 +* the same value for this attribute, the attribute still cannot be applied to
  119.39 +* the combined range as a whole with this value.
  119.40 +* <li>The attribute or its value usually do no longer apply if the underlying text is
  119.41 +* changed.
  119.42 +* </ul>
  119.43 +*
  119.44 +* An example is grammatical information attached to a sentence:
  119.45 +* For the previous sentence, you can say that "an example"
  119.46 +* is the subject, but you cannot say the same about "an", "example", or "exam".
  119.47 +* When the text is changed, the grammatical information typically becomes invalid.
  119.48 +* Another example is Japanese reading information (yomi).
  119.49 +*
  119.50 +* <p>
  119.51 +* Wrapping the attribute value into an Annotation object guarantees that
  119.52 +* adjacent text runs don't get merged even if the attribute values are equal,
  119.53 +* and indicates to text containers that the attribute should be discarded if
  119.54 +* the underlying text is modified.
  119.55 +*
  119.56 +* @see AttributedCharacterIterator
  119.57 +* @since 1.2
  119.58 +*/
  119.59 +
  119.60 +public class Annotation {
  119.61 +
  119.62 +    /**
  119.63 +     * Constructs an annotation record with the given value, which
  119.64 +     * may be null.
  119.65 +     * @param value The value of the attribute
  119.66 +     */
  119.67 +    public Annotation(Object value) {
  119.68 +        this.value = value;
  119.69 +    }
  119.70 +
  119.71 +    /**
  119.72 +     * Returns the value of the attribute, which may be null.
  119.73 +     */
  119.74 +    public Object getValue() {
  119.75 +        return value;
  119.76 +    }
  119.77 +
  119.78 +    /**
  119.79 +     * Returns the String representation of this Annotation.
  119.80 +     */
  119.81 +    public String toString() {
  119.82 +        return getClass().getName() + "[value=" + value + "]";
  119.83 +    }
  119.84 +
  119.85 +    private Object value;
  119.86 +
  119.87 +};
   120.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   120.2 +++ b/rt/emul/compact/src/main/java/java/text/AttributedCharacterIterator.java	Tue Feb 11 13:31:42 2014 +0100
   120.3 @@ -0,0 +1,254 @@
   120.4 +/*
   120.5 + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
   120.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   120.7 + *
   120.8 + * This code is free software; you can redistribute it and/or modify it
   120.9 + * under the terms of the GNU General Public License version 2 only, as
  120.10 + * published by the Free Software Foundation.  Oracle designates this
  120.11 + * particular file as subject to the "Classpath" exception as provided
  120.12 + * by Oracle in the LICENSE file that accompanied this code.
  120.13 + *
  120.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  120.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  120.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  120.17 + * version 2 for more details (a copy is included in the LICENSE file that
  120.18 + * accompanied this code).
  120.19 + *
  120.20 + * You should have received a copy of the GNU General Public License version
  120.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  120.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  120.23 + *
  120.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  120.25 + * or visit www.oracle.com if you need additional information or have any
  120.26 + * questions.
  120.27 + */
  120.28 +
  120.29 +package java.text;
  120.30 +
  120.31 +import java.io.InvalidObjectException;
  120.32 +import java.io.Serializable;
  120.33 +import java.util.HashMap;
  120.34 +import java.util.Map;
  120.35 +import java.util.Set;
  120.36 +
  120.37 +/**
  120.38 + * An {@code AttributedCharacterIterator} allows iteration through both text and
  120.39 + * related attribute information.
  120.40 + *
  120.41 + * <p>
  120.42 + * An attribute is a key/value pair, identified by the key.  No two
  120.43 + * attributes on a given character can have the same key.
  120.44 + *
  120.45 + * <p>The values for an attribute are immutable, or must not be mutated
  120.46 + * by clients or storage.  They are always passed by reference, and not
  120.47 + * cloned.
  120.48 + *
  120.49 + * <p>A <em>run with respect to an attribute</em> is a maximum text range for
  120.50 + * which:
  120.51 + * <ul>
  120.52 + * <li>the attribute is undefined or {@code null} for the entire range, or
  120.53 + * <li>the attribute value is defined and has the same non-{@code null} value for the
  120.54 + *     entire range.
  120.55 + * </ul>
  120.56 + *
  120.57 + * <p>A <em>run with respect to a set of attributes</em> is a maximum text range for
  120.58 + * which this condition is met for each member attribute.
  120.59 + *
  120.60 + * <p>When getting a run with no explicit attributes specified (i.e.,
  120.61 + * calling {@link #getRunStart()} and {@link #getRunLimit()}), any
  120.62 + * contiguous text segments having the same attributes (the same set
  120.63 + * of attribute/value pairs) are treated as separate runs if the
  120.64 + * attributes have been given to those text segments separately.
  120.65 + *
  120.66 + * <p>The returned indexes are limited to the range of the iterator.
  120.67 + *
  120.68 + * <p>The returned attribute information is limited to runs that contain
  120.69 + * the current character.
  120.70 + *
  120.71 + * <p>
  120.72 + * Attribute keys are instances of {@link AttributedCharacterIterator.Attribute} and its
  120.73 + * subclasses, such as {@link java.awt.font.TextAttribute}.
  120.74 + *
  120.75 + * @see AttributedCharacterIterator.Attribute
  120.76 + * @see java.awt.font.TextAttribute
  120.77 + * @see AttributedString
  120.78 + * @see Annotation
  120.79 + * @since 1.2
  120.80 + */
  120.81 +
  120.82 +public interface AttributedCharacterIterator extends CharacterIterator {
  120.83 +
  120.84 +    /**
  120.85 +     * Defines attribute keys that are used to identify text attributes. These
  120.86 +     * keys are used in {@code AttributedCharacterIterator} and {@code AttributedString}.
  120.87 +     * @see AttributedCharacterIterator
  120.88 +     * @see AttributedString
  120.89 +     * @since 1.2
  120.90 +     */
  120.91 +
  120.92 +    public static class Attribute implements Serializable {
  120.93 +
  120.94 +        /**
  120.95 +         * The name of this {@code Attribute}. The name is used primarily by {@code readResolve}
  120.96 +         * to look up the corresponding predefined instance when deserializing
  120.97 +         * an instance.
  120.98 +         * @serial
  120.99 +         */
 120.100 +        private String name;
 120.101 +
 120.102 +        // table of all instances in this class, used by readResolve
 120.103 +        private static final Map instanceMap = new HashMap(7);
 120.104 +
 120.105 +        /**
 120.106 +         * Constructs an {@code Attribute} with the given name.
 120.107 +         */
 120.108 +        protected Attribute(String name) {
 120.109 +            this.name = name;
 120.110 +            if (this.getClass() == Attribute.class) {
 120.111 +                instanceMap.put(name, this);
 120.112 +            }
 120.113 +        }
 120.114 +
 120.115 +        /**
 120.116 +         * Compares two objects for equality. This version only returns true
 120.117 +         * for <code>x.equals(y)</code> if <code>x</code> and <code>y</code> refer
 120.118 +         * to the same object, and guarantees this for all subclasses.
 120.119 +         */
 120.120 +        public final boolean equals(Object obj) {
 120.121 +            return super.equals(obj);
 120.122 +        }
 120.123 +
 120.124 +        /**
 120.125 +         * Returns a hash code value for the object. This version is identical to
 120.126 +         * the one in {@code Object}, but is also final.
 120.127 +         */
 120.128 +        public final int hashCode() {
 120.129 +            return super.hashCode();
 120.130 +        }
 120.131 +
 120.132 +        /**
 120.133 +         * Returns a string representation of the object. This version returns the
 120.134 +         * concatenation of class name, {@code "("}, a name identifying the attribute
 120.135 +         * and {@code ")"}.
 120.136 +         */
 120.137 +        public String toString() {
 120.138 +            return getClass().getName() + "(" + name + ")";
 120.139 +        }
 120.140 +
 120.141 +        /**
 120.142 +         * Returns the name of the attribute.
 120.143 +         */
 120.144 +        protected String getName() {
 120.145 +            return name;
 120.146 +        }
 120.147 +
 120.148 +        /**
 120.149 +         * Resolves instances being deserialized to the predefined constants.
 120.150 +         */
 120.151 +        protected Object readResolve() throws InvalidObjectException {
 120.152 +            if (this.getClass() != Attribute.class) {
 120.153 +                throw new InvalidObjectException("subclass didn't correctly implement readResolve");
 120.154 +            }
 120.155 +
 120.156 +            Attribute instance = (Attribute) instanceMap.get(getName());
 120.157 +            if (instance != null) {
 120.158 +                return instance;
 120.159 +            } else {
 120.160 +                throw new InvalidObjectException("unknown attribute name");
 120.161 +            }
 120.162 +        }
 120.163 +
 120.164 +        /**
 120.165 +         * Attribute key for the language of some text.
 120.166 +         * <p> Values are instances of {@link java.util.Locale Locale}.
 120.167 +         * @see java.util.Locale
 120.168 +         */
 120.169 +        public static final Attribute LANGUAGE = new Attribute("language");
 120.170 +
 120.171 +        /**
 120.172 +         * Attribute key for the reading of some text. In languages where the written form
 120.173 +         * and the pronunciation of a word are only loosely related (such as Japanese),
 120.174 +         * it is often necessary to store the reading (pronunciation) along with the
 120.175 +         * written form.
 120.176 +         * <p>Values are instances of {@link Annotation} holding instances of {@link String}.
 120.177 +         * @see Annotation
 120.178 +         * @see java.lang.String
 120.179 +         */
 120.180 +        public static final Attribute READING = new Attribute("reading");
 120.181 +
 120.182 +        /**
 120.183 +         * Attribute key for input method segments. Input methods often break
 120.184 +         * up text into segments, which usually correspond to words.
 120.185 +         * <p>Values are instances of {@link Annotation} holding a {@code null} reference.
 120.186 +         * @see Annotation
 120.187 +         */
 120.188 +        public static final Attribute INPUT_METHOD_SEGMENT = new Attribute("input_method_segment");
 120.189 +
 120.190 +        // make sure the serial version doesn't change between compiler versions
 120.191 +        private static final long serialVersionUID = -9142742483513960612L;
 120.192 +
 120.193 +    };
 120.194 +
 120.195 +    /**
 120.196 +     * Returns the index of the first character of the run
 120.197 +     * with respect to all attributes containing the current character.
 120.198 +     *
 120.199 +     * <p>Any contiguous text segments having the same attributes (the
 120.200 +     * same set of attribute/value pairs) are treated as separate runs
 120.201 +     * if the attributes have been given to those text segments separately.
 120.202 +     */
 120.203 +    public int getRunStart();
 120.204 +
 120.205 +    /**
 120.206 +     * Returns the index of the first character of the run
 120.207 +     * with respect to the given {@code attribute} containing the current character.
 120.208 +     */
 120.209 +    public int getRunStart(Attribute attribute);
 120.210 +
 120.211 +    /**
 120.212 +     * Returns the index of the first character of the run
 120.213 +     * with respect to the given {@code attributes} containing the current character.
 120.214 +     */
 120.215 +    public int getRunStart(Set<? extends Attribute> attributes);
 120.216 +
 120.217 +    /**
 120.218 +     * Returns the index of the first character following the run
 120.219 +     * with respect to all attributes containing the current character.
 120.220 +     *
 120.221 +     * <p>Any contiguous text segments having the same attributes (the
 120.222 +     * same set of attribute/value pairs) are treated as separate runs
 120.223 +     * if the attributes have been given to those text segments separately.
 120.224 +     */
 120.225 +    public int getRunLimit();
 120.226 +
 120.227 +    /**
 120.228 +     * Returns the index of the first character following the run
 120.229 +     * with respect to the given {@code attribute} containing the current character.
 120.230 +     */
 120.231 +    public int getRunLimit(Attribute attribute);
 120.232 +
 120.233 +    /**
 120.234 +     * Returns the index of the first character following the run
 120.235 +     * with respect to the given {@code attributes} containing the current character.
 120.236 +     */
 120.237 +    public int getRunLimit(Set<? extends Attribute> attributes);
 120.238 +
 120.239 +    /**
 120.240 +     * Returns a map with the attributes defined on the current
 120.241 +     * character.
 120.242 +     */
 120.243 +    public Map<Attribute,Object> getAttributes();
 120.244 +
 120.245 +    /**
 120.246 +     * Returns the value of the named {@code attribute} for the current character.
 120.247 +     * Returns {@code null} if the {@code attribute} is not defined.
 120.248 +     */
 120.249 +    public Object getAttribute(Attribute attribute);
 120.250 +
 120.251 +    /**
 120.252 +     * Returns the keys of all attributes defined on the
 120.253 +     * iterator's text range. The set is empty if no
 120.254 +     * attributes are defined.
 120.255 +     */
 120.256 +    public Set<Attribute> getAllAttributeKeys();
 120.257 +};
   121.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   121.2 +++ b/rt/emul/compact/src/main/java/java/text/AttributedString.java	Tue Feb 11 13:31:42 2014 +0100
   121.3 @@ -0,0 +1,1120 @@
   121.4 +/*
   121.5 + * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved.
   121.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   121.7 + *
   121.8 + * This code is free software; you can redistribute it and/or modify it
   121.9 + * under the terms of the GNU General Public License version 2 only, as
  121.10 + * published by the Free Software Foundation.  Oracle designates this
  121.11 + * particular file as subject to the "Classpath" exception as provided
  121.12 + * by Oracle in the LICENSE file that accompanied this code.
  121.13 + *
  121.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  121.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  121.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  121.17 + * version 2 for more details (a copy is included in the LICENSE file that
  121.18 + * accompanied this code).
  121.19 + *
  121.20 + * You should have received a copy of the GNU General Public License version
  121.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  121.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  121.23 + *
  121.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  121.25 + * or visit www.oracle.com if you need additional information or have any
  121.26 + * questions.
  121.27 + */
  121.28 +
  121.29 +package java.text;
  121.30 +
  121.31 +import java.util.*;
  121.32 +import java.text.AttributedCharacterIterator.Attribute;
  121.33 +
  121.34 +/**
  121.35 + * An AttributedString holds text and related attribute information. It
  121.36 + * may be used as the actual data storage in some cases where a text
  121.37 + * reader wants to access attributed text through the AttributedCharacterIterator
  121.38 + * interface.
  121.39 + *
  121.40 + * <p>
  121.41 + * An attribute is a key/value pair, identified by the key.  No two
  121.42 + * attributes on a given character can have the same key.
  121.43 + *
  121.44 + * <p>The values for an attribute are immutable, or must not be mutated
  121.45 + * by clients or storage.  They are always passed by reference, and not
  121.46 + * cloned.
  121.47 + *
  121.48 + * @see AttributedCharacterIterator
  121.49 + * @see Annotation
  121.50 + * @since 1.2
  121.51 + */
  121.52 +
  121.53 +public class AttributedString {
  121.54 +
  121.55 +    // since there are no vectors of int, we have to use arrays.
  121.56 +    // We allocate them in chunks of 10 elements so we don't have to allocate all the time.
  121.57 +    private static final int ARRAY_SIZE_INCREMENT = 10;
  121.58 +
  121.59 +    // field holding the text
  121.60 +    String text;
  121.61 +
  121.62 +    // fields holding run attribute information
  121.63 +    // run attributes are organized by run
  121.64 +    int runArraySize;               // current size of the arrays
  121.65 +    int runCount;                   // actual number of runs, <= runArraySize
  121.66 +    int runStarts[];                // start index for each run
  121.67 +    Vector runAttributes[];         // vector of attribute keys for each run
  121.68 +    Vector runAttributeValues[];    // parallel vector of attribute values for each run
  121.69 +
  121.70 +    /**
  121.71 +     * Constructs an AttributedString instance with the given
  121.72 +     * AttributedCharacterIterators.
  121.73 +     *
  121.74 +     * @param iterators AttributedCharacterIterators to construct
  121.75 +     * AttributedString from.
  121.76 +     * @throws NullPointerException if iterators is null
  121.77 +     */
  121.78 +    AttributedString(AttributedCharacterIterator[] iterators) {
  121.79 +        if (iterators == null) {
  121.80 +            throw new NullPointerException("Iterators must not be null");
  121.81 +        }
  121.82 +        if (iterators.length == 0) {
  121.83 +            text = "";
  121.84 +        }
  121.85 +        else {
  121.86 +            // Build the String contents
  121.87 +            StringBuffer buffer = new StringBuffer();
  121.88 +            for (int counter = 0; counter < iterators.length; counter++) {
  121.89 +                appendContents(buffer, iterators[counter]);
  121.90 +            }
  121.91 +
  121.92 +            text = buffer.toString();
  121.93 +
  121.94 +            if (text.length() > 0) {
  121.95 +                // Determine the runs, creating a new run when the attributes
  121.96 +                // differ.
  121.97 +                int offset = 0;
  121.98 +                Map last = null;
  121.99 +
 121.100 +                for (int counter = 0; counter < iterators.length; counter++) {
 121.101 +                    AttributedCharacterIterator iterator = iterators[counter];
 121.102 +                    int start = iterator.getBeginIndex();
 121.103 +                    int end = iterator.getEndIndex();
 121.104 +                    int index = start;
 121.105 +
 121.106 +                    while (index < end) {
 121.107 +                        iterator.setIndex(index);
 121.108 +
 121.109 +                        Map attrs = iterator.getAttributes();
 121.110 +
 121.111 +                        if (mapsDiffer(last, attrs)) {
 121.112 +                            setAttributes(attrs, index - start + offset);
 121.113 +                        }
 121.114 +                        last = attrs;
 121.115 +                        index = iterator.getRunLimit();
 121.116 +                    }
 121.117 +                    offset += (end - start);
 121.118 +                }
 121.119 +            }
 121.120 +        }
 121.121 +    }
 121.122 +
 121.123 +    /**
 121.124 +     * Constructs an AttributedString instance with the given text.
 121.125 +     * @param text The text for this attributed string.
 121.126 +     * @exception NullPointerException if <code>text</code> is null.
 121.127 +     */
 121.128 +    public AttributedString(String text) {
 121.129 +        if (text == null) {
 121.130 +            throw new NullPointerException();
 121.131 +        }
 121.132 +        this.text = text;
 121.133 +    }
 121.134 +
 121.135 +    /**
 121.136 +     * Constructs an AttributedString instance with the given text and attributes.
 121.137 +     * @param text The text for this attributed string.
 121.138 +     * @param attributes The attributes that apply to the entire string.
 121.139 +     * @exception NullPointerException if <code>text</code> or
 121.140 +     *            <code>attributes</code> is null.
 121.141 +     * @exception IllegalArgumentException if the text has length 0
 121.142 +     * and the attributes parameter is not an empty Map (attributes
 121.143 +     * cannot be applied to a 0-length range).
 121.144 +     */
 121.145 +    public AttributedString(String text,
 121.146 +                            Map<? extends Attribute, ?> attributes)
 121.147 +    {
 121.148 +        if (text == null || attributes == null) {
 121.149 +            throw new NullPointerException();
 121.150 +        }
 121.151 +        this.text = text;
 121.152 +
 121.153 +        if (text.length() == 0) {
 121.154 +            if (attributes.isEmpty())
 121.155 +                return;
 121.156 +            throw new IllegalArgumentException("Can't add attribute to 0-length text");
 121.157 +        }
 121.158 +
 121.159 +        int attributeCount = attributes.size();
 121.160 +        if (attributeCount > 0) {
 121.161 +            createRunAttributeDataVectors();
 121.162 +            Vector newRunAttributes = new Vector(attributeCount);
 121.163 +            Vector newRunAttributeValues = new Vector(attributeCount);
 121.164 +            runAttributes[0] = newRunAttributes;
 121.165 +            runAttributeValues[0] = newRunAttributeValues;
 121.166 +            Iterator iterator = attributes.entrySet().iterator();
 121.167 +            while (iterator.hasNext()) {
 121.168 +                Map.Entry entry = (Map.Entry) iterator.next();
 121.169 +                newRunAttributes.addElement(entry.getKey());
 121.170 +                newRunAttributeValues.addElement(entry.getValue());
 121.171 +            }
 121.172 +        }
 121.173 +    }
 121.174 +
 121.175 +    /**
 121.176 +     * Constructs an AttributedString instance with the given attributed
 121.177 +     * text represented by AttributedCharacterIterator.
 121.178 +     * @param text The text for this attributed string.
 121.179 +     * @exception NullPointerException if <code>text</code> is null.
 121.180 +     */
 121.181 +    public AttributedString(AttributedCharacterIterator text) {
 121.182 +        // If performance is critical, this constructor should be
 121.183 +        // implemented here rather than invoking the constructor for a
 121.184 +        // subrange. We can avoid some range checking in the loops.
 121.185 +        this(text, text.getBeginIndex(), text.getEndIndex(), null);
 121.186 +    }
 121.187 +
 121.188 +    /**
 121.189 +     * Constructs an AttributedString instance with the subrange of
 121.190 +     * the given attributed text represented by
 121.191 +     * AttributedCharacterIterator. If the given range produces an
 121.192 +     * empty text, all attributes will be discarded.  Note that any
 121.193 +     * attributes wrapped by an Annotation object are discarded for a
 121.194 +     * subrange of the original attribute range.
 121.195 +     *
 121.196 +     * @param text The text for this attributed string.
 121.197 +     * @param beginIndex Index of the first character of the range.
 121.198 +     * @param endIndex Index of the character following the last character
 121.199 +     * of the range.
 121.200 +     * @exception NullPointerException if <code>text</code> is null.
 121.201 +     * @exception IllegalArgumentException if the subrange given by
 121.202 +     * beginIndex and endIndex is out of the text range.
 121.203 +     * @see java.text.Annotation
 121.204 +     */
 121.205 +    public AttributedString(AttributedCharacterIterator text,
 121.206 +                            int beginIndex,
 121.207 +                            int endIndex) {
 121.208 +        this(text, beginIndex, endIndex, null);
 121.209 +    }
 121.210 +
 121.211 +    /**
 121.212 +     * Constructs an AttributedString instance with the subrange of
 121.213 +     * the given attributed text represented by
 121.214 +     * AttributedCharacterIterator.  Only attributes that match the
 121.215 +     * given attributes will be incorporated into the instance. If the
 121.216 +     * given range produces an empty text, all attributes will be
 121.217 +     * discarded. Note that any attributes wrapped by an Annotation
 121.218 +     * object are discarded for a subrange of the original attribute
 121.219 +     * range.
 121.220 +     *
 121.221 +     * @param text The text for this attributed string.
 121.222 +     * @param beginIndex Index of the first character of the range.
 121.223 +     * @param endIndex Index of the character following the last character
 121.224 +     * of the range.
 121.225 +     * @param attributes Specifies attributes to be extracted
 121.226 +     * from the text. If null is specified, all available attributes will
 121.227 +     * be used.
 121.228 +     * @exception NullPointerException if <code>text</code> is null.
 121.229 +     * @exception IllegalArgumentException if the subrange given by
 121.230 +     * beginIndex and endIndex is out of the text range.
 121.231 +     * @see java.text.Annotation
 121.232 +     */
 121.233 +    public AttributedString(AttributedCharacterIterator text,
 121.234 +                            int beginIndex,
 121.235 +                            int endIndex,
 121.236 +                            Attribute[] attributes) {
 121.237 +        if (text == null) {
 121.238 +            throw new NullPointerException();
 121.239 +        }
 121.240 +
 121.241 +        // Validate the given subrange
 121.242 +        int textBeginIndex = text.getBeginIndex();
 121.243 +        int textEndIndex = text.getEndIndex();
 121.244 +        if (beginIndex < textBeginIndex || endIndex > textEndIndex || beginIndex > endIndex)
 121.245 +            throw new IllegalArgumentException("Invalid substring range");
 121.246 +
 121.247 +        // Copy the given string
 121.248 +        StringBuffer textBuffer = new StringBuffer();
 121.249 +        text.setIndex(beginIndex);
 121.250 +        for (char c = text.current(); text.getIndex() < endIndex; c = text.next())
 121.251 +            textBuffer.append(c);
 121.252 +        this.text = textBuffer.toString();
 121.253 +
 121.254 +        if (beginIndex == endIndex)
 121.255 +            return;
 121.256 +
 121.257 +        // Select attribute keys to be taken care of
 121.258 +        HashSet keys = new HashSet();
 121.259 +        if (attributes == null) {
 121.260 +            keys.addAll(text.getAllAttributeKeys());
 121.261 +        } else {
 121.262 +            for (int i = 0; i < attributes.length; i++)
 121.263 +                keys.add(attributes[i]);
 121.264 +            keys.retainAll(text.getAllAttributeKeys());
 121.265 +        }
 121.266 +        if (keys.isEmpty())
 121.267 +            return;
 121.268 +
 121.269 +        // Get and set attribute runs for each attribute name. Need to
 121.270 +        // scan from the top of the text so that we can discard any
 121.271 +        // Annotation that is no longer applied to a subset text segment.
 121.272 +        Iterator itr = keys.iterator();
 121.273 +        while (itr.hasNext()) {
 121.274 +            Attribute attributeKey = (Attribute)itr.next();
 121.275 +            text.setIndex(textBeginIndex);
 121.276 +            while (text.getIndex() < endIndex) {
 121.277 +                int start = text.getRunStart(attributeKey);
 121.278 +                int limit = text.getRunLimit(attributeKey);
 121.279 +                Object value = text.getAttribute(attributeKey);
 121.280 +
 121.281 +                if (value != null) {
 121.282 +                    if (value instanceof Annotation) {
 121.283 +                        if (start >= beginIndex && limit <= endIndex) {
 121.284 +                            addAttribute(attributeKey, value, start - beginIndex, limit - beginIndex);
 121.285 +                        } else {
 121.286 +                            if (limit > endIndex)
 121.287 +                                break;
 121.288 +                        }
 121.289 +                    } else {
 121.290 +                        // if the run is beyond the given (subset) range, we
 121.291 +                        // don't need to process further.
 121.292 +                        if (start >= endIndex)
 121.293 +                            break;
 121.294 +                        if (limit > beginIndex) {
 121.295 +                            // attribute is applied to any subrange
 121.296 +                            if (start < beginIndex)
 121.297 +                                start = beginIndex;
 121.298 +                            if (limit > endIndex)
 121.299 +                                limit = endIndex;
 121.300 +                            if (start != limit) {
 121.301 +                                addAttribute(attributeKey, value, start - beginIndex, limit - beginIndex);
 121.302 +                            }
 121.303 +                        }
 121.304 +                    }
 121.305 +                }
 121.306 +                text.setIndex(limit);
 121.307 +            }
 121.308 +        }
 121.309 +    }
 121.310 +
 121.311 +    /**
 121.312 +     * Adds an attribute to the entire string.
 121.313 +     * @param attribute the attribute key
 121.314 +     * @param value the value of the attribute; may be null
 121.315 +     * @exception NullPointerException if <code>attribute</code> is null.
 121.316 +     * @exception IllegalArgumentException if the AttributedString has length 0
 121.317 +     * (attributes cannot be applied to a 0-length range).
 121.318 +     */
 121.319 +    public void addAttribute(Attribute attribute, Object value) {
 121.320 +
 121.321 +        if (attribute == null) {
 121.322 +            throw new NullPointerException();
 121.323 +        }
 121.324 +
 121.325 +        int len = length();
 121.326 +        if (len == 0) {
 121.327 +            throw new IllegalArgumentException("Can't add attribute to 0-length text");
 121.328 +        }
 121.329 +
 121.330 +        addAttributeImpl(attribute, value, 0, len);
 121.331 +    }
 121.332 +
 121.333 +    /**
 121.334 +     * Adds an attribute to a subrange of the string.
 121.335 +     * @param attribute the attribute key
 121.336 +     * @param value The value of the attribute. May be null.
 121.337 +     * @param beginIndex Index of the first character of the range.
 121.338 +     * @param endIndex Index of the character following the last character of the range.
 121.339 +     * @exception NullPointerException if <code>attribute</code> is null.
 121.340 +     * @exception IllegalArgumentException if beginIndex is less then 0, endIndex is
 121.341 +     * greater than the length of the string, or beginIndex and endIndex together don't
 121.342 +     * define a non-empty subrange of the string.
 121.343 +     */
 121.344 +    public void addAttribute(Attribute attribute, Object value,
 121.345 +            int beginIndex, int endIndex) {
 121.346 +
 121.347 +        if (attribute == null) {
 121.348 +            throw new NullPointerException();
 121.349 +        }
 121.350 +
 121.351 +        if (beginIndex < 0 || endIndex > length() || beginIndex >= endIndex) {
 121.352 +            throw new IllegalArgumentException("Invalid substring range");
 121.353 +        }
 121.354 +
 121.355 +        addAttributeImpl(attribute, value, beginIndex, endIndex);
 121.356 +    }
 121.357 +
 121.358 +    /**
 121.359 +     * Adds a set of attributes to a subrange of the string.
 121.360 +     * @param attributes The attributes to be added to the string.
 121.361 +     * @param beginIndex Index of the first character of the range.
 121.362 +     * @param endIndex Index of the character following the last
 121.363 +     * character of the range.
 121.364 +     * @exception NullPointerException if <code>attributes</code> is null.
 121.365 +     * @exception IllegalArgumentException if beginIndex is less then
 121.366 +     * 0, endIndex is greater than the length of the string, or
 121.367 +     * beginIndex and endIndex together don't define a non-empty
 121.368 +     * subrange of the string and the attributes parameter is not an
 121.369 +     * empty Map.
 121.370 +     */
 121.371 +    public void addAttributes(Map<? extends Attribute, ?> attributes,
 121.372 +                              int beginIndex, int endIndex)
 121.373 +    {
 121.374 +        if (attributes == null) {
 121.375 +            throw new NullPointerException();
 121.376 +        }
 121.377 +
 121.378 +        if (beginIndex < 0 || endIndex > length() || beginIndex > endIndex) {
 121.379 +            throw new IllegalArgumentException("Invalid substring range");
 121.380 +        }
 121.381 +        if (beginIndex == endIndex) {
 121.382 +            if (attributes.isEmpty())
 121.383 +                return;
 121.384 +            throw new IllegalArgumentException("Can't add attribute to 0-length text");
 121.385 +        }
 121.386 +
 121.387 +        // make sure we have run attribute data vectors
 121.388 +        if (runCount == 0) {
 121.389 +            createRunAttributeDataVectors();
 121.390 +        }
 121.391 +
 121.392 +        // break up runs if necessary
 121.393 +        int beginRunIndex = ensureRunBreak(beginIndex);
 121.394 +        int endRunIndex = ensureRunBreak(endIndex);
 121.395 +
 121.396 +        Iterator iterator = attributes.entrySet().iterator();
 121.397 +        while (iterator.hasNext()) {
 121.398 +            Map.Entry entry = (Map.Entry) iterator.next();
 121.399 +            addAttributeRunData((Attribute) entry.getKey(), entry.getValue(), beginRunIndex, endRunIndex);
 121.400 +        }
 121.401 +    }
 121.402 +
 121.403 +    private synchronized void addAttributeImpl(Attribute attribute, Object value,
 121.404 +            int beginIndex, int endIndex) {
 121.405 +
 121.406 +        // make sure we have run attribute data vectors
 121.407 +        if (runCount == 0) {
 121.408 +            createRunAttributeDataVectors();
 121.409 +        }
 121.410 +
 121.411 +        // break up runs if necessary
 121.412 +        int beginRunIndex = ensureRunBreak(beginIndex);
 121.413 +        int endRunIndex = ensureRunBreak(endIndex);
 121.414 +
 121.415 +        addAttributeRunData(attribute, value, beginRunIndex, endRunIndex);
 121.416 +    }
 121.417 +
 121.418 +    private final void createRunAttributeDataVectors() {
 121.419 +        // use temporary variables so things remain consistent in case of an exception
 121.420 +        int newRunStarts[] = new int[ARRAY_SIZE_INCREMENT];
 121.421 +        Vector newRunAttributes[] = new Vector[ARRAY_SIZE_INCREMENT];
 121.422 +        Vector newRunAttributeValues[] = new Vector[ARRAY_SIZE_INCREMENT];
 121.423 +        runStarts = newRunStarts;
 121.424 +        runAttributes = newRunAttributes;
 121.425 +        runAttributeValues = newRunAttributeValues;
 121.426 +        runArraySize = ARRAY_SIZE_INCREMENT;
 121.427 +        runCount = 1; // assume initial run starting at index 0
 121.428 +    }
 121.429 +
 121.430 +    // ensure there's a run break at offset, return the index of the run
 121.431 +    private final int ensureRunBreak(int offset) {
 121.432 +        return ensureRunBreak(offset, true);
 121.433 +    }
 121.434 +
 121.435 +    /**
 121.436 +     * Ensures there is a run break at offset, returning the index of
 121.437 +     * the run. If this results in splitting a run, two things can happen:
 121.438 +     * <ul>
 121.439 +     * <li>If copyAttrs is true, the attributes from the existing run
 121.440 +     *     will be placed in both of the newly created runs.
 121.441 +     * <li>If copyAttrs is false, the attributes from the existing run
 121.442 +     * will NOT be copied to the run to the right (>= offset) of the break,
 121.443 +     * but will exist on the run to the left (< offset).
 121.444 +     * </ul>
 121.445 +     */
 121.446 +    private final int ensureRunBreak(int offset, boolean copyAttrs) {
 121.447 +        if (offset == length()) {
 121.448 +            return runCount;
 121.449 +        }
 121.450 +
 121.451 +        // search for the run index where this offset should be
 121.452 +        int runIndex = 0;
 121.453 +        while (runIndex < runCount && runStarts[runIndex] < offset) {
 121.454 +            runIndex++;
 121.455 +        }
 121.456 +
 121.457 +        // if the offset is at a run start already, we're done
 121.458 +        if (runIndex < runCount && runStarts[runIndex] == offset) {
 121.459 +            return runIndex;
 121.460 +        }
 121.461 +
 121.462 +        // we'll have to break up a run
 121.463 +        // first, make sure we have enough space in our arrays
 121.464 +        if (runCount == runArraySize) {
 121.465 +            int newArraySize = runArraySize + ARRAY_SIZE_INCREMENT;
 121.466 +            int newRunStarts[] = new int[newArraySize];
 121.467 +            Vector newRunAttributes[] = new Vector[newArraySize];
 121.468 +            Vector newRunAttributeValues[] = new Vector[newArraySize];
 121.469 +            for (int i = 0; i < runArraySize; i++) {
 121.470 +                newRunStarts[i] = runStarts[i];
 121.471 +                newRunAttributes[i] = runAttributes[i];
 121.472 +                newRunAttributeValues[i] = runAttributeValues[i];
 121.473 +            }
 121.474 +            runStarts = newRunStarts;
 121.475 +            runAttributes = newRunAttributes;
 121.476 +            runAttributeValues = newRunAttributeValues;
 121.477 +            runArraySize = newArraySize;
 121.478 +        }
 121.479 +
 121.480 +        // make copies of the attribute information of the old run that the new one used to be part of
 121.481 +        // use temporary variables so things remain consistent in case of an exception
 121.482 +        Vector newRunAttributes = null;
 121.483 +        Vector newRunAttributeValues = null;
 121.484 +
 121.485 +        if (copyAttrs) {
 121.486 +            Vector oldRunAttributes = runAttributes[runIndex - 1];
 121.487 +            Vector oldRunAttributeValues = runAttributeValues[runIndex - 1];
 121.488 +            if (oldRunAttributes != null) {
 121.489 +                newRunAttributes = (Vector) oldRunAttributes.clone();
 121.490 +            }
 121.491 +            if (oldRunAttributeValues != null) {
 121.492 +                newRunAttributeValues = (Vector) oldRunAttributeValues.clone();
 121.493 +            }
 121.494 +        }
 121.495 +
 121.496 +        // now actually break up the run
 121.497 +        runCount++;
 121.498 +        for (int i = runCount - 1; i > runIndex; i--) {
 121.499 +            runStarts[i] = runStarts[i - 1];
 121.500 +            runAttributes[i] = runAttributes[i - 1];
 121.501 +            runAttributeValues[i] = runAttributeValues[i - 1];
 121.502 +        }
 121.503 +        runStarts[runIndex] = offset;
 121.504 +        runAttributes[runIndex] = newRunAttributes;
 121.505 +        runAttributeValues[runIndex] = newRunAttributeValues;
 121.506 +
 121.507 +        return runIndex;
 121.508 +    }
 121.509 +
 121.510 +    // add the attribute attribute/value to all runs where beginRunIndex <= runIndex < endRunIndex
 121.511 +    private void addAttributeRunData(Attribute attribute, Object value,
 121.512 +            int beginRunIndex, int endRunIndex) {
 121.513 +
 121.514 +        for (int i = beginRunIndex; i < endRunIndex; i++) {
 121.515 +            int keyValueIndex = -1; // index of key and value in our vectors; assume we don't have an entry yet
 121.516 +            if (runAttributes[i] == null) {
 121.517 +                Vector newRunAttributes = new Vector();
 121.518 +                Vector newRunAttributeValues = new Vector();
 121.519 +                runAttributes[i] = newRunAttributes;
 121.520 +                runAttributeValues[i] = newRunAttributeValues;
 121.521 +            } else {
 121.522 +                // check whether we have an entry already
 121.523 +                keyValueIndex = runAttributes[i].indexOf(attribute);
 121.524 +            }
 121.525 +
 121.526 +            if (keyValueIndex == -1) {
 121.527 +                // create new entry
 121.528 +                int oldSize = runAttributes[i].size();
 121.529 +                runAttributes[i].addElement(attribute);
 121.530 +                try {
 121.531 +                    runAttributeValues[i].addElement(value);
 121.532 +                }
 121.533 +                catch (Exception e) {
 121.534 +                    runAttributes[i].setSize(oldSize);
 121.535 +                    runAttributeValues[i].setSize(oldSize);
 121.536 +                }
 121.537 +            } else {
 121.538 +                // update existing entry
 121.539 +                runAttributeValues[i].set(keyValueIndex, value);
 121.540 +            }
 121.541 +        }
 121.542 +    }
 121.543 +
 121.544 +    /**
 121.545 +     * Creates an AttributedCharacterIterator instance that provides access to the entire contents of
 121.546 +     * this string.
 121.547 +     *
 121.548 +     * @return An iterator providing access to the text and its attributes.
 121.549 +     */
 121.550 +    public AttributedCharacterIterator getIterator() {
 121.551 +        return getIterator(null, 0, length());
 121.552 +    }
 121.553 +
 121.554 +    /**
 121.555 +     * Creates an AttributedCharacterIterator instance that provides access to
 121.556 +     * selected contents of this string.
 121.557 +     * Information about attributes not listed in attributes that the
 121.558 +     * implementor may have need not be made accessible through the iterator.
 121.559 +     * If the list is null, all available attribute information should be made
 121.560 +     * accessible.
 121.561 +     *
 121.562 +     * @param attributes a list of attributes that the client is interested in
 121.563 +     * @return an iterator providing access to the entire text and its selected attributes
 121.564 +     */
 121.565 +    public AttributedCharacterIterator getIterator(Attribute[] attributes) {
 121.566 +        return getIterator(attributes, 0, length());
 121.567 +    }
 121.568 +
 121.569 +    /**
 121.570 +     * Creates an AttributedCharacterIterator instance that provides access to
 121.571 +     * selected contents of this string.
 121.572 +     * Information about attributes not listed in attributes that the
 121.573 +     * implementor may have need not be made accessible through the iterator.
 121.574 +     * If the list is null, all available attribute information should be made
 121.575 +     * accessible.
 121.576 +     *
 121.577 +     * @param attributes a list of attributes that the client is interested in
 121.578 +     * @param beginIndex the index of the first character
 121.579 +     * @param endIndex the index of the character following the last character
 121.580 +     * @return an iterator providing access to the text and its attributes
 121.581 +     * @exception IllegalArgumentException if beginIndex is less then 0,
 121.582 +     * endIndex is greater than the length of the string, or beginIndex is
 121.583 +     * greater than endIndex.
 121.584 +     */
 121.585 +    public AttributedCharacterIterator getIterator(Attribute[] attributes, int beginIndex, int endIndex) {
 121.586 +        return new AttributedStringIterator(attributes, beginIndex, endIndex);
 121.587 +    }
 121.588 +
 121.589 +    // all (with the exception of length) reading operations are private,
 121.590 +    // since AttributedString instances are accessed through iterators.
 121.591 +
 121.592 +    // length is package private so that CharacterIteratorFieldDelegate can
 121.593 +    // access it without creating an AttributedCharacterIterator.
 121.594 +    int length() {
 121.595 +        return text.length();
 121.596 +    }
 121.597 +
 121.598 +    private char charAt(int index) {
 121.599 +        return text.charAt(index);
 121.600 +    }
 121.601 +
 121.602 +    private synchronized Object getAttribute(Attribute attribute, int runIndex) {
 121.603 +        Vector currentRunAttributes = runAttributes[runIndex];
 121.604 +        Vector currentRunAttributeValues = runAttributeValues[runIndex];
 121.605 +        if (currentRunAttributes == null) {
 121.606 +            return null;
 121.607 +        }
 121.608 +        int attributeIndex = currentRunAttributes.indexOf(attribute);
 121.609 +        if (attributeIndex != -1) {
 121.610 +            return currentRunAttributeValues.elementAt(attributeIndex);
 121.611 +        }
 121.612 +        else {
 121.613 +            return null;
 121.614 +        }
 121.615 +    }
 121.616 +
 121.617 +    // gets an attribute value, but returns an annotation only if it's range does not extend outside the range beginIndex..endIndex
 121.618 +    private Object getAttributeCheckRange(Attribute attribute, int runIndex, int beginIndex, int endIndex) {
 121.619 +        Object value = getAttribute(attribute, runIndex);
 121.620 +        if (value instanceof Annotation) {
 121.621 +            // need to check whether the annotation's range extends outside the iterator's range
 121.622 +            if (beginIndex > 0) {
 121.623 +                int currIndex = runIndex;
 121.624 +                int runStart = runStarts[currIndex];
 121.625 +                while (runStart >= beginIndex &&
 121.626 +                        valuesMatch(value, getAttribute(attribute, currIndex - 1))) {
 121.627 +                    currIndex--;
 121.628 +                    runStart = runStarts[currIndex];
 121.629 +                }
 121.630 +                if (runStart < beginIndex) {
 121.631 +                    // annotation's range starts before iterator's range
 121.632 +                    return null;
 121.633 +                }
 121.634 +            }
 121.635 +            int textLength = length();
 121.636 +            if (endIndex < textLength) {
 121.637 +                int currIndex = runIndex;
 121.638 +                int runLimit = (currIndex < runCount - 1) ? runStarts[currIndex + 1] : textLength;
 121.639 +                while (runLimit <= endIndex &&
 121.640 +                        valuesMatch(value, getAttribute(attribute, currIndex + 1))) {
 121.641 +                    currIndex++;
 121.642 +                    runLimit = (currIndex < runCount - 1) ? runStarts[currIndex + 1] : textLength;
 121.643 +                }
 121.644 +                if (runLimit > endIndex) {
 121.645 +                    // annotation's range ends after iterator's range
 121.646 +                    return null;
 121.647 +                }
 121.648 +            }
 121.649 +            // annotation's range is subrange of iterator's range,
 121.650 +            // so we can return the value
 121.651 +        }
 121.652 +        return value;
 121.653 +    }
 121.654 +
 121.655 +    // returns whether all specified attributes have equal values in the runs with the given indices
 121.656 +    private boolean attributeValuesMatch(Set attributes, int runIndex1, int runIndex2) {
 121.657 +        Iterator iterator = attributes.iterator();
 121.658 +        while (iterator.hasNext()) {
 121.659 +            Attribute key = (Attribute) iterator.next();
 121.660 +           if (!valuesMatch(getAttribute(key, runIndex1), getAttribute(key, runIndex2))) {
 121.661 +                return false;
 121.662 +            }
 121.663 +        }
 121.664 +        return true;
 121.665 +    }
 121.666 +
 121.667 +    // returns whether the two objects are either both null or equal
 121.668 +    private final static boolean valuesMatch(Object value1, Object value2) {
 121.669 +        if (value1 == null) {
 121.670 +            return value2 == null;
 121.671 +        } else {
 121.672 +            return value1.equals(value2);
 121.673 +        }
 121.674 +    }
 121.675 +
 121.676 +    /**
 121.677 +     * Appends the contents of the CharacterIterator iterator into the
 121.678 +     * StringBuffer buf.
 121.679 +     */
 121.680 +    private final void appendContents(StringBuffer buf,
 121.681 +                                      CharacterIterator iterator) {
 121.682 +        int index = iterator.getBeginIndex();
 121.683 +        int end = iterator.getEndIndex();
 121.684 +
 121.685 +        while (index < end) {
 121.686 +            iterator.setIndex(index++);
 121.687 +            buf.append(iterator.current());
 121.688 +        }
 121.689 +    }
 121.690 +
 121.691 +    /**
 121.692 +     * Sets the attributes for the range from offset to the next run break
 121.693 +     * (typically the end of the text) to the ones specified in attrs.
 121.694 +     * This is only meant to be called from the constructor!
 121.695 +     */
 121.696 +    private void setAttributes(Map attrs, int offset) {
 121.697 +        if (runCount == 0) {
 121.698 +            createRunAttributeDataVectors();
 121.699 +        }
 121.700 +
 121.701 +        int index = ensureRunBreak(offset, false);
 121.702 +        int size;
 121.703 +
 121.704 +        if (attrs != null && (size = attrs.size()) > 0) {
 121.705 +            Vector runAttrs = new Vector(size);
 121.706 +            Vector runValues = new Vector(size);
 121.707 +            Iterator iterator = attrs.entrySet().iterator();
 121.708 +
 121.709 +            while (iterator.hasNext()) {
 121.710 +                Map.Entry entry = (Map.Entry)iterator.next();
 121.711 +
 121.712 +                runAttrs.add(entry.getKey());
 121.713 +                runValues.add(entry.getValue());
 121.714 +            }
 121.715 +            runAttributes[index] = runAttrs;
 121.716 +            runAttributeValues[index] = runValues;
 121.717 +        }
 121.718 +    }
 121.719 +
 121.720 +    /**
 121.721 +     * Returns true if the attributes specified in last and attrs differ.
 121.722 +     */
 121.723 +    private static boolean mapsDiffer(Map last, Map attrs) {
 121.724 +        if (last == null) {
 121.725 +            return (attrs != null && attrs.size() > 0);
 121.726 +        }
 121.727 +        return (!last.equals(attrs));
 121.728 +    }
 121.729 +
 121.730 +
 121.731 +    // the iterator class associated with this string class
 121.732 +
 121.733 +    final private class AttributedStringIterator implements AttributedCharacterIterator {
 121.734 +
 121.735 +        // note on synchronization:
 121.736 +        // we don't synchronize on the iterator, assuming that an iterator is only used in one thread.
 121.737 +        // we do synchronize access to the AttributedString however, since it's more likely to be shared between threads.
 121.738 +
 121.739 +        // start and end index for our iteration
 121.740 +        private int beginIndex;
 121.741 +        private int endIndex;
 121.742 +
 121.743 +        // attributes that our client is interested in
 121.744 +        private Attribute[] relevantAttributes;
 121.745 +
 121.746 +        // the current index for our iteration
 121.747 +        // invariant: beginIndex <= currentIndex <= endIndex
 121.748 +        private int currentIndex;
 121.749 +
 121.750 +        // information about the run that includes currentIndex
 121.751 +        private int currentRunIndex;
 121.752 +        private int currentRunStart;
 121.753 +        private int currentRunLimit;
 121.754 +
 121.755 +        // constructor
 121.756 +        AttributedStringIterator(Attribute[] attributes, int beginIndex, int endIndex) {
 121.757 +
 121.758 +            if (beginIndex < 0 || beginIndex > endIndex || endIndex > length()) {
 121.759 +                throw new IllegalArgumentException("Invalid substring range");
 121.760 +            }
 121.761 +
 121.762 +            this.beginIndex = beginIndex;
 121.763 +            this.endIndex = endIndex;
 121.764 +            this.currentIndex = beginIndex;
 121.765 +            updateRunInfo();
 121.766 +            if (attributes != null) {
 121.767 +                relevantAttributes = (Attribute[]) attributes.clone();
 121.768 +            }
 121.769 +        }
 121.770 +
 121.771 +        // Object methods. See documentation in that class.
 121.772 +
 121.773 +        public boolean equals(Object obj) {
 121.774 +            if (this == obj) {
 121.775 +                return true;
 121.776 +            }
 121.777 +            if (!(obj instanceof AttributedStringIterator)) {
 121.778 +                return false;
 121.779 +            }
 121.780 +
 121.781 +            AttributedStringIterator that = (AttributedStringIterator) obj;
 121.782 +
 121.783 +            if (AttributedString.this != that.getString())
 121.784 +                return false;
 121.785 +            if (currentIndex != that.currentIndex || beginIndex != that.beginIndex || endIndex != that.endIndex)
 121.786 +                return false;
 121.787 +            return true;
 121.788 +        }
 121.789 +
 121.790 +        public int hashCode() {
 121.791 +            return text.hashCode() ^ currentIndex ^ beginIndex ^ endIndex;
 121.792 +        }
 121.793 +
 121.794 +        public Object clone() {
 121.795 +            try {
 121.796 +                AttributedStringIterator other = (AttributedStringIterator) super.clone();
 121.797 +                return other;
 121.798 +            }
 121.799 +            catch (CloneNotSupportedException e) {
 121.800 +                throw new InternalError();
 121.801 +            }
 121.802 +        }
 121.803 +
 121.804 +        // CharacterIterator methods. See documentation in that interface.
 121.805 +
 121.806 +        public char first() {
 121.807 +            return internalSetIndex(beginIndex);
 121.808 +        }
 121.809 +
 121.810 +        public char last() {
 121.811 +            if (endIndex == beginIndex) {
 121.812 +                return internalSetIndex(endIndex);
 121.813 +            } else {
 121.814 +                return internalSetIndex(endIndex - 1);
 121.815 +            }
 121.816 +        }
 121.817 +
 121.818 +        public char current() {
 121.819 +            if (currentIndex == endIndex) {
 121.820 +                return DONE;
 121.821 +            } else {
 121.822 +                return charAt(currentIndex);
 121.823 +            }
 121.824 +        }
 121.825 +
 121.826 +        public char next() {
 121.827 +            if (currentIndex < endIndex) {
 121.828 +                return internalSetIndex(currentIndex + 1);
 121.829 +            }
 121.830 +            else {
 121.831 +                return DONE;
 121.832 +            }
 121.833 +        }
 121.834 +
 121.835 +        public char previous() {
 121.836 +            if (currentIndex > beginIndex) {
 121.837 +                return internalSetIndex(currentIndex - 1);
 121.838 +            }
 121.839 +            else {
 121.840 +                return DONE;
 121.841 +            }
 121.842 +        }
 121.843 +
 121.844 +        public char setIndex(int position) {
 121.845 +            if (position < beginIndex || position > endIndex)
 121.846 +                throw new IllegalArgumentException("Invalid index");
 121.847 +            return internalSetIndex(position);
 121.848 +        }
 121.849 +
 121.850 +        public int getBeginIndex() {
 121.851 +            return beginIndex;
 121.852 +        }
 121.853 +
 121.854 +        public int getEndIndex() {
 121.855 +            return endIndex;
 121.856 +        }
 121.857 +
 121.858 +        public int getIndex() {
 121.859 +            return currentIndex;
 121.860 +        }
 121.861 +
 121.862 +        // AttributedCharacterIterator methods. See documentation in that interface.
 121.863 +
 121.864 +        public int getRunStart() {
 121.865 +            return currentRunStart;
 121.866 +        }
 121.867 +
 121.868 +        public int getRunStart(Attribute attribute) {
 121.869 +            if (currentRunStart == beginIndex || currentRunIndex == -1) {
 121.870 +                return currentRunStart;
 121.871 +            } else {
 121.872 +                Object value = getAttribute(attribute);
 121.873 +                int runStart = currentRunStart;
 121.874 +                int runIndex = currentRunIndex;
 121.875 +                while (runStart > beginIndex &&
 121.876 +                        valuesMatch(value, AttributedString.this.getAttribute(attribute, runIndex - 1))) {
 121.877 +                    runIndex--;
 121.878 +                    runStart = runStarts[runIndex];
 121.879 +                }
 121.880 +                if (runStart < beginIndex) {
 121.881 +                    runStart = beginIndex;
 121.882 +                }
 121.883 +                return runStart;
 121.884 +            }
 121.885 +        }
 121.886 +
 121.887 +        public int getRunStart(Set<? extends Attribute> attributes) {
 121.888 +            if (currentRunStart == beginIndex || currentRunIndex == -1) {
 121.889 +                return currentRunStart;
 121.890 +            } else {
 121.891 +                int runStart = currentRunStart;
 121.892 +                int runIndex = currentRunIndex;
 121.893 +                while (runStart > beginIndex &&
 121.894 +                        AttributedString.this.attributeValuesMatch(attributes, currentRunIndex, runIndex - 1)) {
 121.895 +                    runIndex--;
 121.896 +                    runStart = runStarts[runIndex];
 121.897 +                }
 121.898 +                if (runStart < beginIndex) {
 121.899 +                    runStart = beginIndex;
 121.900 +                }
 121.901 +                return runStart;
 121.902 +            }
 121.903 +        }
 121.904 +
 121.905 +        public int getRunLimit() {
 121.906 +            return currentRunLimit;
 121.907 +        }
 121.908 +
 121.909 +        public int getRunLimit(Attribute attribute) {
 121.910 +            if (currentRunLimit == endIndex || currentRunIndex == -1) {
 121.911 +                return currentRunLimit;
 121.912 +            } else {
 121.913 +                Object value = getAttribute(attribute);
 121.914 +                int runLimit = currentRunLimit;
 121.915 +                int runIndex = currentRunIndex;
 121.916 +                while (runLimit < endIndex &&
 121.917 +                        valuesMatch(value, AttributedString.this.getAttribute(attribute, runIndex + 1))) {
 121.918 +                    runIndex++;
 121.919 +                    runLimit = runIndex < runCount - 1 ? runStarts[runIndex + 1] : endIndex;
 121.920 +                }
 121.921 +                if (runLimit > endIndex) {
 121.922 +                    runLimit = endIndex;
 121.923 +                }
 121.924 +                return runLimit;
 121.925 +            }
 121.926 +        }
 121.927 +
 121.928 +        public int getRunLimit(Set<? extends Attribute> attributes) {
 121.929 +            if (currentRunLimit == endIndex || currentRunIndex == -1) {
 121.930 +                return currentRunLimit;
 121.931 +            } else {
 121.932 +                int runLimit = currentRunLimit;
 121.933 +                int runIndex = currentRunIndex;
 121.934 +                while (runLimit < endIndex &&
 121.935 +                        AttributedString.this.attributeValuesMatch(attributes, currentRunIndex, runIndex + 1)) {
 121.936 +                    runIndex++;
 121.937 +                    runLimit = runIndex < runCount - 1 ? runStarts[runIndex + 1] : endIndex;
 121.938 +                }
 121.939 +                if (runLimit > endIndex) {
 121.940 +                    runLimit = endIndex;
 121.941 +                }
 121.942 +                return runLimit;
 121.943 +            }
 121.944 +        }
 121.945 +
 121.946 +        public Map<Attribute,Object> getAttributes() {
 121.947 +            if (runAttributes == null || currentRunIndex == -1 || runAttributes[currentRunIndex] == null) {
 121.948 +                // ??? would be nice to return null, but current spec doesn't allow it
 121.949 +                // returning Hashtable saves AttributeMap from dealing with emptiness
 121.950 +                return new Hashtable();
 121.951 +            }
 121.952 +            return new AttributeMap(currentRunIndex, beginIndex, endIndex);
 121.953 +        }
 121.954 +
 121.955 +        public Set<Attribute> getAllAttributeKeys() {
 121.956 +            // ??? This should screen out attribute keys that aren't relevant to the client
 121.957 +            if (runAttributes == null) {
 121.958 +                // ??? would be nice to return null, but current spec doesn't allow it
 121.959 +                // returning HashSet saves us from dealing with emptiness
 121.960 +                return new HashSet();
 121.961 +            }
 121.962 +            synchronized (AttributedString.this) {
 121.963 +                // ??? should try to create this only once, then update if necessary,
 121.964 +                // and give callers read-only view
 121.965 +                Set keys = new HashSet();
 121.966 +                int i = 0;
 121.967 +                while (i < runCount) {
 121.968 +                    if (runStarts[i] < endIndex && (i == runCount - 1 || runStarts[i + 1] > beginIndex)) {
 121.969 +                        Vector currentRunAttributes = runAttributes[i];
 121.970 +                        if (currentRunAttributes != null) {
 121.971 +                            int j = currentRunAttributes.size();
 121.972 +                            while (j-- > 0) {
 121.973 +                                keys.add(currentRunAttributes.get(j));
 121.974 +                            }
 121.975 +                        }
 121.976 +                    }
 121.977 +                    i++;
 121.978 +                }
 121.979 +                return keys;
 121.980 +            }
 121.981 +        }
 121.982 +
 121.983 +        public Object getAttribute(Attribute attribute) {
 121.984 +            int runIndex = currentRunIndex;
 121.985 +            if (runIndex < 0) {
 121.986 +                return null;
 121.987 +            }
 121.988 +            return AttributedString.this.getAttributeCheckRange(attribute, runIndex, beginIndex, endIndex);
 121.989 +        }
 121.990 +
 121.991 +        // internally used methods
 121.992 +
 121.993 +        private AttributedString getString() {
 121.994 +            return AttributedString.this;
 121.995 +        }
 121.996 +
 121.997 +        // set the current index, update information about the current run if necessary,
 121.998 +        // return the character at the current index
 121.999 +        private char internalSetIndex(int position) {
121.1000 +            currentIndex = position;
121.1001 +            if (position < currentRunStart || position >= currentRunLimit) {
121.1002 +                updateRunInfo();
121.1003 +            }
121.1004 +            if (currentIndex == endIndex) {
121.1005 +                return DONE;
121.1006 +            } else {
121.1007 +                return charAt(position);
121.1008 +            }
121.1009 +        }
121.1010 +
121.1011 +        // update the information about the current run
121.1012 +        private void updateRunInfo() {
121.1013 +            if (currentIndex == endIndex) {
121.1014 +                currentRunStart = currentRunLimit = endIndex;
121.1015 +                currentRunIndex = -1;
121.1016 +            } else {
121.1017 +                synchronized (AttributedString.this) {
121.1018 +                    int runIndex = -1;
121.1019 +                    while (runIndex < runCount - 1 && runStarts[runIndex + 1] <= currentIndex)
121.1020 +                        runIndex++;
121.1021 +                    currentRunIndex = runIndex;
121.1022 +                    if (runIndex >= 0) {
121.1023 +                        currentRunStart = runStarts[runIndex];
121.1024 +                        if (currentRunStart < beginIndex)
121.1025 +                            currentRunStart = beginIndex;
121.1026 +                    }
121.1027 +                    else {
121.1028 +                        currentRunStart = beginIndex;
121.1029 +                    }
121.1030 +                    if (runIndex < runCount - 1) {
121.1031 +                        currentRunLimit = runStarts[runIndex + 1];
121.1032 +                        if (currentRunLimit > endIndex)
121.1033 +                            currentRunLimit = endIndex;
121.1034 +                    }
121.1035 +                    else {
121.1036 +                        currentRunLimit = endIndex;
121.1037 +                    }
121.1038 +                }
121.1039 +            }
121.1040 +        }
121.1041 +
121.1042 +    }
121.1043 +
121.1044 +    // the map class associated with this string class, giving access to the attributes of one run
121.1045 +
121.1046 +    final private class AttributeMap extends AbstractMap<Attribute,Object> {
121.1047 +
121.1048 +        int runIndex;
121.1049 +        int beginIndex;
121.1050 +        int endIndex;
121.1051 +
121.1052 +        AttributeMap(int runIndex, int beginIndex, int endIndex) {
121.1053 +            this.runIndex = runIndex;
121.1054 +            this.beginIndex = beginIndex;
121.1055 +            this.endIndex = endIndex;
121.1056 +        }
121.1057 +
121.1058 +        public Set entrySet() {
121.1059 +            HashSet set = new HashSet();
121.1060 +            synchronized (AttributedString.this) {
121.1061 +                int size = runAttributes[runIndex].size();
121.1062 +                for (int i = 0; i < size; i++) {
121.1063 +                    Attribute key = (Attribute) runAttributes[runIndex].get(i);
121.1064 +                    Object value = runAttributeValues[runIndex].get(i);
121.1065 +                    if (value instanceof Annotation) {
121.1066 +                        value = AttributedString.this.getAttributeCheckRange(key,
121.1067 +                                                             runIndex, beginIndex, endIndex);
121.1068 +                        if (value == null) {
121.1069 +                            continue;
121.1070 +                        }
121.1071 +                    }
121.1072 +                    Map.Entry entry = new AttributeEntry(key, value);
121.1073 +                    set.add(entry);
121.1074 +                }
121.1075 +            }
121.1076 +            return set;
121.1077 +        }
121.1078 +
121.1079 +        public Object get(Object key) {
121.1080 +            return AttributedString.this.getAttributeCheckRange((Attribute) key, runIndex, beginIndex, endIndex);
121.1081 +        }
121.1082 +    }
121.1083 +}
121.1084 +
121.1085 +class AttributeEntry implements Map.Entry {
121.1086 +
121.1087 +    private Attribute key;
121.1088 +    private Object value;
121.1089 +
121.1090 +    AttributeEntry(Attribute key, Object value) {
121.1091 +        this.key = key;
121.1092 +        this.value = value;
121.1093 +    }
121.1094 +
121.1095 +    public boolean equals(Object o) {
121.1096 +        if (!(o instanceof AttributeEntry)) {
121.1097 +            return false;
121.1098 +        }
121.1099 +        AttributeEntry other = (AttributeEntry) o;
121.1100 +        return other.key.equals(key) &&
121.1101 +            (value == null ? other.value == null : other.value.equals(value));
121.1102 +    }
121.1103 +
121.1104 +    public Object getKey() {
121.1105 +        return key;
121.1106 +    }
121.1107 +
121.1108 +    public Object getValue() {
121.1109 +        return value;
121.1110 +    }
121.1111 +
121.1112 +    public Object setValue(Object newValue) {
121.1113 +        throw new UnsupportedOperationException();
121.1114 +    }
121.1115 +
121.1116 +    public int hashCode() {
121.1117 +        return key.hashCode() ^ (value==null ? 0 : value.hashCode());
121.1118 +    }
121.1119 +
121.1120 +    public String toString() {
121.1121 +        return key.toString()+"="+value.toString();
121.1122 +    }
121.1123 +}
   122.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   122.2 +++ b/rt/emul/compact/src/main/java/java/text/CalendarBuilder.java	Tue Feb 11 13:31:42 2014 +0100
   122.3 @@ -0,0 +1,170 @@
   122.4 +/*
   122.5 + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
   122.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   122.7 + *
   122.8 + * This code is free software; you can redistribute it and/or modify it
   122.9 + * under the terms of the GNU General Public License version 2 only, as
  122.10 + * published by the Free Software Foundation.  Oracle designates this
  122.11 + * particular file as subject to the "Classpath" exception as provided
  122.12 + * by Oracle in the LICENSE file that accompanied this code.
  122.13 + *
  122.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  122.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  122.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  122.17 + * version 2 for more details (a copy is included in the LICENSE file that
  122.18 + * accompanied this code).
  122.19 + *
  122.20 + * You should have received a copy of the GNU General Public License version
  122.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  122.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  122.23 + *
  122.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  122.25 + * or visit www.oracle.com if you need additional information or have any
  122.26 + * questions.
  122.27 + */
  122.28 +
  122.29 +package java.text;
  122.30 +
  122.31 +import java.util.Calendar;
  122.32 +import static java.util.Calendar.*;
  122.33 +
  122.34 +/**
  122.35 + * {@code CalendarBuilder} keeps field-value pairs for setting
  122.36 + * the calendar fields of the given {@code Calendar}. It has the
  122.37 + * {@link Calendar#FIELD_COUNT FIELD_COUNT}-th field for the week year
  122.38 + * support. Also {@code ISO_DAY_OF_WEEK} is used to specify
  122.39 + * {@code DAY_OF_WEEK} in the ISO day of week numbering.
  122.40 + *
  122.41 + * <p>{@code CalendarBuilder} retains the semantic of the pseudo
  122.42 + * timestamp for fields. {@code CalendarBuilder} uses a single
  122.43 + * int array combining fields[] and stamp[] of {@code Calendar}.
  122.44 + *
  122.45 + * @author Masayoshi Okutsu
  122.46 + */
  122.47 +class CalendarBuilder {
  122.48 +    /*
  122.49 +     * Pseudo time stamp constants used in java.util.Calendar
  122.50 +     */
  122.51 +    private static final int UNSET = 0;
  122.52 +    private static final int COMPUTED = 1;
  122.53 +    private static final int MINIMUM_USER_STAMP = 2;
  122.54 +
  122.55 +    private static final int MAX_FIELD = FIELD_COUNT + 1;
  122.56 +
  122.57 +    public static final int WEEK_YEAR = FIELD_COUNT;
  122.58 +    public static final int ISO_DAY_OF_WEEK = 1000; // pseudo field index
  122.59 +
  122.60 +    // stamp[] (lower half) and field[] (upper half) combined
  122.61 +    private final int[] field;
  122.62 +    private int nextStamp;
  122.63 +    private int maxFieldIndex;
  122.64 +
  122.65 +    CalendarBuilder() {
  122.66 +        field = new int[MAX_FIELD * 2];
  122.67 +        nextStamp = MINIMUM_USER_STAMP;
  122.68 +        maxFieldIndex = -1;
  122.69 +    }
  122.70 +
  122.71 +    CalendarBuilder set(int index, int value) {
  122.72 +        if (index == ISO_DAY_OF_WEEK) {
  122.73 +            index = DAY_OF_WEEK;
  122.74 +            value = toCalendarDayOfWeek(value);
  122.75 +        }
  122.76 +        field[index] = nextStamp++;
  122.77 +        field[MAX_FIELD + index] = value;
  122.78 +        if (index > maxFieldIndex && index < FIELD_COUNT) {
  122.79 +            maxFieldIndex = index;
  122.80 +        }
  122.81 +        return this;
  122.82 +    }
  122.83 +
  122.84 +    CalendarBuilder addYear(int value) {
  122.85 +        field[MAX_FIELD + YEAR] += value;
  122.86 +        field[MAX_FIELD + WEEK_YEAR] += value;
  122.87 +        return this;
  122.88 +    }
  122.89 +
  122.90 +    boolean isSet(int index) {
  122.91 +        if (index == ISO_DAY_OF_WEEK) {
  122.92 +            index = DAY_OF_WEEK;
  122.93 +        }
  122.94 +        return field[index] > UNSET;
  122.95 +    }
  122.96 +
  122.97 +    Calendar establish(Calendar cal) {
  122.98 +        boolean weekDate = isSet(WEEK_YEAR)
  122.99 +                            && field[WEEK_YEAR] > field[YEAR];
 122.100 +        if (weekDate && !cal.isWeekDateSupported()) {
 122.101 +            // Use YEAR instead
 122.102 +            if (!isSet(YEAR)) {
 122.103 +                set(YEAR, field[MAX_FIELD + WEEK_YEAR]);
 122.104 +            }
 122.105 +            weekDate = false;
 122.106 +        }
 122.107 +
 122.108 +        cal.clear();
 122.109 +        // Set the fields from the min stamp to the max stamp so that
 122.110 +        // the field resolution works in the Calendar.
 122.111 +        for (int stamp = MINIMUM_USER_STAMP; stamp < nextStamp; stamp++) {
 122.112 +            for (int index = 0; index <= maxFieldIndex; index++) {
 122.113 +                if (field[index] == stamp) {
 122.114 +                    cal.set(index, field[MAX_FIELD + index]);
 122.115 +                    break;
 122.116 +                }
 122.117 +            }
 122.118 +        }
 122.119 +
 122.120 +        if (weekDate) {
 122.121 +            int weekOfYear = isSet(WEEK_OF_YEAR) ? field[MAX_FIELD + WEEK_OF_YEAR] : 1;
 122.122 +            int dayOfWeek = isSet(DAY_OF_WEEK) ?
 122.123 +                                field[MAX_FIELD + DAY_OF_WEEK] : cal.getFirstDayOfWeek();
 122.124 +            if (!isValidDayOfWeek(dayOfWeek) && cal.isLenient()) {
 122.125 +                if (dayOfWeek >= 8) {
 122.126 +                    dayOfWeek--;
 122.127 +                    weekOfYear += dayOfWeek / 7;
 122.128 +                    dayOfWeek = (dayOfWeek % 7) + 1;
 122.129 +                } else {
 122.130 +                    while (dayOfWeek <= 0) {
 122.131 +                        dayOfWeek += 7;
 122.132 +                        weekOfYear--;
 122.133 +                    }
 122.134 +                }
 122.135 +                dayOfWeek = toCalendarDayOfWeek(dayOfWeek);
 122.136 +            }
 122.137 +            cal.setWeekDate(field[MAX_FIELD + WEEK_YEAR], weekOfYear, dayOfWeek);
 122.138 +        }
 122.139 +        return cal;
 122.140 +    }
 122.141 +
 122.142 +    public String toString() {
 122.143 +        StringBuilder sb = new StringBuilder();
 122.144 +        sb.append("CalendarBuilder:[");
 122.145 +        for (int i = 0; i < field.length; i++) {
 122.146 +            if (isSet(i)) {
 122.147 +                sb.append(i).append('=').append(field[MAX_FIELD + i]).append(',');
 122.148 +            }
 122.149 +        }
 122.150 +        int lastIndex = sb.length() - 1;
 122.151 +        if (sb.charAt(lastIndex) == ',') {
 122.152 +            sb.setLength(lastIndex);
 122.153 +        }
 122.154 +        sb.append(']');
 122.155 +        return sb.toString();
 122.156 +    }
 122.157 +
 122.158 +    static int toISODayOfWeek(int calendarDayOfWeek) {
 122.159 +        return calendarDayOfWeek == SUNDAY ? 7 : calendarDayOfWeek - 1;
 122.160 +    }
 122.161 +
 122.162 +    static int toCalendarDayOfWeek(int isoDayOfWeek) {
 122.163 +        if (!isValidDayOfWeek(isoDayOfWeek)) {
 122.164 +            // adjust later for lenient mode
 122.165 +            return isoDayOfWeek;
 122.166 +        }
 122.167 +        return isoDayOfWeek == 7 ? SUNDAY : isoDayOfWeek + 1;
 122.168 +    }
 122.169 +
 122.170 +    static boolean isValidDayOfWeek(int dayOfWeek) {
 122.171 +        return dayOfWeek > 0 && dayOfWeek <= 7;
 122.172 +    }
 122.173 +}
   123.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   123.2 +++ b/rt/emul/compact/src/main/java/java/text/CharacterIterator.java	Tue Feb 11 13:31:42 2014 +0100
   123.3 @@ -0,0 +1,193 @@
   123.4 +/*
   123.5 + * Copyright (c) 1996, 2000, Oracle and/or its affiliates. All rights reserved.
   123.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   123.7 + *
   123.8 + * This code is free software; you can redistribute it and/or modify it
   123.9 + * under the terms of the GNU General Public License version 2 only, as
  123.10 + * published by the Free Software Foundation.  Oracle designates this
  123.11 + * particular file as subject to the "Classpath" exception as provided
  123.12 + * by Oracle in the LICENSE file that accompanied this code.
  123.13 + *
  123.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  123.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  123.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  123.17 + * version 2 for more details (a copy is included in the LICENSE file that
  123.18 + * accompanied this code).
  123.19 + *
  123.20 + * You should have received a copy of the GNU General Public License version
  123.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  123.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  123.23 + *
  123.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  123.25 + * or visit www.oracle.com if you need additional information or have any
  123.26 + * questions.
  123.27 + */
  123.28 +
  123.29 +/*
  123.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
  123.31 + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
  123.32 + *
  123.33 + * The original version of this source code and documentation
  123.34 + * is copyrighted and owned by Taligent, Inc., a wholly-owned
  123.35 + * subsidiary of IBM. These materials are provided under terms
  123.36 + * of a License Agreement between Taligent and Sun. This technology
  123.37 + * is protected by multiple US and International patents.
  123.38 + *
  123.39 + * This notice and attribution to Taligent may not be removed.
  123.40 + * Taligent is a registered trademark of Taligent, Inc.
  123.41 + *
  123.42 + */
  123.43 +
  123.44 +package java.text;
  123.45 +
  123.46 +
  123.47 +/**
  123.48 + * This interface defines a protocol for bidirectional iteration over text.
  123.49 + * The iterator iterates over a bounded sequence of characters.  Characters
  123.50 + * are indexed with values beginning with the value returned by getBeginIndex() and
  123.51 + * continuing through the value returned by getEndIndex()-1.
  123.52 + * <p>
  123.53 + * Iterators maintain a current character index, whose valid range is from
  123.54 + * getBeginIndex() to getEndIndex(); the value getEndIndex() is included to allow
  123.55 + * handling of zero-length text ranges and for historical reasons.
  123.56 + * The current index can be retrieved by calling getIndex() and set directly
  123.57 + * by calling setIndex(), first(), and last().
  123.58 + * <p>
  123.59 + * The methods previous() and next() are used for iteration. They return DONE if
  123.60 + * they would move outside the range from getBeginIndex() to getEndIndex() -1,
  123.61 + * signaling that the iterator has reached the end of the sequence. DONE is
  123.62 + * also returned by other methods to indicate that the current index is
  123.63 + * outside this range.
  123.64 + *
  123.65 + * <P>Examples:<P>
  123.66 + *
  123.67 + * Traverse the text from start to finish
  123.68 + * <pre>
  123.69 + * public void traverseForward(CharacterIterator iter) {
  123.70 + *     for(char c = iter.first(); c != CharacterIterator.DONE; c = iter.next()) {
  123.71 + *         processChar(c);
  123.72 + *     }
  123.73 + * }
  123.74 + * </pre>
  123.75 + *
  123.76 + * Traverse the text backwards, from end to start
  123.77 + * <pre>
  123.78 + * public void traverseBackward(CharacterIterator iter) {
  123.79 + *     for(char c = iter.last(); c != CharacterIterator.DONE; c = iter.previous()) {
  123.80 + *         processChar(c);
  123.81 + *     }
  123.82 + * }
  123.83 + * </pre>
  123.84 + *
  123.85 + * Traverse both forward and backward from a given position in the text.
  123.86 + * Calls to notBoundary() in this example represents some
  123.87 + * additional stopping criteria.
  123.88 + * <pre>
  123.89 + * public void traverseOut(CharacterIterator iter, int pos) {
  123.90 + *     for (char c = iter.setIndex(pos);
  123.91 + *              c != CharacterIterator.DONE && notBoundary(c);
  123.92 + *              c = iter.next()) {
  123.93 + *     }
  123.94 + *     int end = iter.getIndex();
  123.95 + *     for (char c = iter.setIndex(pos);
  123.96 + *             c != CharacterIterator.DONE && notBoundary(c);
  123.97 + *             c = iter.previous()) {
  123.98 + *     }
  123.99 + *     int start = iter.getIndex();
 123.100 + *     processSection(start, end);
 123.101 + * }
 123.102 + * </pre>
 123.103 + *
 123.104 + * @see StringCharacterIterator
 123.105 + * @see AttributedCharacterIterator
 123.106 + */
 123.107 +
 123.108 +public interface CharacterIterator extends Cloneable
 123.109 +{
 123.110 +
 123.111 +    /**
 123.112 +     * Constant that is returned when the iterator has reached either the end
 123.113 +     * or the beginning of the text. The value is '\\uFFFF', the "not a
 123.114 +     * character" value which should not occur in any valid Unicode string.
 123.115 +     */
 123.116 +    public static final char DONE = '\uFFFF';
 123.117 +
 123.118 +    /**
 123.119 +     * Sets the position to getBeginIndex() and returns the character at that
 123.120 +     * position.
 123.121 +     * @return the first character in the text, or DONE if the text is empty
 123.122 +     * @see #getBeginIndex()
 123.123 +     */
 123.124 +    public char first();
 123.125 +
 123.126 +    /**
 123.127 +     * Sets the position to getEndIndex()-1 (getEndIndex() if the text is empty)
 123.128 +     * and returns the character at that position.
 123.129 +     * @return the last character in the text, or DONE if the text is empty
 123.130 +     * @see #getEndIndex()
 123.131 +     */
 123.132 +    public char last();
 123.133 +
 123.134 +    /**
 123.135 +     * Gets the character at the current position (as returned by getIndex()).
 123.136 +     * @return the character at the current position or DONE if the current
 123.137 +     * position is off the end of the text.
 123.138 +     * @see #getIndex()
 123.139 +     */
 123.140 +    public char current();
 123.141 +
 123.142 +    /**
 123.143 +     * Increments the iterator's index by one and returns the character
 123.144 +     * at the new index.  If the resulting index is greater or equal
 123.145 +     * to getEndIndex(), the current index is reset to getEndIndex() and
 123.146 +     * a value of DONE is returned.
 123.147 +     * @return the character at the new position or DONE if the new
 123.148 +     * position is off the end of the text range.
 123.149 +     */
 123.150 +    public char next();
 123.151 +
 123.152 +    /**
 123.153 +     * Decrements the iterator's index by one and returns the character
 123.154 +     * at the new index. If the current index is getBeginIndex(), the index
 123.155 +     * remains at getBeginIndex() and a value of DONE is returned.
 123.156 +     * @return the character at the new position or DONE if the current
 123.157 +     * position is equal to getBeginIndex().
 123.158 +     */
 123.159 +    public char previous();
 123.160 +
 123.161 +    /**
 123.162 +     * Sets the position to the specified position in the text and returns that
 123.163 +     * character.
 123.164 +     * @param position the position within the text.  Valid values range from
 123.165 +     * getBeginIndex() to getEndIndex().  An IllegalArgumentException is thrown
 123.166 +     * if an invalid value is supplied.
 123.167 +     * @return the character at the specified position or DONE if the specified position is equal to getEndIndex()
 123.168 +     */
 123.169 +    public char setIndex(int position);
 123.170 +
 123.171 +    /**
 123.172 +     * Returns the start index of the text.
 123.173 +     * @return the index at which the text begins.
 123.174 +     */
 123.175 +    public int getBeginIndex();
 123.176 +
 123.177 +    /**
 123.178 +     * Returns the end index of the text.  This index is the index of the first
 123.179 +     * character following the end of the text.
 123.180 +     * @return the index after the last character in the text
 123.181 +     */
 123.182 +    public int getEndIndex();
 123.183 +
 123.184 +    /**
 123.185 +     * Returns the current index.
 123.186 +     * @return the current index.
 123.187 +     */
 123.188 +    public int getIndex();
 123.189 +
 123.190 +    /**
 123.191 +     * Create a copy of this iterator
 123.192 +     * @return A copy of this
 123.193 +     */
 123.194 +    public Object clone();
 123.195 +
 123.196 +}
   124.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   124.2 +++ b/rt/emul/compact/src/main/java/java/text/CharacterIteratorFieldDelegate.java	Tue Feb 11 13:31:42 2014 +0100
   124.3 @@ -0,0 +1,124 @@
   124.4 +/*
   124.5 + * Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved.
   124.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   124.7 + *
   124.8 + * This code is free software; you can redistribute it and/or modify it
   124.9 + * under the terms of the GNU General Public License version 2 only, as
  124.10 + * published by the Free Software Foundation.  Oracle designates this
  124.11 + * particular file as subject to the "Classpath" exception as provided
  124.12 + * by Oracle in the LICENSE file that accompanied this code.
  124.13 + *
  124.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  124.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  124.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  124.17 + * version 2 for more details (a copy is included in the LICENSE file that
  124.18 + * accompanied this code).
  124.19 + *
  124.20 + * You should have received a copy of the GNU General Public License version
  124.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  124.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  124.23 + *
  124.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  124.25 + * or visit www.oracle.com if you need additional information or have any
  124.26 + * questions.
  124.27 + */
  124.28 +package java.text;
  124.29 +
  124.30 +import java.util.ArrayList;
  124.31 +
  124.32 +/**
  124.33 + * CharacterIteratorFieldDelegate combines the notifications from a Format
  124.34 + * into a resulting <code>AttributedCharacterIterator</code>. The resulting
  124.35 + * <code>AttributedCharacterIterator</code> can be retrieved by way of
  124.36 + * the <code>getIterator</code> method.
  124.37 + *
  124.38 + */
  124.39 +class CharacterIteratorFieldDelegate implements Format.FieldDelegate {
  124.40 +    /**
  124.41 +     * Array of AttributeStrings. Whenever <code>formatted</code> is invoked
  124.42 +     * for a region > size, a new instance of AttributedString is added to
  124.43 +     * attributedStrings. Subsequent invocations of <code>formatted</code>
  124.44 +     * for existing regions result in invoking addAttribute on the existing
  124.45 +     * AttributedStrings.
  124.46 +     */
  124.47 +    private ArrayList attributedStrings;
  124.48 +    /**
  124.49 +     * Running count of the number of characters that have
  124.50 +     * been encountered.
  124.51 +     */
  124.52 +    private int size;
  124.53 +
  124.54 +
  124.55 +    CharacterIteratorFieldDelegate() {
  124.56 +        attributedStrings = new ArrayList();
  124.57 +    }
  124.58 +
  124.59 +    public void formatted(Format.Field attr, Object value, int start, int end,
  124.60 +                          StringBuffer buffer) {
  124.61 +        if (start != end) {
  124.62 +            if (start < size) {
  124.63 +                // Adjust attributes of existing runs
  124.64 +                int index = size;
  124.65 +                int asIndex = attributedStrings.size() - 1;
  124.66 +
  124.67 +                while (start < index) {
  124.68 +                    AttributedString as = (AttributedString)attributedStrings.
  124.69 +                                           get(asIndex--);
  124.70 +                    int newIndex = index - as.length();
  124.71 +                    int aStart = Math.max(0, start - newIndex);
  124.72 +
  124.73 +                    as.addAttribute(attr, value, aStart, Math.min(
  124.74 +                                    end - start, as.length() - aStart) +
  124.75 +                                    aStart);
  124.76 +                    index = newIndex;
  124.77 +                }
  124.78 +            }
  124.79 +            if (size < start) {
  124.80 +                // Pad attributes
  124.81 +                attributedStrings.add(new AttributedString(
  124.82 +                                          buffer.substring(size, start)));
  124.83 +                size = start;
  124.84 +            }
  124.85 +            if (size < end) {
  124.86 +                // Add new string
  124.87 +                int aStart = Math.max(start, size);
  124.88 +                AttributedString string = new AttributedString(
  124.89 +                                   buffer.substring(aStart, end));
  124.90 +
  124.91 +                string.addAttribute(attr, value);
  124.92 +                attributedStrings.add(string);
  124.93 +                size = end;
  124.94 +            }
  124.95 +        }
  124.96 +    }
  124.97 +
  124.98 +    public void formatted(int fieldID, Format.Field attr, Object value,
  124.99 +                          int start, int end, StringBuffer buffer) {
 124.100 +        formatted(attr, value, start, end, buffer);
 124.101 +    }
 124.102 +
 124.103 +    /**
 124.104 +     * Returns an <code>AttributedCharacterIterator</code> that can be used
 124.105 +     * to iterate over the resulting formatted String.
 124.106 +     *
 124.107 +     * @pararm string Result of formatting.
 124.108 +     */
 124.109 +    public AttributedCharacterIterator getIterator(String string) {
 124.110 +        // Add the last AttributedCharacterIterator if necessary
 124.111 +        // assert(size <= string.length());
 124.112 +        if (string.length() > size) {
 124.113 +            attributedStrings.add(new AttributedString(
 124.114 +                                  string.substring(size)));
 124.115 +            size = string.length();
 124.116 +        }
 124.117 +        int iCount = attributedStrings.size();
 124.118 +        AttributedCharacterIterator iterators[] = new
 124.119 +                                    AttributedCharacterIterator[iCount];
 124.120 +
 124.121 +        for (int counter = 0; counter < iCount; counter++) {
 124.122 +            iterators[counter] = ((AttributedString)attributedStrings.
 124.123 +                                  get(counter)).getIterator();
 124.124 +        }
 124.125 +        return new AttributedString(iterators).getIterator();
 124.126 +    }
 124.127 +}
   125.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   125.2 +++ b/rt/emul/compact/src/main/java/java/text/ChoiceFormat.java	Tue Feb 11 13:31:42 2014 +0100
   125.3 @@ -0,0 +1,619 @@
   125.4 +/*
   125.5 + * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
   125.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   125.7 + *
   125.8 + * This code is free software; you can redistribute it and/or modify it
   125.9 + * under the terms of the GNU General Public License version 2 only, as
  125.10 + * published by the Free Software Foundation.  Oracle designates this
  125.11 + * particular file as subject to the "Classpath" exception as provided
  125.12 + * by Oracle in the LICENSE file that accompanied this code.
  125.13 + *
  125.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  125.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  125.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  125.17 + * version 2 for more details (a copy is included in the LICENSE file that
  125.18 + * accompanied this code).
  125.19 + *
  125.20 + * You should have received a copy of the GNU General Public License version
  125.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  125.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  125.23 + *
  125.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  125.25 + * or visit www.oracle.com if you need additional information or have any
  125.26 + * questions.
  125.27 + */
  125.28 +
  125.29 +/*
  125.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
  125.31 + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
  125.32 + *
  125.33 + *   The original version of this source code and documentation is copyrighted
  125.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
  125.35 + * materials are provided under terms of a License Agreement between Taligent
  125.36 + * and Sun. This technology is protected by multiple US and International
  125.37 + * patents. This notice and attribution to Taligent may not be removed.
  125.38 + *   Taligent is a registered trademark of Taligent, Inc.
  125.39 + *
  125.40 + */
  125.41 +
  125.42 +package java.text;
  125.43 +
  125.44 +import java.io.InvalidObjectException;
  125.45 +import java.io.IOException;
  125.46 +import java.io.ObjectInputStream;
  125.47 +import java.util.Arrays;
  125.48 +
  125.49 +/**
  125.50 + * A <code>ChoiceFormat</code> allows you to attach a format to a range of numbers.
  125.51 + * It is generally used in a <code>MessageFormat</code> for handling plurals.
  125.52 + * The choice is specified with an ascending list of doubles, where each item
  125.53 + * specifies a half-open interval up to the next item:
  125.54 + * <blockquote>
  125.55 + * <pre>
  125.56 + * X matches j if and only if limit[j] &lt;= X &lt; limit[j+1]
  125.57 + * </pre>
  125.58 + * </blockquote>
  125.59 + * If there is no match, then either the first or last index is used, depending
  125.60 + * on whether the number (X) is too low or too high.  If the limit array is not
  125.61 + * in ascending order, the results of formatting will be incorrect.  ChoiceFormat
  125.62 + * also accepts <code>&#92;u221E</code> as equivalent to infinity(INF).
  125.63 + *
  125.64 + * <p>
  125.65 + * <strong>Note:</strong>
  125.66 + * <code>ChoiceFormat</code> differs from the other <code>Format</code>
  125.67 + * classes in that you create a <code>ChoiceFormat</code> object with a
  125.68 + * constructor (not with a <code>getInstance</code> style factory
  125.69 + * method). The factory methods aren't necessary because <code>ChoiceFormat</code>
  125.70 + * doesn't require any complex setup for a given locale. In fact,
  125.71 + * <code>ChoiceFormat</code> doesn't implement any locale specific behavior.
  125.72 + *
  125.73 + * <p>
  125.74 + * When creating a <code>ChoiceFormat</code>, you must specify an array of formats
  125.75 + * and an array of limits. The length of these arrays must be the same.
  125.76 + * For example,
  125.77 + * <ul>
  125.78 + * <li>
  125.79 + *     <em>limits</em> = {1,2,3,4,5,6,7}<br>
  125.80 + *     <em>formats</em> = {"Sun","Mon","Tue","Wed","Thur","Fri","Sat"}
  125.81 + * <li>
  125.82 + *     <em>limits</em> = {0, 1, ChoiceFormat.nextDouble(1)}<br>
  125.83 + *     <em>formats</em> = {"no files", "one file", "many files"}<br>
  125.84 + *     (<code>nextDouble</code> can be used to get the next higher double, to
  125.85 + *     make the half-open interval.)
  125.86 + * </ul>
  125.87 + *
  125.88 + * <p>
  125.89 + * Here is a simple example that shows formatting and parsing:
  125.90 + * <blockquote>
  125.91 + * <pre>
  125.92 + * double[] limits = {1,2,3,4,5,6,7};
  125.93 + * String[] dayOfWeekNames = {"Sun","Mon","Tue","Wed","Thur","Fri","Sat"};
  125.94 + * ChoiceFormat form = new ChoiceFormat(limits, dayOfWeekNames);
  125.95 + * ParsePosition status = new ParsePosition(0);
  125.96 + * for (double i = 0.0; i &lt;= 8.0; ++i) {
  125.97 + *     status.setIndex(0);
  125.98 + *     System.out.println(i + " -&gt; " + form.format(i) + " -&gt; "
  125.99 + *                              + form.parse(form.format(i),status));
 125.100 + * }
 125.101 + * </pre>
 125.102 + * </blockquote>
 125.103 + * Here is a more complex example, with a pattern format:
 125.104 + * <blockquote>
 125.105 + * <pre>
 125.106 + * double[] filelimits = {0,1,2};
 125.107 + * String[] filepart = {"are no files","is one file","are {2} files"};
 125.108 + * ChoiceFormat fileform = new ChoiceFormat(filelimits, filepart);
 125.109 + * Format[] testFormats = {fileform, null, NumberFormat.getInstance()};
 125.110 + * MessageFormat pattform = new MessageFormat("There {0} on {1}");
 125.111 + * pattform.setFormats(testFormats);
 125.112 + * Object[] testArgs = {null, "ADisk", null};
 125.113 + * for (int i = 0; i &lt; 4; ++i) {
 125.114 + *     testArgs[0] = new Integer(i);
 125.115 + *     testArgs[2] = testArgs[0];
 125.116 + *     System.out.println(pattform.format(testArgs));
 125.117 + * }
 125.118 + * </pre>
 125.119 + * </blockquote>
 125.120 + * <p>
 125.121 + * Specifying a pattern for ChoiceFormat objects is fairly straightforward.
 125.122 + * For example:
 125.123 + * <blockquote>
 125.124 + * <pre>
 125.125 + * ChoiceFormat fmt = new ChoiceFormat(
 125.126 + *      "-1#is negative| 0#is zero or fraction | 1#is one |1.0&lt;is 1+ |2#is two |2&lt;is more than 2.");
 125.127 + * System.out.println("Formatter Pattern : " + fmt.toPattern());
 125.128 + *
 125.129 + * System.out.println("Format with -INF : " + fmt.format(Double.NEGATIVE_INFINITY));
 125.130 + * System.out.println("Format with -1.0 : " + fmt.format(-1.0));
 125.131 + * System.out.println("Format with 0 : " + fmt.format(0));
 125.132 + * System.out.println("Format with 0.9 : " + fmt.format(0.9));
 125.133 + * System.out.println("Format with 1.0 : " + fmt.format(1));
 125.134 + * System.out.println("Format with 1.5 : " + fmt.format(1.5));
 125.135 + * System.out.println("Format with 2 : " + fmt.format(2));
 125.136 + * System.out.println("Format with 2.1 : " + fmt.format(2.1));
 125.137 + * System.out.println("Format with NaN : " + fmt.format(Double.NaN));
 125.138 + * System.out.println("Format with +INF : " + fmt.format(Double.POSITIVE_INFINITY));
 125.139 + * </pre>
 125.140 + * </blockquote>
 125.141 + * And the output result would be like the following:
 125.142 + * <blockquote>
 125.143 + * <pre>
 125.144 + *   Format with -INF : is negative
 125.145 + *   Format with -1.0 : is negative
 125.146 + *   Format with 0 : is zero or fraction
 125.147 + *   Format with 0.9 : is zero or fraction
 125.148 + *   Format with 1.0 : is one
 125.149 + *   Format with 1.5 : is 1+
 125.150 + *   Format with 2 : is two
 125.151 + *   Format with 2.1 : is more than 2.
 125.152 + *   Format with NaN : is negative
 125.153 + *   Format with +INF : is more than 2.
 125.154 + * </pre>
 125.155 + * </blockquote>
 125.156 + *
 125.157 + * <h4><a name="synchronization">Synchronization</a></h4>
 125.158 + *
 125.159 + * <p>
 125.160 + * Choice formats are not synchronized.
 125.161 + * It is recommended to create separate format instances for each thread.
 125.162 + * If multiple threads access a format concurrently, it must be synchronized
 125.163 + * externally.
 125.164 + *
 125.165 + *
 125.166 + * @see          DecimalFormat
 125.167 + * @see          MessageFormat
 125.168 + * @author       Mark Davis
 125.169 + */
 125.170 +public class ChoiceFormat extends NumberFormat {
 125.171 +
 125.172 +    // Proclaim serial compatibility with 1.1 FCS
 125.173 +    private static final long serialVersionUID = 1795184449645032964L;
 125.174 +
 125.175 +    /**
 125.176 +     * Sets the pattern.
 125.177 +     * @param newPattern See the class description.
 125.178 +     */
 125.179 +    public void applyPattern(String newPattern) {
 125.180 +        StringBuffer[] segments = new StringBuffer[2];
 125.181 +        for (int i = 0; i < segments.length; ++i) {
 125.182 +            segments[i] = new StringBuffer();
 125.183 +        }
 125.184 +        double[] newChoiceLimits = new double[30];
 125.185 +        String[] newChoiceFormats = new String[30];
 125.186 +        int count = 0;
 125.187 +        int part = 0;
 125.188 +        double startValue = 0;
 125.189 +        double oldStartValue = Double.NaN;
 125.190 +        boolean inQuote = false;
 125.191 +        for (int i = 0; i < newPattern.length(); ++i) {
 125.192 +            char ch = newPattern.charAt(i);
 125.193 +            if (ch=='\'') {
 125.194 +                // Check for "''" indicating a literal quote
 125.195 +                if ((i+1)<newPattern.length() && newPattern.charAt(i+1)==ch) {
 125.196 +                    segments[part].append(ch);
 125.197 +                    ++i;
 125.198 +                } else {
 125.199 +                    inQuote = !inQuote;
 125.200 +                }
 125.201 +            } else if (inQuote) {
 125.202 +                segments[part].append(ch);
 125.203 +            } else if (ch == '<' || ch == '#' || ch == '\u2264') {
 125.204 +                if (segments[0].length() == 0) {
 125.205 +                    throw new IllegalArgumentException();
 125.206 +                }
 125.207 +                try {
 125.208 +                    String tempBuffer = segments[0].toString();
 125.209 +                    if (tempBuffer.equals("\u221E")) {
 125.210 +                        startValue = Double.POSITIVE_INFINITY;
 125.211 +                    } else if (tempBuffer.equals("-\u221E")) {
 125.212 +                        startValue = Double.NEGATIVE_INFINITY;
 125.213 +                    } else {
 125.214 +                        startValue = Double.valueOf(segments[0].toString()).doubleValue();
 125.215 +                    }
 125.216 +                } catch (Exception e) {
 125.217 +                    throw new IllegalArgumentException();
 125.218 +                }
 125.219 +                if (ch == '<' && startValue != Double.POSITIVE_INFINITY &&
 125.220 +                        startValue != Double.NEGATIVE_INFINITY) {
 125.221 +                    startValue = nextDouble(startValue);
 125.222 +                }
 125.223 +                if (startValue <= oldStartValue) {
 125.224 +                    throw new IllegalArgumentException();
 125.225 +                }
 125.226 +                segments[0].setLength(0);
 125.227 +                part = 1;
 125.228 +            } else if (ch == '|') {
 125.229 +                if (count == newChoiceLimits.length) {
 125.230 +                    newChoiceLimits = doubleArraySize(newChoiceLimits);
 125.231 +                    newChoiceFormats = doubleArraySize(newChoiceFormats);
 125.232 +                }
 125.233 +                newChoiceLimits[count] = startValue;
 125.234 +                newChoiceFormats[count] = segments[1].toString();
 125.235 +                ++count;
 125.236 +                oldStartValue = startValue;
 125.237 +                segments[1].setLength(0);
 125.238 +                part = 0;
 125.239 +            } else {
 125.240 +                segments[part].append(ch);
 125.241 +            }
 125.242 +        }
 125.243 +        // clean up last one
 125.244 +        if (part == 1) {
 125.245 +            if (count == newChoiceLimits.length) {
 125.246 +                newChoiceLimits = doubleArraySize(newChoiceLimits);
 125.247 +                newChoiceFormats = doubleArraySize(newChoiceFormats);
 125.248 +            }
 125.249 +            newChoiceLimits[count] = startValue;
 125.250 +            newChoiceFormats[count] = segments[1].toString();
 125.251 +            ++count;
 125.252 +        }
 125.253 +        choiceLimits = new double[count];
 125.254 +        System.arraycopy(newChoiceLimits, 0, choiceLimits, 0, count);
 125.255 +        choiceFormats = new String[count];
 125.256 +        System.arraycopy(newChoiceFormats, 0, choiceFormats, 0, count);
 125.257 +    }
 125.258 +
 125.259 +    /**
 125.260 +     * Gets the pattern.
 125.261 +     */
 125.262 +    public String toPattern() {
 125.263 +        StringBuffer result = new StringBuffer();
 125.264 +        for (int i = 0; i < choiceLimits.length; ++i) {
 125.265 +            if (i != 0) {
 125.266 +                result.append('|');
 125.267 +            }
 125.268 +            // choose based upon which has less precision
 125.269 +            // approximate that by choosing the closest one to an integer.
 125.270 +            // could do better, but it's not worth it.
 125.271 +            double less = previousDouble(choiceLimits[i]);
 125.272 +            double tryLessOrEqual = Math.abs(Math.IEEEremainder(choiceLimits[i], 1.0d));
 125.273 +            double tryLess = Math.abs(Math.IEEEremainder(less, 1.0d));
 125.274 +
 125.275 +            if (tryLessOrEqual < tryLess) {
 125.276 +                result.append(""+choiceLimits[i]);
 125.277 +                result.append('#');
 125.278 +            } else {
 125.279 +                if (choiceLimits[i] == Double.POSITIVE_INFINITY) {
 125.280 +                    result.append("\u221E");
 125.281 +                } else if (choiceLimits[i] == Double.NEGATIVE_INFINITY) {
 125.282 +                    result.append("-\u221E");
 125.283 +                } else {
 125.284 +                    result.append(""+less);
 125.285 +                }
 125.286 +                result.append('<');
 125.287 +            }
 125.288 +            // Append choiceFormats[i], using quotes if there are special characters.
 125.289 +            // Single quotes themselves must be escaped in either case.
 125.290 +            String text = choiceFormats[i];
 125.291 +            boolean needQuote = text.indexOf('<') >= 0
 125.292 +                || text.indexOf('#') >= 0
 125.293 +                || text.indexOf('\u2264') >= 0
 125.294 +                || text.indexOf('|') >= 0;
 125.295 +            if (needQuote) result.append('\'');
 125.296 +            if (text.indexOf('\'') < 0) result.append(text);
 125.297 +            else {
 125.298 +                for (int j=0; j<text.length(); ++j) {
 125.299 +                    char c = text.charAt(j);
 125.300 +                    result.append(c);
 125.301 +                    if (c == '\'') result.append(c);
 125.302 +                }
 125.303 +            }
 125.304 +            if (needQuote) result.append('\'');
 125.305 +        }
 125.306 +        return result.toString();
 125.307 +    }
 125.308 +
 125.309 +    /**
 125.310 +     * Constructs with limits and corresponding formats based on the pattern.
 125.311 +     * @see #applyPattern
 125.312 +     */
 125.313 +    public ChoiceFormat(String newPattern)  {
 125.314 +        applyPattern(newPattern);
 125.315 +    }
 125.316 +
 125.317 +    /**
 125.318 +     * Constructs with the limits and the corresponding formats.
 125.319 +     * @see #setChoices
 125.320 +     */
 125.321 +    public ChoiceFormat(double[] limits, String[] formats) {
 125.322 +        setChoices(limits, formats);
 125.323 +    }
 125.324 +
 125.325 +    /**
 125.326 +     * Set the choices to be used in formatting.
 125.327 +     * @param limits contains the top value that you want
 125.328 +     * parsed with that format,and should be in ascending sorted order. When
 125.329 +     * formatting X, the choice will be the i, where
 125.330 +     * limit[i] &lt;= X &lt; limit[i+1].
 125.331 +     * If the limit array is not in ascending order, the results of formatting
 125.332 +     * will be incorrect.
 125.333 +     * @param formats are the formats you want to use for each limit.
 125.334 +     * They can be either Format objects or Strings.
 125.335 +     * When formatting with object Y,
 125.336 +     * if the object is a NumberFormat, then ((NumberFormat) Y).format(X)
 125.337 +     * is called. Otherwise Y.toString() is called.
 125.338 +     */
 125.339 +    public void setChoices(double[] limits, String formats[]) {
 125.340 +        if (limits.length != formats.length) {
 125.341 +            throw new IllegalArgumentException(
 125.342 +                "Array and limit arrays must be of the same length.");
 125.343 +        }
 125.344 +        choiceLimits = limits;
 125.345 +        choiceFormats = formats;
 125.346 +    }
 125.347 +
 125.348 +    /**
 125.349 +     * Get the limits passed in the constructor.
 125.350 +     * @return the limits.
 125.351 +     */
 125.352 +    public double[] getLimits() {
 125.353 +        return choiceLimits;
 125.354 +    }
 125.355 +
 125.356 +    /**
 125.357 +     * Get the formats passed in the constructor.
 125.358 +     * @return the formats.
 125.359 +     */
 125.360 +    public Object[] getFormats() {
 125.361 +        return choiceFormats;
 125.362 +    }
 125.363 +
 125.364 +    // Overrides
 125.365 +
 125.366 +    /**
 125.367 +     * Specialization of format. This method really calls
 125.368 +     * <code>format(double, StringBuffer, FieldPosition)</code>
 125.369 +     * thus the range of longs that are supported is only equal to
 125.370 +     * the range that can be stored by double. This will never be
 125.371 +     * a practical limitation.
 125.372 +     */
 125.373 +    public StringBuffer format(long number, StringBuffer toAppendTo,
 125.374 +                               FieldPosition status) {
 125.375 +        return format((double)number, toAppendTo, status);
 125.376 +    }
 125.377 +
 125.378 +    /**
 125.379 +     * Returns pattern with formatted double.
 125.380 +     * @param number number to be formatted & substituted.
 125.381 +     * @param toAppendTo where text is appended.
 125.382 +     * @param status ignore no useful status is returned.
 125.383 +     */
 125.384 +   public StringBuffer format(double number, StringBuffer toAppendTo,
 125.385 +                               FieldPosition status) {
 125.386 +        // find the number
 125.387 +        int i;
 125.388 +        for (i = 0; i < choiceLimits.length; ++i) {
 125.389 +            if (!(number >= choiceLimits[i])) {
 125.390 +                // same as number < choiceLimits, except catchs NaN
 125.391 +                break;
 125.392 +            }
 125.393 +        }
 125.394 +        --i;
 125.395 +        if (i < 0) i = 0;
 125.396 +        // return either a formatted number, or a string
 125.397 +        return toAppendTo.append(choiceFormats[i]);
 125.398 +    }
 125.399 +
 125.400 +    /**
 125.401 +     * Parses a Number from the input text.
 125.402 +     * @param text the source text.
 125.403 +     * @param status an input-output parameter.  On input, the
 125.404 +     * status.index field indicates the first character of the
 125.405 +     * source text that should be parsed.  On exit, if no error
 125.406 +     * occured, status.index is set to the first unparsed character
 125.407 +     * in the source text.  On exit, if an error did occur,
 125.408 +     * status.index is unchanged and status.errorIndex is set to the
 125.409 +     * first index of the character that caused the parse to fail.
 125.410 +     * @return A Number representing the value of the number parsed.
 125.411 +     */
 125.412 +    public Number parse(String text, ParsePosition status) {
 125.413 +        // find the best number (defined as the one with the longest parse)
 125.414 +        int start = status.index;
 125.415 +        int furthest = start;
 125.416 +        double bestNumber = Double.NaN;
 125.417 +        double tempNumber = 0.0;
 125.418 +        for (int i = 0; i < choiceFormats.length; ++i) {
 125.419 +            String tempString = choiceFormats[i];
 125.420 +            if (text.regionMatches(start, tempString, 0, tempString.length())) {
 125.421 +                status.index = start + tempString.length();
 125.422 +                tempNumber = choiceLimits[i];
 125.423 +                if (status.index > furthest) {
 125.424 +                    furthest = status.index;
 125.425 +                    bestNumber = tempNumber;
 125.426 +                    if (furthest == text.length()) break;
 125.427 +                }
 125.428 +            }
 125.429 +        }
 125.430 +        status.index = furthest;
 125.431 +        if (status.index == start) {
 125.432 +            status.errorIndex = furthest;
 125.433 +        }
 125.434 +        return new Double(bestNumber);
 125.435 +    }
 125.436 +
 125.437 +    /**
 125.438 +     * Finds the least double greater than d.
 125.439 +     * If NaN, returns same value.
 125.440 +     * <p>Used to make half-open intervals.
 125.441 +     * @see #previousDouble
 125.442 +     */
 125.443 +    public static final double nextDouble (double d) {
 125.444 +        return nextDouble(d,true);
 125.445 +    }
 125.446 +
 125.447 +    /**
 125.448 +     * Finds the greatest double less than d.
 125.449 +     * If NaN, returns same value.
 125.450 +     * @see #nextDouble
 125.451 +     */
 125.452 +    public static final double previousDouble (double d) {
 125.453 +        return nextDouble(d,false);
 125.454 +    }
 125.455 +
 125.456 +    /**
 125.457 +     * Overrides Cloneable
 125.458 +     */
 125.459 +    public Object clone()
 125.460 +    {
 125.461 +        ChoiceFormat other = (ChoiceFormat) super.clone();
 125.462 +        // for primitives or immutables, shallow clone is enough
 125.463 +        other.choiceLimits = (double[]) choiceLimits.clone();
 125.464 +        other.choiceFormats = (String[]) choiceFormats.clone();
 125.465 +        return other;
 125.466 +    }
 125.467 +
 125.468 +    /**
 125.469 +     * Generates a hash code for the message format object.
 125.470 +     */
 125.471 +    public int hashCode() {
 125.472 +        int result = choiceLimits.length;
 125.473 +        if (choiceFormats.length > 0) {
 125.474 +            // enough for reasonable distribution
 125.475 +            result ^= choiceFormats[choiceFormats.length-1].hashCode();
 125.476 +        }
 125.477 +        return result;
 125.478 +    }
 125.479 +
 125.480 +    /**
 125.481 +     * Equality comparision between two
 125.482 +     */
 125.483 +    public boolean equals(Object obj) {
 125.484 +        if (obj == null) return false;
 125.485 +        if (this == obj)                      // quick check
 125.486 +            return true;
 125.487 +        if (getClass() != obj.getClass())
 125.488 +            return false;
 125.489 +        ChoiceFormat other = (ChoiceFormat) obj;
 125.490 +        return (Arrays.equals(choiceLimits, other.choiceLimits)
 125.491 +             && Arrays.equals(choiceFormats, other.choiceFormats));
 125.492 +    }
 125.493 +
 125.494 +    /**
 125.495 +     * After reading an object from the input stream, do a simple verification
 125.496 +     * to maintain class invariants.
 125.497 +     * @throws InvalidObjectException if the objects read from the stream is invalid.
 125.498 +     */
 125.499 +    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
 125.500 +        in.defaultReadObject();
 125.501 +        if (choiceLimits.length != choiceFormats.length) {
 125.502 +            throw new InvalidObjectException(
 125.503 +                    "limits and format arrays of different length.");
 125.504 +        }
 125.505 +    }
 125.506 +
 125.507 +    // ===============privates===========================
 125.508 +
 125.509 +    /**
 125.510 +     * A list of lower bounds for the choices.  The formatter will return
 125.511 +     * <code>choiceFormats[i]</code> if the number being formatted is greater than or equal to
 125.512 +     * <code>choiceLimits[i]</code> and less than <code>choiceLimits[i+1]</code>.
 125.513 +     * @serial
 125.514 +     */
 125.515 +    private double[] choiceLimits;
 125.516 +
 125.517 +    /**
 125.518 +     * A list of choice strings.  The formatter will return
 125.519 +     * <code>choiceFormats[i]</code> if the number being formatted is greater than or equal to
 125.520 +     * <code>choiceLimits[i]</code> and less than <code>choiceLimits[i+1]</code>.
 125.521 +     * @serial
 125.522 +     */
 125.523 +    private String[] choiceFormats;
 125.524 +
 125.525 +    /*
 125.526 +    static final long SIGN          = 0x8000000000000000L;
 125.527 +    static final long EXPONENT      = 0x7FF0000000000000L;
 125.528 +    static final long SIGNIFICAND   = 0x000FFFFFFFFFFFFFL;
 125.529 +
 125.530 +    private static double nextDouble (double d, boolean positive) {
 125.531 +        if (Double.isNaN(d) || Double.isInfinite(d)) {
 125.532 +                return d;
 125.533 +            }
 125.534 +        long bits = Double.doubleToLongBits(d);
 125.535 +        long significand = bits & SIGNIFICAND;
 125.536 +        if (bits < 0) {
 125.537 +            significand |= (SIGN | EXPONENT);
 125.538 +        }
 125.539 +        long exponent = bits & EXPONENT;
 125.540 +        if (positive) {
 125.541 +            significand += 1;
 125.542 +            // FIXME fix overflow & underflow
 125.543 +        } else {
 125.544 +            significand -= 1;
 125.545 +            // FIXME fix overflow & underflow
 125.546 +        }
 125.547 +        bits = exponent | (significand & ~EXPONENT);
 125.548 +        return Double.longBitsToDouble(bits);
 125.549 +    }
 125.550 +    */
 125.551 +
 125.552 +    static final long SIGN                = 0x8000000000000000L;
 125.553 +    static final long EXPONENT            = 0x7FF0000000000000L;
 125.554 +    static final long POSITIVEINFINITY    = 0x7FF0000000000000L;
 125.555 +
 125.556 +    /**
 125.557 +     * Finds the least double greater than d (if positive == true),
 125.558 +     * or the greatest double less than d (if positive == false).
 125.559 +     * If NaN, returns same value.
 125.560 +     *
 125.561 +     * Does not affect floating-point flags,
 125.562 +     * provided these member functions do not:
 125.563 +     *          Double.longBitsToDouble(long)
 125.564 +     *          Double.doubleToLongBits(double)
 125.565 +     *          Double.isNaN(double)
 125.566 +     */
 125.567 +    public static double nextDouble (double d, boolean positive) {
 125.568 +
 125.569 +        /* filter out NaN's */
 125.570 +        if (Double.isNaN(d)) {
 125.571 +            return d;
 125.572 +        }
 125.573 +
 125.574 +        /* zero's are also a special case */
 125.575 +        if (d == 0.0) {
 125.576 +            double smallestPositiveDouble = Double.longBitsToDouble(1L);
 125.577 +            if (positive) {
 125.578 +                return smallestPositiveDouble;
 125.579 +            } else {
 125.580 +                return -smallestPositiveDouble;
 125.581 +            }
 125.582 +        }
 125.583 +
 125.584 +        /* if entering here, d is a nonzero value */
 125.585 +
 125.586 +        /* hold all bits in a long for later use */
 125.587 +        long bits = Double.doubleToLongBits(d);
 125.588 +
 125.589 +        /* strip off the sign bit */
 125.590 +        long magnitude = bits & ~SIGN;
 125.591 +
 125.592 +        /* if next double away from zero, increase magnitude */
 125.593 +        if ((bits > 0) == positive) {
 125.594 +            if (magnitude != POSITIVEINFINITY) {
 125.595 +                magnitude += 1;
 125.596 +            }
 125.597 +        }
 125.598 +        /* else decrease magnitude */
 125.599 +        else {
 125.600 +            magnitude -= 1;
 125.601 +        }
 125.602 +
 125.603 +        /* restore sign bit and return */
 125.604 +        long signbit = bits & SIGN;
 125.605 +        return Double.longBitsToDouble (magnitude | signbit);
 125.606 +    }
 125.607 +
 125.608 +    private static double[] doubleArraySize(double[] array) {
 125.609 +        int oldSize = array.length;
 125.610 +        double[] newArray = new double[oldSize * 2];
 125.611 +        System.arraycopy(array, 0, newArray, 0, oldSize);
 125.612 +        return newArray;
 125.613 +    }
 125.614 +
 125.615 +    private String[] doubleArraySize(String[] array) {
 125.616 +        int oldSize = array.length;
 125.617 +        String[] newArray = new String[oldSize * 2];
 125.618 +        System.arraycopy(array, 0, newArray, 0, oldSize);
 125.619 +        return newArray;
 125.620 +    }
 125.621 +
 125.622 +}
   126.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   126.2 +++ b/rt/emul/compact/src/main/java/java/text/DateFormat.java	Tue Feb 11 13:31:42 2014 +0100
   126.3 @@ -0,0 +1,1025 @@
   126.4 +/*
   126.5 + * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
   126.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   126.7 + *
   126.8 + * This code is free software; you can redistribute it and/or modify it
   126.9 + * under the terms of the GNU General Public License version 2 only, as
  126.10 + * published by the Free Software Foundation.  Oracle designates this
  126.11 + * particular file as subject to the "Classpath" exception as provided
  126.12 + * by Oracle in the LICENSE file that accompanied this code.
  126.13 + *
  126.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  126.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  126.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  126.17 + * version 2 for more details (a copy is included in the LICENSE file that
  126.18 + * accompanied this code).
  126.19 + *
  126.20 + * You should have received a copy of the GNU General Public License version
  126.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  126.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  126.23 + *
  126.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  126.25 + * or visit www.oracle.com if you need additional information or have any
  126.26 + * questions.
  126.27 + */
  126.28 +
  126.29 +/*
  126.30 + * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
  126.31 + * (C) Copyright IBM Corp. 1996 - All Rights Reserved
  126.32 + *
  126.33 + *   The original version of this source code and documentation is copyrighted
  126.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
  126.35 + * materials are provided under terms of a License Agreement between Taligent
  126.36 + * and Sun. This technology is protected by multiple US and International
  126.37 + * patents. This notice and attribution to Taligent may not be removed.
  126.38 + *   Taligent is a registered trademark of Taligent, Inc.
  126.39 + *
  126.40 + */
  126.41 +
  126.42 +package java.text;
  126.43 +
  126.44 +import java.io.InvalidObjectException;
  126.45 +import java.util.Calendar;
  126.46 +import java.util.Date;
  126.47 +import java.util.HashMap;
  126.48 +import java.util.Locale;
  126.49 +import java.util.Map;
  126.50 +import java.util.MissingResourceException;
  126.51 +import java.util.TimeZone;
  126.52 +
  126.53 +/**
  126.54 + * {@code DateFormat} is an abstract class for date/time formatting subclasses which
  126.55 + * formats and parses dates or time in a language-independent manner.
  126.56 + * The date/time formatting subclass, such as {@link SimpleDateFormat}, allows for
  126.57 + * formatting (i.e., date -> text), parsing (text -> date), and
  126.58 + * normalization.  The date is represented as a <code>Date</code> object or
  126.59 + * as the milliseconds since January 1, 1970, 00:00:00 GMT.
  126.60 + *
  126.61 + * <p>{@code DateFormat} provides many class methods for obtaining default date/time
  126.62 + * formatters based on the default or a given locale and a number of formatting
  126.63 + * styles. The formatting styles include {@link #FULL}, {@link #LONG}, {@link #MEDIUM}, and {@link #SHORT}. More
  126.64 + * detail and examples of using these styles are provided in the method
  126.65 + * descriptions.
  126.66 + *
  126.67 + * <p>{@code DateFormat} helps you to format and parse dates for any locale.
  126.68 + * Your code can be completely independent of the locale conventions for
  126.69 + * months, days of the week, or even the calendar format: lunar vs. solar.
  126.70 + *
  126.71 + * <p>To format a date for the current Locale, use one of the
  126.72 + * static factory methods:
  126.73 + * <pre>
  126.74 + *  myString = DateFormat.getDateInstance().format(myDate);
  126.75 + * </pre>
  126.76 + * <p>If you are formatting multiple dates, it is
  126.77 + * more efficient to get the format and use it multiple times so that
  126.78 + * the system doesn't have to fetch the information about the local
  126.79 + * language and country conventions multiple times.
  126.80 + * <pre>
  126.81 + *  DateFormat df = DateFormat.getDateInstance();
  126.82 + *  for (int i = 0; i < myDate.length; ++i) {
  126.83 + *    output.println(df.format(myDate[i]) + "; ");
  126.84 + *  }
  126.85 + * </pre>
  126.86 + * <p>To format a date for a different Locale, specify it in the
  126.87 + * call to {@link #getDateInstance(int, Locale) getDateInstance()}.
  126.88 + * <pre>
  126.89 + *  DateFormat df = DateFormat.getDateInstance(DateFormat.LONG, Locale.FRANCE);
  126.90 + * </pre>
  126.91 + * <p>You can use a DateFormat to parse also.
  126.92 + * <pre>
  126.93 + *  myDate = df.parse(myString);
  126.94 + * </pre>
  126.95 + * <p>Use {@code getDateInstance} to get the normal date format for that country.
  126.96 + * There are other static factory methods available.
  126.97 + * Use {@code getTimeInstance} to get the time format for that country.
  126.98 + * Use {@code getDateTimeInstance} to get a date and time format. You can pass in
  126.99 + * different options to these factory methods to control the length of the
 126.100 + * result; from {@link #SHORT} to {@link #MEDIUM} to {@link #LONG} to {@link #FULL}. The exact result depends
 126.101 + * on the locale, but generally:
 126.102 + * <ul><li>{@link #SHORT} is completely numeric, such as {@code 12.13.52} or {@code 3:30pm}
 126.103 + * <li>{@link #MEDIUM} is longer, such as {@code Jan 12, 1952}
 126.104 + * <li>{@link #LONG} is longer, such as {@code January 12, 1952} or {@code 3:30:32pm}
 126.105 + * <li>{@link #FULL} is pretty completely specified, such as
 126.106 + * {@code Tuesday, April 12, 1952 AD or 3:30:42pm PST}.
 126.107 + * </ul>
 126.108 + *
 126.109 + * <p>You can also set the time zone on the format if you wish.
 126.110 + * If you want even more control over the format or parsing,
 126.111 + * (or want to give your users more control),
 126.112 + * you can try casting the {@code DateFormat} you get from the factory methods
 126.113 + * to a {@link SimpleDateFormat}. This will work for the majority
 126.114 + * of countries; just remember to put it in a {@code try} block in case you
 126.115 + * encounter an unusual one.
 126.116 + *
 126.117 + * <p>You can also use forms of the parse and format methods with
 126.118 + * {@link ParsePosition} and {@link FieldPosition} to
 126.119 + * allow you to
 126.120 + * <ul><li>progressively parse through pieces of a string.
 126.121 + * <li>align any particular field, or find out where it is for selection
 126.122 + * on the screen.
 126.123 + * </ul>
 126.124 + *
 126.125 + * <h4><a name="synchronization">Synchronization</a></h4>
 126.126 + *
 126.127 + * <p>
 126.128 + * Date formats are not synchronized.
 126.129 + * It is recommended to create separate format instances for each thread.
 126.130 + * If multiple threads access a format concurrently, it must be synchronized
 126.131 + * externally.
 126.132 + *
 126.133 + * @see          Format
 126.134 + * @see          NumberFormat
 126.135 + * @see          SimpleDateFormat
 126.136 + * @see          java.util.Calendar
 126.137 + * @see          java.util.GregorianCalendar
 126.138 + * @see          java.util.TimeZone
 126.139 + * @author       Mark Davis, Chen-Lieh Huang, Alan Liu
 126.140 + */
 126.141 +public abstract class DateFormat extends Format {
 126.142 +
 126.143 +    /**
 126.144 +     * The {@link Calendar} instance used for calculating the date-time fields
 126.145 +     * and the instant of time. This field is used for both formatting and
 126.146 +     * parsing.
 126.147 +     *
 126.148 +     * <p>Subclasses should initialize this field to a {@link Calendar}
 126.149 +     * appropriate for the {@link Locale} associated with this
 126.150 +     * <code>DateFormat</code>.
 126.151 +     * @serial
 126.152 +     */
 126.153 +    protected Calendar calendar;
 126.154 +
 126.155 +    /**
 126.156 +     * The number formatter that <code>DateFormat</code> uses to format numbers
 126.157 +     * in dates and times.  Subclasses should initialize this to a number format
 126.158 +     * appropriate for the locale associated with this <code>DateFormat</code>.
 126.159 +     * @serial
 126.160 +     */
 126.161 +    protected NumberFormat numberFormat;
 126.162 +
 126.163 +    /**
 126.164 +     * Useful constant for ERA field alignment.
 126.165 +     * Used in FieldPosition of date/time formatting.
 126.166 +     */
 126.167 +    public final static int ERA_FIELD = 0;
 126.168 +    /**
 126.169 +     * Useful constant for YEAR field alignment.
 126.170 +     * Used in FieldPosition of date/time formatting.
 126.171 +     */
 126.172 +    public final static int YEAR_FIELD = 1;
 126.173 +    /**
 126.174 +     * Useful constant for MONTH field alignment.
 126.175 +     * Used in FieldPosition of date/time formatting.
 126.176 +     */
 126.177 +    public final static int MONTH_FIELD = 2;
 126.178 +    /**
 126.179 +     * Useful constant for DATE field alignment.
 126.180 +     * Used in FieldPosition of date/time formatting.
 126.181 +     */
 126.182 +    public final static int DATE_FIELD = 3;
 126.183 +    /**
 126.184 +     * Useful constant for one-based HOUR_OF_DAY field alignment.
 126.185 +     * Used in FieldPosition of date/time formatting.
 126.186 +     * HOUR_OF_DAY1_FIELD is used for the one-based 24-hour clock.
 126.187 +     * For example, 23:59 + 01:00 results in 24:59.
 126.188 +     */
 126.189 +    public final static int HOUR_OF_DAY1_FIELD = 4;
 126.190 +    /**
 126.191 +     * Useful constant for zero-based HOUR_OF_DAY field alignment.
 126.192 +     * Used in FieldPosition of date/time formatting.
 126.193 +     * HOUR_OF_DAY0_FIELD is used for the zero-based 24-hour clock.
 126.194 +     * For example, 23:59 + 01:00 results in 00:59.
 126.195 +     */
 126.196 +    public final static int HOUR_OF_DAY0_FIELD = 5;
 126.197 +    /**
 126.198 +     * Useful constant for MINUTE field alignment.
 126.199 +     * Used in FieldPosition of date/time formatting.
 126.200 +     */
 126.201 +    public final static int MINUTE_FIELD = 6;
 126.202 +    /**
 126.203 +     * Useful constant for SECOND field alignment.
 126.204 +     * Used in FieldPosition of date/time formatting.
 126.205 +     */
 126.206 +    public final static int SECOND_FIELD = 7;
 126.207 +    /**
 126.208 +     * Useful constant for MILLISECOND field alignment.
 126.209 +     * Used in FieldPosition of date/time formatting.
 126.210 +     */
 126.211 +    public final static int MILLISECOND_FIELD = 8;
 126.212 +    /**
 126.213 +     * Useful constant for DAY_OF_WEEK field alignment.
 126.214 +     * Used in FieldPosition of date/time formatting.
 126.215 +     */
 126.216 +    public final static int DAY_OF_WEEK_FIELD = 9;
 126.217 +    /**
 126.218 +     * Useful constant for DAY_OF_YEAR field alignment.
 126.219 +     * Used in FieldPosition of date/time formatting.
 126.220 +     */
 126.221 +    public final static int DAY_OF_YEAR_FIELD = 10;
 126.222 +    /**
 126.223 +     * Useful constant for DAY_OF_WEEK_IN_MONTH field alignment.
 126.224 +     * Used in FieldPosition of date/time formatting.
 126.225 +     */
 126.226 +    public final static int DAY_OF_WEEK_IN_MONTH_FIELD = 11;
 126.227 +    /**
 126.228 +     * Useful constant for WEEK_OF_YEAR field alignment.
 126.229 +     * Used in FieldPosition of date/time formatting.
 126.230 +     */
 126.231 +    public final static int WEEK_OF_YEAR_FIELD = 12;
 126.232 +    /**
 126.233 +     * Useful constant for WEEK_OF_MONTH field alignment.
 126.234 +     * Used in FieldPosition of date/time formatting.
 126.235 +     */
 126.236 +    public final static int WEEK_OF_MONTH_FIELD = 13;
 126.237 +    /**
 126.238 +     * Useful constant for AM_PM field alignment.
 126.239 +     * Used in FieldPosition of date/time formatting.
 126.240 +     */
 126.241 +    public final static int AM_PM_FIELD = 14;
 126.242 +    /**
 126.243 +     * Useful constant for one-based HOUR field alignment.
 126.244 +     * Used in FieldPosition of date/time formatting.
 126.245 +     * HOUR1_FIELD is used for the one-based 12-hour clock.
 126.246 +     * For example, 11:30 PM + 1 hour results in 12:30 AM.
 126.247 +     */
 126.248 +    public final static int HOUR1_FIELD = 15;
 126.249 +    /**
 126.250 +     * Useful constant for zero-based HOUR field alignment.
 126.251 +     * Used in FieldPosition of date/time formatting.
 126.252 +     * HOUR0_FIELD is used for the zero-based 12-hour clock.
 126.253 +     * For example, 11:30 PM + 1 hour results in 00:30 AM.
 126.254 +     */
 126.255 +    public final static int HOUR0_FIELD = 16;
 126.256 +    /**
 126.257 +     * Useful constant for TIMEZONE field alignment.
 126.258 +     * Used in FieldPosition of date/time formatting.
 126.259 +     */
 126.260 +    public final static int TIMEZONE_FIELD = 17;
 126.261 +
 126.262 +    // Proclaim serial compatibility with 1.1 FCS
 126.263 +    private static final long serialVersionUID = 7218322306649953788L;
 126.264 +
 126.265 +    /**
 126.266 +     * Overrides Format.
 126.267 +     * Formats a time object into a time string. Examples of time objects
 126.268 +     * are a time value expressed in milliseconds and a Date object.
 126.269 +     * @param obj must be a Number or a Date.
 126.270 +     * @param toAppendTo the string buffer for the returning time string.
 126.271 +     * @return the string buffer passed in as toAppendTo, with formatted text appended.
 126.272 +     * @param fieldPosition keeps track of the position of the field
 126.273 +     * within the returned string.
 126.274 +     * On input: an alignment field,
 126.275 +     * if desired. On output: the offsets of the alignment field. For
 126.276 +     * example, given a time text "1996.07.10 AD at 15:08:56 PDT",
 126.277 +     * if the given fieldPosition is DateFormat.YEAR_FIELD, the
 126.278 +     * begin index and end index of fieldPosition will be set to
 126.279 +     * 0 and 4, respectively.
 126.280 +     * Notice that if the same time field appears
 126.281 +     * more than once in a pattern, the fieldPosition will be set for the first
 126.282 +     * occurrence of that time field. For instance, formatting a Date to
 126.283 +     * the time string "1 PM PDT (Pacific Daylight Time)" using the pattern
 126.284 +     * "h a z (zzzz)" and the alignment field DateFormat.TIMEZONE_FIELD,
 126.285 +     * the begin index and end index of fieldPosition will be set to
 126.286 +     * 5 and 8, respectively, for the first occurrence of the timezone
 126.287 +     * pattern character 'z'.
 126.288 +     * @see java.text.Format
 126.289 +     */
 126.290 +    public final StringBuffer format(Object obj, StringBuffer toAppendTo,
 126.291 +                                     FieldPosition fieldPosition)
 126.292 +    {
 126.293 +        if (obj instanceof Date)
 126.294 +            return format( (Date)obj, toAppendTo, fieldPosition );
 126.295 +        else if (obj instanceof Number)
 126.296 +            return format( new Date(((Number)obj).longValue()),
 126.297 +                          toAppendTo, fieldPosition );
 126.298 +        else
 126.299 +            throw new IllegalArgumentException("Cannot format given Object as a Date");
 126.300 +    }
 126.301 +
 126.302 +    /**
 126.303 +     * Formats a Date into a date/time string.
 126.304 +     * @param date a Date to be formatted into a date/time string.
 126.305 +     * @param toAppendTo the string buffer for the returning date/time string.
 126.306 +     * @param fieldPosition keeps track of the position of the field
 126.307 +     * within the returned string.
 126.308 +     * On input: an alignment field,
 126.309 +     * if desired. On output: the offsets of the alignment field. For
 126.310 +     * example, given a time text "1996.07.10 AD at 15:08:56 PDT",
 126.311 +     * if the given fieldPosition is DateFormat.YEAR_FIELD, the
 126.312 +     * begin index and end index of fieldPosition will be set to
 126.313 +     * 0 and 4, respectively.
 126.314 +     * Notice that if the same time field appears
 126.315 +     * more than once in a pattern, the fieldPosition will be set for the first
 126.316 +     * occurrence of that time field. For instance, formatting a Date to
 126.317 +     * the time string "1 PM PDT (Pacific Daylight Time)" using the pattern
 126.318 +     * "h a z (zzzz)" and the alignment field DateFormat.TIMEZONE_FIELD,
 126.319 +     * the begin index and end index of fieldPosition will be set to
 126.320 +     * 5 and 8, respectively, for the first occurrence of the timezone
 126.321 +     * pattern character 'z'.
 126.322 +     * @return the string buffer passed in as toAppendTo, with formatted text appended.
 126.323 +     */
 126.324 +    public abstract StringBuffer format(Date date, StringBuffer toAppendTo,
 126.325 +                                        FieldPosition fieldPosition);
 126.326 +
 126.327 +    /**
 126.328 +     * Formats a Date into a date/time string.
 126.329 +     * @param date the time value to be formatted into a time string.
 126.330 +     * @return the formatted time string.
 126.331 +     */
 126.332 +    public final String format(Date date)
 126.333 +    {
 126.334 +        return format(date, new StringBuffer(),
 126.335 +                      DontCareFieldPosition.INSTANCE).toString();
 126.336 +    }
 126.337 +
 126.338 +    /**
 126.339 +     * Parses text from the beginning of the given string to produce a date.
 126.340 +     * The method may not use the entire text of the given string.
 126.341 +     * <p>
 126.342 +     * See the {@link #parse(String, ParsePosition)} method for more information
 126.343 +     * on date parsing.
 126.344 +     *
 126.345 +     * @param source A <code>String</code> whose beginning should be parsed.
 126.346 +     * @return A <code>Date</code> parsed from the string.
 126.347 +     * @exception ParseException if the beginning of the specified string
 126.348 +     *            cannot be parsed.
 126.349 +     */
 126.350 +    public Date parse(String source) throws ParseException
 126.351 +    {
 126.352 +        ParsePosition pos = new ParsePosition(0);
 126.353 +        Date result = parse(source, pos);
 126.354 +        if (pos.index == 0)
 126.355 +            throw new ParseException("Unparseable date: \"" + source + "\"" ,
 126.356 +                pos.errorIndex);
 126.357 +        return result;
 126.358 +    }
 126.359 +
 126.360 +    /**
 126.361 +     * Parse a date/time string according to the given parse position.  For
 126.362 +     * example, a time text {@code "07/10/96 4:5 PM, PDT"} will be parsed into a {@code Date}
 126.363 +     * that is equivalent to {@code Date(837039900000L)}.
 126.364 +     *
 126.365 +     * <p> By default, parsing is lenient: If the input is not in the form used
 126.366 +     * by this object's format method but can still be parsed as a date, then
 126.367 +     * the parse succeeds.  Clients may insist on strict adherence to the
 126.368 +     * format by calling {@link #setLenient(boolean) setLenient(false)}.
 126.369 +     *
 126.370 +     * <p>This parsing operation uses the {@link #calendar} to produce
 126.371 +     * a {@code Date}. As a result, the {@code calendar}'s date-time
 126.372 +     * fields and the {@code TimeZone} value may have been
 126.373 +     * overwritten, depending on subclass implementations. Any {@code
 126.374 +     * TimeZone} value that has previously been set by a call to
 126.375 +     * {@link #setTimeZone(java.util.TimeZone) setTimeZone} may need
 126.376 +     * to be restored for further operations.
 126.377 +     *
 126.378 +     * @param source  The date/time string to be parsed
 126.379 +     *
 126.380 +     * @param pos   On input, the position at which to start parsing; on
 126.381 +     *              output, the position at which parsing terminated, or the
 126.382 +     *              start position if the parse failed.
 126.383 +     *
 126.384 +     * @return      A {@code Date}, or {@code null} if the input could not be parsed
 126.385 +     */
 126.386 +    public abstract Date parse(String source, ParsePosition pos);
 126.387 +
 126.388 +    /**
 126.389 +     * Parses text from a string to produce a <code>Date</code>.
 126.390 +     * <p>
 126.391 +     * The method attempts to parse text starting at the index given by
 126.392 +     * <code>pos</code>.
 126.393 +     * If parsing succeeds, then the index of <code>pos</code> is updated
 126.394 +     * to the index after the last character used (parsing does not necessarily
 126.395 +     * use all characters up to the end of the string), and the parsed
 126.396 +     * date is returned. The updated <code>pos</code> can be used to
 126.397 +     * indicate the starting point for the next call to this method.
 126.398 +     * If an error occurs, then the index of <code>pos</code> is not
 126.399 +     * changed, the error index of <code>pos</code> is set to the index of
 126.400 +     * the character where the error occurred, and null is returned.
 126.401 +     * <p>
 126.402 +     * See the {@link #parse(String, ParsePosition)} method for more information
 126.403 +     * on date parsing.
 126.404 +     *
 126.405 +     * @param source A <code>String</code>, part of which should be parsed.
 126.406 +     * @param pos A <code>ParsePosition</code> object with index and error
 126.407 +     *            index information as described above.
 126.408 +     * @return A <code>Date</code> parsed from the string. In case of
 126.409 +     *         error, returns null.
 126.410 +     * @exception NullPointerException if <code>pos</code> is null.
 126.411 +     */
 126.412 +    public Object parseObject(String source, ParsePosition pos) {
 126.413 +        return parse(source, pos);
 126.414 +    }
 126.415 +
 126.416 +    /**
 126.417 +     * Constant for full style pattern.
 126.418 +     */
 126.419 +    public static final int FULL = 0;
 126.420 +    /**
 126.421 +     * Constant for long style pattern.
 126.422 +     */
 126.423 +    public static final int LONG = 1;
 126.424 +    /**
 126.425 +     * Constant for medium style pattern.
 126.426 +     */
 126.427 +    public static final int MEDIUM = 2;
 126.428 +    /**
 126.429 +     * Constant for short style pattern.
 126.430 +     */
 126.431 +    public static final int SHORT = 3;
 126.432 +    /**
 126.433 +     * Constant for default style pattern.  Its value is MEDIUM.
 126.434 +     */
 126.435 +    public static final int DEFAULT = MEDIUM;
 126.436 +
 126.437 +    /**
 126.438 +     * Gets the time formatter with the default formatting style
 126.439 +     * for the default locale.
 126.440 +     * @return a time formatter.
 126.441 +     */
 126.442 +    public final static DateFormat getTimeInstance()
 126.443 +    {
 126.444 +        return get(DEFAULT, 0, 1, Locale.getDefault(Locale.Category.FORMAT));
 126.445 +    }
 126.446 +
 126.447 +    /**
 126.448 +     * Gets the time formatter with the given formatting style
 126.449 +     * for the default locale.
 126.450 +     * @param style the given formatting style. For example,
 126.451 +     * SHORT for "h:mm a" in the US locale.
 126.452 +     * @return a time formatter.
 126.453 +     */
 126.454 +    public final static DateFormat getTimeInstance(int style)
 126.455 +    {
 126.456 +        return get(style, 0, 1, Locale.getDefault(Locale.Category.FORMAT));
 126.457 +    }
 126.458 +
 126.459 +    /**
 126.460 +     * Gets the time formatter with the given formatting style
 126.461 +     * for the given locale.
 126.462 +     * @param style the given formatting style. For example,
 126.463 +     * SHORT for "h:mm a" in the US locale.
 126.464 +     * @param aLocale the given locale.
 126.465 +     * @return a time formatter.
 126.466 +     */
 126.467 +    public final static DateFormat getTimeInstance(int style,
 126.468 +                                                 Locale aLocale)
 126.469 +    {
 126.470 +        return get(style, 0, 1, aLocale);
 126.471 +    }
 126.472 +
 126.473 +    /**
 126.474 +     * Gets the date formatter with the default formatting style
 126.475 +     * for the default locale.
 126.476 +     * @return a date formatter.
 126.477 +     */
 126.478 +    public final static DateFormat getDateInstance()
 126.479 +    {
 126.480 +        return get(0, DEFAULT, 2, Locale.getDefault(Locale.Category.FORMAT));
 126.481 +    }
 126.482 +
 126.483 +    /**
 126.484 +     * Gets the date formatter with the given formatting style
 126.485 +     * for the default locale.
 126.486 +     * @param style the given formatting style. For example,
 126.487 +     * SHORT for "M/d/yy" in the US locale.
 126.488 +     * @return a date formatter.
 126.489 +     */
 126.490 +    public final static DateFormat getDateInstance(int style)
 126.491 +    {
 126.492 +        return get(0, style, 2, Locale.getDefault(Locale.Category.FORMAT));
 126.493 +    }
 126.494 +
 126.495 +    /**
 126.496 +     * Gets the date formatter with the given formatting style
 126.497 +     * for the given locale.
 126.498 +     * @param style the given formatting style. For example,
 126.499 +     * SHORT for "M/d/yy" in the US locale.
 126.500 +     * @param aLocale the given locale.
 126.501 +     * @return a date formatter.
 126.502 +     */
 126.503 +    public final static DateFormat getDateInstance(int style,
 126.504 +                                                 Locale aLocale)
 126.505 +    {
 126.506 +        return get(0, style, 2, aLocale);
 126.507 +    }
 126.508 +
 126.509 +    /**
 126.510 +     * Gets the date/time formatter with the default formatting style
 126.511 +     * for the default locale.
 126.512 +     * @return a date/time formatter.
 126.513 +     */
 126.514 +    public final static DateFormat getDateTimeInstance()
 126.515 +    {
 126.516 +        return get(DEFAULT, DEFAULT, 3, Locale.getDefault(Locale.Category.FORMAT));
 126.517 +    }
 126.518 +
 126.519 +    /**
 126.520 +     * Gets the date/time formatter with the given date and time
 126.521 +     * formatting styles for the default locale.
 126.522 +     * @param dateStyle the given date formatting style. For example,
 126.523 +     * SHORT for "M/d/yy" in the US locale.
 126.524 +     * @param timeStyle the given time formatting style. For example,
 126.525 +     * SHORT for "h:mm a" in the US locale.
 126.526 +     * @return a date/time formatter.
 126.527 +     */
 126.528 +    public final static DateFormat getDateTimeInstance(int dateStyle,
 126.529 +                                                       int timeStyle)
 126.530 +    {
 126.531 +        return get(timeStyle, dateStyle, 3, Locale.getDefault(Locale.Category.FORMAT));
 126.532 +    }
 126.533 +
 126.534 +    /**
 126.535 +     * Gets the date/time formatter with the given formatting styles
 126.536 +     * for the given locale.
 126.537 +     * @param dateStyle the given date formatting style.
 126.538 +     * @param timeStyle the given time formatting style.
 126.539 +     * @param aLocale the given locale.
 126.540 +     * @return a date/time formatter.
 126.541 +     */
 126.542 +    public final static DateFormat
 126.543 +        getDateTimeInstance(int dateStyle, int timeStyle, Locale aLocale)
 126.544 +    {
 126.545 +        return get(timeStyle, dateStyle, 3, aLocale);
 126.546 +    }
 126.547 +
 126.548 +    /**
 126.549 +     * Get a default date/time formatter that uses the SHORT style for both the
 126.550 +     * date and the time.
 126.551 +     */
 126.552 +    public final static DateFormat getInstance() {
 126.553 +        return getDateTimeInstance(SHORT, SHORT);
 126.554 +    }
 126.555 +
 126.556 +    /**
 126.557 +     * Returns an array of all locales for which the
 126.558 +     * <code>get*Instance</code> methods of this class can return
 126.559 +     * localized instances.
 126.560 +     * The returned array represents the union of locales supported by the Java
 126.561 +     * runtime and by installed
 126.562 +     * {@link java.text.spi.DateFormatProvider DateFormatProvider} implementations.
 126.563 +     * It must contain at least a <code>Locale</code> instance equal to
 126.564 +     * {@link java.util.Locale#US Locale.US}.
 126.565 +     *
 126.566 +     * @return An array of locales for which localized
 126.567 +     *         <code>DateFormat</code> instances are available.
 126.568 +     */
 126.569 +    public static Locale[] getAvailableLocales()
 126.570 +    {
 126.571 +        return new Locale[] { Locale.US };
 126.572 +    }
 126.573 +
 126.574 +    /**
 126.575 +     * Set the calendar to be used by this date format.  Initially, the default
 126.576 +     * calendar for the specified or default locale is used.
 126.577 +     *
 126.578 +     * <p>Any {@link java.util.TimeZone TimeZone} and {@linkplain
 126.579 +     * #isLenient() leniency} values that have previously been set are
 126.580 +     * overwritten by {@code newCalendar}'s values.
 126.581 +     *
 126.582 +     * @param newCalendar the new {@code Calendar} to be used by the date format
 126.583 +     */
 126.584 +    public void setCalendar(Calendar newCalendar)
 126.585 +    {
 126.586 +        this.calendar = newCalendar;
 126.587 +    }
 126.588 +
 126.589 +    /**
 126.590 +     * Gets the calendar associated with this date/time formatter.
 126.591 +     *
 126.592 +     * @return the calendar associated with this date/time formatter.
 126.593 +     */
 126.594 +    public Calendar getCalendar()
 126.595 +    {
 126.596 +        return calendar;
 126.597 +    }
 126.598 +
 126.599 +    /**
 126.600 +     * Allows you to set the number formatter.
 126.601 +     * @param newNumberFormat the given new NumberFormat.
 126.602 +     */
 126.603 +    public void setNumberFormat(NumberFormat newNumberFormat)
 126.604 +    {
 126.605 +        this.numberFormat = newNumberFormat;
 126.606 +    }
 126.607 +
 126.608 +    /**
 126.609 +     * Gets the number formatter which this date/time formatter uses to
 126.610 +     * format and parse a time.
 126.611 +     * @return the number formatter which this date/time formatter uses.
 126.612 +     */
 126.613 +    public NumberFormat getNumberFormat()
 126.614 +    {
 126.615 +        return numberFormat;
 126.616 +    }
 126.617 +
 126.618 +    /**
 126.619 +     * Sets the time zone for the calendar of this {@code DateFormat} object.
 126.620 +     * This method is equivalent to the following call.
 126.621 +     * <blockquote><pre>
 126.622 +     *  getCalendar().setTimeZone(zone)
 126.623 +     * </pre></blockquote>
 126.624 +     *
 126.625 +     * <p>The {@code TimeZone} set by this method is overwritten by a
 126.626 +     * {@link #setCalendar(java.util.Calendar) setCalendar} call.
 126.627 +     *
 126.628 +     * <p>The {@code TimeZone} set by this method may be overwritten as
 126.629 +     * a result of a call to the parse method.
 126.630 +     *
 126.631 +     * @param zone the given new time zone.
 126.632 +     */
 126.633 +    public void setTimeZone(TimeZone zone)
 126.634 +    {
 126.635 +        calendar.setTimeZone(zone);
 126.636 +    }
 126.637 +
 126.638 +    /**
 126.639 +     * Gets the time zone.
 126.640 +     * This method is equivalent to the following call.
 126.641 +     * <blockquote><pre>
 126.642 +     *  getCalendar().getTimeZone()
 126.643 +     * </pre></blockquote>
 126.644 +     *
 126.645 +     * @return the time zone associated with the calendar of DateFormat.
 126.646 +     */
 126.647 +    public TimeZone getTimeZone()
 126.648 +    {
 126.649 +        return calendar.getTimeZone();
 126.650 +    }
 126.651 +
 126.652 +    /**
 126.653 +     * Specify whether or not date/time parsing is to be lenient.  With
 126.654 +     * lenient parsing, the parser may use heuristics to interpret inputs that
 126.655 +     * do not precisely match this object's format.  With strict parsing,
 126.656 +     * inputs must match this object's format.
 126.657 +     *
 126.658 +     * <p>This method is equivalent to the following call.
 126.659 +     * <blockquote><pre>
 126.660 +     *  getCalendar().setLenient(lenient)
 126.661 +     * </pre></blockquote>
 126.662 +     *
 126.663 +     * <p>This leniency value is overwritten by a call to {@link
 126.664 +     * #setCalendar(java.util.Calendar) setCalendar()}.
 126.665 +     *
 126.666 +     * @param lenient when {@code true}, parsing is lenient
 126.667 +     * @see java.util.Calendar#setLenient(boolean)
 126.668 +     */
 126.669 +    public void setLenient(boolean lenient)
 126.670 +    {
 126.671 +        calendar.setLenient(lenient);
 126.672 +    }
 126.673 +
 126.674 +    /**
 126.675 +     * Tell whether date/time parsing is to be lenient.
 126.676 +     * This method is equivalent to the following call.
 126.677 +     * <blockquote><pre>
 126.678 +     *  getCalendar().isLenient()
 126.679 +     * </pre></blockquote>
 126.680 +     *
 126.681 +     * @return {@code true} if the {@link #calendar} is lenient;
 126.682 +     *         {@code false} otherwise.
 126.683 +     * @see java.util.Calendar#isLenient()
 126.684 +     */
 126.685 +    public boolean isLenient()
 126.686 +    {
 126.687 +        return calendar.isLenient();
 126.688 +    }
 126.689 +
 126.690 +    /**
 126.691 +     * Overrides hashCode
 126.692 +     */
 126.693 +    public int hashCode() {
 126.694 +        return numberFormat.hashCode();
 126.695 +        // just enough fields for a reasonable distribution
 126.696 +    }
 126.697 +
 126.698 +    /**
 126.699 +     * Overrides equals
 126.700 +     */
 126.701 +    public boolean equals(Object obj) {
 126.702 +        if (this == obj) return true;
 126.703 +        if (obj == null || getClass() != obj.getClass()) return false;
 126.704 +        DateFormat other = (DateFormat) obj;
 126.705 +        return (// calendar.equivalentTo(other.calendar) // THIS API DOESN'T EXIST YET!
 126.706 +                calendar.getFirstDayOfWeek() == other.calendar.getFirstDayOfWeek() &&
 126.707 +                calendar.getMinimalDaysInFirstWeek() == other.calendar.getMinimalDaysInFirstWeek() &&
 126.708 +                calendar.isLenient() == other.calendar.isLenient() &&
 126.709 +                calendar.getTimeZone().equals(other.calendar.getTimeZone()) &&
 126.710 +                numberFormat.equals(other.numberFormat));
 126.711 +    }
 126.712 +
 126.713 +    /**
 126.714 +     * Overrides Cloneable
 126.715 +     */
 126.716 +    public Object clone()
 126.717 +    {
 126.718 +        DateFormat other = (DateFormat) super.clone();
 126.719 +        other.calendar = (Calendar) calendar.clone();
 126.720 +        other.numberFormat = (NumberFormat) numberFormat.clone();
 126.721 +        return other;
 126.722 +    }
 126.723 +
 126.724 +    /**
 126.725 +     * Creates a DateFormat with the given time and/or date style in the given
 126.726 +     * locale.
 126.727 +     * @param timeStyle a value from 0 to 3 indicating the time format,
 126.728 +     * ignored if flags is 2
 126.729 +     * @param dateStyle a value from 0 to 3 indicating the time format,
 126.730 +     * ignored if flags is 1
 126.731 +     * @param flags either 1 for a time format, 2 for a date format,
 126.732 +     * or 3 for a date/time format
 126.733 +     * @param loc the locale for the format
 126.734 +     */
 126.735 +    private static DateFormat get(int timeStyle, int dateStyle,
 126.736 +                                  int flags, Locale loc) {
 126.737 +        if ((flags & 1) != 0) {
 126.738 +            if (timeStyle < 0 || timeStyle > 3) {
 126.739 +                throw new IllegalArgumentException("Illegal time style " + timeStyle);
 126.740 +            }
 126.741 +        } else {
 126.742 +            timeStyle = -1;
 126.743 +        }
 126.744 +        if ((flags & 2) != 0) {
 126.745 +            if (dateStyle < 0 || dateStyle > 3) {
 126.746 +                throw new IllegalArgumentException("Illegal date style " + dateStyle);
 126.747 +            }
 126.748 +        } else {
 126.749 +            dateStyle = -1;
 126.750 +        }
 126.751 +        try {
 126.752 +            // Check whether a provider can provide an implementation that's closer
 126.753 +            // to the requested locale than what the Java runtime itself can provide.
 126.754 +            /*
 126.755 +            LocaleServiceProviderPool pool =
 126.756 +                LocaleServiceProviderPool.getPool(DateFormatProvider.class);
 126.757 +            if (pool.hasProviders()) {
 126.758 +                DateFormat providersInstance = pool.getLocalizedObject(
 126.759 +                                                    DateFormatGetter.INSTANCE,
 126.760 +                                                    loc,
 126.761 +                                                    timeStyle,
 126.762 +                                                    dateStyle,
 126.763 +                                                    flags);
 126.764 +                if (providersInstance != null) {
 126.765 +                    return providersInstance;
 126.766 +                }
 126.767 +            }
 126.768 +            */
 126.769 +
 126.770 +            return new SimpleDateFormat(timeStyle, dateStyle, loc);
 126.771 +        } catch (MissingResourceException e) {
 126.772 +            return new SimpleDateFormat("M/d/yy h:mm a");
 126.773 +        }
 126.774 +    }
 126.775 +
 126.776 +    /**
 126.777 +     * Create a new date format.
 126.778 +     */
 126.779 +    protected DateFormat() {}
 126.780 +
 126.781 +    /**
 126.782 +     * Defines constants that are used as attribute keys in the
 126.783 +     * <code>AttributedCharacterIterator</code> returned
 126.784 +     * from <code>DateFormat.formatToCharacterIterator</code> and as
 126.785 +     * field identifiers in <code>FieldPosition</code>.
 126.786 +     * <p>
 126.787 +     * The class also provides two methods to map
 126.788 +     * between its constants and the corresponding Calendar constants.
 126.789 +     *
 126.790 +     * @since 1.4
 126.791 +     * @see java.util.Calendar
 126.792 +     */
 126.793 +    public static class Field extends Format.Field {
 126.794 +
 126.795 +        // Proclaim serial compatibility with 1.4 FCS
 126.796 +        private static final long serialVersionUID = 7441350119349544720L;
 126.797 +
 126.798 +        // table of all instances in this class, used by readResolve
 126.799 +        private static final Map instanceMap = new HashMap(18);
 126.800 +        // Maps from Calendar constant (such as Calendar.ERA) to Field
 126.801 +        // constant (such as Field.ERA).
 126.802 +        private static final Field[] calendarToFieldMapping =
 126.803 +                                             new Field[Calendar.FIELD_COUNT];
 126.804 +
 126.805 +        /** Calendar field. */
 126.806 +        private int calendarField;
 126.807 +
 126.808 +        /**
 126.809 +         * Returns the <code>Field</code> constant that corresponds to
 126.810 +         * the <code>Calendar</code> constant <code>calendarField</code>.
 126.811 +         * If there is no direct mapping between the <code>Calendar</code>
 126.812 +         * constant and a <code>Field</code>, null is returned.
 126.813 +         *
 126.814 +         * @throws IllegalArgumentException if <code>calendarField</code> is
 126.815 +         *         not the value of a <code>Calendar</code> field constant.
 126.816 +         * @param calendarField Calendar field constant
 126.817 +         * @return Field instance representing calendarField.
 126.818 +         * @see java.util.Calendar
 126.819 +         */
 126.820 +        public static Field ofCalendarField(int calendarField) {
 126.821 +            if (calendarField < 0 || calendarField >=
 126.822 +                        calendarToFieldMapping.length) {
 126.823 +                throw new IllegalArgumentException("Unknown Calendar constant "
 126.824 +                                                   + calendarField);
 126.825 +            }
 126.826 +            return calendarToFieldMapping[calendarField];
 126.827 +        }
 126.828 +
 126.829 +        /**
 126.830 +         * Creates a <code>Field</code>.
 126.831 +         *
 126.832 +         * @param name the name of the <code>Field</code>
 126.833 +         * @param calendarField the <code>Calendar</code> constant this
 126.834 +         *        <code>Field</code> corresponds to; any value, even one
 126.835 +         *        outside the range of legal <code>Calendar</code> values may
 126.836 +         *        be used, but <code>-1</code> should be used for values
 126.837 +         *        that don't correspond to legal <code>Calendar</code> values
 126.838 +         */
 126.839 +        protected Field(String name, int calendarField) {
 126.840 +            super(name);
 126.841 +            this.calendarField = calendarField;
 126.842 +            if (this.getClass() == DateFormat.Field.class) {
 126.843 +                instanceMap.put(name, this);
 126.844 +                if (calendarField >= 0) {
 126.845 +                    // assert(calendarField < Calendar.FIELD_COUNT);
 126.846 +                    calendarToFieldMapping[calendarField] = this;
 126.847 +                }
 126.848 +            }
 126.849 +        }
 126.850 +
 126.851 +        /**
 126.852 +         * Returns the <code>Calendar</code> field associated with this
 126.853 +         * attribute. For example, if this represents the hours field of
 126.854 +         * a <code>Calendar</code>, this would return
 126.855 +         * <code>Calendar.HOUR</code>. If there is no corresponding
 126.856 +         * <code>Calendar</code> constant, this will return -1.
 126.857 +         *
 126.858 +         * @return Calendar constant for this field
 126.859 +         * @see java.util.Calendar
 126.860 +         */
 126.861 +        public int getCalendarField() {
 126.862 +            return calendarField;
 126.863 +        }
 126.864 +
 126.865 +        /**
 126.866 +         * Resolves instances being deserialized to the predefined constants.
 126.867 +         *
 126.868 +         * @throws InvalidObjectException if the constant could not be
 126.869 +         *         resolved.
 126.870 +         * @return resolved DateFormat.Field constant
 126.871 +         */
 126.872 +        protected Object readResolve() throws InvalidObjectException {
 126.873 +            if (this.getClass() != DateFormat.Field.class) {
 126.874 +                throw new InvalidObjectException("subclass didn't correctly implement readResolve");
 126.875 +            }
 126.876 +
 126.877 +            Object instance = instanceMap.get(getName());
 126.878 +            if (instance != null) {
 126.879 +                return instance;
 126.880 +            } else {
 126.881 +                throw new InvalidObjectException("unknown attribute name");
 126.882 +            }
 126.883 +        }
 126.884 +
 126.885 +        //
 126.886 +        // The constants
 126.887 +        //
 126.888 +
 126.889 +        /**
 126.890 +         * Constant identifying the era field.
 126.891 +         */
 126.892 +        public final static Field ERA = new Field("era", Calendar.ERA);
 126.893 +
 126.894 +        /**
 126.895 +         * Constant identifying the year field.
 126.896 +         */
 126.897 +        public final static Field YEAR = new Field("year", Calendar.YEAR);
 126.898 +
 126.899 +        /**
 126.900 +         * Constant identifying the month field.
 126.901 +         */
 126.902 +        public final static Field MONTH = new Field("month", Calendar.MONTH);
 126.903 +
 126.904 +        /**
 126.905 +         * Constant identifying the day of month field.
 126.906 +         */
 126.907 +        public final static Field DAY_OF_MONTH = new
 126.908 +                            Field("day of month", Calendar.DAY_OF_MONTH);
 126.909 +
 126.910 +        /**
 126.911 +         * Constant identifying the hour of day field, where the legal values
 126.912 +         * are 1 to 24.
 126.913 +         */
 126.914 +        public final static Field HOUR_OF_DAY1 = new Field("hour of day 1",-1);
 126.915 +
 126.916 +        /**
 126.917 +         * Constant identifying the hour of day field, where the legal values
 126.918 +         * are 0 to 23.
 126.919 +         */
 126.920 +        public final static Field HOUR_OF_DAY0 = new
 126.921 +               Field("hour of day", Calendar.HOUR_OF_DAY);
 126.922 +
 126.923 +        /**
 126.924 +         * Constant identifying the minute field.
 126.925 +         */
 126.926 +        public final static Field MINUTE =new Field("minute", Calendar.MINUTE);
 126.927 +
 126.928 +        /**
 126.929 +         * Constant identifying the second field.
 126.930 +         */
 126.931 +        public final static Field SECOND =new Field("second", Calendar.SECOND);
 126.932 +
 126.933 +        /**
 126.934 +         * Constant identifying the millisecond field.
 126.935 +         */
 126.936 +        public final static Field MILLISECOND = new
 126.937 +                Field("millisecond", Calendar.MILLISECOND);
 126.938 +
 126.939 +        /**
 126.940 +         * Constant identifying the day of week field.
 126.941 +         */
 126.942 +        public final static Field DAY_OF_WEEK = new
 126.943 +                Field("day of week", Calendar.DAY_OF_WEEK);
 126.944 +
 126.945 +        /**
 126.946 +         * Constant identifying the day of year field.
 126.947 +         */
 126.948 +        public final static Field DAY_OF_YEAR = new
 126.949 +                Field("day of year", Calendar.DAY_OF_YEAR);
 126.950 +
 126.951 +        /**
 126.952 +         * Constant identifying the day of week field.
 126.953 +         */
 126.954 +        public final static Field DAY_OF_WEEK_IN_MONTH =
 126.955 +                     new Field("day of week in month",
 126.956 +                                            Calendar.DAY_OF_WEEK_IN_MONTH);
 126.957 +
 126.958 +        /**
 126.959 +         * Constant identifying the week of year field.
 126.960 +         */
 126.961 +        public final static Field WEEK_OF_YEAR = new
 126.962 +              Field("week of year", Calendar.WEEK_OF_YEAR);
 126.963 +
 126.964 +        /**
 126.965 +         * Constant identifying the week of month field.
 126.966 +         */
 126.967 +        public final static Field WEEK_OF_MONTH = new
 126.968 +            Field("week of month", Calendar.WEEK_OF_MONTH);
 126.969 +
 126.970 +        /**
 126.971 +         * Constant identifying the time of day indicator
 126.972 +         * (e.g. "a.m." or "p.m.") field.
 126.973 +         */
 126.974 +        public final static Field AM_PM = new
 126.975 +                            Field("am pm", Calendar.AM_PM);
 126.976 +
 126.977 +        /**
 126.978 +         * Constant identifying the hour field, where the legal values are
 126.979 +         * 1 to 12.
 126.980 +         */
 126.981 +        public final static Field HOUR1 = new Field("hour 1", -1);
 126.982 +
 126.983 +        /**
 126.984 +         * Constant identifying the hour field, where the legal values are
 126.985 +         * 0 to 11.
 126.986 +         */
 126.987 +        public final static Field HOUR0 = new
 126.988 +                            Field("hour", Calendar.HOUR);
 126.989 +
 126.990 +        /**
 126.991 +         * Constant identifying the time zone field.
 126.992 +         */
 126.993 +        public final static Field TIME_ZONE = new Field("time zone", -1);
 126.994 +    }
 126.995 +
 126.996 +    /**
 126.997 +     * Obtains a DateFormat instance from a DateFormatProvider
 126.998 +     * implementation.
 126.999 +    private static class DateFormatGetter
126.1000 +        implements LocaleServiceProviderPool.LocalizedObjectGetter<DateFormatProvider, DateFormat> {
126.1001 +        private static final DateFormatGetter INSTANCE = new DateFormatGetter();
126.1002 +
126.1003 +        public DateFormat getObject(DateFormatProvider dateFormatProvider,
126.1004 +                                Locale locale,
126.1005 +                                String key,
126.1006 +                                Object... params) {
126.1007 +            assert params.length == 3;
126.1008 +
126.1009 +            int timeStyle = (Integer)params[0];
126.1010 +            int dateStyle = (Integer)params[1];
126.1011 +            int flags = (Integer)params[2];
126.1012 +
126.1013 +            switch (flags) {
126.1014 +            case 1:
126.1015 +                return dateFormatProvider.getTimeInstance(timeStyle, locale);
126.1016 +            case 2:
126.1017 +                return dateFormatProvider.getDateInstance(dateStyle, locale);
126.1018 +            case 3:
126.1019 +                return dateFormatProvider.getDateTimeInstance(dateStyle, timeStyle, locale);
126.1020 +            default:
126.1021 +                assert false : "should not happen";
126.1022 +            }
126.1023 +
126.1024 +            return null;
126.1025 +        }
126.1026 +    }
126.1027 +     */
126.1028 +}
   127.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   127.2 +++ b/rt/emul/compact/src/main/java/java/text/DateFormatSymbols.java	Tue Feb 11 13:31:42 2014 +0100
   127.3 @@ -0,0 +1,786 @@
   127.4 +/*
   127.5 + * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
   127.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   127.7 + *
   127.8 + * This code is free software; you can redistribute it and/or modify it
   127.9 + * under the terms of the GNU General Public License version 2 only, as
  127.10 + * published by the Free Software Foundation.  Oracle designates this
  127.11 + * particular file as subject to the "Classpath" exception as provided
  127.12 + * by Oracle in the LICENSE file that accompanied this code.
  127.13 + *
  127.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  127.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  127.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  127.17 + * version 2 for more details (a copy is included in the LICENSE file that
  127.18 + * accompanied this code).
  127.19 + *
  127.20 + * You should have received a copy of the GNU General Public License version
  127.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  127.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  127.23 + *
  127.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  127.25 + * or visit www.oracle.com if you need additional information or have any
  127.26 + * questions.
  127.27 + */
  127.28 +
  127.29 +/*
  127.30 + * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
  127.31 + * (C) Copyright IBM Corp. 1996 - All Rights Reserved
  127.32 + *
  127.33 + *   The original version of this source code and documentation is copyrighted
  127.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
  127.35 + * materials are provided under terms of a License Agreement between Taligent
  127.36 + * and Sun. This technology is protected by multiple US and International
  127.37 + * patents. This notice and attribution to Taligent may not be removed.
  127.38 + *   Taligent is a registered trademark of Taligent, Inc.
  127.39 + *
  127.40 + */
  127.41 +
  127.42 +package java.text;
  127.43 +
  127.44 +import java.io.IOException;
  127.45 +import java.io.ObjectOutputStream;
  127.46 +import java.io.Serializable;
  127.47 +import java.lang.ref.SoftReference;
  127.48 +import java.util.Arrays;
  127.49 +import java.util.Locale;
  127.50 +import java.util.ResourceBundle;
  127.51 +import java.util.concurrent.ConcurrentHashMap;
  127.52 +import java.util.concurrent.ConcurrentMap;
  127.53 +
  127.54 +/**
  127.55 + * <code>DateFormatSymbols</code> is a public class for encapsulating
  127.56 + * localizable date-time formatting data, such as the names of the
  127.57 + * months, the names of the days of the week, and the time zone data.
  127.58 + * <code>DateFormat</code> and <code>SimpleDateFormat</code> both use
  127.59 + * <code>DateFormatSymbols</code> to encapsulate this information.
  127.60 + *
  127.61 + * <p>
  127.62 + * Typically you shouldn't use <code>DateFormatSymbols</code> directly.
  127.63 + * Rather, you are encouraged to create a date-time formatter with the
  127.64 + * <code>DateFormat</code> class's factory methods: <code>getTimeInstance</code>,
  127.65 + * <code>getDateInstance</code>, or <code>getDateTimeInstance</code>.
  127.66 + * These methods automatically create a <code>DateFormatSymbols</code> for
  127.67 + * the formatter so that you don't have to. After the
  127.68 + * formatter is created, you may modify its format pattern using the
  127.69 + * <code>setPattern</code> method. For more information about
  127.70 + * creating formatters using <code>DateFormat</code>'s factory methods,
  127.71 + * see {@link DateFormat}.
  127.72 + *
  127.73 + * <p>
  127.74 + * If you decide to create a date-time formatter with a specific
  127.75 + * format pattern for a specific locale, you can do so with:
  127.76 + * <blockquote>
  127.77 + * <pre>
  127.78 + * new SimpleDateFormat(aPattern, DateFormatSymbols.getInstance(aLocale)).
  127.79 + * </pre>
  127.80 + * </blockquote>
  127.81 + *
  127.82 + * <p>
  127.83 + * <code>DateFormatSymbols</code> objects are cloneable. When you obtain
  127.84 + * a <code>DateFormatSymbols</code> object, feel free to modify the
  127.85 + * date-time formatting data. For instance, you can replace the localized
  127.86 + * date-time format pattern characters with the ones that you feel easy
  127.87 + * to remember. Or you can change the representative cities
  127.88 + * to your favorite ones.
  127.89 + *
  127.90 + * <p>
  127.91 + * New <code>DateFormatSymbols</code> subclasses may be added to support
  127.92 + * <code>SimpleDateFormat</code> for date-time formatting for additional locales.
  127.93 +
  127.94 + * @see          DateFormat
  127.95 + * @see          SimpleDateFormat
  127.96 + * @see          java.util.SimpleTimeZone
  127.97 + * @author       Chen-Lieh Huang
  127.98 + */
  127.99 +public class DateFormatSymbols implements Serializable, Cloneable {
 127.100 +
 127.101 +    /**
 127.102 +     * Construct a DateFormatSymbols object by loading format data from
 127.103 +     * resources for the default locale. This constructor can only
 127.104 +     * construct instances for the locales supported by the Java
 127.105 +     * runtime environment, not for those supported by installed
 127.106 +     * {@link java.text.spi.DateFormatSymbolsProvider DateFormatSymbolsProvider}
 127.107 +     * implementations. For full locale coverage, use the
 127.108 +     * {@link #getInstance(Locale) getInstance} method.
 127.109 +     *
 127.110 +     * @see #getInstance()
 127.111 +     * @exception  java.util.MissingResourceException
 127.112 +     *             if the resources for the default locale cannot be
 127.113 +     *             found or cannot be loaded.
 127.114 +     */
 127.115 +    public DateFormatSymbols()
 127.116 +    {
 127.117 +        initializeData(Locale.getDefault(Locale.Category.FORMAT));
 127.118 +    }
 127.119 +
 127.120 +    /**
 127.121 +     * Construct a DateFormatSymbols object by loading format data from
 127.122 +     * resources for the given locale. This constructor can only
 127.123 +     * construct instances for the locales supported by the Java
 127.124 +     * runtime environment, not for those supported by installed
 127.125 +     * {@link java.text.spi.DateFormatSymbolsProvider DateFormatSymbolsProvider}
 127.126 +     * implementations. For full locale coverage, use the
 127.127 +     * {@link #getInstance(Locale) getInstance} method.
 127.128 +     *
 127.129 +     * @see #getInstance(Locale)
 127.130 +     * @exception  java.util.MissingResourceException
 127.131 +     *             if the resources for the specified locale cannot be
 127.132 +     *             found or cannot be loaded.
 127.133 +     */
 127.134 +    public DateFormatSymbols(Locale locale)
 127.135 +    {
 127.136 +        initializeData(locale);
 127.137 +    }
 127.138 +
 127.139 +    /**
 127.140 +     * Era strings. For example: "AD" and "BC".  An array of 2 strings,
 127.141 +     * indexed by <code>Calendar.BC</code> and <code>Calendar.AD</code>.
 127.142 +     * @serial
 127.143 +     */
 127.144 +    String eras[] = null;
 127.145 +
 127.146 +    /**
 127.147 +     * Month strings. For example: "January", "February", etc.  An array
 127.148 +     * of 13 strings (some calendars have 13 months), indexed by
 127.149 +     * <code>Calendar.JANUARY</code>, <code>Calendar.FEBRUARY</code>, etc.
 127.150 +     * @serial
 127.151 +     */
 127.152 +    String months[] = null;
 127.153 +
 127.154 +    /**
 127.155 +     * Short month strings. For example: "Jan", "Feb", etc.  An array of
 127.156 +     * 13 strings (some calendars have 13 months), indexed by
 127.157 +     * <code>Calendar.JANUARY</code>, <code>Calendar.FEBRUARY</code>, etc.
 127.158 +
 127.159 +     * @serial
 127.160 +     */
 127.161 +    String shortMonths[] = null;
 127.162 +
 127.163 +    /**
 127.164 +     * Weekday strings. For example: "Sunday", "Monday", etc.  An array
 127.165 +     * of 8 strings, indexed by <code>Calendar.SUNDAY</code>,
 127.166 +     * <code>Calendar.MONDAY</code>, etc.
 127.167 +     * The element <code>weekdays[0]</code> is ignored.
 127.168 +     * @serial
 127.169 +     */
 127.170 +    String weekdays[] = null;
 127.171 +
 127.172 +    /**
 127.173 +     * Short weekday strings. For example: "Sun", "Mon", etc.  An array
 127.174 +     * of 8 strings, indexed by <code>Calendar.SUNDAY</code>,
 127.175 +     * <code>Calendar.MONDAY</code>, etc.
 127.176 +     * The element <code>shortWeekdays[0]</code> is ignored.
 127.177 +     * @serial
 127.178 +     */
 127.179 +    String shortWeekdays[] = null;
 127.180 +
 127.181 +    /**
 127.182 +     * AM and PM strings. For example: "AM" and "PM".  An array of
 127.183 +     * 2 strings, indexed by <code>Calendar.AM</code> and
 127.184 +     * <code>Calendar.PM</code>.
 127.185 +     * @serial
 127.186 +     */
 127.187 +    String ampms[] = null;
 127.188 +
 127.189 +    /**
 127.190 +     * Localized names of time zones in this locale.  This is a
 127.191 +     * two-dimensional array of strings of size <em>n</em> by <em>m</em>,
 127.192 +     * where <em>m</em> is at least 5.  Each of the <em>n</em> rows is an
 127.193 +     * entry containing the localized names for a single <code>TimeZone</code>.
 127.194 +     * Each such row contains (with <code>i</code> ranging from
 127.195 +     * 0..<em>n</em>-1):
 127.196 +     * <ul>
 127.197 +     * <li><code>zoneStrings[i][0]</code> - time zone ID</li>
 127.198 +     * <li><code>zoneStrings[i][1]</code> - long name of zone in standard
 127.199 +     * time</li>
 127.200 +     * <li><code>zoneStrings[i][2]</code> - short name of zone in
 127.201 +     * standard time</li>
 127.202 +     * <li><code>zoneStrings[i][3]</code> - long name of zone in daylight
 127.203 +     * saving time</li>
 127.204 +     * <li><code>zoneStrings[i][4]</code> - short name of zone in daylight
 127.205 +     * saving time</li>
 127.206 +     * </ul>
 127.207 +     * The zone ID is <em>not</em> localized; it's one of the valid IDs of
 127.208 +     * the {@link java.util.TimeZone TimeZone} class that are not
 127.209 +     * <a href="../java/util/TimeZone.html#CustomID">custom IDs</a>.
 127.210 +     * All other entries are localized names.
 127.211 +     * @see java.util.TimeZone
 127.212 +     * @serial
 127.213 +     */
 127.214 +    String zoneStrings[][] = null;
 127.215 +
 127.216 +    /**
 127.217 +     * Indicates that zoneStrings is set externally with setZoneStrings() method.
 127.218 +     */
 127.219 +    transient boolean isZoneStringsSet = false;
 127.220 +
 127.221 +    /**
 127.222 +     * Unlocalized date-time pattern characters. For example: 'y', 'd', etc.
 127.223 +     * All locales use the same these unlocalized pattern characters.
 127.224 +     */
 127.225 +    static final String  patternChars = "GyMdkHmsSEDFwWahKzZYuX";
 127.226 +
 127.227 +    static final int PATTERN_ERA                  =  0; // G
 127.228 +    static final int PATTERN_YEAR                 =  1; // y
 127.229 +    static final int PATTERN_MONTH                =  2; // M
 127.230 +    static final int PATTERN_DAY_OF_MONTH         =  3; // d
 127.231 +    static final int PATTERN_HOUR_OF_DAY1         =  4; // k
 127.232 +    static final int PATTERN_HOUR_OF_DAY0         =  5; // H
 127.233 +    static final int PATTERN_MINUTE               =  6; // m
 127.234 +    static final int PATTERN_SECOND               =  7; // s
 127.235 +    static final int PATTERN_MILLISECOND          =  8; // S
 127.236 +    static final int PATTERN_DAY_OF_WEEK          =  9; // E
 127.237 +    static final int PATTERN_DAY_OF_YEAR          = 10; // D
 127.238 +    static final int PATTERN_DAY_OF_WEEK_IN_MONTH = 11; // F
 127.239 +    static final int PATTERN_WEEK_OF_YEAR         = 12; // w
 127.240 +    static final int PATTERN_WEEK_OF_MONTH        = 13; // W
 127.241 +    static final int PATTERN_AM_PM                = 14; // a
 127.242 +    static final int PATTERN_HOUR1                = 15; // h
 127.243 +    static final int PATTERN_HOUR0                = 16; // K
 127.244 +    static final int PATTERN_ZONE_NAME            = 17; // z
 127.245 +    static final int PATTERN_ZONE_VALUE           = 18; // Z
 127.246 +    static final int PATTERN_WEEK_YEAR            = 19; // Y
 127.247 +    static final int PATTERN_ISO_DAY_OF_WEEK      = 20; // u
 127.248 +    static final int PATTERN_ISO_ZONE             = 21; // X
 127.249 +
 127.250 +    /**
 127.251 +     * Localized date-time pattern characters. For example, a locale may
 127.252 +     * wish to use 'u' rather than 'y' to represent years in its date format
 127.253 +     * pattern strings.
 127.254 +     * This string must be exactly 18 characters long, with the index of
 127.255 +     * the characters described by <code>DateFormat.ERA_FIELD</code>,
 127.256 +     * <code>DateFormat.YEAR_FIELD</code>, etc.  Thus, if the string were
 127.257 +     * "Xz...", then localized patterns would use 'X' for era and 'z' for year.
 127.258 +     * @serial
 127.259 +     */
 127.260 +    String  localPatternChars = null;
 127.261 +
 127.262 +    /**
 127.263 +     * The locale which is used for initializing this DateFormatSymbols object.
 127.264 +     *
 127.265 +     * @since 1.6
 127.266 +     * @serial
 127.267 +     */
 127.268 +    Locale locale = null;
 127.269 +
 127.270 +    /* use serialVersionUID from JDK 1.1.4 for interoperability */
 127.271 +    static final long serialVersionUID = -5987973545549424702L;
 127.272 +
 127.273 +    /**
 127.274 +     * Returns an array of all locales for which the
 127.275 +     * <code>getInstance</code> methods of this class can return
 127.276 +     * localized instances.
 127.277 +     * The returned array represents the union of locales supported by the
 127.278 +     * Java runtime and by installed
 127.279 +     * {@link java.text.spi.DateFormatSymbolsProvider DateFormatSymbolsProvider}
 127.280 +     * implementations.  It must contain at least a <code>Locale</code>
 127.281 +     * instance equal to {@link java.util.Locale#US Locale.US}.
 127.282 +     *
 127.283 +     * @return An array of locales for which localized
 127.284 +     *         <code>DateFormatSymbols</code> instances are available.
 127.285 +     * @since 1.6
 127.286 +     */
 127.287 +    public static Locale[] getAvailableLocales() {
 127.288 +        return new Locale[] { Locale.US };
 127.289 +//        LocaleServiceProviderPool pool=
 127.290 +//            LocaleServiceProviderPool.getPool(DateFormatSymbolsProvider.class);
 127.291 +//        return pool.getAvailableLocales();
 127.292 +    }
 127.293 +
 127.294 +    /**
 127.295 +     * Gets the <code>DateFormatSymbols</code> instance for the default
 127.296 +     * locale.  This method provides access to <code>DateFormatSymbols</code>
 127.297 +     * instances for locales supported by the Java runtime itself as well
 127.298 +     * as for those supported by installed
 127.299 +     * {@link java.text.spi.DateFormatSymbolsProvider DateFormatSymbolsProvider}
 127.300 +     * implementations.
 127.301 +     * @return a <code>DateFormatSymbols</code> instance.
 127.302 +     * @since 1.6
 127.303 +     */
 127.304 +    public static final DateFormatSymbols getInstance() {
 127.305 +        return getInstance(Locale.getDefault(Locale.Category.FORMAT));
 127.306 +    }
 127.307 +
 127.308 +    /**
 127.309 +     * Gets the <code>DateFormatSymbols</code> instance for the specified
 127.310 +     * locale.  This method provides access to <code>DateFormatSymbols</code>
 127.311 +     * instances for locales supported by the Java runtime itself as well
 127.312 +     * as for those supported by installed
 127.313 +     * {@link java.text.spi.DateFormatSymbolsProvider DateFormatSymbolsProvider}
 127.314 +     * implementations.
 127.315 +     * @param locale the given locale.
 127.316 +     * @return a <code>DateFormatSymbols</code> instance.
 127.317 +     * @exception NullPointerException if <code>locale</code> is null
 127.318 +     * @since 1.6
 127.319 +     */
 127.320 +    public static final DateFormatSymbols getInstance(Locale locale) {
 127.321 +        DateFormatSymbols dfs = getProviderInstance(locale);
 127.322 +        if (dfs != null) {
 127.323 +            return dfs;
 127.324 +        }
 127.325 +        return (DateFormatSymbols) getCachedInstance(locale).clone();
 127.326 +    }
 127.327 +
 127.328 +    /**
 127.329 +     * Returns a DateFormatSymbols provided by a provider or found in
 127.330 +     * the cache. Note that this method returns a cached instance,
 127.331 +     * not its clone. Therefore, the instance should never be given to
 127.332 +     * an application.
 127.333 +     */
 127.334 +    static final DateFormatSymbols getInstanceRef(Locale locale) {
 127.335 +        DateFormatSymbols dfs = getProviderInstance(locale);
 127.336 +        if (dfs != null) {
 127.337 +            return dfs;
 127.338 +        }
 127.339 +        return getCachedInstance(locale);
 127.340 +    }
 127.341 +
 127.342 +    private static DateFormatSymbols getProviderInstance(Locale locale) {
 127.343 +        DateFormatSymbols providersInstance = null;
 127.344 +
 127.345 +        // Check whether a provider can provide an implementation that's closer
 127.346 +        // to the requested locale than what the Java runtime itself can provide.
 127.347 +//        LocaleServiceProviderPool pool =
 127.348 +//            LocaleServiceProviderPool.getPool(DateFormatSymbolsProvider.class);
 127.349 +//        if (pool.hasProviders()) {
 127.350 +//            providersInstance = pool.getLocalizedObject(
 127.351 +//                                    DateFormatSymbolsGetter.INSTANCE, locale);
 127.352 +//        }
 127.353 +        return providersInstance;
 127.354 +    }
 127.355 +
 127.356 +    /**
 127.357 +     * Returns a cached DateFormatSymbols if it's found in the
 127.358 +     * cache. Otherwise, this method returns a newly cached instance
 127.359 +     * for the given locale.
 127.360 +     */
 127.361 +    private static DateFormatSymbols getCachedInstance(Locale locale) {
 127.362 +        SoftReference<DateFormatSymbols> ref = cachedInstances.get(locale);
 127.363 +        DateFormatSymbols dfs = null;
 127.364 +        if (ref == null || (dfs = ref.get()) == null) {
 127.365 +            dfs = new DateFormatSymbols(locale);
 127.366 +            ref = new SoftReference<DateFormatSymbols>(dfs);
 127.367 +            SoftReference<DateFormatSymbols> x = cachedInstances.putIfAbsent(locale, ref);
 127.368 +            if (x != null) {
 127.369 +                DateFormatSymbols y = x.get();
 127.370 +                if (y != null) {
 127.371 +                    dfs = y;
 127.372 +                } else {
 127.373 +                    // Replace the empty SoftReference with ref.
 127.374 +                    cachedInstances.put(locale, ref);
 127.375 +                }
 127.376 +            }
 127.377 +        }
 127.378 +        return dfs;
 127.379 +    }
 127.380 +
 127.381 +    /**
 127.382 +     * Gets era strings. For example: "AD" and "BC".
 127.383 +     * @return the era strings.
 127.384 +     */
 127.385 +    public String[] getEras() {
 127.386 +        return Arrays.copyOf(eras, eras.length);
 127.387 +    }
 127.388 +
 127.389 +    /**
 127.390 +     * Sets era strings. For example: "AD" and "BC".
 127.391 +     * @param newEras the new era strings.
 127.392 +     */
 127.393 +    public void setEras(String[] newEras) {
 127.394 +        eras = Arrays.copyOf(newEras, newEras.length);
 127.395 +    }
 127.396 +
 127.397 +    /**
 127.398 +     * Gets month strings. For example: "January", "February", etc.
 127.399 +     * @return the month strings.
 127.400 +     */
 127.401 +    public String[] getMonths() {
 127.402 +        return Arrays.copyOf(months, months.length);
 127.403 +    }
 127.404 +
 127.405 +    /**
 127.406 +     * Sets month strings. For example: "January", "February", etc.
 127.407 +     * @param newMonths the new month strings.
 127.408 +     */
 127.409 +    public void setMonths(String[] newMonths) {
 127.410 +        months = Arrays.copyOf(newMonths, newMonths.length);
 127.411 +    }
 127.412 +
 127.413 +    /**
 127.414 +     * Gets short month strings. For example: "Jan", "Feb", etc.
 127.415 +     * @return the short month strings.
 127.416 +     */
 127.417 +    public String[] getShortMonths() {
 127.418 +        return Arrays.copyOf(shortMonths, shortMonths.length);
 127.419 +    }
 127.420 +
 127.421 +    /**
 127.422 +     * Sets short month strings. For example: "Jan", "Feb", etc.
 127.423 +     * @param newShortMonths the new short month strings.
 127.424 +     */
 127.425 +    public void setShortMonths(String[] newShortMonths) {
 127.426 +        shortMonths = Arrays.copyOf(newShortMonths, newShortMonths.length);
 127.427 +    }
 127.428 +
 127.429 +    /**
 127.430 +     * Gets weekday strings. For example: "Sunday", "Monday", etc.
 127.431 +     * @return the weekday strings. Use <code>Calendar.SUNDAY</code>,
 127.432 +     * <code>Calendar.MONDAY</code>, etc. to index the result array.
 127.433 +     */
 127.434 +    public String[] getWeekdays() {
 127.435 +        return Arrays.copyOf(weekdays, weekdays.length);
 127.436 +    }
 127.437 +
 127.438 +    /**
 127.439 +     * Sets weekday strings. For example: "Sunday", "Monday", etc.
 127.440 +     * @param newWeekdays the new weekday strings. The array should
 127.441 +     * be indexed by <code>Calendar.SUNDAY</code>,
 127.442 +     * <code>Calendar.MONDAY</code>, etc.
 127.443 +     */
 127.444 +    public void setWeekdays(String[] newWeekdays) {
 127.445 +        weekdays = Arrays.copyOf(newWeekdays, newWeekdays.length);
 127.446 +    }
 127.447 +
 127.448 +    /**
 127.449 +     * Gets short weekday strings. For example: "Sun", "Mon", etc.
 127.450 +     * @return the short weekday strings. Use <code>Calendar.SUNDAY</code>,
 127.451 +     * <code>Calendar.MONDAY</code>, etc. to index the result array.
 127.452 +     */
 127.453 +    public String[] getShortWeekdays() {
 127.454 +        return Arrays.copyOf(shortWeekdays, shortWeekdays.length);
 127.455 +    }
 127.456 +
 127.457 +    /**
 127.458 +     * Sets short weekday strings. For example: "Sun", "Mon", etc.
 127.459 +     * @param newShortWeekdays the new short weekday strings. The array should
 127.460 +     * be indexed by <code>Calendar.SUNDAY</code>,
 127.461 +     * <code>Calendar.MONDAY</code>, etc.
 127.462 +     */
 127.463 +    public void setShortWeekdays(String[] newShortWeekdays) {
 127.464 +        shortWeekdays = Arrays.copyOf(newShortWeekdays, newShortWeekdays.length);
 127.465 +    }
 127.466 +
 127.467 +    /**
 127.468 +     * Gets ampm strings. For example: "AM" and "PM".
 127.469 +     * @return the ampm strings.
 127.470 +     */
 127.471 +    public String[] getAmPmStrings() {
 127.472 +        return Arrays.copyOf(ampms, ampms.length);
 127.473 +    }
 127.474 +
 127.475 +    /**
 127.476 +     * Sets ampm strings. For example: "AM" and "PM".
 127.477 +     * @param newAmpms the new ampm strings.
 127.478 +     */
 127.479 +    public void setAmPmStrings(String[] newAmpms) {
 127.480 +        ampms = Arrays.copyOf(newAmpms, newAmpms.length);
 127.481 +    }
 127.482 +
 127.483 +    /**
 127.484 +     * Gets time zone strings.  Use of this method is discouraged; use
 127.485 +     * {@link java.util.TimeZone#getDisplayName() TimeZone.getDisplayName()}
 127.486 +     * instead.
 127.487 +     * <p>
 127.488 +     * The value returned is a
 127.489 +     * two-dimensional array of strings of size <em>n</em> by <em>m</em>,
 127.490 +     * where <em>m</em> is at least 5.  Each of the <em>n</em> rows is an
 127.491 +     * entry containing the localized names for a single <code>TimeZone</code>.
 127.492 +     * Each such row contains (with <code>i</code> ranging from
 127.493 +     * 0..<em>n</em>-1):
 127.494 +     * <ul>
 127.495 +     * <li><code>zoneStrings[i][0]</code> - time zone ID</li>
 127.496 +     * <li><code>zoneStrings[i][1]</code> - long name of zone in standard
 127.497 +     * time</li>
 127.498 +     * <li><code>zoneStrings[i][2]</code> - short name of zone in
 127.499 +     * standard time</li>
 127.500 +     * <li><code>zoneStrings[i][3]</code> - long name of zone in daylight
 127.501 +     * saving time</li>
 127.502 +     * <li><code>zoneStrings[i][4]</code> - short name of zone in daylight
 127.503 +     * saving time</li>
 127.504 +     * </ul>
 127.505 +     * The zone ID is <em>not</em> localized; it's one of the valid IDs of
 127.506 +     * the {@link java.util.TimeZone TimeZone} class that are not
 127.507 +     * <a href="../util/TimeZone.html#CustomID">custom IDs</a>.
 127.508 +     * All other entries are localized names.  If a zone does not implement
 127.509 +     * daylight saving time, the daylight saving time names should not be used.
 127.510 +     * <p>
 127.511 +     * If {@link #setZoneStrings(String[][]) setZoneStrings} has been called
 127.512 +     * on this <code>DateFormatSymbols</code> instance, then the strings
 127.513 +     * provided by that call are returned. Otherwise, the returned array
 127.514 +     * contains names provided by the Java runtime and by installed
 127.515 +     * {@link java.util.spi.TimeZoneNameProvider TimeZoneNameProvider}
 127.516 +     * implementations.
 127.517 +     *
 127.518 +     * @return the time zone strings.
 127.519 +     * @see #setZoneStrings(String[][])
 127.520 +     */
 127.521 +    public String[][] getZoneStrings() {
 127.522 +        return getZoneStringsImpl(true);
 127.523 +    }
 127.524 +
 127.525 +    /**
 127.526 +     * Sets time zone strings.  The argument must be a
 127.527 +     * two-dimensional array of strings of size <em>n</em> by <em>m</em>,
 127.528 +     * where <em>m</em> is at least 5.  Each of the <em>n</em> rows is an
 127.529 +     * entry containing the localized names for a single <code>TimeZone</code>.
 127.530 +     * Each such row contains (with <code>i</code> ranging from
 127.531 +     * 0..<em>n</em>-1):
 127.532 +     * <ul>
 127.533 +     * <li><code>zoneStrings[i][0]</code> - time zone ID</li>
 127.534 +     * <li><code>zoneStrings[i][1]</code> - long name of zone in standard
 127.535 +     * time</li>
 127.536 +     * <li><code>zoneStrings[i][2]</code> - short name of zone in
 127.537 +     * standard time</li>
 127.538 +     * <li><code>zoneStrings[i][3]</code> - long name of zone in daylight
 127.539 +     * saving time</li>
 127.540 +     * <li><code>zoneStrings[i][4]</code> - short name of zone in daylight
 127.541 +     * saving time</li>
 127.542 +     * </ul>
 127.543 +     * The zone ID is <em>not</em> localized; it's one of the valid IDs of
 127.544 +     * the {@link java.util.TimeZone TimeZone} class that are not
 127.545 +     * <a href="../util/TimeZone.html#CustomID">custom IDs</a>.
 127.546 +     * All other entries are localized names.
 127.547 +     *
 127.548 +     * @param newZoneStrings the new time zone strings.
 127.549 +     * @exception IllegalArgumentException if the length of any row in
 127.550 +     *    <code>newZoneStrings</code> is less than 5
 127.551 +     * @exception NullPointerException if <code>newZoneStrings</code> is null
 127.552 +     * @see #getZoneStrings()
 127.553 +     */
 127.554 +    public void setZoneStrings(String[][] newZoneStrings) {
 127.555 +        String[][] aCopy = new String[newZoneStrings.length][];
 127.556 +        for (int i = 0; i < newZoneStrings.length; ++i) {
 127.557 +            int len = newZoneStrings[i].length;
 127.558 +            if (len < 5) {
 127.559 +                throw new IllegalArgumentException();
 127.560 +            }
 127.561 +            aCopy[i] = Arrays.copyOf(newZoneStrings[i], len);
 127.562 +        }
 127.563 +        zoneStrings = aCopy;
 127.564 +        isZoneStringsSet = true;
 127.565 +    }
 127.566 +
 127.567 +    /**
 127.568 +     * Gets localized date-time pattern characters. For example: 'u', 't', etc.
 127.569 +     * @return the localized date-time pattern characters.
 127.570 +     */
 127.571 +    public String getLocalPatternChars() {
 127.572 +        return localPatternChars;
 127.573 +    }
 127.574 +
 127.575 +    /**
 127.576 +     * Sets localized date-time pattern characters. For example: 'u', 't', etc.
 127.577 +     * @param newLocalPatternChars the new localized date-time
 127.578 +     * pattern characters.
 127.579 +     */
 127.580 +    public void setLocalPatternChars(String newLocalPatternChars) {
 127.581 +        // Call toString() to throw an NPE in case the argument is null
 127.582 +        localPatternChars = newLocalPatternChars.toString();
 127.583 +    }
 127.584 +
 127.585 +    /**
 127.586 +     * Overrides Cloneable
 127.587 +     */
 127.588 +    public Object clone()
 127.589 +    {
 127.590 +        try
 127.591 +        {
 127.592 +            DateFormatSymbols other = (DateFormatSymbols)super.clone();
 127.593 +            copyMembers(this, other);
 127.594 +            return other;
 127.595 +        } catch (CloneNotSupportedException e) {
 127.596 +            throw new InternalError();
 127.597 +        }
 127.598 +    }
 127.599 +
 127.600 +    /**
 127.601 +     * Override hashCode.
 127.602 +     * Generates a hash code for the DateFormatSymbols object.
 127.603 +     */
 127.604 +    public int hashCode() {
 127.605 +        int hashcode = 0;
 127.606 +        String[][] zoneStrings = getZoneStringsWrapper();
 127.607 +        for (int index = 0; index < zoneStrings[0].length; ++index)
 127.608 +            hashcode ^= zoneStrings[0][index].hashCode();
 127.609 +        return hashcode;
 127.610 +    }
 127.611 +
 127.612 +    /**
 127.613 +     * Override equals
 127.614 +     */
 127.615 +    public boolean equals(Object obj)
 127.616 +    {
 127.617 +        if (this == obj) return true;
 127.618 +        if (obj == null || getClass() != obj.getClass()) return false;
 127.619 +        DateFormatSymbols that = (DateFormatSymbols) obj;
 127.620 +        return (Arrays.equals(eras, that.eras)
 127.621 +                && Arrays.equals(months, that.months)
 127.622 +                && Arrays.equals(shortMonths, that.shortMonths)
 127.623 +                && Arrays.equals(weekdays, that.weekdays)
 127.624 +                && Arrays.equals(shortWeekdays, that.shortWeekdays)
 127.625 +                && Arrays.equals(ampms, that.ampms)
 127.626 +                && Arrays.deepEquals(getZoneStringsWrapper(), that.getZoneStringsWrapper())
 127.627 +                && ((localPatternChars != null
 127.628 +                  && localPatternChars.equals(that.localPatternChars))
 127.629 +                 || (localPatternChars == null
 127.630 +                  && that.localPatternChars == null)));
 127.631 +    }
 127.632 +
 127.633 +    // =======================privates===============================
 127.634 +
 127.635 +    /**
 127.636 +     * Useful constant for defining time zone offsets.
 127.637 +     */
 127.638 +    static final int millisPerHour = 60*60*1000;
 127.639 +
 127.640 +    /**
 127.641 +     * Cache to hold DateFormatSymbols instances per Locale.
 127.642 +     */
 127.643 +    private static final ConcurrentMap<Locale, SoftReference<DateFormatSymbols>> cachedInstances
 127.644 +        = new ConcurrentHashMap<Locale, SoftReference<DateFormatSymbols>>(3);
 127.645 +
 127.646 +    private void initializeData(Locale desiredLocale) {
 127.647 +        locale = desiredLocale;
 127.648 +
 127.649 +        // Copy values of a cached instance if any.
 127.650 +        SoftReference<DateFormatSymbols> ref = cachedInstances.get(locale);
 127.651 +        DateFormatSymbols dfs;
 127.652 +        if (ref != null && (dfs = ref.get()) != null) {
 127.653 +            copyMembers(dfs, this);
 127.654 +            return;
 127.655 +        }
 127.656 +
 127.657 +        // Initialize the fields from the ResourceBundle for locale.
 127.658 +//        ResourceBundle resource = LocaleData.getDateFormatData(locale);
 127.659 +//
 127.660 +//        eras = resource.getStringArray("Eras");
 127.661 +//        months = resource.getStringArray("MonthNames");
 127.662 +//        shortMonths = resource.getStringArray("MonthAbbreviations");
 127.663 +//        ampms = resource.getStringArray("AmPmMarkers");
 127.664 +//        localPatternChars = resource.getString("DateTimePatternChars");
 127.665 +//
 127.666 +//        // Day of week names are stored in a 1-based array.
 127.667 +//        weekdays = toOneBasedArray(resource.getStringArray("DayNames"));
 127.668 +//        shortWeekdays = toOneBasedArray(resource.getStringArray("DayAbbreviations"));
 127.669 +    }
 127.670 +
 127.671 +    private static String[] toOneBasedArray(String[] src) {
 127.672 +        int len = src.length;
 127.673 +        String[] dst = new String[len + 1];
 127.674 +        dst[0] = "";
 127.675 +        for (int i = 0; i < len; i++) {
 127.676 +            dst[i + 1] = src[i];
 127.677 +        }
 127.678 +        return dst;
 127.679 +    }
 127.680 +
 127.681 +    /**
 127.682 +     * Package private: used by SimpleDateFormat
 127.683 +     * Gets the index for the given time zone ID to obtain the time zone
 127.684 +     * strings for formatting. The time zone ID is just for programmatic
 127.685 +     * lookup. NOT LOCALIZED!!!
 127.686 +     * @param ID the given time zone ID.
 127.687 +     * @return the index of the given time zone ID.  Returns -1 if
 127.688 +     * the given time zone ID can't be located in the DateFormatSymbols object.
 127.689 +     * @see java.util.SimpleTimeZone
 127.690 +     */
 127.691 +    final int getZoneIndex(String ID)
 127.692 +    {
 127.693 +        String[][] zoneStrings = getZoneStringsWrapper();
 127.694 +        for (int index=0; index<zoneStrings.length; index++)
 127.695 +        {
 127.696 +            if (ID.equals(zoneStrings[index][0])) return index;
 127.697 +        }
 127.698 +
 127.699 +        return -1;
 127.700 +    }
 127.701 +
 127.702 +    /**
 127.703 +     * Wrapper method to the getZoneStrings(), which is called from inside
 127.704 +     * the java.text package and not to mutate the returned arrays, so that
 127.705 +     * it does not need to create a defensive copy.
 127.706 +     */
 127.707 +    final String[][] getZoneStringsWrapper() {
 127.708 +        if (isSubclassObject()) {
 127.709 +            return getZoneStrings();
 127.710 +        } else {
 127.711 +            return getZoneStringsImpl(false);
 127.712 +        }
 127.713 +    }
 127.714 +
 127.715 +    private final String[][] getZoneStringsImpl(boolean needsCopy) {
 127.716 +        if (zoneStrings == null) {
 127.717 +//            zoneStrings = TimeZoneNameUtility.getZoneStrings(locale);
 127.718 +        }
 127.719 +
 127.720 +        if (!needsCopy) {
 127.721 +            return zoneStrings;
 127.722 +        }
 127.723 +
 127.724 +        int len = zoneStrings.length;
 127.725 +        String[][] aCopy = new String[len][];
 127.726 +        for (int i = 0; i < len; i++) {
 127.727 +            aCopy[i] = Arrays.copyOf(zoneStrings[i], zoneStrings[i].length);
 127.728 +        }
 127.729 +        return aCopy;
 127.730 +    }
 127.731 +
 127.732 +    private final boolean isSubclassObject() {
 127.733 +        return !getClass().getName().equals("java.text.DateFormatSymbols");
 127.734 +    }
 127.735 +
 127.736 +    /**
 127.737 +     * Clones all the data members from the source DateFormatSymbols to
 127.738 +     * the target DateFormatSymbols. This is only for subclasses.
 127.739 +     * @param src the source DateFormatSymbols.
 127.740 +     * @param dst the target DateFormatSymbols.
 127.741 +     */
 127.742 +    private final void copyMembers(DateFormatSymbols src, DateFormatSymbols dst)
 127.743 +    {
 127.744 +        dst.eras = Arrays.copyOf(src.eras, src.eras.length);
 127.745 +        dst.months = Arrays.copyOf(src.months, src.months.length);
 127.746 +        dst.shortMonths = Arrays.copyOf(src.shortMonths, src.shortMonths.length);
 127.747 +        dst.weekdays = Arrays.copyOf(src.weekdays, src.weekdays.length);
 127.748 +        dst.shortWeekdays = Arrays.copyOf(src.shortWeekdays, src.shortWeekdays.length);
 127.749 +        dst.ampms = Arrays.copyOf(src.ampms, src.ampms.length);
 127.750 +        if (src.zoneStrings != null) {
 127.751 +            dst.zoneStrings = src.getZoneStringsImpl(true);
 127.752 +        } else {
 127.753 +            dst.zoneStrings = null;
 127.754 +        }
 127.755 +        dst.localPatternChars = src.localPatternChars;
 127.756 +    }
 127.757 +
 127.758 +    /**
 127.759 +     * Write out the default serializable data, after ensuring the
 127.760 +     * <code>zoneStrings</code> field is initialized in order to make
 127.761 +     * sure the backward compatibility.
 127.762 +     *
 127.763 +     * @since 1.6
 127.764 +    private void writeObject(ObjectOutputStream stream) throws IOException {
 127.765 +        if (zoneStrings == null) {
 127.766 +            zoneStrings = TimeZoneNameUtility.getZoneStrings(locale);
 127.767 +        }
 127.768 +        stream.defaultWriteObject();
 127.769 +    }
 127.770 +
 127.771 +    /**
 127.772 +     * Obtains a DateFormatSymbols instance from a DateFormatSymbolsProvider
 127.773 +     * implementation.
 127.774 +    private static class DateFormatSymbolsGetter
 127.775 +        implements LocaleServiceProviderPool.LocalizedObjectGetter<DateFormatSymbolsProvider,
 127.776 +                                                                   DateFormatSymbols> {
 127.777 +        private static final DateFormatSymbolsGetter INSTANCE =
 127.778 +            new DateFormatSymbolsGetter();
 127.779 +
 127.780 +        public DateFormatSymbols getObject(DateFormatSymbolsProvider dateFormatSymbolsProvider,
 127.781 +                                Locale locale,
 127.782 +                                String key,
 127.783 +                                Object... params) {
 127.784 +            assert params.length == 0;
 127.785 +            return dateFormatSymbolsProvider.getInstance(locale);
 127.786 +        }
 127.787 +    }
 127.788 +     */
 127.789 +}
   128.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   128.2 +++ b/rt/emul/compact/src/main/java/java/text/DecimalFormat.java	Tue Feb 11 13:31:42 2014 +0100
   128.3 @@ -0,0 +1,3277 @@
   128.4 +/*
   128.5 + * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
   128.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   128.7 + *
   128.8 + * This code is free software; you can redistribute it and/or modify it
   128.9 + * under the terms of the GNU General Public License version 2 only, as
  128.10 + * published by the Free Software Foundation.  Oracle designates this
  128.11 + * particular file as subject to the "Classpath" exception as provided
  128.12 + * by Oracle in the LICENSE file that accompanied this code.
  128.13 + *
  128.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  128.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  128.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  128.17 + * version 2 for more details (a copy is included in the LICENSE file that
  128.18 + * accompanied this code).
  128.19 + *
  128.20 + * You should have received a copy of the GNU General Public License version
  128.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  128.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  128.23 + *
  128.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  128.25 + * or visit www.oracle.com if you need additional information or have any
  128.26 + * questions.
  128.27 + */
  128.28 +
  128.29 +/*
  128.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
  128.31 + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
  128.32 + *
  128.33 + *   The original version of this source code and documentation is copyrighted
  128.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
  128.35 + * materials are provided under terms of a License Agreement between Taligent
  128.36 + * and Sun. This technology is protected by multiple US and International
  128.37 + * patents. This notice and attribution to Taligent may not be removed.
  128.38 + *   Taligent is a registered trademark of Taligent, Inc.
  128.39 + *
  128.40 + */
  128.41 +
  128.42 +package java.text;
  128.43 +
  128.44 +import java.io.InvalidObjectException;
  128.45 +import java.io.IOException;
  128.46 +import java.io.ObjectInputStream;
  128.47 +import java.math.BigDecimal;
  128.48 +import java.math.BigInteger;
  128.49 +import java.math.RoundingMode;
  128.50 +import java.util.ArrayList;
  128.51 +import java.util.Currency;
  128.52 +import java.util.Locale;
  128.53 +import java.util.ResourceBundle;
  128.54 +import java.util.concurrent.ConcurrentHashMap;
  128.55 +import java.util.concurrent.ConcurrentMap;
  128.56 +import java.util.concurrent.atomic.AtomicInteger;
  128.57 +import java.util.concurrent.atomic.AtomicLong;
  128.58 +
  128.59 +/**
  128.60 + * <code>DecimalFormat</code> is a concrete subclass of
  128.61 + * <code>NumberFormat</code> that formats decimal numbers. It has a variety of
  128.62 + * features designed to make it possible to parse and format numbers in any
  128.63 + * locale, including support for Western, Arabic, and Indic digits.  It also
  128.64 + * supports different kinds of numbers, including integers (123), fixed-point
  128.65 + * numbers (123.4), scientific notation (1.23E4), percentages (12%), and
  128.66 + * currency amounts ($123).  All of these can be localized.
  128.67 + *
  128.68 + * <p>To obtain a <code>NumberFormat</code> for a specific locale, including the
  128.69 + * default locale, call one of <code>NumberFormat</code>'s factory methods, such
  128.70 + * as <code>getInstance()</code>.  In general, do not call the
  128.71 + * <code>DecimalFormat</code> constructors directly, since the
  128.72 + * <code>NumberFormat</code> factory methods may return subclasses other than
  128.73 + * <code>DecimalFormat</code>. If you need to customize the format object, do
  128.74 + * something like this:
  128.75 + *
  128.76 + * <blockquote><pre>
  128.77 + * NumberFormat f = NumberFormat.getInstance(loc);
  128.78 + * if (f instanceof DecimalFormat) {
  128.79 + *     ((DecimalFormat) f).setDecimalSeparatorAlwaysShown(true);
  128.80 + * }
  128.81 + * </pre></blockquote>
  128.82 + *
  128.83 + * <p>A <code>DecimalFormat</code> comprises a <em>pattern</em> and a set of
  128.84 + * <em>symbols</em>.  The pattern may be set directly using
  128.85 + * <code>applyPattern()</code>, or indirectly using the API methods.  The
  128.86 + * symbols are stored in a <code>DecimalFormatSymbols</code> object.  When using
  128.87 + * the <code>NumberFormat</code> factory methods, the pattern and symbols are
  128.88 + * read from localized <code>ResourceBundle</code>s.
  128.89 + *
  128.90 + * <h4>Patterns</h4>
  128.91 + *
  128.92 + * <code>DecimalFormat</code> patterns have the following syntax:
  128.93 + * <blockquote><pre>
  128.94 + * <i>Pattern:</i>
  128.95 + *         <i>PositivePattern</i>
  128.96 + *         <i>PositivePattern</i> ; <i>NegativePattern</i>
  128.97 + * <i>PositivePattern:</i>
  128.98 + *         <i>Prefix<sub>opt</sub></i> <i>Number</i> <i>Suffix<sub>opt</sub></i>
  128.99 + * <i>NegativePattern:</i>
 128.100 + *         <i>Prefix<sub>opt</sub></i> <i>Number</i> <i>Suffix<sub>opt</sub></i>
 128.101 + * <i>Prefix:</i>
 128.102 + *         any Unicode characters except &#92;uFFFE, &#92;uFFFF, and special characters
 128.103 + * <i>Suffix:</i>
 128.104 + *         any Unicode characters except &#92;uFFFE, &#92;uFFFF, and special characters
 128.105 + * <i>Number:</i>
 128.106 + *         <i>Integer</i> <i>Exponent<sub>opt</sub></i>
 128.107 + *         <i>Integer</i> . <i>Fraction</i> <i>Exponent<sub>opt</sub></i>
 128.108 + * <i>Integer:</i>
 128.109 + *         <i>MinimumInteger</i>
 128.110 + *         #
 128.111 + *         # <i>Integer</i>
 128.112 + *         # , <i>Integer</i>
 128.113 + * <i>MinimumInteger:</i>
 128.114 + *         0
 128.115 + *         0 <i>MinimumInteger</i>
 128.116 + *         0 , <i>MinimumInteger</i>
 128.117 + * <i>Fraction:</i>
 128.118 + *         <i>MinimumFraction<sub>opt</sub></i> <i>OptionalFraction<sub>opt</sub></i>
 128.119 + * <i>MinimumFraction:</i>
 128.120 + *         0 <i>MinimumFraction<sub>opt</sub></i>
 128.121 + * <i>OptionalFraction:</i>
 128.122 + *         # <i>OptionalFraction<sub>opt</sub></i>
 128.123 + * <i>Exponent:</i>
 128.124 + *         E <i>MinimumExponent</i>
 128.125 + * <i>MinimumExponent:</i>
 128.126 + *         0 <i>MinimumExponent<sub>opt</sub></i>
 128.127 + * </pre></blockquote>
 128.128 + *
 128.129 + * <p>A <code>DecimalFormat</code> pattern contains a positive and negative
 128.130 + * subpattern, for example, <code>"#,##0.00;(#,##0.00)"</code>.  Each
 128.131 + * subpattern has a prefix, numeric part, and suffix. The negative subpattern
 128.132 + * is optional; if absent, then the positive subpattern prefixed with the
 128.133 + * localized minus sign (<code>'-'</code> in most locales) is used as the
 128.134 + * negative subpattern. That is, <code>"0.00"</code> alone is equivalent to
 128.135 + * <code>"0.00;-0.00"</code>.  If there is an explicit negative subpattern, it
 128.136 + * serves only to specify the negative prefix and suffix; the number of digits,
 128.137 + * minimal digits, and other characteristics are all the same as the positive
 128.138 + * pattern. That means that <code>"#,##0.0#;(#)"</code> produces precisely
 128.139 + * the same behavior as <code>"#,##0.0#;(#,##0.0#)"</code>.
 128.140 + *
 128.141 + * <p>The prefixes, suffixes, and various symbols used for infinity, digits,
 128.142 + * thousands separators, decimal separators, etc. may be set to arbitrary
 128.143 + * values, and they will appear properly during formatting.  However, care must
 128.144 + * be taken that the symbols and strings do not conflict, or parsing will be
 128.145 + * unreliable.  For example, either the positive and negative prefixes or the
 128.146 + * suffixes must be distinct for <code>DecimalFormat.parse()</code> to be able
 128.147 + * to distinguish positive from negative values.  (If they are identical, then
 128.148 + * <code>DecimalFormat</code> will behave as if no negative subpattern was
 128.149 + * specified.)  Another example is that the decimal separator and thousands
 128.150 + * separator should be distinct characters, or parsing will be impossible.
 128.151 + *
 128.152 + * <p>The grouping separator is commonly used for thousands, but in some
 128.153 + * countries it separates ten-thousands. The grouping size is a constant number
 128.154 + * of digits between the grouping characters, such as 3 for 100,000,000 or 4 for
 128.155 + * 1,0000,0000.  If you supply a pattern with multiple grouping characters, the
 128.156 + * interval between the last one and the end of the integer is the one that is
 128.157 + * used. So <code>"#,##,###,####"</code> == <code>"######,####"</code> ==
 128.158 + * <code>"##,####,####"</code>.
 128.159 + *
 128.160 + * <h4>Special Pattern Characters</h4>
 128.161 + *
 128.162 + * <p>Many characters in a pattern are taken literally; they are matched during
 128.163 + * parsing and output unchanged during formatting.  Special characters, on the
 128.164 + * other hand, stand for other characters, strings, or classes of characters.
 128.165 + * They must be quoted, unless noted otherwise, if they are to appear in the
 128.166 + * prefix or suffix as literals.
 128.167 + *
 128.168 + * <p>The characters listed here are used in non-localized patterns.  Localized
 128.169 + * patterns use the corresponding characters taken from this formatter's
 128.170 + * <code>DecimalFormatSymbols</code> object instead, and these characters lose
 128.171 + * their special status.  Two exceptions are the currency sign and quote, which
 128.172 + * are not localized.
 128.173 + *
 128.174 + * <blockquote>
 128.175 + * <table border=0 cellspacing=3 cellpadding=0 summary="Chart showing symbol,
 128.176 + *  location, localized, and meaning.">
 128.177 + *     <tr bgcolor="#ccccff">
 128.178 + *          <th align=left>Symbol
 128.179 + *          <th align=left>Location
 128.180 + *          <th align=left>Localized?
 128.181 + *          <th align=left>Meaning
 128.182 + *     <tr valign=top>
 128.183 + *          <td><code>0</code>
 128.184 + *          <td>Number
 128.185 + *          <td>Yes
 128.186 + *          <td>Digit
 128.187 + *     <tr valign=top bgcolor="#eeeeff">
 128.188 + *          <td><code>#</code>
 128.189 + *          <td>Number
 128.190 + *          <td>Yes
 128.191 + *          <td>Digit, zero shows as absent
 128.192 + *     <tr valign=top>
 128.193 + *          <td><code>.</code>
 128.194 + *          <td>Number
 128.195 + *          <td>Yes
 128.196 + *          <td>Decimal separator or monetary decimal separator
 128.197 + *     <tr valign=top bgcolor="#eeeeff">
 128.198 + *          <td><code>-</code>
 128.199 + *          <td>Number
 128.200 + *          <td>Yes
 128.201 + *          <td>Minus sign
 128.202 + *     <tr valign=top>
 128.203 + *          <td><code>,</code>
 128.204 + *          <td>Number
 128.205 + *          <td>Yes
 128.206 + *          <td>Grouping separator
 128.207 + *     <tr valign=top bgcolor="#eeeeff">
 128.208 + *          <td><code>E</code>
 128.209 + *          <td>Number
 128.210 + *          <td>Yes
 128.211 + *          <td>Separates mantissa and exponent in scientific notation.
 128.212 + *              <em>Need not be quoted in prefix or suffix.</em>
 128.213 + *     <tr valign=top>
 128.214 + *          <td><code>;</code>
 128.215 + *          <td>Subpattern boundary
 128.216 + *          <td>Yes
 128.217 + *          <td>Separates positive and negative subpatterns
 128.218 + *     <tr valign=top bgcolor="#eeeeff">
 128.219 + *          <td><code>%</code>
 128.220 + *          <td>Prefix or suffix
 128.221 + *          <td>Yes
 128.222 + *          <td>Multiply by 100 and show as percentage
 128.223 + *     <tr valign=top>
 128.224 + *          <td><code>&#92;u2030</code>
 128.225 + *          <td>Prefix or suffix
 128.226 + *          <td>Yes
 128.227 + *          <td>Multiply by 1000 and show as per mille value
 128.228 + *     <tr valign=top bgcolor="#eeeeff">
 128.229 + *          <td><code>&#164;</code> (<code>&#92;u00A4</code>)
 128.230 + *          <td>Prefix or suffix
 128.231 + *          <td>No
 128.232 + *          <td>Currency sign, replaced by currency symbol.  If
 128.233 + *              doubled, replaced by international currency symbol.
 128.234 + *              If present in a pattern, the monetary decimal separator
 128.235 + *              is used instead of the decimal separator.
 128.236 + *     <tr valign=top>
 128.237 + *          <td><code>'</code>
 128.238 + *          <td>Prefix or suffix
 128.239 + *          <td>No
 128.240 + *          <td>Used to quote special characters in a prefix or suffix,
 128.241 + *              for example, <code>"'#'#"</code> formats 123 to
 128.242 + *              <code>"#123"</code>.  To create a single quote
 128.243 + *              itself, use two in a row: <code>"# o''clock"</code>.
 128.244 + * </table>
 128.245 + * </blockquote>
 128.246 + *
 128.247 + * <h4>Scientific Notation</h4>
 128.248 + *
 128.249 + * <p>Numbers in scientific notation are expressed as the product of a mantissa
 128.250 + * and a power of ten, for example, 1234 can be expressed as 1.234 x 10^3.  The
 128.251 + * mantissa is often in the range 1.0 <= x < 10.0, but it need not be.
 128.252 + * <code>DecimalFormat</code> can be instructed to format and parse scientific
 128.253 + * notation <em>only via a pattern</em>; there is currently no factory method
 128.254 + * that creates a scientific notation format.  In a pattern, the exponent
 128.255 + * character immediately followed by one or more digit characters indicates
 128.256 + * scientific notation.  Example: <code>"0.###E0"</code> formats the number
 128.257 + * 1234 as <code>"1.234E3"</code>.
 128.258 + *
 128.259 + * <ul>
 128.260 + * <li>The number of digit characters after the exponent character gives the
 128.261 + * minimum exponent digit count.  There is no maximum.  Negative exponents are
 128.262 + * formatted using the localized minus sign, <em>not</em> the prefix and suffix
 128.263 + * from the pattern.  This allows patterns such as <code>"0.###E0 m/s"</code>.
 128.264 + *
 128.265 + * <li>The minimum and maximum number of integer digits are interpreted
 128.266 + * together:
 128.267 + *
 128.268 + * <ul>
 128.269 + * <li>If the maximum number of integer digits is greater than their minimum number
 128.270 + * and greater than 1, it forces the exponent to be a multiple of the maximum
 128.271 + * number of integer digits, and the minimum number of integer digits to be
 128.272 + * interpreted as 1.  The most common use of this is to generate
 128.273 + * <em>engineering notation</em>, in which the exponent is a multiple of three,
 128.274 + * e.g., <code>"##0.#####E0"</code>. Using this pattern, the number 12345
 128.275 + * formats to <code>"12.345E3"</code>, and 123456 formats to
 128.276 + * <code>"123.456E3"</code>.
 128.277 + *
 128.278 + * <li>Otherwise, the minimum number of integer digits is achieved by adjusting the
 128.279 + * exponent.  Example: 0.00123 formatted with <code>"00.###E0"</code> yields
 128.280 + * <code>"12.3E-4"</code>.
 128.281 + * </ul>
 128.282 + *
 128.283 + * <li>The number of significant digits in the mantissa is the sum of the
 128.284 + * <em>minimum integer</em> and <em>maximum fraction</em> digits, and is
 128.285 + * unaffected by the maximum integer digits.  For example, 12345 formatted with
 128.286 + * <code>"##0.##E0"</code> is <code>"12.3E3"</code>. To show all digits, set
 128.287 + * the significant digits count to zero.  The number of significant digits
 128.288 + * does not affect parsing.
 128.289 + *
 128.290 + * <li>Exponential patterns may not contain grouping separators.
 128.291 + * </ul>
 128.292 + *
 128.293 + * <h4>Rounding</h4>
 128.294 + *
 128.295 + * <code>DecimalFormat</code> provides rounding modes defined in
 128.296 + * {@link java.math.RoundingMode} for formatting.  By default, it uses
 128.297 + * {@link java.math.RoundingMode#HALF_EVEN RoundingMode.HALF_EVEN}.
 128.298 + *
 128.299 + * <h4>Digits</h4>
 128.300 + *
 128.301 + * For formatting, <code>DecimalFormat</code> uses the ten consecutive
 128.302 + * characters starting with the localized zero digit defined in the
 128.303 + * <code>DecimalFormatSymbols</code> object as digits. For parsing, these
 128.304 + * digits as well as all Unicode decimal digits, as defined by
 128.305 + * {@link Character#digit Character.digit}, are recognized.
 128.306 + *
 128.307 + * <h4>Special Values</h4>
 128.308 + *
 128.309 + * <p><code>NaN</code> is formatted as a string, which typically has a single character
 128.310 + * <code>&#92;uFFFD</code>.  This string is determined by the
 128.311 + * <code>DecimalFormatSymbols</code> object.  This is the only value for which
 128.312 + * the prefixes and suffixes are not used.
 128.313 + *
 128.314 + * <p>Infinity is formatted as a string, which typically has a single character
 128.315 + * <code>&#92;u221E</code>, with the positive or negative prefixes and suffixes
 128.316 + * applied.  The infinity string is determined by the
 128.317 + * <code>DecimalFormatSymbols</code> object.
 128.318 + *
 128.319 + * <p>Negative zero (<code>"-0"</code>) parses to
 128.320 + * <ul>
 128.321 + * <li><code>BigDecimal(0)</code> if <code>isParseBigDecimal()</code> is
 128.322 + * true,
 128.323 + * <li><code>Long(0)</code> if <code>isParseBigDecimal()</code> is false
 128.324 + *     and <code>isParseIntegerOnly()</code> is true,
 128.325 + * <li><code>Double(-0.0)</code> if both <code>isParseBigDecimal()</code>
 128.326 + * and <code>isParseIntegerOnly()</code> are false.
 128.327 + * </ul>
 128.328 + *
 128.329 + * <h4><a name="synchronization">Synchronization</a></h4>
 128.330 + *
 128.331 + * <p>
 128.332 + * Decimal formats are generally not synchronized.
 128.333 + * It is recommended to create separate format instances for each thread.
 128.334 + * If multiple threads access a format concurrently, it must be synchronized
 128.335 + * externally.
 128.336 + *
 128.337 + * <h4>Example</h4>
 128.338 + *
 128.339 + * <blockquote><pre>
 128.340 + * <strong>// Print out a number using the localized number, integer, currency,
 128.341 + * // and percent format for each locale</strong>
 128.342 + * Locale[] locales = NumberFormat.getAvailableLocales();
 128.343 + * double myNumber = -1234.56;
 128.344 + * NumberFormat form;
 128.345 + * for (int j=0; j<4; ++j) {
 128.346 + *     System.out.println("FORMAT");
 128.347 + *     for (int i = 0; i < locales.length; ++i) {
 128.348 + *         if (locales[i].getCountry().length() == 0) {
 128.349 + *            continue; // Skip language-only locales
 128.350 + *         }
 128.351 + *         System.out.print(locales[i].getDisplayName());
 128.352 + *         switch (j) {
 128.353 + *         case 0:
 128.354 + *             form = NumberFormat.getInstance(locales[i]); break;
 128.355 + *         case 1:
 128.356 + *             form = NumberFormat.getIntegerInstance(locales[i]); break;
 128.357 + *         case 2:
 128.358 + *             form = NumberFormat.getCurrencyInstance(locales[i]); break;
 128.359 + *         default:
 128.360 + *             form = NumberFormat.getPercentInstance(locales[i]); break;
 128.361 + *         }
 128.362 + *         if (form instanceof DecimalFormat) {
 128.363 + *             System.out.print(": " + ((DecimalFormat) form).toPattern());
 128.364 + *         }
 128.365 + *         System.out.print(" -> " + form.format(myNumber));
 128.366 + *         try {
 128.367 + *             System.out.println(" -> " + form.parse(form.format(myNumber)));
 128.368 + *         } catch (ParseException e) {}
 128.369 + *     }
 128.370 + * }
 128.371 + * </pre></blockquote>
 128.372 + *
 128.373 + * @see          <a href="http://java.sun.com/docs/books/tutorial/i18n/format/decimalFormat.html">Java Tutorial</a>
 128.374 + * @see          NumberFormat
 128.375 + * @see          DecimalFormatSymbols
 128.376 + * @see          ParsePosition
 128.377 + * @author       Mark Davis
 128.378 + * @author       Alan Liu
 128.379 + */
 128.380 +public class DecimalFormat extends NumberFormat {
 128.381 +
 128.382 +    /**
 128.383 +     * Creates a DecimalFormat using the default pattern and symbols
 128.384 +     * for the default locale. This is a convenient way to obtain a
 128.385 +     * DecimalFormat when internationalization is not the main concern.
 128.386 +     * <p>
 128.387 +     * To obtain standard formats for a given locale, use the factory methods
 128.388 +     * on NumberFormat such as getNumberInstance. These factories will
 128.389 +     * return the most appropriate sub-class of NumberFormat for a given
 128.390 +     * locale.
 128.391 +     *
 128.392 +     * @see java.text.NumberFormat#getInstance
 128.393 +     * @see java.text.NumberFormat#getNumberInstance
 128.394 +     * @see java.text.NumberFormat#getCurrencyInstance
 128.395 +     * @see java.text.NumberFormat#getPercentInstance
 128.396 +     */
 128.397 +    public DecimalFormat() {
 128.398 +        Locale def = Locale.getDefault(Locale.Category.FORMAT);
 128.399 +        // try to get the pattern from the cache
 128.400 +        String pattern = cachedLocaleData.get(def);
 128.401 +        if (pattern == null) {  /* cache miss */
 128.402 +            // Get the pattern for the default locale.
 128.403 +//            ResourceBundle rb = LocaleData.getNumberFormatData(def);
 128.404 +//            String[] all = rb.getStringArray("NumberPatterns");
 128.405 +//            pattern = all[0];
 128.406 +//            /* update cache */
 128.407 +//            cachedLocaleData.putIfAbsent(def, pattern);
 128.408 +        }
 128.409 +
 128.410 +        // Always applyPattern after the symbols are set
 128.411 +        this.symbols = new DecimalFormatSymbols(def);
 128.412 +        applyPattern(pattern, false);
 128.413 +    }
 128.414 +
 128.415 +
 128.416 +    /**
 128.417 +     * Creates a DecimalFormat using the given pattern and the symbols
 128.418 +     * for the default locale. This is a convenient way to obtain a
 128.419 +     * DecimalFormat when internationalization is not the main concern.
 128.420 +     * <p>
 128.421 +     * To obtain standard formats for a given locale, use the factory methods
 128.422 +     * on NumberFormat such as getNumberInstance. These factories will
 128.423 +     * return the most appropriate sub-class of NumberFormat for a given
 128.424 +     * locale.
 128.425 +     *
 128.426 +     * @param pattern A non-localized pattern string.
 128.427 +     * @exception NullPointerException if <code>pattern</code> is null
 128.428 +     * @exception IllegalArgumentException if the given pattern is invalid.
 128.429 +     * @see java.text.NumberFormat#getInstance
 128.430 +     * @see java.text.NumberFormat#getNumberInstance
 128.431 +     * @see java.text.NumberFormat#getCurrencyInstance
 128.432 +     * @see java.text.NumberFormat#getPercentInstance
 128.433 +     */
 128.434 +    public DecimalFormat(String pattern) {
 128.435 +        // Always applyPattern after the symbols are set
 128.436 +        this.symbols = new DecimalFormatSymbols(Locale.getDefault(Locale.Category.FORMAT));
 128.437 +        applyPattern(pattern, false);
 128.438 +    }
 128.439 +
 128.440 +
 128.441 +    /**
 128.442 +     * Creates a DecimalFormat using the given pattern and symbols.
 128.443 +     * Use this constructor when you need to completely customize the
 128.444 +     * behavior of the format.
 128.445 +     * <p>
 128.446 +     * To obtain standard formats for a given
 128.447 +     * locale, use the factory methods on NumberFormat such as
 128.448 +     * getInstance or getCurrencyInstance. If you need only minor adjustments
 128.449 +     * to a standard format, you can modify the format returned by
 128.450 +     * a NumberFormat factory method.
 128.451 +     *
 128.452 +     * @param pattern a non-localized pattern string
 128.453 +     * @param symbols the set of symbols to be used
 128.454 +     * @exception NullPointerException if any of the given arguments is null
 128.455 +     * @exception IllegalArgumentException if the given pattern is invalid
 128.456 +     * @see java.text.NumberFormat#getInstance
 128.457 +     * @see java.text.NumberFormat#getNumberInstance
 128.458 +     * @see java.text.NumberFormat#getCurrencyInstance
 128.459 +     * @see java.text.NumberFormat#getPercentInstance
 128.460 +     * @see java.text.DecimalFormatSymbols
 128.461 +     */
 128.462 +    public DecimalFormat (String pattern, DecimalFormatSymbols symbols) {
 128.463 +        // Always applyPattern after the symbols are set
 128.464 +        this.symbols = (DecimalFormatSymbols)symbols.clone();
 128.465 +        applyPattern(pattern, false);
 128.466 +    }
 128.467 +
 128.468 +
 128.469 +    // Overrides
 128.470 +    /**
 128.471 +     * Formats a number and appends the resulting text to the given string
 128.472 +     * buffer.
 128.473 +     * The number can be of any subclass of {@link java.lang.Number}.
 128.474 +     * <p>
 128.475 +     * This implementation uses the maximum precision permitted.
 128.476 +     * @param number     the number to format
 128.477 +     * @param toAppendTo the <code>StringBuffer</code> to which the formatted
 128.478 +     *                   text is to be appended
 128.479 +     * @param pos        On input: an alignment field, if desired.
 128.480 +     *                   On output: the offsets of the alignment field.
 128.481 +     * @return           the value passed in as <code>toAppendTo</code>
 128.482 +     * @exception        IllegalArgumentException if <code>number</code> is
 128.483 +     *                   null or not an instance of <code>Number</code>.
 128.484 +     * @exception        NullPointerException if <code>toAppendTo</code> or
 128.485 +     *                   <code>pos</code> is null
 128.486 +     * @exception        ArithmeticException if rounding is needed with rounding
 128.487 +     *                   mode being set to RoundingMode.UNNECESSARY
 128.488 +     * @see              java.text.FieldPosition
 128.489 +     */
 128.490 +    public final StringBuffer format(Object number,
 128.491 +                                     StringBuffer toAppendTo,
 128.492 +                                     FieldPosition pos) {
 128.493 +        if (number instanceof Long || number instanceof Integer ||
 128.494 +                   number instanceof Short || number instanceof Byte ||
 128.495 +                   number instanceof AtomicInteger ||
 128.496 +                   number instanceof AtomicLong ||
 128.497 +                   (number instanceof BigInteger &&
 128.498 +                    ((BigInteger)number).bitLength () < 64)) {
 128.499 +            return format(((Number)number).longValue(), toAppendTo, pos);
 128.500 +        } else if (number instanceof BigDecimal) {
 128.501 +            return format((BigDecimal)number, toAppendTo, pos);
 128.502 +        } else if (number instanceof BigInteger) {
 128.503 +            return format((BigInteger)number, toAppendTo, pos);
 128.504 +        } else if (number instanceof Number) {
 128.505 +            return format(((Number)number).doubleValue(), toAppendTo, pos);
 128.506 +        } else {
 128.507 +            throw new IllegalArgumentException("Cannot format given Object as a Number");
 128.508 +        }
 128.509 +    }
 128.510 +
 128.511 +    /**
 128.512 +     * Formats a double to produce a string.
 128.513 +     * @param number    The double to format
 128.514 +     * @param result    where the text is to be appended
 128.515 +     * @param fieldPosition    On input: an alignment field, if desired.
 128.516 +     * On output: the offsets of the alignment field.
 128.517 +     * @exception ArithmeticException if rounding is needed with rounding
 128.518 +     *            mode being set to RoundingMode.UNNECESSARY
 128.519 +     * @return The formatted number string
 128.520 +     * @see java.text.FieldPosition
 128.521 +     */
 128.522 +    public StringBuffer format(double number, StringBuffer result,
 128.523 +                               FieldPosition fieldPosition) {
 128.524 +        fieldPosition.setBeginIndex(0);
 128.525 +        fieldPosition.setEndIndex(0);
 128.526 +
 128.527 +        return format(number, result, fieldPosition.getFieldDelegate());
 128.528 +    }
 128.529 +
 128.530 +    /**
 128.531 +     * Formats a double to produce a string.
 128.532 +     * @param number    The double to format
 128.533 +     * @param result    where the text is to be appended
 128.534 +     * @param delegate notified of locations of sub fields
 128.535 +     * @exception       ArithmeticException if rounding is needed with rounding
 128.536 +     *                  mode being set to RoundingMode.UNNECESSARY
 128.537 +     * @return The formatted number string
 128.538 +     */
 128.539 +    private StringBuffer format(double number, StringBuffer result,
 128.540 +                                FieldDelegate delegate) {
 128.541 +        if (Double.isNaN(number) ||
 128.542 +           (Double.isInfinite(number) && multiplier == 0)) {
 128.543 +            int iFieldStart = result.length();
 128.544 +            result.append(symbols.getNaN());
 128.545 +            delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER,
 128.546 +                               iFieldStart, result.length(), result);
 128.547 +            return result;
 128.548 +        }
 128.549 +
 128.550 +        /* Detecting whether a double is negative is easy with the exception of
 128.551 +         * the value -0.0.  This is a double which has a zero mantissa (and
 128.552 +         * exponent), but a negative sign bit.  It is semantically distinct from
 128.553 +         * a zero with a positive sign bit, and this distinction is important
 128.554 +         * to certain kinds of computations.  However, it's a little tricky to
 128.555 +         * detect, since (-0.0 == 0.0) and !(-0.0 < 0.0).  How then, you may
 128.556 +         * ask, does it behave distinctly from +0.0?  Well, 1/(-0.0) ==
 128.557 +         * -Infinity.  Proper detection of -0.0 is needed to deal with the
 128.558 +         * issues raised by bugs 4106658, 4106667, and 4147706.  Liu 7/6/98.
 128.559 +         */
 128.560 +        boolean isNegative = ((number < 0.0) || (number == 0.0 && 1/number < 0.0)) ^ (multiplier < 0);
 128.561 +
 128.562 +        if (multiplier != 1) {
 128.563 +            number *= multiplier;
 128.564 +        }
 128.565 +
 128.566 +        if (Double.isInfinite(number)) {
 128.567 +            if (isNegative) {
 128.568 +                append(result, negativePrefix, delegate,
 128.569 +                       getNegativePrefixFieldPositions(), Field.SIGN);
 128.570 +            } else {
 128.571 +                append(result, positivePrefix, delegate,
 128.572 +                       getPositivePrefixFieldPositions(), Field.SIGN);
 128.573 +            }
 128.574 +
 128.575 +            int iFieldStart = result.length();
 128.576 +            result.append(symbols.getInfinity());
 128.577 +            delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER,
 128.578 +                               iFieldStart, result.length(), result);
 128.579 +
 128.580 +            if (isNegative) {
 128.581 +                append(result, negativeSuffix, delegate,
 128.582 +                       getNegativeSuffixFieldPositions(), Field.SIGN);
 128.583 +            } else {
 128.584 +                append(result, positiveSuffix, delegate,
 128.585 +                       getPositiveSuffixFieldPositions(), Field.SIGN);
 128.586 +            }
 128.587 +
 128.588 +            return result;
 128.589 +        }
 128.590 +
 128.591 +        if (isNegative) {
 128.592 +            number = -number;
 128.593 +        }
 128.594 +
 128.595 +        // at this point we are guaranteed a nonnegative finite number.
 128.596 +        assert(number >= 0 && !Double.isInfinite(number));
 128.597 +
 128.598 +        synchronized(digitList) {
 128.599 +            int maxIntDigits = super.getMaximumIntegerDigits();
 128.600 +            int minIntDigits = super.getMinimumIntegerDigits();
 128.601 +            int maxFraDigits = super.getMaximumFractionDigits();
 128.602 +            int minFraDigits = super.getMinimumFractionDigits();
 128.603 +
 128.604 +            digitList.set(isNegative, number, useExponentialNotation ?
 128.605 +                          maxIntDigits + maxFraDigits : maxFraDigits,
 128.606 +                          !useExponentialNotation);
 128.607 +            return subformat(result, delegate, isNegative, false,
 128.608 +                       maxIntDigits, minIntDigits, maxFraDigits, minFraDigits);
 128.609 +        }
 128.610 +    }
 128.611 +
 128.612 +    /**
 128.613 +     * Format a long to produce a string.
 128.614 +     * @param number    The long to format
 128.615 +     * @param result    where the text is to be appended
 128.616 +     * @param fieldPosition    On input: an alignment field, if desired.
 128.617 +     * On output: the offsets of the alignment field.
 128.618 +     * @exception       ArithmeticException if rounding is needed with rounding
 128.619 +     *                  mode being set to RoundingMode.UNNECESSARY
 128.620 +     * @return The formatted number string
 128.621 +     * @see java.text.FieldPosition
 128.622 +     */
 128.623 +    public StringBuffer format(long number, StringBuffer result,
 128.624 +                               FieldPosition fieldPosition) {
 128.625 +        fieldPosition.setBeginIndex(0);
 128.626 +        fieldPosition.setEndIndex(0);
 128.627 +
 128.628 +        return format(number, result, fieldPosition.getFieldDelegate());
 128.629 +    }
 128.630 +
 128.631 +    /**
 128.632 +     * Format a long to produce a string.
 128.633 +     * @param number    The long to format
 128.634 +     * @param result    where the text is to be appended
 128.635 +     * @param delegate notified of locations of sub fields
 128.636 +     * @return The formatted number string
 128.637 +     * @exception        ArithmeticException if rounding is needed with rounding
 128.638 +     *                   mode being set to RoundingMode.UNNECESSARY
 128.639 +     * @see java.text.FieldPosition
 128.640 +     */
 128.641 +    private StringBuffer format(long number, StringBuffer result,
 128.642 +                               FieldDelegate delegate) {
 128.643 +        boolean isNegative = (number < 0);
 128.644 +        if (isNegative) {
 128.645 +            number = -number;
 128.646 +        }
 128.647 +
 128.648 +        // In general, long values always represent real finite numbers, so
 128.649 +        // we don't have to check for +/- Infinity or NaN.  However, there
 128.650 +        // is one case we have to be careful of:  The multiplier can push
 128.651 +        // a number near MIN_VALUE or MAX_VALUE outside the legal range.  We
 128.652 +        // check for this before multiplying, and if it happens we use
 128.653 +        // BigInteger instead.
 128.654 +        boolean useBigInteger = false;
 128.655 +        if (number < 0) { // This can only happen if number == Long.MIN_VALUE.
 128.656 +            if (multiplier != 0) {
 128.657 +                useBigInteger = true;
 128.658 +            }
 128.659 +        } else if (multiplier != 1 && multiplier != 0) {
 128.660 +            long cutoff = Long.MAX_VALUE / multiplier;
 128.661 +            if (cutoff < 0) {
 128.662 +                cutoff = -cutoff;
 128.663 +            }
 128.664 +            useBigInteger = (number > cutoff);
 128.665 +        }
 128.666 +
 128.667 +        if (useBigInteger) {
 128.668 +            if (isNegative) {
 128.669 +                number = -number;
 128.670 +            }
 128.671 +            BigInteger bigIntegerValue = BigInteger.valueOf(number);
 128.672 +            return format(bigIntegerValue, result, delegate, true);
 128.673 +        }
 128.674 +
 128.675 +        number *= multiplier;
 128.676 +        if (number == 0) {
 128.677 +            isNegative = false;
 128.678 +        } else {
 128.679 +            if (multiplier < 0) {
 128.680 +                number = -number;
 128.681 +                isNegative = !isNegative;
 128.682 +            }
 128.683 +        }
 128.684 +
 128.685 +        synchronized(digitList) {
 128.686 +            int maxIntDigits = super.getMaximumIntegerDigits();
 128.687 +            int minIntDigits = super.getMinimumIntegerDigits();
 128.688 +            int maxFraDigits = super.getMaximumFractionDigits();
 128.689 +            int minFraDigits = super.getMinimumFractionDigits();
 128.690 +
 128.691 +            digitList.set(isNegative, number,
 128.692 +                     useExponentialNotation ? maxIntDigits + maxFraDigits : 0);
 128.693 +
 128.694 +            return subformat(result, delegate, isNegative, true,
 128.695 +                       maxIntDigits, minIntDigits, maxFraDigits, minFraDigits);
 128.696 +        }
 128.697 +    }
 128.698 +
 128.699 +    /**
 128.700 +     * Formats a BigDecimal to produce a string.
 128.701 +     * @param number    The BigDecimal to format
 128.702 +     * @param result    where the text is to be appended
 128.703 +     * @param fieldPosition    On input: an alignment field, if desired.
 128.704 +     * On output: the offsets of the alignment field.
 128.705 +     * @return The formatted number string
 128.706 +     * @exception        ArithmeticException if rounding is needed with rounding
 128.707 +     *                   mode being set to RoundingMode.UNNECESSARY
 128.708 +     * @see java.text.FieldPosition
 128.709 +     */
 128.710 +    private StringBuffer format(BigDecimal number, StringBuffer result,
 128.711 +                                FieldPosition fieldPosition) {
 128.712 +        fieldPosition.setBeginIndex(0);
 128.713 +        fieldPosition.setEndIndex(0);
 128.714 +        return format(number, result, fieldPosition.getFieldDelegate());
 128.715 +    }
 128.716 +
 128.717 +    /**
 128.718 +     * Formats a BigDecimal to produce a string.
 128.719 +     * @param number    The BigDecimal to format
 128.720 +     * @param result    where the text is to be appended
 128.721 +     * @param delegate notified of locations of sub fields
 128.722 +     * @exception        ArithmeticException if rounding is needed with rounding
 128.723 +     *                   mode being set to RoundingMode.UNNECESSARY
 128.724 +     * @return The formatted number string
 128.725 +     */
 128.726 +    private StringBuffer format(BigDecimal number, StringBuffer result,
 128.727 +                                FieldDelegate delegate) {
 128.728 +        if (multiplier != 1) {
 128.729 +            number = number.multiply(getBigDecimalMultiplier());
 128.730 +        }
 128.731 +        boolean isNegative = number.signum() == -1;
 128.732 +        if (isNegative) {
 128.733 +            number = number.negate();
 128.734 +        }
 128.735 +
 128.736 +        synchronized(digitList) {
 128.737 +            int maxIntDigits = getMaximumIntegerDigits();
 128.738 +            int minIntDigits = getMinimumIntegerDigits();
 128.739 +            int maxFraDigits = getMaximumFractionDigits();
 128.740 +            int minFraDigits = getMinimumFractionDigits();
 128.741 +            int maximumDigits = maxIntDigits + maxFraDigits;
 128.742 +
 128.743 +            digitList.set(isNegative, number, useExponentialNotation ?
 128.744 +                ((maximumDigits < 0) ? Integer.MAX_VALUE : maximumDigits) :
 128.745 +                maxFraDigits, !useExponentialNotation);
 128.746 +
 128.747 +            return subformat(result, delegate, isNegative, false,
 128.748 +                maxIntDigits, minIntDigits, maxFraDigits, minFraDigits);
 128.749 +        }
 128.750 +    }
 128.751 +
 128.752 +    /**
 128.753 +     * Format a BigInteger to produce a string.
 128.754 +     * @param number    The BigInteger to format
 128.755 +     * @param result    where the text is to be appended
 128.756 +     * @param fieldPosition    On input: an alignment field, if desired.
 128.757 +     * On output: the offsets of the alignment field.
 128.758 +     * @return The formatted number string
 128.759 +     * @exception        ArithmeticException if rounding is needed with rounding
 128.760 +     *                   mode being set to RoundingMode.UNNECESSARY
 128.761 +     * @see java.text.FieldPosition
 128.762 +     */
 128.763 +    private StringBuffer format(BigInteger number, StringBuffer result,
 128.764 +                               FieldPosition fieldPosition) {
 128.765 +        fieldPosition.setBeginIndex(0);
 128.766 +        fieldPosition.setEndIndex(0);
 128.767 +
 128.768 +        return format(number, result, fieldPosition.getFieldDelegate(), false);
 128.769 +    }
 128.770 +
 128.771 +    /**
 128.772 +     * Format a BigInteger to produce a string.
 128.773 +     * @param number    The BigInteger to format
 128.774 +     * @param result    where the text is to be appended
 128.775 +     * @param delegate notified of locations of sub fields
 128.776 +     * @return The formatted number string
 128.777 +     * @exception        ArithmeticException if rounding is needed with rounding
 128.778 +     *                   mode being set to RoundingMode.UNNECESSARY
 128.779 +     * @see java.text.FieldPosition
 128.780 +     */
 128.781 +    private StringBuffer format(BigInteger number, StringBuffer result,
 128.782 +                               FieldDelegate delegate, boolean formatLong) {
 128.783 +        if (multiplier != 1) {
 128.784 +            number = number.multiply(getBigIntegerMultiplier());
 128.785 +        }
 128.786 +        boolean isNegative = number.signum() == -1;
 128.787 +        if (isNegative) {
 128.788 +            number = number.negate();
 128.789 +        }
 128.790 +
 128.791 +        synchronized(digitList) {
 128.792 +            int maxIntDigits, minIntDigits, maxFraDigits, minFraDigits, maximumDigits;
 128.793 +            if (formatLong) {
 128.794 +                maxIntDigits = super.getMaximumIntegerDigits();
 128.795 +                minIntDigits = super.getMinimumIntegerDigits();
 128.796 +                maxFraDigits = super.getMaximumFractionDigits();
 128.797 +                minFraDigits = super.getMinimumFractionDigits();
 128.798 +                maximumDigits = maxIntDigits + maxFraDigits;
 128.799 +            } else {
 128.800 +                maxIntDigits = getMaximumIntegerDigits();
 128.801 +                minIntDigits = getMinimumIntegerDigits();
 128.802 +                maxFraDigits = getMaximumFractionDigits();
 128.803 +                minFraDigits = getMinimumFractionDigits();
 128.804 +                maximumDigits = maxIntDigits + maxFraDigits;
 128.805 +                if (maximumDigits < 0) {
 128.806 +                    maximumDigits = Integer.MAX_VALUE;
 128.807 +                }
 128.808 +            }
 128.809 +
 128.810 +            digitList.set(isNegative, number,
 128.811 +                          useExponentialNotation ? maximumDigits : 0);
 128.812 +
 128.813 +            return subformat(result, delegate, isNegative, true,
 128.814 +                maxIntDigits, minIntDigits, maxFraDigits, minFraDigits);
 128.815 +        }
 128.816 +    }
 128.817 +
 128.818 +    /**
 128.819 +     * Formats an Object producing an <code>AttributedCharacterIterator</code>.
 128.820 +     * You can use the returned <code>AttributedCharacterIterator</code>
 128.821 +     * to build the resulting String, as well as to determine information
 128.822 +     * about the resulting String.
 128.823 +     * <p>
 128.824 +     * Each attribute key of the AttributedCharacterIterator will be of type
 128.825 +     * <code>NumberFormat.Field</code>, with the attribute value being the
 128.826 +     * same as the attribute key.
 128.827 +     *
 128.828 +     * @exception NullPointerException if obj is null.
 128.829 +     * @exception IllegalArgumentException when the Format cannot format the
 128.830 +     *            given object.
 128.831 +     * @exception        ArithmeticException if rounding is needed with rounding
 128.832 +     *                   mode being set to RoundingMode.UNNECESSARY
 128.833 +     * @param obj The object to format
 128.834 +     * @return AttributedCharacterIterator describing the formatted value.
 128.835 +     * @since 1.4
 128.836 +     */
 128.837 +    public AttributedCharacterIterator formatToCharacterIterator(Object obj) {
 128.838 +        CharacterIteratorFieldDelegate delegate =
 128.839 +                         new CharacterIteratorFieldDelegate();
 128.840 +        StringBuffer sb = new StringBuffer();
 128.841 +
 128.842 +        if (obj instanceof Double || obj instanceof Float) {
 128.843 +            format(((Number)obj).doubleValue(), sb, delegate);
 128.844 +        } else if (obj instanceof Long || obj instanceof Integer ||
 128.845 +                   obj instanceof Short || obj instanceof Byte ||
 128.846 +                   obj instanceof AtomicInteger || obj instanceof AtomicLong) {
 128.847 +            format(((Number)obj).longValue(), sb, delegate);
 128.848 +        } else if (obj instanceof BigDecimal) {
 128.849 +            format((BigDecimal)obj, sb, delegate);
 128.850 +        } else if (obj instanceof BigInteger) {
 128.851 +            format((BigInteger)obj, sb, delegate, false);
 128.852 +        } else if (obj == null) {
 128.853 +            throw new NullPointerException(
 128.854 +                "formatToCharacterIterator must be passed non-null object");
 128.855 +        } else {
 128.856 +            throw new IllegalArgumentException(
 128.857 +                "Cannot format given Object as a Number");
 128.858 +        }
 128.859 +        return delegate.getIterator(sb.toString());
 128.860 +    }
 128.861 +
 128.862 +    /**
 128.863 +     * Complete the formatting of a finite number.  On entry, the digitList must
 128.864 +     * be filled in with the correct digits.
 128.865 +     */
 128.866 +    private StringBuffer subformat(StringBuffer result, FieldDelegate delegate,
 128.867 +                                   boolean isNegative, boolean isInteger,
 128.868 +                                   int maxIntDigits, int minIntDigits,
 128.869 +                                   int maxFraDigits, int minFraDigits) {
 128.870 +        // NOTE: This isn't required anymore because DigitList takes care of this.
 128.871 +        //
 128.872 +        //  // The negative of the exponent represents the number of leading
 128.873 +        //  // zeros between the decimal and the first non-zero digit, for
 128.874 +        //  // a value < 0.1 (e.g., for 0.00123, -fExponent == 2).  If this
 128.875 +        //  // is more than the maximum fraction digits, then we have an underflow
 128.876 +        //  // for the printed representation.  We recognize this here and set
 128.877 +        //  // the DigitList representation to zero in this situation.
 128.878 +        //
 128.879 +        //  if (-digitList.decimalAt >= getMaximumFractionDigits())
 128.880 +        //  {
 128.881 +        //      digitList.count = 0;
 128.882 +        //  }
 128.883 +
 128.884 +        char zero = symbols.getZeroDigit();
 128.885 +        int zeroDelta = zero - '0'; // '0' is the DigitList representation of zero
 128.886 +        char grouping = symbols.getGroupingSeparator();
 128.887 +        char decimal = isCurrencyFormat ?
 128.888 +            symbols.getMonetaryDecimalSeparator() :
 128.889 +            symbols.getDecimalSeparator();
 128.890 +
 128.891 +        /* Per bug 4147706, DecimalFormat must respect the sign of numbers which
 128.892 +         * format as zero.  This allows sensible computations and preserves
 128.893 +         * relations such as signum(1/x) = signum(x), where x is +Infinity or
 128.894 +         * -Infinity.  Prior to this fix, we always formatted zero values as if
 128.895 +         * they were positive.  Liu 7/6/98.
 128.896 +         */
 128.897 +        if (digitList.isZero()) {
 128.898 +            digitList.decimalAt = 0; // Normalize
 128.899 +        }
 128.900 +
 128.901 +        if (isNegative) {
 128.902 +            append(result, negativePrefix, delegate,
 128.903 +                   getNegativePrefixFieldPositions(), Field.SIGN);
 128.904 +        } else {
 128.905 +            append(result, positivePrefix, delegate,
 128.906 +                   getPositivePrefixFieldPositions(), Field.SIGN);
 128.907 +        }
 128.908 +
 128.909 +        if (useExponentialNotation) {
 128.910 +            int iFieldStart = result.length();
 128.911 +            int iFieldEnd = -1;
 128.912 +            int fFieldStart = -1;
 128.913 +
 128.914 +            // Minimum integer digits are handled in exponential format by
 128.915 +            // adjusting the exponent.  For example, 0.01234 with 3 minimum
 128.916 +            // integer digits is "123.4E-4".
 128.917 +
 128.918 +            // Maximum integer digits are interpreted as indicating the
 128.919 +            // repeating range.  This is useful for engineering notation, in
 128.920 +            // which the exponent is restricted to a multiple of 3.  For
 128.921 +            // example, 0.01234 with 3 maximum integer digits is "12.34e-3".
 128.922 +            // If maximum integer digits are > 1 and are larger than
 128.923 +            // minimum integer digits, then minimum integer digits are
 128.924 +            // ignored.
 128.925 +            int exponent = digitList.decimalAt;
 128.926 +            int repeat = maxIntDigits;
 128.927 +            int minimumIntegerDigits = minIntDigits;
 128.928 +            if (repeat > 1 && repeat > minIntDigits) {
 128.929 +                // A repeating range is defined; adjust to it as follows.
 128.930 +                // If repeat == 3, we have 6,5,4=>3; 3,2,1=>0; 0,-1,-2=>-3;
 128.931 +                // -3,-4,-5=>-6, etc. This takes into account that the
 128.932 +                // exponent we have here is off by one from what we expect;
 128.933 +                // it is for the format 0.MMMMMx10^n.
 128.934 +                if (exponent >= 1) {
 128.935 +                    exponent = ((exponent - 1) / repeat) * repeat;
 128.936 +                } else {
 128.937 +                    // integer division rounds towards 0
 128.938 +                    exponent = ((exponent - repeat) / repeat) * repeat;
 128.939 +                }
 128.940 +                minimumIntegerDigits = 1;
 128.941 +            } else {
 128.942 +                // No repeating range is defined; use minimum integer digits.
 128.943 +                exponent -= minimumIntegerDigits;
 128.944 +            }
 128.945 +
 128.946 +            // We now output a minimum number of digits, and more if there
 128.947 +            // are more digits, up to the maximum number of digits.  We
 128.948 +            // place the decimal point after the "integer" digits, which
 128.949 +            // are the first (decimalAt - exponent) digits.
 128.950 +            int minimumDigits = minIntDigits + minFraDigits;
 128.951 +            if (minimumDigits < 0) {    // overflow?
 128.952 +                minimumDigits = Integer.MAX_VALUE;
 128.953 +            }
 128.954 +
 128.955 +            // The number of integer digits is handled specially if the number
 128.956 +            // is zero, since then there may be no digits.
 128.957 +            int integerDigits = digitList.isZero() ? minimumIntegerDigits :
 128.958 +                    digitList.decimalAt - exponent;
 128.959 +            if (minimumDigits < integerDigits) {
 128.960 +                minimumDigits = integerDigits;
 128.961 +            }
 128.962 +            int totalDigits = digitList.count;
 128.963 +            if (minimumDigits > totalDigits) {
 128.964 +                totalDigits = minimumDigits;
 128.965 +            }
 128.966 +            boolean addedDecimalSeparator = false;
 128.967 +
 128.968 +            for (int i=0; i<totalDigits; ++i) {
 128.969 +                if (i == integerDigits) {
 128.970 +                    // Record field information for caller.
 128.971 +                    iFieldEnd = result.length();
 128.972 +
 128.973 +                    result.append(decimal);
 128.974 +                    addedDecimalSeparator = true;
 128.975 +
 128.976 +                    // Record field information for caller.
 128.977 +                    fFieldStart = result.length();
 128.978 +                }
 128.979 +                result.append((i < digitList.count) ?
 128.980 +                              (char)(digitList.digits[i] + zeroDelta) :
 128.981 +                              zero);
 128.982 +            }
 128.983 +
 128.984 +            if (decimalSeparatorAlwaysShown && totalDigits == integerDigits) {
 128.985 +                // Record field information for caller.
 128.986 +                iFieldEnd = result.length();
 128.987 +
 128.988 +                result.append(decimal);
 128.989 +                addedDecimalSeparator = true;
 128.990 +
 128.991 +                // Record field information for caller.
 128.992 +                fFieldStart = result.length();
 128.993 +            }
 128.994 +
 128.995 +            // Record field information
 128.996 +            if (iFieldEnd == -1) {
 128.997 +                iFieldEnd = result.length();
 128.998 +            }
 128.999 +            delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER,
128.1000 +                               iFieldStart, iFieldEnd, result);
128.1001 +            if (addedDecimalSeparator) {
128.1002 +                delegate.formatted(Field.DECIMAL_SEPARATOR,
128.1003 +                                   Field.DECIMAL_SEPARATOR,
128.1004 +                                   iFieldEnd, fFieldStart, result);
128.1005 +            }
128.1006 +            if (fFieldStart == -1) {
128.1007 +                fFieldStart = result.length();
128.1008 +            }
128.1009 +            delegate.formatted(FRACTION_FIELD, Field.FRACTION, Field.FRACTION,
128.1010 +                               fFieldStart, result.length(), result);
128.1011 +
128.1012 +            // The exponent is output using the pattern-specified minimum
128.1013 +            // exponent digits.  There is no maximum limit to the exponent
128.1014 +            // digits, since truncating the exponent would result in an
128.1015 +            // unacceptable inaccuracy.
128.1016 +            int fieldStart = result.length();
128.1017 +
128.1018 +            result.append(symbols.getExponentSeparator());
128.1019 +
128.1020 +            delegate.formatted(Field.EXPONENT_SYMBOL, Field.EXPONENT_SYMBOL,
128.1021 +                               fieldStart, result.length(), result);
128.1022 +
128.1023 +            // For zero values, we force the exponent to zero.  We
128.1024 +            // must do this here, and not earlier, because the value
128.1025 +            // is used to determine integer digit count above.
128.1026 +            if (digitList.isZero()) {
128.1027 +                exponent = 0;
128.1028 +            }
128.1029 +
128.1030 +            boolean negativeExponent = exponent < 0;
128.1031 +            if (negativeExponent) {
128.1032 +                exponent = -exponent;
128.1033 +                fieldStart = result.length();
128.1034 +                result.append(symbols.getMinusSign());
128.1035 +                delegate.formatted(Field.EXPONENT_SIGN, Field.EXPONENT_SIGN,
128.1036 +                                   fieldStart, result.length(), result);
128.1037 +            }
128.1038 +            digitList.set(negativeExponent, exponent);
128.1039 +
128.1040 +            int eFieldStart = result.length();
128.1041 +
128.1042 +            for (int i=digitList.decimalAt; i<minExponentDigits; ++i) {
128.1043 +                result.append(zero);
128.1044 +            }
128.1045 +            for (int i=0; i<digitList.decimalAt; ++i) {
128.1046 +                result.append((i < digitList.count) ?
128.1047 +                          (char)(digitList.digits[i] + zeroDelta) : zero);
128.1048 +            }
128.1049 +            delegate.formatted(Field.EXPONENT, Field.EXPONENT, eFieldStart,
128.1050 +                               result.length(), result);
128.1051 +        } else {
128.1052 +            int iFieldStart = result.length();
128.1053 +
128.1054 +            // Output the integer portion.  Here 'count' is the total
128.1055 +            // number of integer digits we will display, including both
128.1056 +            // leading zeros required to satisfy getMinimumIntegerDigits,
128.1057 +            // and actual digits present in the number.
128.1058 +            int count = minIntDigits;
128.1059 +            int digitIndex = 0; // Index into digitList.fDigits[]
128.1060 +            if (digitList.decimalAt > 0 && count < digitList.decimalAt) {
128.1061 +                count = digitList.decimalAt;
128.1062 +            }
128.1063 +
128.1064 +            // Handle the case where getMaximumIntegerDigits() is smaller
128.1065 +            // than the real number of integer digits.  If this is so, we
128.1066 +            // output the least significant max integer digits.  For example,
128.1067 +            // the value 1997 printed with 2 max integer digits is just "97".
128.1068 +            if (count > maxIntDigits) {
128.1069 +                count = maxIntDigits;
128.1070 +                digitIndex = digitList.decimalAt - count;
128.1071 +            }
128.1072 +
128.1073 +            int sizeBeforeIntegerPart = result.length();
128.1074 +            for (int i=count-1; i>=0; --i) {
128.1075 +                if (i < digitList.decimalAt && digitIndex < digitList.count) {
128.1076 +                    // Output a real digit
128.1077 +                    result.append((char)(digitList.digits[digitIndex++] + zeroDelta));
128.1078 +                } else {
128.1079 +                    // Output a leading zero
128.1080 +                    result.append(zero);
128.1081 +                }
128.1082 +
128.1083 +                // Output grouping separator if necessary.  Don't output a
128.1084 +                // grouping separator if i==0 though; that's at the end of
128.1085 +                // the integer part.
128.1086 +                if (isGroupingUsed() && i>0 && (groupingSize != 0) &&
128.1087 +                    (i % groupingSize == 0)) {
128.1088 +                    int gStart = result.length();
128.1089 +                    result.append(grouping);
128.1090 +                    delegate.formatted(Field.GROUPING_SEPARATOR,
128.1091 +                                       Field.GROUPING_SEPARATOR, gStart,
128.1092 +                                       result.length(), result);
128.1093 +                }
128.1094 +            }
128.1095 +
128.1096 +            // Determine whether or not there are any printable fractional
128.1097 +            // digits.  If we've used up the digits we know there aren't.
128.1098 +            boolean fractionPresent = (minFraDigits > 0) ||
128.1099 +                (!isInteger && digitIndex < digitList.count);
128.1100 +
128.1101 +            // If there is no fraction present, and we haven't printed any
128.1102 +            // integer digits, then print a zero.  Otherwise we won't print
128.1103 +            // _any_ digits, and we won't be able to parse this string.
128.1104 +            if (!fractionPresent && result.length() == sizeBeforeIntegerPart) {
128.1105 +                result.append(zero);
128.1106 +            }
128.1107 +
128.1108 +            delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER,
128.1109 +                               iFieldStart, result.length(), result);
128.1110 +
128.1111 +            // Output the decimal separator if we always do so.
128.1112 +            int sStart = result.length();
128.1113 +            if (decimalSeparatorAlwaysShown || fractionPresent) {
128.1114 +                result.append(decimal);
128.1115 +            }
128.1116 +
128.1117 +            if (sStart != result.length()) {
128.1118 +                delegate.formatted(Field.DECIMAL_SEPARATOR,
128.1119 +                                   Field.DECIMAL_SEPARATOR,
128.1120 +                                   sStart, result.length(), result);
128.1121 +            }
128.1122 +            int fFieldStart = result.length();
128.1123 +
128.1124 +            for (int i=0; i < maxFraDigits; ++i) {
128.1125 +                // Here is where we escape from the loop.  We escape if we've
128.1126 +                // output the maximum fraction digits (specified in the for
128.1127 +                // expression above).
128.1128 +                // We also stop when we've output the minimum digits and either:
128.1129 +                // we have an integer, so there is no fractional stuff to
128.1130 +                // display, or we're out of significant digits.
128.1131 +                if (i >= minFraDigits &&
128.1132 +                    (isInteger || digitIndex >= digitList.count)) {
128.1133 +                    break;
128.1134 +                }
128.1135 +
128.1136 +                // Output leading fractional zeros. These are zeros that come
128.1137 +                // after the decimal but before any significant digits. These
128.1138 +                // are only output if abs(number being formatted) < 1.0.
128.1139 +                if (-1-i > (digitList.decimalAt-1)) {
128.1140 +                    result.append(zero);
128.1141 +                    continue;
128.1142 +                }
128.1143 +
128.1144 +                // Output a digit, if we have any precision left, or a
128.1145 +                // zero if we don't.  We don't want to output noise digits.
128.1146 +                if (!isInteger && digitIndex < digitList.count) {
128.1147 +                    result.append((char)(digitList.digits[digitIndex++] + zeroDelta));
128.1148 +                } else {
128.1149 +                    result.append(zero);
128.1150 +                }
128.1151 +            }
128.1152 +
128.1153 +            // Record field information for caller.
128.1154 +            delegate.formatted(FRACTION_FIELD, Field.FRACTION, Field.FRACTION,
128.1155 +                               fFieldStart, result.length(), result);
128.1156 +        }
128.1157 +
128.1158 +        if (isNegative) {
128.1159 +            append(result, negativeSuffix, delegate,
128.1160 +                   getNegativeSuffixFieldPositions(), Field.SIGN);
128.1161 +        }
128.1162 +        else {
128.1163 +            append(result, positiveSuffix, delegate,
128.1164 +                   getPositiveSuffixFieldPositions(), Field.SIGN);
128.1165 +        }
128.1166 +
128.1167 +        return result;
128.1168 +    }
128.1169 +
128.1170 +    /**
128.1171 +     * Appends the String <code>string</code> to <code>result</code>.
128.1172 +     * <code>delegate</code> is notified of all  the
128.1173 +     * <code>FieldPosition</code>s in <code>positions</code>.
128.1174 +     * <p>
128.1175 +     * If one of the <code>FieldPosition</code>s in <code>positions</code>
128.1176 +     * identifies a <code>SIGN</code> attribute, it is mapped to
128.1177 +     * <code>signAttribute</code>. This is used
128.1178 +     * to map the <code>SIGN</code> attribute to the <code>EXPONENT</code>
128.1179 +     * attribute as necessary.
128.1180 +     * <p>
128.1181 +     * This is used by <code>subformat</code> to add the prefix/suffix.
128.1182 +     */
128.1183 +    private void append(StringBuffer result, String string,
128.1184 +                        FieldDelegate delegate,
128.1185 +                        FieldPosition[] positions,
128.1186 +                        Format.Field signAttribute) {
128.1187 +        int start = result.length();
128.1188 +
128.1189 +        if (string.length() > 0) {
128.1190 +            result.append(string);
128.1191 +            for (int counter = 0, max = positions.length; counter < max;
128.1192 +                 counter++) {
128.1193 +                FieldPosition fp = positions[counter];
128.1194 +                Format.Field attribute = fp.getFieldAttribute();
128.1195 +
128.1196 +                if (attribute == Field.SIGN) {
128.1197 +                    attribute = signAttribute;
128.1198 +                }
128.1199 +                delegate.formatted(attribute, attribute,
128.1200 +                                   start + fp.getBeginIndex(),
128.1201 +                                   start + fp.getEndIndex(), result);
128.1202 +            }
128.1203 +        }
128.1204 +    }
128.1205 +
128.1206 +    /**
128.1207 +     * Parses text from a string to produce a <code>Number</code>.
128.1208 +     * <p>
128.1209 +     * The method attempts to parse text starting at the index given by
128.1210 +     * <code>pos</code>.
128.1211 +     * If parsing succeeds, then the index of <code>pos</code> is updated
128.1212 +     * to the index after the last character used (parsing does not necessarily
128.1213 +     * use all characters up to the end of the string), and the parsed
128.1214 +     * number is returned. The updated <code>pos</code> can be used to
128.1215 +     * indicate the starting point for the next call to this method.
128.1216 +     * If an error occurs, then the index of <code>pos</code> is not
128.1217 +     * changed, the error index of <code>pos</code> is set to the index of
128.1218 +     * the character where the error occurred, and null is returned.
128.1219 +     * <p>
128.1220 +     * The subclass returned depends on the value of {@link #isParseBigDecimal}
128.1221 +     * as well as on the string being parsed.
128.1222 +     * <ul>
128.1223 +     *   <li>If <code>isParseBigDecimal()</code> is false (the default),
128.1224 +     *       most integer values are returned as <code>Long</code>
128.1225 +     *       objects, no matter how they are written: <code>"17"</code> and
128.1226 +     *       <code>"17.000"</code> both parse to <code>Long(17)</code>.
128.1227 +     *       Values that cannot fit into a <code>Long</code> are returned as
128.1228 +     *       <code>Double</code>s. This includes values with a fractional part,
128.1229 +     *       infinite values, <code>NaN</code>, and the value -0.0.
128.1230 +     *       <code>DecimalFormat</code> does <em>not</em> decide whether to
128.1231 +     *       return a <code>Double</code> or a <code>Long</code> based on the
128.1232 +     *       presence of a decimal separator in the source string. Doing so
128.1233 +     *       would prevent integers that overflow the mantissa of a double,
128.1234 +     *       such as <code>"-9,223,372,036,854,775,808.00"</code>, from being
128.1235 +     *       parsed accurately.
128.1236 +     *       <p>
128.1237 +     *       Callers may use the <code>Number</code> methods
128.1238 +     *       <code>doubleValue</code>, <code>longValue</code>, etc., to obtain
128.1239 +     *       the type they want.
128.1240 +     *   <li>If <code>isParseBigDecimal()</code> is true, values are returned
128.1241 +     *       as <code>BigDecimal</code> objects. The values are the ones
128.1242 +     *       constructed by {@link java.math.BigDecimal#BigDecimal(String)}
128.1243 +     *       for corresponding strings in locale-independent format. The
128.1244 +     *       special cases negative and positive infinity and NaN are returned
128.1245 +     *       as <code>Double</code> instances holding the values of the
128.1246 +     *       corresponding <code>Double</code> constants.
128.1247 +     * </ul>
128.1248 +     * <p>
128.1249 +     * <code>DecimalFormat</code> parses all Unicode characters that represent
128.1250 +     * decimal digits, as defined by <code>Character.digit()</code>. In
128.1251 +     * addition, <code>DecimalFormat</code> also recognizes as digits the ten
128.1252 +     * consecutive characters starting with the localized zero digit defined in
128.1253 +     * the <code>DecimalFormatSymbols</code> object.
128.1254 +     *
128.1255 +     * @param text the string to be parsed
128.1256 +     * @param pos  A <code>ParsePosition</code> object with index and error
128.1257 +     *             index information as described above.
128.1258 +     * @return     the parsed value, or <code>null</code> if the parse fails
128.1259 +     * @exception  NullPointerException if <code>text</code> or
128.1260 +     *             <code>pos</code> is null.
128.1261 +     */
128.1262 +    public Number parse(String text, ParsePosition pos) {
128.1263 +        // special case NaN
128.1264 +        if (text.regionMatches(pos.index, symbols.getNaN(), 0, symbols.getNaN().length())) {
128.1265 +            pos.index = pos.index + symbols.getNaN().length();
128.1266 +            return new Double(Double.NaN);
128.1267 +        }
128.1268 +
128.1269 +        boolean[] status = new boolean[STATUS_LENGTH];
128.1270 +        if (!subparse(text, pos, positivePrefix, negativePrefix, digitList, false, status)) {
128.1271 +            return null;
128.1272 +        }
128.1273 +
128.1274 +        // special case INFINITY
128.1275 +        if (status[STATUS_INFINITE]) {
128.1276 +            if (status[STATUS_POSITIVE] == (multiplier >= 0)) {
128.1277 +                return new Double(Double.POSITIVE_INFINITY);
128.1278 +            } else {
128.1279 +                return new Double(Double.NEGATIVE_INFINITY);
128.1280 +            }
128.1281 +        }
128.1282 +
128.1283 +        if (multiplier == 0) {
128.1284 +            if (digitList.isZero()) {
128.1285 +                return new Double(Double.NaN);
128.1286 +            } else if (status[STATUS_POSITIVE]) {
128.1287 +                return new Double(Double.POSITIVE_INFINITY);
128.1288 +            } else {
128.1289 +                return new Double(Double.NEGATIVE_INFINITY);
128.1290 +            }
128.1291 +        }
128.1292 +
128.1293 +        if (isParseBigDecimal()) {
128.1294 +            BigDecimal bigDecimalResult = digitList.getBigDecimal();
128.1295 +
128.1296 +            if (multiplier != 1) {
128.1297 +                try {
128.1298 +                    bigDecimalResult = bigDecimalResult.divide(getBigDecimalMultiplier());
128.1299 +                }
128.1300 +                catch (ArithmeticException e) {  // non-terminating decimal expansion
128.1301 +                    bigDecimalResult = bigDecimalResult.divide(getBigDecimalMultiplier(), roundingMode);
128.1302 +                }
128.1303 +            }
128.1304 +
128.1305 +            if (!status[STATUS_POSITIVE]) {
128.1306 +                bigDecimalResult = bigDecimalResult.negate();
128.1307 +            }
128.1308 +            return bigDecimalResult;
128.1309 +        } else {
128.1310 +            boolean gotDouble = true;
128.1311 +            boolean gotLongMinimum = false;
128.1312 +            double  doubleResult = 0.0;
128.1313 +            long    longResult = 0;
128.1314 +
128.1315 +            // Finally, have DigitList parse the digits into a value.
128.1316 +            if (digitList.fitsIntoLong(status[STATUS_POSITIVE], isParseIntegerOnly())) {
128.1317 +                gotDouble = false;
128.1318 +                longResult = digitList.getLong();
128.1319 +                if (longResult < 0) {  // got Long.MIN_VALUE
128.1320 +                    gotLongMinimum = true;
128.1321 +                }
128.1322 +            } else {
128.1323 +                doubleResult = digitList.getDouble();
128.1324 +            }
128.1325 +
128.1326 +            // Divide by multiplier. We have to be careful here not to do
128.1327 +            // unneeded conversions between double and long.
128.1328 +            if (multiplier != 1) {
128.1329 +                if (gotDouble) {
128.1330 +                    doubleResult /= multiplier;
128.1331 +                } else {
128.1332 +                    // Avoid converting to double if we can
128.1333 +                    if (longResult % multiplier == 0) {
128.1334 +                        longResult /= multiplier;
128.1335 +                    } else {
128.1336 +                        doubleResult = ((double)longResult) / multiplier;
128.1337 +                        gotDouble = true;
128.1338 +                    }
128.1339 +                }
128.1340 +            }
128.1341 +
128.1342 +            if (!status[STATUS_POSITIVE] && !gotLongMinimum) {
128.1343 +                doubleResult = -doubleResult;
128.1344 +                longResult = -longResult;
128.1345 +            }
128.1346 +
128.1347 +            // At this point, if we divided the result by the multiplier, the
128.1348 +            // result may fit into a long.  We check for this case and return
128.1349 +            // a long if possible.
128.1350 +            // We must do this AFTER applying the negative (if appropriate)
128.1351 +            // in order to handle the case of LONG_MIN; otherwise, if we do
128.1352 +            // this with a positive value -LONG_MIN, the double is > 0, but
128.1353 +            // the long is < 0. We also must retain a double in the case of
128.1354 +            // -0.0, which will compare as == to a long 0 cast to a double
128.1355 +            // (bug 4162852).
128.1356 +            if (multiplier != 1 && gotDouble) {
128.1357 +                longResult = (long)doubleResult;
128.1358 +                gotDouble = ((doubleResult != (double)longResult) ||
128.1359 +                            (doubleResult == 0.0 && 1/doubleResult < 0.0)) &&
128.1360 +                            !isParseIntegerOnly();
128.1361 +            }
128.1362 +
128.1363 +            return gotDouble ?
128.1364 +                (Number)new Double(doubleResult) : (Number)new Long(longResult);
128.1365 +        }
128.1366 +    }
128.1367 +
128.1368 +    /**
128.1369 +     * Return a BigInteger multiplier.
128.1370 +     */
128.1371 +    private BigInteger getBigIntegerMultiplier() {
128.1372 +        if (bigIntegerMultiplier == null) {
128.1373 +            bigIntegerMultiplier = BigInteger.valueOf(multiplier);
128.1374 +        }
128.1375 +        return bigIntegerMultiplier;
128.1376 +    }
128.1377 +    private transient BigInteger bigIntegerMultiplier;
128.1378 +
128.1379 +    /**
128.1380 +     * Return a BigDecimal multiplier.
128.1381 +     */
128.1382 +    private BigDecimal getBigDecimalMultiplier() {
128.1383 +        if (bigDecimalMultiplier == null) {
128.1384 +            bigDecimalMultiplier = new BigDecimal(multiplier);
128.1385 +        }
128.1386 +        return bigDecimalMultiplier;
128.1387 +    }
128.1388 +    private transient BigDecimal bigDecimalMultiplier;
128.1389 +
128.1390 +    private static final int STATUS_INFINITE = 0;
128.1391 +    private static final int STATUS_POSITIVE = 1;
128.1392 +    private static final int STATUS_LENGTH   = 2;
128.1393 +
128.1394 +    /**
128.1395 +     * Parse the given text into a number.  The text is parsed beginning at
128.1396 +     * parsePosition, until an unparseable character is seen.
128.1397 +     * @param text The string to parse.
128.1398 +     * @param parsePosition The position at which to being parsing.  Upon
128.1399 +     * return, the first unparseable character.
128.1400 +     * @param digits The DigitList to set to the parsed value.
128.1401 +     * @param isExponent If true, parse an exponent.  This means no
128.1402 +     * infinite values and integer only.
128.1403 +     * @param status Upon return contains boolean status flags indicating
128.1404 +     * whether the value was infinite and whether it was positive.
128.1405 +     */
128.1406 +    private final boolean subparse(String text, ParsePosition parsePosition,
128.1407 +                   String positivePrefix, String negativePrefix,
128.1408 +                   DigitList digits, boolean isExponent,
128.1409 +                   boolean status[]) {
128.1410 +        int position = parsePosition.index;
128.1411 +        int oldStart = parsePosition.index;
128.1412 +        int backup;
128.1413 +        boolean gotPositive, gotNegative;
128.1414 +
128.1415 +        // check for positivePrefix; take longest
128.1416 +        gotPositive = text.regionMatches(position, positivePrefix, 0,
128.1417 +                                         positivePrefix.length());
128.1418 +        gotNegative = text.regionMatches(position, negativePrefix, 0,
128.1419 +                                         negativePrefix.length());
128.1420 +
128.1421 +        if (gotPositive && gotNegative) {
128.1422 +            if (positivePrefix.length() > negativePrefix.length()) {
128.1423 +                gotNegative = false;
128.1424 +            } else if (positivePrefix.length() < negativePrefix.length()) {
128.1425 +                gotPositive = false;
128.1426 +            }
128.1427 +        }
128.1428 +
128.1429 +        if (gotPositive) {
128.1430 +            position += positivePrefix.length();
128.1431 +        } else if (gotNegative) {
128.1432 +            position += negativePrefix.length();
128.1433 +        } else {
128.1434 +            parsePosition.errorIndex = position;
128.1435 +            return false;
128.1436 +        }
128.1437 +
128.1438 +        // process digits or Inf, find decimal position
128.1439 +        status[STATUS_INFINITE] = false;
128.1440 +        if (!isExponent && text.regionMatches(position,symbols.getInfinity(),0,
128.1441 +                          symbols.getInfinity().length())) {
128.1442 +            position += symbols.getInfinity().length();
128.1443 +            status[STATUS_INFINITE] = true;
128.1444 +        } else {
128.1445 +            // We now have a string of digits, possibly with grouping symbols,
128.1446 +            // and decimal points.  We want to process these into a DigitList.
128.1447 +            // We don't want to put a bunch of leading zeros into the DigitList
128.1448 +            // though, so we keep track of the location of the decimal point,
128.1449 +            // put only significant digits into the DigitList, and adjust the
128.1450 +            // exponent as needed.
128.1451 +
128.1452 +            digits.decimalAt = digits.count = 0;
128.1453 +            char zero = symbols.getZeroDigit();
128.1454 +            char decimal = isCurrencyFormat ?
128.1455 +                symbols.getMonetaryDecimalSeparator() :
128.1456 +                symbols.getDecimalSeparator();
128.1457 +            char grouping = symbols.getGroupingSeparator();
128.1458 +            String exponentString = symbols.getExponentSeparator();
128.1459 +            boolean sawDecimal = false;
128.1460 +            boolean sawExponent = false;
128.1461 +            boolean sawDigit = false;
128.1462 +            int exponent = 0; // Set to the exponent value, if any
128.1463 +
128.1464 +            // We have to track digitCount ourselves, because digits.count will
128.1465 +            // pin when the maximum allowable digits is reached.
128.1466 +            int digitCount = 0;
128.1467 +
128.1468 +            backup = -1;
128.1469 +            for (; position < text.length(); ++position) {
128.1470 +                char ch = text.charAt(position);
128.1471 +
128.1472 +                /* We recognize all digit ranges, not only the Latin digit range
128.1473 +                 * '0'..'9'.  We do so by using the Character.digit() method,
128.1474 +                 * which converts a valid Unicode digit to the range 0..9.
128.1475 +                 *
128.1476 +                 * The character 'ch' may be a digit.  If so, place its value
128.1477 +                 * from 0 to 9 in 'digit'.  First try using the locale digit,
128.1478 +                 * which may or MAY NOT be a standard Unicode digit range.  If
128.1479 +                 * this fails, try using the standard Unicode digit ranges by
128.1480 +                 * calling Character.digit().  If this also fails, digit will
128.1481 +                 * have a value outside the range 0..9.
128.1482 +                 */
128.1483 +                int digit = ch - zero;
128.1484 +                if (digit < 0 || digit > 9) {
128.1485 +                    digit = Character.digit(ch, 10);
128.1486 +                }
128.1487 +
128.1488 +                if (digit == 0) {
128.1489 +                    // Cancel out backup setting (see grouping handler below)
128.1490 +                    backup = -1; // Do this BEFORE continue statement below!!!
128.1491 +                    sawDigit = true;
128.1492 +
128.1493 +                    // Handle leading zeros
128.1494 +                    if (digits.count == 0) {
128.1495 +                        // Ignore leading zeros in integer part of number.
128.1496 +                        if (!sawDecimal) {
128.1497 +                            continue;
128.1498 +                        }
128.1499 +
128.1500 +                        // If we have seen the decimal, but no significant
128.1501 +                        // digits yet, then we account for leading zeros by
128.1502 +                        // decrementing the digits.decimalAt into negative
128.1503 +                        // values.
128.1504 +                        --digits.decimalAt;
128.1505 +                    } else {
128.1506 +                        ++digitCount;
128.1507 +                        digits.append((char)(digit + '0'));
128.1508 +                    }
128.1509 +                } else if (digit > 0 && digit <= 9) { // [sic] digit==0 handled above
128.1510 +                    sawDigit = true;
128.1511 +                    ++digitCount;
128.1512 +                    digits.append((char)(digit + '0'));
128.1513 +
128.1514 +                    // Cancel out backup setting (see grouping handler below)
128.1515 +                    backup = -1;
128.1516 +                } else if (!isExponent && ch == decimal) {
128.1517 +                    // If we're only parsing integers, or if we ALREADY saw the
128.1518 +                    // decimal, then don't parse this one.
128.1519 +                    if (isParseIntegerOnly() || sawDecimal) {
128.1520 +                        break;
128.1521 +                    }
128.1522 +                    digits.decimalAt = digitCount; // Not digits.count!
128.1523 +                    sawDecimal = true;
128.1524 +                } else if (!isExponent && ch == grouping && isGroupingUsed()) {
128.1525 +                    if (sawDecimal) {
128.1526 +                        break;
128.1527 +                    }
128.1528 +                    // Ignore grouping characters, if we are using them, but
128.1529 +                    // require that they be followed by a digit.  Otherwise
128.1530 +                    // we backup and reprocess them.
128.1531 +                    backup = position;
128.1532 +                } else if (!isExponent && text.regionMatches(position, exponentString, 0, exponentString.length())
128.1533 +                             && !sawExponent) {
128.1534 +                    // Process the exponent by recursively calling this method.
128.1535 +                     ParsePosition pos = new ParsePosition(position + exponentString.length());
128.1536 +                    boolean[] stat = new boolean[STATUS_LENGTH];
128.1537 +                    DigitList exponentDigits = new DigitList();
128.1538 +
128.1539 +                    if (subparse(text, pos, "", Character.toString(symbols.getMinusSign()), exponentDigits, true, stat) &&
128.1540 +                        exponentDigits.fitsIntoLong(stat[STATUS_POSITIVE], true)) {
128.1541 +                        position = pos.index; // Advance past the exponent
128.1542 +                        exponent = (int)exponentDigits.getLong();
128.1543 +                        if (!stat[STATUS_POSITIVE]) {
128.1544 +                            exponent = -exponent;
128.1545 +                        }
128.1546 +                        sawExponent = true;
128.1547 +                    }
128.1548 +                    break; // Whether we fail or succeed, we exit this loop
128.1549 +                }
128.1550 +                else {
128.1551 +                    break;
128.1552 +                }
128.1553 +            }
128.1554 +
128.1555 +            if (backup != -1) {
128.1556 +                position = backup;
128.1557 +            }
128.1558 +
128.1559 +            // If there was no decimal point we have an integer
128.1560 +            if (!sawDecimal) {
128.1561 +                digits.decimalAt = digitCount; // Not digits.count!
128.1562 +            }
128.1563 +
128.1564 +            // Adjust for exponent, if any
128.1565 +            digits.decimalAt += exponent;
128.1566 +
128.1567 +            // If none of the text string was recognized.  For example, parse
128.1568 +            // "x" with pattern "#0.00" (return index and error index both 0)
128.1569 +            // parse "$" with pattern "$#0.00". (return index 0 and error
128.1570 +            // index 1).
128.1571 +            if (!sawDigit && digitCount == 0) {
128.1572 +                parsePosition.index = oldStart;
128.1573 +                parsePosition.errorIndex = oldStart;
128.1574 +                return false;
128.1575 +            }
128.1576 +        }
128.1577 +
128.1578 +        // check for suffix
128.1579 +        if (!isExponent) {
128.1580 +            if (gotPositive) {
128.1581 +                gotPositive = text.regionMatches(position,positiveSuffix,0,
128.1582 +                                                 positiveSuffix.length());
128.1583 +            }
128.1584 +            if (gotNegative) {
128.1585 +                gotNegative = text.regionMatches(position,negativeSuffix,0,
128.1586 +                                                 negativeSuffix.length());
128.1587 +            }
128.1588 +
128.1589 +        // if both match, take longest
128.1590 +        if (gotPositive && gotNegative) {
128.1591 +            if (positiveSuffix.length() > negativeSuffix.length()) {
128.1592 +                gotNegative = false;
128.1593 +            } else if (positiveSuffix.length() < negativeSuffix.length()) {
128.1594 +                gotPositive = false;
128.1595 +            }
128.1596 +        }
128.1597 +
128.1598 +        // fail if neither or both
128.1599 +        if (gotPositive == gotNegative) {
128.1600 +            parsePosition.errorIndex = position;
128.1601 +            return false;
128.1602 +        }
128.1603 +
128.1604 +        parsePosition.index = position +
128.1605 +            (gotPositive ? positiveSuffix.length() : negativeSuffix.length()); // mark success!
128.1606 +        } else {
128.1607 +            parsePosition.index = position;
128.1608 +        }
128.1609 +
128.1610 +        status[STATUS_POSITIVE] = gotPositive;
128.1611 +        if (parsePosition.index == oldStart) {
128.1612 +            parsePosition.errorIndex = position;
128.1613 +            return false;
128.1614 +        }
128.1615 +        return true;
128.1616 +    }
128.1617 +
128.1618 +    /**
128.1619 +     * Returns a copy of the decimal format symbols, which is generally not
128.1620 +     * changed by the programmer or user.
128.1621 +     * @return a copy of the desired DecimalFormatSymbols
128.1622 +     * @see java.text.DecimalFormatSymbols
128.1623 +     */
128.1624 +    public DecimalFormatSymbols getDecimalFormatSymbols() {
128.1625 +        try {
128.1626 +            // don't allow multiple references
128.1627 +            return (DecimalFormatSymbols) symbols.clone();
128.1628 +        } catch (Exception foo) {
128.1629 +            return null; // should never happen
128.1630 +        }
128.1631 +    }
128.1632 +
128.1633 +
128.1634 +    /**
128.1635 +     * Sets the decimal format symbols, which is generally not changed
128.1636 +     * by the programmer or user.
128.1637 +     * @param newSymbols desired DecimalFormatSymbols
128.1638 +     * @see java.text.DecimalFormatSymbols
128.1639 +     */
128.1640 +    public void setDecimalFormatSymbols(DecimalFormatSymbols newSymbols) {
128.1641 +        try {
128.1642 +            // don't allow multiple references
128.1643 +            symbols = (DecimalFormatSymbols) newSymbols.clone();
128.1644 +            expandAffixes();
128.1645 +        } catch (Exception foo) {
128.1646 +            // should never happen
128.1647 +        }
128.1648 +    }
128.1649 +
128.1650 +    /**
128.1651 +     * Get the positive prefix.
128.1652 +     * <P>Examples: +123, $123, sFr123
128.1653 +     */
128.1654 +    public String getPositivePrefix () {
128.1655 +        return positivePrefix;
128.1656 +    }
128.1657 +
128.1658 +    /**
128.1659 +     * Set the positive prefix.
128.1660 +     * <P>Examples: +123, $123, sFr123
128.1661 +     */
128.1662 +    public void setPositivePrefix (String newValue) {
128.1663 +        positivePrefix = newValue;
128.1664 +        posPrefixPattern = null;
128.1665 +        positivePrefixFieldPositions = null;
128.1666 +    }
128.1667 +
128.1668 +    /**
128.1669 +     * Returns the FieldPositions of the fields in the prefix used for
128.1670 +     * positive numbers. This is not used if the user has explicitly set
128.1671 +     * a positive prefix via <code>setPositivePrefix</code>. This is
128.1672 +     * lazily created.
128.1673 +     *
128.1674 +     * @return FieldPositions in positive prefix
128.1675 +     */
128.1676 +    private FieldPosition[] getPositivePrefixFieldPositions() {
128.1677 +        if (positivePrefixFieldPositions == null) {
128.1678 +            if (posPrefixPattern != null) {
128.1679 +                positivePrefixFieldPositions = expandAffix(posPrefixPattern);
128.1680 +            }
128.1681 +            else {
128.1682 +                positivePrefixFieldPositions = EmptyFieldPositionArray;
128.1683 +            }
128.1684 +        }
128.1685 +        return positivePrefixFieldPositions;
128.1686 +    }
128.1687 +
128.1688 +    /**
128.1689 +     * Get the negative prefix.
128.1690 +     * <P>Examples: -123, ($123) (with negative suffix), sFr-123
128.1691 +     */
128.1692 +    public String getNegativePrefix () {
128.1693 +        return negativePrefix;
128.1694 +    }
128.1695 +
128.1696 +    /**
128.1697 +     * Set the negative prefix.
128.1698 +     * <P>Examples: -123, ($123) (with negative suffix), sFr-123
128.1699 +     */
128.1700 +    public void setNegativePrefix (String newValue) {
128.1701 +        negativePrefix = newValue;
128.1702 +        negPrefixPattern = null;
128.1703 +    }
128.1704 +
128.1705 +    /**
128.1706 +     * Returns the FieldPositions of the fields in the prefix used for
128.1707 +     * negative numbers. This is not used if the user has explicitly set
128.1708 +     * a negative prefix via <code>setNegativePrefix</code>. This is
128.1709 +     * lazily created.
128.1710 +     *
128.1711 +     * @return FieldPositions in positive prefix
128.1712 +     */
128.1713 +    private FieldPosition[] getNegativePrefixFieldPositions() {
128.1714 +        if (negativePrefixFieldPositions == null) {
128.1715 +            if (negPrefixPattern != null) {
128.1716 +                negativePrefixFieldPositions = expandAffix(negPrefixPattern);
128.1717 +            }
128.1718 +            else {
128.1719 +                negativePrefixFieldPositions = EmptyFieldPositionArray;
128.1720 +            }
128.1721 +        }
128.1722 +        return negativePrefixFieldPositions;
128.1723 +    }
128.1724 +
128.1725 +    /**
128.1726 +     * Get the positive suffix.
128.1727 +     * <P>Example: 123%
128.1728 +     */
128.1729 +    public String getPositiveSuffix () {
128.1730 +        return positiveSuffix;
128.1731 +    }
128.1732 +
128.1733 +    /**
128.1734 +     * Set the positive suffix.
128.1735 +     * <P>Example: 123%
128.1736 +     */
128.1737 +    public void setPositiveSuffix (String newValue) {
128.1738 +        positiveSuffix = newValue;
128.1739 +        posSuffixPattern = null;
128.1740 +    }
128.1741 +
128.1742 +    /**
128.1743 +     * Returns the FieldPositions of the fields in the suffix used for
128.1744 +     * positive numbers. This is not used if the user has explicitly set
128.1745 +     * a positive suffix via <code>setPositiveSuffix</code>. This is
128.1746 +     * lazily created.
128.1747 +     *
128.1748 +     * @return FieldPositions in positive prefix
128.1749 +     */
128.1750 +    private FieldPosition[] getPositiveSuffixFieldPositions() {
128.1751 +        if (positiveSuffixFieldPositions == null) {
128.1752 +            if (posSuffixPattern != null) {
128.1753 +                positiveSuffixFieldPositions = expandAffix(posSuffixPattern);
128.1754 +            }
128.1755 +            else {
128.1756 +                positiveSuffixFieldPositions = EmptyFieldPositionArray;
128.1757 +            }
128.1758 +        }
128.1759 +        return positiveSuffixFieldPositions;
128.1760 +    }
128.1761 +
128.1762 +    /**
128.1763 +     * Get the negative suffix.
128.1764 +     * <P>Examples: -123%, ($123) (with positive suffixes)
128.1765 +     */
128.1766 +    public String getNegativeSuffix () {
128.1767 +        return negativeSuffix;
128.1768 +    }
128.1769 +
128.1770 +    /**
128.1771 +     * Set the negative suffix.
128.1772 +     * <P>Examples: 123%
128.1773 +     */
128.1774 +    public void setNegativeSuffix (String newValue) {
128.1775 +        negativeSuffix = newValue;
128.1776 +        negSuffixPattern = null;
128.1777 +    }
128.1778 +
128.1779 +    /**
128.1780 +     * Returns the FieldPositions of the fields in the suffix used for
128.1781 +     * negative numbers. This is not used if the user has explicitly set
128.1782 +     * a negative suffix via <code>setNegativeSuffix</code>. This is
128.1783 +     * lazily created.
128.1784 +     *
128.1785 +     * @return FieldPositions in positive prefix
128.1786 +     */
128.1787 +    private FieldPosition[] getNegativeSuffixFieldPositions() {
128.1788 +        if (negativeSuffixFieldPositions == null) {
128.1789 +            if (negSuffixPattern != null) {
128.1790 +                negativeSuffixFieldPositions = expandAffix(negSuffixPattern);
128.1791 +            }
128.1792 +            else {
128.1793 +                negativeSuffixFieldPositions = EmptyFieldPositionArray;
128.1794 +            }
128.1795 +        }
128.1796 +        return negativeSuffixFieldPositions;
128.1797 +    }
128.1798 +
128.1799 +    /**
128.1800 +     * Gets the multiplier for use in percent, per mille, and similar
128.1801 +     * formats.
128.1802 +     *
128.1803 +     * @see #setMultiplier(int)
128.1804 +     */
128.1805 +    public int getMultiplier () {
128.1806 +        return multiplier;
128.1807 +    }
128.1808 +
128.1809 +    /**
128.1810 +     * Sets the multiplier for use in percent, per mille, and similar
128.1811 +     * formats.
128.1812 +     * For a percent format, set the multiplier to 100 and the suffixes to
128.1813 +     * have '%' (for Arabic, use the Arabic percent sign).
128.1814 +     * For a per mille format, set the multiplier to 1000 and the suffixes to
128.1815 +     * have '&#92;u2030'.
128.1816 +     *
128.1817 +     * <P>Example: with multiplier 100, 1.23 is formatted as "123", and
128.1818 +     * "123" is parsed into 1.23.
128.1819 +     *
128.1820 +     * @see #getMultiplier
128.1821 +     */
128.1822 +    public void setMultiplier (int newValue) {
128.1823 +        multiplier = newValue;
128.1824 +        bigDecimalMultiplier = null;
128.1825 +        bigIntegerMultiplier = null;
128.1826 +    }
128.1827 +
128.1828 +    /**
128.1829 +     * Return the grouping size. Grouping size is the number of digits between
128.1830 +     * grouping separators in the integer portion of a number.  For example,
128.1831 +     * in the number "123,456.78", the grouping size is 3.
128.1832 +     * @see #setGroupingSize
128.1833 +     * @see java.text.NumberFormat#isGroupingUsed
128.1834 +     * @see java.text.DecimalFormatSymbols#getGroupingSeparator
128.1835 +     */
128.1836 +    public int getGroupingSize () {
128.1837 +        return groupingSize;
128.1838 +    }
128.1839 +
128.1840 +    /**
128.1841 +     * Set the grouping size. Grouping size is the number of digits between
128.1842 +     * grouping separators in the integer portion of a number.  For example,
128.1843 +     * in the number "123,456.78", the grouping size is 3.
128.1844 +     * <br>
128.1845 +     * The value passed in is converted to a byte, which may lose information.
128.1846 +     * @see #getGroupingSize
128.1847 +     * @see java.text.NumberFormat#setGroupingUsed
128.1848 +     * @see java.text.DecimalFormatSymbols#setGroupingSeparator
128.1849 +     */
128.1850 +    public void setGroupingSize (int newValue) {
128.1851 +        groupingSize = (byte)newValue;
128.1852 +    }
128.1853 +
128.1854 +    /**
128.1855 +     * Allows you to get the behavior of the decimal separator with integers.
128.1856 +     * (The decimal separator will always appear with decimals.)
128.1857 +     * <P>Example: Decimal ON: 12345 -> 12345.; OFF: 12345 -> 12345
128.1858 +     */
128.1859 +    public boolean isDecimalSeparatorAlwaysShown() {
128.1860 +        return decimalSeparatorAlwaysShown;
128.1861 +    }
128.1862 +
128.1863 +    /**
128.1864 +     * Allows you to set the behavior of the decimal separator with integers.
128.1865 +     * (The decimal separator will always appear with decimals.)
128.1866 +     * <P>Example: Decimal ON: 12345 -> 12345.; OFF: 12345 -> 12345
128.1867 +     */
128.1868 +    public void setDecimalSeparatorAlwaysShown(boolean newValue) {
128.1869 +        decimalSeparatorAlwaysShown = newValue;
128.1870 +    }
128.1871 +
128.1872 +    /**
128.1873 +     * Returns whether the {@link #parse(java.lang.String, java.text.ParsePosition)}
128.1874 +     * method returns <code>BigDecimal</code>. The default value is false.
128.1875 +     * @see #setParseBigDecimal
128.1876 +     * @since 1.5
128.1877 +     */
128.1878 +    public boolean isParseBigDecimal() {
128.1879 +        return parseBigDecimal;
128.1880 +    }
128.1881 +
128.1882 +    /**
128.1883 +     * Sets whether the {@link #parse(java.lang.String, java.text.ParsePosition)}
128.1884 +     * method returns <code>BigDecimal</code>.
128.1885 +     * @see #isParseBigDecimal
128.1886 +     * @since 1.5
128.1887 +     */
128.1888 +    public void setParseBigDecimal(boolean newValue) {
128.1889 +        parseBigDecimal = newValue;
128.1890 +    }
128.1891 +
128.1892 +    /**
128.1893 +     * Standard override; no change in semantics.
128.1894 +     */
128.1895 +    public Object clone() {
128.1896 +        try {
128.1897 +            DecimalFormat other = (DecimalFormat) super.clone();
128.1898 +            other.symbols = (DecimalFormatSymbols) symbols.clone();
128.1899 +            other.digitList = (DigitList) digitList.clone();
128.1900 +            return other;
128.1901 +        } catch (Exception e) {
128.1902 +            throw new InternalError();
128.1903 +        }
128.1904 +    }
128.1905 +
128.1906 +    /**
128.1907 +     * Overrides equals
128.1908 +     */
128.1909 +    public boolean equals(Object obj)
128.1910 +    {
128.1911 +        if (obj == null) return false;
128.1912 +        if (!super.equals(obj)) return false; // super does class check
128.1913 +        DecimalFormat other = (DecimalFormat) obj;
128.1914 +        return ((posPrefixPattern == other.posPrefixPattern &&
128.1915 +                 positivePrefix.equals(other.positivePrefix))
128.1916 +                || (posPrefixPattern != null &&
128.1917 +                    posPrefixPattern.equals(other.posPrefixPattern)))
128.1918 +            && ((posSuffixPattern == other.posSuffixPattern &&
128.1919 +                 positiveSuffix.equals(other.positiveSuffix))
128.1920 +                || (posSuffixPattern != null &&
128.1921 +                    posSuffixPattern.equals(other.posSuffixPattern)))
128.1922 +            && ((negPrefixPattern == other.negPrefixPattern &&
128.1923 +                 negativePrefix.equals(other.negativePrefix))
128.1924 +                || (negPrefixPattern != null &&
128.1925 +                    negPrefixPattern.equals(other.negPrefixPattern)))
128.1926 +            && ((negSuffixPattern == other.negSuffixPattern &&
128.1927 +                 negativeSuffix.equals(other.negativeSuffix))
128.1928 +                || (negSuffixPattern != null &&
128.1929 +                    negSuffixPattern.equals(other.negSuffixPattern)))
128.1930 +            && multiplier == other.multiplier
128.1931 +            && groupingSize == other.groupingSize
128.1932 +            && decimalSeparatorAlwaysShown == other.decimalSeparatorAlwaysShown
128.1933 +            && parseBigDecimal == other.parseBigDecimal
128.1934 +            && useExponentialNotation == other.useExponentialNotation
128.1935 +            && (!useExponentialNotation ||
128.1936 +                minExponentDigits == other.minExponentDigits)
128.1937 +            && maximumIntegerDigits == other.maximumIntegerDigits
128.1938 +            && minimumIntegerDigits == other.minimumIntegerDigits
128.1939 +            && maximumFractionDigits == other.maximumFractionDigits
128.1940 +            && minimumFractionDigits == other.minimumFractionDigits
128.1941 +            && roundingMode == other.roundingMode
128.1942 +            && symbols.equals(other.symbols);
128.1943 +    }
128.1944 +
128.1945 +    /**
128.1946 +     * Overrides hashCode
128.1947 +     */
128.1948 +    public int hashCode() {
128.1949 +        return super.hashCode() * 37 + positivePrefix.hashCode();
128.1950 +        // just enough fields for a reasonable distribution
128.1951 +    }
128.1952 +
128.1953 +    /**
128.1954 +     * Synthesizes a pattern string that represents the current state
128.1955 +     * of this Format object.
128.1956 +     * @see #applyPattern
128.1957 +     */
128.1958 +    public String toPattern() {
128.1959 +        return toPattern( false );
128.1960 +    }
128.1961 +
128.1962 +    /**
128.1963 +     * Synthesizes a localized pattern string that represents the current
128.1964 +     * state of this Format object.
128.1965 +     * @see #applyPattern
128.1966 +     */
128.1967 +    public String toLocalizedPattern() {
128.1968 +        return toPattern( true );
128.1969 +    }
128.1970 +
128.1971 +    /**
128.1972 +     * Expand the affix pattern strings into the expanded affix strings.  If any
128.1973 +     * affix pattern string is null, do not expand it.  This method should be
128.1974 +     * called any time the symbols or the affix patterns change in order to keep
128.1975 +     * the expanded affix strings up to date.
128.1976 +     */
128.1977 +    private void expandAffixes() {
128.1978 +        // Reuse one StringBuffer for better performance
128.1979 +        StringBuffer buffer = new StringBuffer();
128.1980 +        if (posPrefixPattern != null) {
128.1981 +            positivePrefix = expandAffix(posPrefixPattern, buffer);
128.1982 +            positivePrefixFieldPositions = null;
128.1983 +        }
128.1984 +        if (posSuffixPattern != null) {
128.1985 +            positiveSuffix = expandAffix(posSuffixPattern, buffer);
128.1986 +            positiveSuffixFieldPositions = null;
128.1987 +        }
128.1988 +        if (negPrefixPattern != null) {
128.1989 +            negativePrefix = expandAffix(negPrefixPattern, buffer);
128.1990 +            negativePrefixFieldPositions = null;
128.1991 +        }
128.1992 +        if (negSuffixPattern != null) {
128.1993 +            negativeSuffix = expandAffix(negSuffixPattern, buffer);
128.1994 +            negativeSuffixFieldPositions = null;
128.1995 +        }
128.1996 +    }
128.1997 +
128.1998 +    /**
128.1999 +     * Expand an affix pattern into an affix string.  All characters in the
128.2000 +     * pattern are literal unless prefixed by QUOTE.  The following characters
128.2001 +     * after QUOTE are recognized: PATTERN_PERCENT, PATTERN_PER_MILLE,
128.2002 +     * PATTERN_MINUS, and CURRENCY_SIGN.  If CURRENCY_SIGN is doubled (QUOTE +
128.2003 +     * CURRENCY_SIGN + CURRENCY_SIGN), it is interpreted as an ISO 4217
128.2004 +     * currency code.  Any other character after a QUOTE represents itself.
128.2005 +     * QUOTE must be followed by another character; QUOTE may not occur by
128.2006 +     * itself at the end of the pattern.
128.2007 +     *
128.2008 +     * @param pattern the non-null, possibly empty pattern
128.2009 +     * @param buffer a scratch StringBuffer; its contents will be lost
128.2010 +     * @return the expanded equivalent of pattern
128.2011 +     */
128.2012 +    private String expandAffix(String pattern, StringBuffer buffer) {
128.2013 +        buffer.setLength(0);
128.2014 +        for (int i=0; i<pattern.length(); ) {
128.2015 +            char c = pattern.charAt(i++);
128.2016 +            if (c == QUOTE) {
128.2017 +                c = pattern.charAt(i++);
128.2018 +                switch (c) {
128.2019 +                case CURRENCY_SIGN:
128.2020 +                    if (i<pattern.length() &&
128.2021 +                        pattern.charAt(i) == CURRENCY_SIGN) {
128.2022 +                        ++i;
128.2023 +                        buffer.append(symbols.getInternationalCurrencySymbol());
128.2024 +                    } else {
128.2025 +                        buffer.append(symbols.getCurrencySymbol());
128.2026 +                    }
128.2027 +                    continue;
128.2028 +                case PATTERN_PERCENT:
128.2029 +                    c = symbols.getPercent();
128.2030 +                    break;
128.2031 +                case PATTERN_PER_MILLE:
128.2032 +                    c = symbols.getPerMill();
128.2033 +                    break;
128.2034 +                case PATTERN_MINUS:
128.2035 +                    c = symbols.getMinusSign();
128.2036 +                    break;
128.2037 +                }
128.2038 +            }
128.2039 +            buffer.append(c);
128.2040 +        }
128.2041 +        return buffer.toString();
128.2042 +    }
128.2043 +
128.2044 +    /**
128.2045 +     * Expand an affix pattern into an array of FieldPositions describing
128.2046 +     * how the pattern would be expanded.
128.2047 +     * All characters in the
128.2048 +     * pattern are literal unless prefixed by QUOTE.  The following characters
128.2049 +     * after QUOTE are recognized: PATTERN_PERCENT, PATTERN_PER_MILLE,
128.2050 +     * PATTERN_MINUS, and CURRENCY_SIGN.  If CURRENCY_SIGN is doubled (QUOTE +
128.2051 +     * CURRENCY_SIGN + CURRENCY_SIGN), it is interpreted as an ISO 4217
128.2052 +     * currency code.  Any other character after a QUOTE represents itself.
128.2053 +     * QUOTE must be followed by another character; QUOTE may not occur by
128.2054 +     * itself at the end of the pattern.
128.2055 +     *
128.2056 +     * @param pattern the non-null, possibly empty pattern
128.2057 +     * @return FieldPosition array of the resulting fields.
128.2058 +     */
128.2059 +    private FieldPosition[] expandAffix(String pattern) {
128.2060 +        ArrayList positions = null;
128.2061 +        int stringIndex = 0;
128.2062 +        for (int i=0; i<pattern.length(); ) {
128.2063 +            char c = pattern.charAt(i++);
128.2064 +            if (c == QUOTE) {
128.2065 +                int field = -1;
128.2066 +                Format.Field fieldID = null;
128.2067 +                c = pattern.charAt(i++);
128.2068 +                switch (c) {
128.2069 +                case CURRENCY_SIGN:
128.2070 +                    String string;
128.2071 +                    if (i<pattern.length() &&
128.2072 +                        pattern.charAt(i) == CURRENCY_SIGN) {
128.2073 +                        ++i;
128.2074 +                        string = symbols.getInternationalCurrencySymbol();
128.2075 +                    } else {
128.2076 +                        string = symbols.getCurrencySymbol();
128.2077 +                    }
128.2078 +                    if (string.length() > 0) {
128.2079 +                        if (positions == null) {
128.2080 +                            positions = new ArrayList(2);
128.2081 +                        }
128.2082 +                        FieldPosition fp = new FieldPosition(Field.CURRENCY);
128.2083 +                        fp.setBeginIndex(stringIndex);
128.2084 +                        fp.setEndIndex(stringIndex + string.length());
128.2085 +                        positions.add(fp);
128.2086 +                        stringIndex += string.length();
128.2087 +                    }
128.2088 +                    continue;
128.2089 +                case PATTERN_PERCENT:
128.2090 +                    c = symbols.getPercent();
128.2091 +                    field = -1;
128.2092 +                    fieldID = Field.PERCENT;
128.2093 +                    break;
128.2094 +                case PATTERN_PER_MILLE:
128.2095 +                    c = symbols.getPerMill();
128.2096 +                    field = -1;
128.2097 +                    fieldID = Field.PERMILLE;
128.2098 +                    break;
128.2099 +                case PATTERN_MINUS:
128.2100 +                    c = symbols.getMinusSign();
128.2101 +                    field = -1;
128.2102 +                    fieldID = Field.SIGN;
128.2103 +                    break;
128.2104 +                }
128.2105 +                if (fieldID != null) {
128.2106 +                    if (positions == null) {
128.2107 +                        positions = new ArrayList(2);
128.2108 +                    }
128.2109 +                    FieldPosition fp = new FieldPosition(fieldID, field);
128.2110 +                    fp.setBeginIndex(stringIndex);
128.2111 +                    fp.setEndIndex(stringIndex + 1);
128.2112 +                    positions.add(fp);
128.2113 +                }
128.2114 +            }
128.2115 +            stringIndex++;
128.2116 +        }
128.2117 +        if (positions != null) {
128.2118 +            return (FieldPosition[])positions.toArray(EmptyFieldPositionArray);
128.2119 +        }
128.2120 +        return EmptyFieldPositionArray;
128.2121 +    }
128.2122 +
128.2123 +    /**
128.2124 +     * Appends an affix pattern to the given StringBuffer, quoting special
128.2125 +     * characters as needed.  Uses the internal affix pattern, if that exists,
128.2126 +     * or the literal affix, if the internal affix pattern is null.  The
128.2127 +     * appended string will generate the same affix pattern (or literal affix)
128.2128 +     * when passed to toPattern().
128.2129 +     *
128.2130 +     * @param buffer the affix string is appended to this
128.2131 +     * @param affixPattern a pattern such as posPrefixPattern; may be null
128.2132 +     * @param expAffix a corresponding expanded affix, such as positivePrefix.
128.2133 +     * Ignored unless affixPattern is null.  If affixPattern is null, then
128.2134 +     * expAffix is appended as a literal affix.
128.2135 +     * @param localized true if the appended pattern should contain localized
128.2136 +     * pattern characters; otherwise, non-localized pattern chars are appended
128.2137 +     */
128.2138 +    private void appendAffix(StringBuffer buffer, String affixPattern,
128.2139 +                             String expAffix, boolean localized) {
128.2140 +        if (affixPattern == null) {
128.2141 +            appendAffix(buffer, expAffix, localized);
128.2142 +        } else {
128.2143 +            int i;
128.2144 +            for (int pos=0; pos<affixPattern.length(); pos=i) {
128.2145 +                i = affixPattern.indexOf(QUOTE, pos);
128.2146 +                if (i < 0) {
128.2147 +                    appendAffix(buffer, affixPattern.substring(pos), localized);
128.2148 +                    break;
128.2149 +                }
128.2150 +                if (i > pos) {
128.2151 +                    appendAffix(buffer, affixPattern.substring(pos, i), localized);
128.2152 +                }
128.2153 +                char c = affixPattern.charAt(++i);
128.2154 +                ++i;
128.2155 +                if (c == QUOTE) {
128.2156 +                    buffer.append(c);
128.2157 +                    // Fall through and append another QUOTE below
128.2158 +                } else if (c == CURRENCY_SIGN &&
128.2159 +                           i<affixPattern.length() &&
128.2160 +                           affixPattern.charAt(i) == CURRENCY_SIGN) {
128.2161 +                    ++i;
128.2162 +                    buffer.append(c);
128.2163 +                    // Fall through and append another CURRENCY_SIGN below
128.2164 +                } else if (localized) {
128.2165 +                    switch (c) {
128.2166 +                    case PATTERN_PERCENT:
128.2167 +                        c = symbols.getPercent();
128.2168 +                        break;
128.2169 +                    case PATTERN_PER_MILLE:
128.2170 +                        c = symbols.getPerMill();
128.2171 +                        break;
128.2172 +                    case PATTERN_MINUS:
128.2173 +                        c = symbols.getMinusSign();
128.2174 +                        break;
128.2175 +                    }
128.2176 +                }
128.2177 +                buffer.append(c);
128.2178 +            }
128.2179 +        }
128.2180 +    }
128.2181 +
128.2182 +    /**
128.2183 +     * Append an affix to the given StringBuffer, using quotes if
128.2184 +     * there are special characters.  Single quotes themselves must be
128.2185 +     * escaped in either case.
128.2186 +     */
128.2187 +    private void appendAffix(StringBuffer buffer, String affix, boolean localized) {
128.2188 +        boolean needQuote;
128.2189 +        if (localized) {
128.2190 +            needQuote = affix.indexOf(symbols.getZeroDigit()) >= 0
128.2191 +                || affix.indexOf(symbols.getGroupingSeparator()) >= 0
128.2192 +                || affix.indexOf(symbols.getDecimalSeparator()) >= 0
128.2193 +                || affix.indexOf(symbols.getPercent()) >= 0
128.2194 +                || affix.indexOf(symbols.getPerMill()) >= 0
128.2195 +                || affix.indexOf(symbols.getDigit()) >= 0
128.2196 +                || affix.indexOf(symbols.getPatternSeparator()) >= 0
128.2197 +                || affix.indexOf(symbols.getMinusSign()) >= 0
128.2198 +                || affix.indexOf(CURRENCY_SIGN) >= 0;
128.2199 +        }
128.2200 +        else {
128.2201 +            needQuote = affix.indexOf(PATTERN_ZERO_DIGIT) >= 0
128.2202 +                || affix.indexOf(PATTERN_GROUPING_SEPARATOR) >= 0
128.2203 +                || affix.indexOf(PATTERN_DECIMAL_SEPARATOR) >= 0
128.2204 +                || affix.indexOf(PATTERN_PERCENT) >= 0
128.2205 +                || affix.indexOf(PATTERN_PER_MILLE) >= 0
128.2206 +                || affix.indexOf(PATTERN_DIGIT) >= 0
128.2207 +                || affix.indexOf(PATTERN_SEPARATOR) >= 0
128.2208 +                || affix.indexOf(PATTERN_MINUS) >= 0
128.2209 +                || affix.indexOf(CURRENCY_SIGN) >= 0;
128.2210 +        }
128.2211 +        if (needQuote) buffer.append('\'');
128.2212 +        if (affix.indexOf('\'') < 0) buffer.append(affix);
128.2213 +        else {
128.2214 +            for (int j=0; j<affix.length(); ++j) {
128.2215 +                char c = affix.charAt(j);
128.2216 +                buffer.append(c);
128.2217 +                if (c == '\'') buffer.append(c);
128.2218 +            }
128.2219 +        }
128.2220 +        if (needQuote) buffer.append('\'');
128.2221 +    }
128.2222 +
128.2223 +    /**
128.2224 +     * Does the real work of generating a pattern.  */
128.2225 +    private String toPattern(boolean localized) {
128.2226 +        StringBuffer result = new StringBuffer();
128.2227 +        for (int j = 1; j >= 0; --j) {
128.2228 +            if (j == 1)
128.2229 +                appendAffix(result, posPrefixPattern, positivePrefix, localized);
128.2230 +            else appendAffix(result, negPrefixPattern, negativePrefix, localized);
128.2231 +            int i;
128.2232 +            int digitCount = useExponentialNotation
128.2233 +                        ? getMaximumIntegerDigits()
128.2234 +                        : Math.max(groupingSize, getMinimumIntegerDigits())+1;
128.2235 +            for (i = digitCount; i > 0; --i) {
128.2236 +                if (i != digitCount && isGroupingUsed() && groupingSize != 0 &&
128.2237 +                    i % groupingSize == 0) {
128.2238 +                    result.append(localized ? symbols.getGroupingSeparator() :
128.2239 +                                  PATTERN_GROUPING_SEPARATOR);
128.2240 +                }
128.2241 +                result.append(i <= getMinimumIntegerDigits()
128.2242 +                    ? (localized ? symbols.getZeroDigit() : PATTERN_ZERO_DIGIT)
128.2243 +                    : (localized ? symbols.getDigit() : PATTERN_DIGIT));
128.2244 +            }
128.2245 +            if (getMaximumFractionDigits() > 0 || decimalSeparatorAlwaysShown)
128.2246 +                result.append(localized ? symbols.getDecimalSeparator() :
128.2247 +                              PATTERN_DECIMAL_SEPARATOR);
128.2248 +            for (i = 0; i < getMaximumFractionDigits(); ++i) {
128.2249 +                if (i < getMinimumFractionDigits()) {
128.2250 +                    result.append(localized ? symbols.getZeroDigit() :
128.2251 +                                  PATTERN_ZERO_DIGIT);
128.2252 +                } else {
128.2253 +                    result.append(localized ? symbols.getDigit() :
128.2254 +                                  PATTERN_DIGIT);
128.2255 +                }
128.2256 +            }
128.2257 +        if (useExponentialNotation)
128.2258 +        {
128.2259 +            result.append(localized ? symbols.getExponentSeparator() :
128.2260 +                  PATTERN_EXPONENT);
128.2261 +        for (i=0; i<minExponentDigits; ++i)
128.2262 +                    result.append(localized ? symbols.getZeroDigit() :
128.2263 +                                  PATTERN_ZERO_DIGIT);
128.2264 +        }
128.2265 +            if (j == 1) {
128.2266 +                appendAffix(result, posSuffixPattern, positiveSuffix, localized);
128.2267 +                if ((negSuffixPattern == posSuffixPattern && // n == p == null
128.2268 +                     negativeSuffix.equals(positiveSuffix))
128.2269 +                    || (negSuffixPattern != null &&
128.2270 +                        negSuffixPattern.equals(posSuffixPattern))) {
128.2271 +                    if ((negPrefixPattern != null && posPrefixPattern != null &&
128.2272 +                         negPrefixPattern.equals("'-" + posPrefixPattern)) ||
128.2273 +                        (negPrefixPattern == posPrefixPattern && // n == p == null
128.2274 +                         negativePrefix.equals(symbols.getMinusSign() + positivePrefix)))
128.2275 +                        break;
128.2276 +                }
128.2277 +                result.append(localized ? symbols.getPatternSeparator() :
128.2278 +                              PATTERN_SEPARATOR);
128.2279 +            } else appendAffix(result, negSuffixPattern, negativeSuffix, localized);
128.2280 +        }
128.2281 +        return result.toString();
128.2282 +    }
128.2283 +
128.2284 +    /**
128.2285 +     * Apply the given pattern to this Format object.  A pattern is a
128.2286 +     * short-hand specification for the various formatting properties.
128.2287 +     * These properties can also be changed individually through the
128.2288 +     * various setter methods.
128.2289 +     * <p>
128.2290 +     * There is no limit to integer digits set
128.2291 +     * by this routine, since that is the typical end-user desire;
128.2292 +     * use setMaximumInteger if you want to set a real value.
128.2293 +     * For negative numbers, use a second pattern, separated by a semicolon
128.2294 +     * <P>Example <code>"#,#00.0#"</code> -> 1,234.56
128.2295 +     * <P>This means a minimum of 2 integer digits, 1 fraction digit, and
128.2296 +     * a maximum of 2 fraction digits.
128.2297 +     * <p>Example: <code>"#,#00.0#;(#,#00.0#)"</code> for negatives in
128.2298 +     * parentheses.
128.2299 +     * <p>In negative patterns, the minimum and maximum counts are ignored;
128.2300 +     * these are presumed to be set in the positive pattern.
128.2301 +     *
128.2302 +     * @exception NullPointerException if <code>pattern</code> is null
128.2303 +     * @exception IllegalArgumentException if the given pattern is invalid.
128.2304 +     */
128.2305 +    public void applyPattern(String pattern) {
128.2306 +        applyPattern(pattern, false);
128.2307 +    }
128.2308 +
128.2309 +    /**
128.2310 +     * Apply the given pattern to this Format object.  The pattern
128.2311 +     * is assumed to be in a localized notation. A pattern is a
128.2312 +     * short-hand specification for the various formatting properties.
128.2313 +     * These properties can also be changed individually through the
128.2314 +     * various setter methods.
128.2315 +     * <p>
128.2316 +     * There is no limit to integer digits set
128.2317 +     * by this routine, since that is the typical end-user desire;
128.2318 +     * use setMaximumInteger if you want to set a real value.
128.2319 +     * For negative numbers, use a second pattern, separated by a semicolon
128.2320 +     * <P>Example <code>"#,#00.0#"</code> -> 1,234.56
128.2321 +     * <P>This means a minimum of 2 integer digits, 1 fraction digit, and
128.2322 +     * a maximum of 2 fraction digits.
128.2323 +     * <p>Example: <code>"#,#00.0#;(#,#00.0#)"</code> for negatives in
128.2324 +     * parentheses.
128.2325 +     * <p>In negative patterns, the minimum and maximum counts are ignored;
128.2326 +     * these are presumed to be set in the positive pattern.
128.2327 +     *
128.2328 +     * @exception NullPointerException if <code>pattern</code> is null
128.2329 +     * @exception IllegalArgumentException if the given pattern is invalid.
128.2330 +     */
128.2331 +    public void applyLocalizedPattern(String pattern) {
128.2332 +        applyPattern(pattern, true);
128.2333 +    }
128.2334 +
128.2335 +    /**
128.2336 +     * Does the real work of applying a pattern.
128.2337 +     */
128.2338 +    private void applyPattern(String pattern, boolean localized) {
128.2339 +        char zeroDigit         = PATTERN_ZERO_DIGIT;
128.2340 +        char groupingSeparator = PATTERN_GROUPING_SEPARATOR;
128.2341 +        char decimalSeparator  = PATTERN_DECIMAL_SEPARATOR;
128.2342 +        char percent           = PATTERN_PERCENT;
128.2343 +        char perMill           = PATTERN_PER_MILLE;
128.2344 +        char digit             = PATTERN_DIGIT;
128.2345 +        char separator         = PATTERN_SEPARATOR;
128.2346 +        String exponent          = PATTERN_EXPONENT;
128.2347 +        char minus             = PATTERN_MINUS;
128.2348 +        if (localized) {
128.2349 +            zeroDigit         = symbols.getZeroDigit();
128.2350 +            groupingSeparator = symbols.getGroupingSeparator();
128.2351 +            decimalSeparator  = symbols.getDecimalSeparator();
128.2352 +            percent           = symbols.getPercent();
128.2353 +            perMill           = symbols.getPerMill();
128.2354 +            digit             = symbols.getDigit();
128.2355 +            separator         = symbols.getPatternSeparator();
128.2356 +            exponent          = symbols.getExponentSeparator();
128.2357 +            minus             = symbols.getMinusSign();
128.2358 +        }
128.2359 +        boolean gotNegative = false;
128.2360 +        decimalSeparatorAlwaysShown = false;
128.2361 +        isCurrencyFormat = false;
128.2362 +        useExponentialNotation = false;
128.2363 +
128.2364 +        // Two variables are used to record the subrange of the pattern
128.2365 +        // occupied by phase 1.  This is used during the processing of the
128.2366 +        // second pattern (the one representing negative numbers) to ensure
128.2367 +        // that no deviation exists in phase 1 between the two patterns.
128.2368 +        int phaseOneStart = 0;
128.2369 +        int phaseOneLength = 0;
128.2370 +
128.2371 +        int start = 0;
128.2372 +        for (int j = 1; j >= 0 && start < pattern.length(); --j) {
128.2373 +            boolean inQuote = false;
128.2374 +            StringBuffer prefix = new StringBuffer();
128.2375 +            StringBuffer suffix = new StringBuffer();
128.2376 +            int decimalPos = -1;
128.2377 +            int multiplier = 1;
128.2378 +            int digitLeftCount = 0, zeroDigitCount = 0, digitRightCount = 0;
128.2379 +            byte groupingCount = -1;
128.2380 +
128.2381 +            // The phase ranges from 0 to 2.  Phase 0 is the prefix.  Phase 1 is
128.2382 +            // the section of the pattern with digits, decimal separator,
128.2383 +            // grouping characters.  Phase 2 is the suffix.  In phases 0 and 2,
128.2384 +            // percent, per mille, and currency symbols are recognized and
128.2385 +            // translated.  The separation of the characters into phases is
128.2386 +            // strictly enforced; if phase 1 characters are to appear in the
128.2387 +            // suffix, for example, they must be quoted.
128.2388 +            int phase = 0;
128.2389 +
128.2390 +            // The affix is either the prefix or the suffix.
128.2391 +            StringBuffer affix = prefix;
128.2392 +
128.2393 +            for (int pos = start; pos < pattern.length(); ++pos) {
128.2394 +                char ch = pattern.charAt(pos);
128.2395 +                switch (phase) {
128.2396 +                case 0:
128.2397 +                case 2:
128.2398 +                    // Process the prefix / suffix characters
128.2399 +                    if (inQuote) {
128.2400 +                        // A quote within quotes indicates either the closing
128.2401 +                        // quote or two quotes, which is a quote literal. That
128.2402 +                        // is, we have the second quote in 'do' or 'don''t'.
128.2403 +                        if (ch == QUOTE) {
128.2404 +                            if ((pos+1) < pattern.length() &&
128.2405 +                                pattern.charAt(pos+1) == QUOTE) {
128.2406 +                                ++pos;
128.2407 +                                affix.append("''"); // 'don''t'
128.2408 +                            } else {
128.2409 +                                inQuote = false; // 'do'
128.2410 +                            }
128.2411 +                            continue;
128.2412 +                        }
128.2413 +                    } else {
128.2414 +                        // Process unquoted characters seen in prefix or suffix
128.2415 +                        // phase.
128.2416 +                        if (ch == digit ||
128.2417 +                            ch == zeroDigit ||
128.2418 +                            ch == groupingSeparator ||
128.2419 +                            ch == decimalSeparator) {
128.2420 +                            phase = 1;
128.2421 +                            if (j == 1) {
128.2422 +                                phaseOneStart = pos;
128.2423 +                            }
128.2424 +                            --pos; // Reprocess this character
128.2425 +                            continue;
128.2426 +                        } else if (ch == CURRENCY_SIGN) {
128.2427 +                            // Use lookahead to determine if the currency sign
128.2428 +                            // is doubled or not.
128.2429 +                            boolean doubled = (pos + 1) < pattern.length() &&
128.2430 +                                pattern.charAt(pos + 1) == CURRENCY_SIGN;
128.2431 +                            if (doubled) { // Skip over the doubled character
128.2432 +                             ++pos;
128.2433 +                            }
128.2434 +                            isCurrencyFormat = true;
128.2435 +                            affix.append(doubled ? "'\u00A4\u00A4" : "'\u00A4");
128.2436 +                            continue;
128.2437 +                        } else if (ch == QUOTE) {
128.2438 +                            // A quote outside quotes indicates either the
128.2439 +                            // opening quote or two quotes, which is a quote
128.2440 +                            // literal. That is, we have the first quote in 'do'
128.2441 +                            // or o''clock.
128.2442 +                            if (ch == QUOTE) {
128.2443 +                                if ((pos+1) < pattern.length() &&
128.2444 +                                    pattern.charAt(pos+1) == QUOTE) {
128.2445 +                                    ++pos;
128.2446 +                                    affix.append("''"); // o''clock
128.2447 +                                } else {
128.2448 +                                    inQuote = true; // 'do'
128.2449 +                                }
128.2450 +                                continue;
128.2451 +                            }
128.2452 +                        } else if (ch == separator) {
128.2453 +                            // Don't allow separators before we see digit
128.2454 +                            // characters of phase 1, and don't allow separators
128.2455 +                            // in the second pattern (j == 0).
128.2456 +                            if (phase == 0 || j == 0) {
128.2457 +                                throw new IllegalArgumentException("Unquoted special character '" +
128.2458 +                                    ch + "' in pattern \"" + pattern + '"');
128.2459 +                            }
128.2460 +                            start = pos + 1;
128.2461 +                            pos = pattern.length();
128.2462 +                            continue;
128.2463 +                        }
128.2464 +
128.2465 +                        // Next handle characters which are appended directly.
128.2466 +                        else if (ch == percent) {
128.2467 +                            if (multiplier != 1) {
128.2468 +                                throw new IllegalArgumentException("Too many percent/per mille characters in pattern \"" +
128.2469 +                                    pattern + '"');
128.2470 +                            }
128.2471 +                            multiplier = 100;
128.2472 +                            affix.append("'%");
128.2473 +                            continue;
128.2474 +                        } else if (ch == perMill) {
128.2475 +                            if (multiplier != 1) {
128.2476 +                                throw new IllegalArgumentException("Too many percent/per mille characters in pattern \"" +
128.2477 +                                    pattern + '"');
128.2478 +                            }
128.2479 +                            multiplier = 1000;
128.2480 +                            affix.append("'\u2030");
128.2481 +                            continue;
128.2482 +                        } else if (ch == minus) {
128.2483 +                            affix.append("'-");
128.2484 +                            continue;
128.2485 +                        }
128.2486 +                    }
128.2487 +                    // Note that if we are within quotes, or if this is an
128.2488 +                    // unquoted, non-special character, then we usually fall
128.2489 +                    // through to here.
128.2490 +                    affix.append(ch);
128.2491 +                    break;
128.2492 +
128.2493 +                case 1:
128.2494 +                    // Phase one must be identical in the two sub-patterns. We
128.2495 +                    // enforce this by doing a direct comparison. While
128.2496 +                    // processing the first sub-pattern, we just record its
128.2497 +                    // length. While processing the second, we compare
128.2498 +                    // characters.
128.2499 +                    if (j == 1) {
128.2500 +                        ++phaseOneLength;
128.2501 +                    } else {
128.2502 +                        if (--phaseOneLength == 0) {
128.2503 +                            phase = 2;
128.2504 +                            affix = suffix;
128.2505 +                        }
128.2506 +                        continue;
128.2507 +                    }
128.2508 +
128.2509 +                    // Process the digits, decimal, and grouping characters. We
128.2510 +                    // record five pieces of information. We expect the digits
128.2511 +                    // to occur in the pattern ####0000.####, and we record the
128.2512 +                    // number of left digits, zero (central) digits, and right
128.2513 +                    // digits. The position of the last grouping character is
128.2514 +                    // recorded (should be somewhere within the first two blocks
128.2515 +                    // of characters), as is the position of the decimal point,
128.2516 +                    // if any (should be in the zero digits). If there is no
128.2517 +                    // decimal point, then there should be no right digits.
128.2518 +                    if (ch == digit) {
128.2519 +                        if (zeroDigitCount > 0) {
128.2520 +                            ++digitRightCount;
128.2521 +                        } else {
128.2522 +                            ++digitLeftCount;
128.2523 +                        }
128.2524 +                        if (groupingCount >= 0 && decimalPos < 0) {
128.2525 +                            ++groupingCount;
128.2526 +                        }
128.2527 +                    } else if (ch == zeroDigit) {
128.2528 +                        if (digitRightCount > 0) {
128.2529 +                            throw new IllegalArgumentException("Unexpected '0' in pattern \"" +
128.2530 +                                pattern + '"');
128.2531 +                        }
128.2532 +                        ++zeroDigitCount;
128.2533 +                        if (groupingCount >= 0 && decimalPos < 0) {
128.2534 +                            ++groupingCount;
128.2535 +                        }
128.2536 +                    } else if (ch == groupingSeparator) {
128.2537 +                        groupingCount = 0;
128.2538 +                    } else if (ch == decimalSeparator) {
128.2539 +                        if (decimalPos >= 0) {
128.2540 +                            throw new IllegalArgumentException("Multiple decimal separators in pattern \"" +
128.2541 +                                pattern + '"');
128.2542 +                        }
128.2543 +                        decimalPos = digitLeftCount + zeroDigitCount + digitRightCount;
128.2544 +                    } else if (pattern.regionMatches(pos, exponent, 0, exponent.length())){
128.2545 +                        if (useExponentialNotation) {
128.2546 +                            throw new IllegalArgumentException("Multiple exponential " +
128.2547 +                                "symbols in pattern \"" + pattern + '"');
128.2548 +                        }
128.2549 +                        useExponentialNotation = true;
128.2550 +                        minExponentDigits = 0;
128.2551 +
128.2552 +                        // Use lookahead to parse out the exponential part
128.2553 +                        // of the pattern, then jump into phase 2.
128.2554 +                        pos = pos+exponent.length();
128.2555 +                         while (pos < pattern.length() &&
128.2556 +                               pattern.charAt(pos) == zeroDigit) {
128.2557 +                            ++minExponentDigits;
128.2558 +                            ++phaseOneLength;
128.2559 +                            ++pos;
128.2560 +                        }
128.2561 +
128.2562 +                        if ((digitLeftCount + zeroDigitCount) < 1 ||
128.2563 +                            minExponentDigits < 1) {
128.2564 +                            throw new IllegalArgumentException("Malformed exponential " +
128.2565 +                                "pattern \"" + pattern + '"');
128.2566 +                        }
128.2567 +
128.2568 +                        // Transition to phase 2
128.2569 +                        phase = 2;
128.2570 +                        affix = suffix;
128.2571 +                        --pos;
128.2572 +                        continue;
128.2573 +                    } else {
128.2574 +                        phase = 2;
128.2575 +                        affix = suffix;
128.2576 +                        --pos;
128.2577 +                        --phaseOneLength;
128.2578 +                        continue;
128.2579 +                    }
128.2580 +                    break;
128.2581 +                }
128.2582 +            }
128.2583 +
128.2584 +            // Handle patterns with no '0' pattern character. These patterns
128.2585 +            // are legal, but must be interpreted.  "##.###" -> "#0.###".
128.2586 +            // ".###" -> ".0##".
128.2587 +            /* We allow patterns of the form "####" to produce a zeroDigitCount
128.2588 +             * of zero (got that?); although this seems like it might make it
128.2589 +             * possible for format() to produce empty strings, format() checks
128.2590 +             * for this condition and outputs a zero digit in this situation.
128.2591 +             * Having a zeroDigitCount of zero yields a minimum integer digits
128.2592 +             * of zero, which allows proper round-trip patterns.  That is, we
128.2593 +             * don't want "#" to become "#0" when toPattern() is called (even
128.2594 +             * though that's what it really is, semantically).
128.2595 +             */
128.2596 +            if (zeroDigitCount == 0 && digitLeftCount > 0 && decimalPos >= 0) {
128.2597 +                // Handle "###.###" and "###." and ".###"
128.2598 +                int n = decimalPos;
128.2599 +                if (n == 0) { // Handle ".###"
128.2600 +                    ++n;
128.2601 +                }
128.2602 +                digitRightCount = digitLeftCount - n;
128.2603 +                digitLeftCount = n - 1;
128.2604 +                zeroDigitCount = 1;
128.2605 +            }
128.2606 +
128.2607 +            // Do syntax checking on the digits.
128.2608 +            if ((decimalPos < 0 && digitRightCount > 0) ||
128.2609 +                (decimalPos >= 0 && (decimalPos < digitLeftCount ||
128.2610 +                 decimalPos > (digitLeftCount + zeroDigitCount))) ||
128.2611 +                 groupingCount == 0 || inQuote) {
128.2612 +                throw new IllegalArgumentException("Malformed pattern \"" +
128.2613 +                    pattern + '"');
128.2614 +            }
128.2615 +
128.2616 +            if (j == 1) {
128.2617 +                posPrefixPattern = prefix.toString();
128.2618 +                posSuffixPattern = suffix.toString();
128.2619 +                negPrefixPattern = posPrefixPattern;   // assume these for now
128.2620 +                negSuffixPattern = posSuffixPattern;
128.2621 +                int digitTotalCount = digitLeftCount + zeroDigitCount + digitRightCount;
128.2622 +                /* The effectiveDecimalPos is the position the decimal is at or
128.2623 +                 * would be at if there is no decimal. Note that if decimalPos<0,
128.2624 +                 * then digitTotalCount == digitLeftCount + zeroDigitCount.
128.2625 +                 */
128.2626 +                int effectiveDecimalPos = decimalPos >= 0 ?
128.2627 +                    decimalPos : digitTotalCount;
128.2628 +                setMinimumIntegerDigits(effectiveDecimalPos - digitLeftCount);
128.2629 +                setMaximumIntegerDigits(useExponentialNotation ?
128.2630 +                    digitLeftCount + getMinimumIntegerDigits() :
128.2631 +                    MAXIMUM_INTEGER_DIGITS);
128.2632 +                setMaximumFractionDigits(decimalPos >= 0 ?
128.2633 +                    (digitTotalCount - decimalPos) : 0);
128.2634 +                setMinimumFractionDigits(decimalPos >= 0 ?
128.2635 +                    (digitLeftCount + zeroDigitCount - decimalPos) : 0);
128.2636 +                setGroupingUsed(groupingCount > 0);
128.2637 +                this.groupingSize = (groupingCount > 0) ? groupingCount : 0;
128.2638 +                this.multiplier = multiplier;
128.2639 +                setDecimalSeparatorAlwaysShown(decimalPos == 0 ||
128.2640 +                    decimalPos == digitTotalCount);
128.2641 +            } else {
128.2642 +                negPrefixPattern = prefix.toString();
128.2643 +                negSuffixPattern = suffix.toString();
128.2644 +                gotNegative = true;
128.2645 +            }
128.2646 +        }
128.2647 +
128.2648 +        if (pattern.length() == 0) {
128.2649 +            posPrefixPattern = posSuffixPattern = "";
128.2650 +            setMinimumIntegerDigits(0);
128.2651 +            setMaximumIntegerDigits(MAXIMUM_INTEGER_DIGITS);
128.2652 +            setMinimumFractionDigits(0);
128.2653 +            setMaximumFractionDigits(MAXIMUM_FRACTION_DIGITS);
128.2654 +        }
128.2655 +
128.2656 +        // If there was no negative pattern, or if the negative pattern is
128.2657 +        // identical to the positive pattern, then prepend the minus sign to
128.2658 +        // the positive pattern to form the negative pattern.
128.2659 +        if (!gotNegative ||
128.2660 +            (negPrefixPattern.equals(posPrefixPattern)
128.2661 +             && negSuffixPattern.equals(posSuffixPattern))) {
128.2662 +            negSuffixPattern = posSuffixPattern;
128.2663 +            negPrefixPattern = "'-" + posPrefixPattern;
128.2664 +        }
128.2665 +
128.2666 +        expandAffixes();
128.2667 +    }
128.2668 +
128.2669 +    /**
128.2670 +     * Sets the maximum number of digits allowed in the integer portion of a
128.2671 +     * number.
128.2672 +     * For formatting numbers other than <code>BigInteger</code> and
128.2673 +     * <code>BigDecimal</code> objects, the lower of <code>newValue</code> and
128.2674 +     * 309 is used. Negative input values are replaced with 0.
128.2675 +     * @see NumberFormat#setMaximumIntegerDigits
128.2676 +     */
128.2677 +    public void setMaximumIntegerDigits(int newValue) {
128.2678 +        maximumIntegerDigits = Math.min(Math.max(0, newValue), MAXIMUM_INTEGER_DIGITS);
128.2679 +        super.setMaximumIntegerDigits((maximumIntegerDigits > DOUBLE_INTEGER_DIGITS) ?
128.2680 +            DOUBLE_INTEGER_DIGITS : maximumIntegerDigits);
128.2681 +        if (minimumIntegerDigits > maximumIntegerDigits) {
128.2682 +            minimumIntegerDigits = maximumIntegerDigits;
128.2683 +            super.setMinimumIntegerDigits((minimumIntegerDigits > DOUBLE_INTEGER_DIGITS) ?
128.2684 +                DOUBLE_INTEGER_DIGITS : minimumIntegerDigits);
128.2685 +        }
128.2686 +    }
128.2687 +
128.2688 +    /**
128.2689 +     * Sets the minimum number of digits allowed in the integer portion of a
128.2690 +     * number.
128.2691 +     * For formatting numbers other than <code>BigInteger</code> and
128.2692 +     * <code>BigDecimal</code> objects, the lower of <code>newValue</code> and
128.2693 +     * 309 is used. Negative input values are replaced with 0.
128.2694 +     * @see NumberFormat#setMinimumIntegerDigits
128.2695 +     */
128.2696 +    public void setMinimumIntegerDigits(int newValue) {
128.2697 +        minimumIntegerDigits = Math.min(Math.max(0, newValue), MAXIMUM_INTEGER_DIGITS);
128.2698 +        super.setMinimumIntegerDigits((minimumIntegerDigits > DOUBLE_INTEGER_DIGITS) ?
128.2699 +            DOUBLE_INTEGER_DIGITS : minimumIntegerDigits);
128.2700 +        if (minimumIntegerDigits > maximumIntegerDigits) {
128.2701 +            maximumIntegerDigits = minimumIntegerDigits;
128.2702 +            super.setMaximumIntegerDigits((maximumIntegerDigits > DOUBLE_INTEGER_DIGITS) ?
128.2703 +                DOUBLE_INTEGER_DIGITS : maximumIntegerDigits);
128.2704 +        }
128.2705 +    }
128.2706 +
128.2707 +    /**
128.2708 +     * Sets the maximum number of digits allowed in the fraction portion of a
128.2709 +     * number.
128.2710 +     * For formatting numbers other than <code>BigInteger</code> and
128.2711 +     * <code>BigDecimal</code> objects, the lower of <code>newValue</code> and
128.2712 +     * 340 is used. Negative input values are replaced with 0.
128.2713 +     * @see NumberFormat#setMaximumFractionDigits
128.2714 +     */
128.2715 +    public void setMaximumFractionDigits(int newValue) {
128.2716 +        maximumFractionDigits = Math.min(Math.max(0, newValue), MAXIMUM_FRACTION_DIGITS);
128.2717 +        super.setMaximumFractionDigits((maximumFractionDigits > DOUBLE_FRACTION_DIGITS) ?
128.2718 +            DOUBLE_FRACTION_DIGITS : maximumFractionDigits);
128.2719 +        if (minimumFractionDigits > maximumFractionDigits) {
128.2720 +            minimumFractionDigits = maximumFractionDigits;
128.2721 +            super.setMinimumFractionDigits((minimumFractionDigits > DOUBLE_FRACTION_DIGITS) ?
128.2722 +                DOUBLE_FRACTION_DIGITS : minimumFractionDigits);
128.2723 +        }
128.2724 +    }
128.2725 +
128.2726 +    /**
128.2727 +     * Sets the minimum number of digits allowed in the fraction portion of a
128.2728 +     * number.
128.2729 +     * For formatting numbers other than <code>BigInteger</code> and
128.2730 +     * <code>BigDecimal</code> objects, the lower of <code>newValue</code> and
128.2731 +     * 340 is used. Negative input values are replaced with 0.
128.2732 +     * @see NumberFormat#setMinimumFractionDigits
128.2733 +     */
128.2734 +    public void setMinimumFractionDigits(int newValue) {
128.2735 +        minimumFractionDigits = Math.min(Math.max(0, newValue), MAXIMUM_FRACTION_DIGITS);
128.2736 +        super.setMinimumFractionDigits((minimumFractionDigits > DOUBLE_FRACTION_DIGITS) ?
128.2737 +            DOUBLE_FRACTION_DIGITS : minimumFractionDigits);
128.2738 +        if (minimumFractionDigits > maximumFractionDigits) {
128.2739 +            maximumFractionDigits = minimumFractionDigits;
128.2740 +            super.setMaximumFractionDigits((maximumFractionDigits > DOUBLE_FRACTION_DIGITS) ?
128.2741 +                DOUBLE_FRACTION_DIGITS : maximumFractionDigits);
128.2742 +        }
128.2743 +    }
128.2744 +
128.2745 +    /**
128.2746 +     * Gets the maximum number of digits allowed in the integer portion of a
128.2747 +     * number.
128.2748 +     * For formatting numbers other than <code>BigInteger</code> and
128.2749 +     * <code>BigDecimal</code> objects, the lower of the return value and
128.2750 +     * 309 is used.
128.2751 +     * @see #setMaximumIntegerDigits
128.2752 +     */
128.2753 +    public int getMaximumIntegerDigits() {
128.2754 +        return maximumIntegerDigits;
128.2755 +    }
128.2756 +
128.2757 +    /**
128.2758 +     * Gets the minimum number of digits allowed in the integer portion of a
128.2759 +     * number.
128.2760 +     * For formatting numbers other than <code>BigInteger</code> and
128.2761 +     * <code>BigDecimal</code> objects, the lower of the return value and
128.2762 +     * 309 is used.
128.2763 +     * @see #setMinimumIntegerDigits
128.2764 +     */
128.2765 +    public int getMinimumIntegerDigits() {
128.2766 +        return minimumIntegerDigits;
128.2767 +    }
128.2768 +
128.2769 +    /**
128.2770 +     * Gets the maximum number of digits allowed in the fraction portion of a
128.2771 +     * number.
128.2772 +     * For formatting numbers other than <code>BigInteger</code> and
128.2773 +     * <code>BigDecimal</code> objects, the lower of the return value and
128.2774 +     * 340 is used.
128.2775 +     * @see #setMaximumFractionDigits
128.2776 +     */
128.2777 +    public int getMaximumFractionDigits() {
128.2778 +        return maximumFractionDigits;
128.2779 +    }
128.2780 +
128.2781 +    /**
128.2782 +     * Gets the minimum number of digits allowed in the fraction portion of a
128.2783 +     * number.
128.2784 +     * For formatting numbers other than <code>BigInteger</code> and
128.2785 +     * <code>BigDecimal</code> objects, the lower of the return value and
128.2786 +     * 340 is used.
128.2787 +     * @see #setMinimumFractionDigits
128.2788 +     */
128.2789 +    public int getMinimumFractionDigits() {
128.2790 +        return minimumFractionDigits;
128.2791 +    }
128.2792 +
128.2793 +    /**
128.2794 +     * Gets the currency used by this decimal format when formatting
128.2795 +     * currency values.
128.2796 +     * The currency is obtained by calling
128.2797 +     * {@link DecimalFormatSymbols#getCurrency DecimalFormatSymbols.getCurrency}
128.2798 +     * on this number format's symbols.
128.2799 +     *
128.2800 +     * @return the currency used by this decimal format, or <code>null</code>
128.2801 +     * @since 1.4
128.2802 +     */
128.2803 +    public Currency getCurrency() {
128.2804 +        return symbols.getCurrency();
128.2805 +    }
128.2806 +
128.2807 +    /**
128.2808 +     * Sets the currency used by this number format when formatting
128.2809 +     * currency values. This does not update the minimum or maximum
128.2810 +     * number of fraction digits used by the number format.
128.2811 +     * The currency is set by calling
128.2812 +     * {@link DecimalFormatSymbols#setCurrency DecimalFormatSymbols.setCurrency}
128.2813 +     * on this number format's symbols.
128.2814 +     *
128.2815 +     * @param currency the new currency to be used by this decimal format
128.2816 +     * @exception NullPointerException if <code>currency</code> is null
128.2817 +     * @since 1.4
128.2818 +     */
128.2819 +    public void setCurrency(Currency currency) {
128.2820 +        if (currency != symbols.getCurrency()) {
128.2821 +            symbols.setCurrency(currency);
128.2822 +            if (isCurrencyFormat) {
128.2823 +                expandAffixes();
128.2824 +            }
128.2825 +        }
128.2826 +    }
128.2827 +
128.2828 +    /**
128.2829 +     * Gets the {@link java.math.RoundingMode} used in this DecimalFormat.
128.2830 +     *
128.2831 +     * @return The <code>RoundingMode</code> used for this DecimalFormat.
128.2832 +     * @see #setRoundingMode(RoundingMode)
128.2833 +     * @since 1.6
128.2834 +     */
128.2835 +    public RoundingMode getRoundingMode() {
128.2836 +        return roundingMode;
128.2837 +    }
128.2838 +
128.2839 +    /**
128.2840 +     * Sets the {@link java.math.RoundingMode} used in this DecimalFormat.
128.2841 +     *
128.2842 +     * @param roundingMode The <code>RoundingMode</code> to be used
128.2843 +     * @see #getRoundingMode()
128.2844 +     * @exception NullPointerException if <code>roundingMode</code> is null.
128.2845 +     * @since 1.6
128.2846 +     */
128.2847 +    public void setRoundingMode(RoundingMode roundingMode) {
128.2848 +        if (roundingMode == null) {
128.2849 +            throw new NullPointerException();
128.2850 +        }
128.2851 +
128.2852 +        this.roundingMode = roundingMode;
128.2853 +        digitList.setRoundingMode(roundingMode);
128.2854 +    }
128.2855 +
128.2856 +    /**
128.2857 +     * Adjusts the minimum and maximum fraction digits to values that
128.2858 +     * are reasonable for the currency's default fraction digits.
128.2859 +     */
128.2860 +    void adjustForCurrencyDefaultFractionDigits() {
128.2861 +        Currency currency = symbols.getCurrency();
128.2862 +        if (currency == null) {
128.2863 +            try {
128.2864 +                currency = Currency.getInstance(symbols.getInternationalCurrencySymbol());
128.2865 +            } catch (IllegalArgumentException e) {
128.2866 +            }
128.2867 +        }
128.2868 +        if (currency != null) {
128.2869 +            int digits = currency.getDefaultFractionDigits();
128.2870 +            if (digits != -1) {
128.2871 +                int oldMinDigits = getMinimumFractionDigits();
128.2872 +                // Common patterns are "#.##", "#.00", "#".
128.2873 +                // Try to adjust all of them in a reasonable way.
128.2874 +                if (oldMinDigits == getMaximumFractionDigits()) {
128.2875 +                    setMinimumFractionDigits(digits);
128.2876 +                    setMaximumFractionDigits(digits);
128.2877 +                } else {
128.2878 +                    setMinimumFractionDigits(Math.min(digits, oldMinDigits));
128.2879 +                    setMaximumFractionDigits(digits);
128.2880 +                }
128.2881 +            }
128.2882 +        }
128.2883 +    }
128.2884 +
128.2885 +    /**
128.2886 +     * Reads the default serializable fields from the stream and performs
128.2887 +     * validations and adjustments for older serialized versions. The
128.2888 +     * validations and adjustments are:
128.2889 +     * <ol>
128.2890 +     * <li>
128.2891 +     * Verify that the superclass's digit count fields correctly reflect
128.2892 +     * the limits imposed on formatting numbers other than
128.2893 +     * <code>BigInteger</code> and <code>BigDecimal</code> objects. These
128.2894 +     * limits are stored in the superclass for serialization compatibility
128.2895 +     * with older versions, while the limits for <code>BigInteger</code> and
128.2896 +     * <code>BigDecimal</code> objects are kept in this class.
128.2897 +     * If, in the superclass, the minimum or maximum integer digit count is
128.2898 +     * larger than <code>DOUBLE_INTEGER_DIGITS</code> or if the minimum or
128.2899 +     * maximum fraction digit count is larger than
128.2900 +     * <code>DOUBLE_FRACTION_DIGITS</code>, then the stream data is invalid
128.2901 +     * and this method throws an <code>InvalidObjectException</code>.
128.2902 +     * <li>
128.2903 +     * If <code>serialVersionOnStream</code> is less than 4, initialize
128.2904 +     * <code>roundingMode</code> to {@link java.math.RoundingMode#HALF_EVEN
128.2905 +     * RoundingMode.HALF_EVEN}.  This field is new with version 4.
128.2906 +     * <li>
128.2907 +     * If <code>serialVersionOnStream</code> is less than 3, then call
128.2908 +     * the setters for the minimum and maximum integer and fraction digits with
128.2909 +     * the values of the corresponding superclass getters to initialize the
128.2910 +     * fields in this class. The fields in this class are new with version 3.
128.2911 +     * <li>
128.2912 +     * If <code>serialVersionOnStream</code> is less than 1, indicating that
128.2913 +     * the stream was written by JDK 1.1, initialize
128.2914 +     * <code>useExponentialNotation</code>
128.2915 +     * to false, since it was not present in JDK 1.1.
128.2916 +     * <li>
128.2917 +     * Set <code>serialVersionOnStream</code> to the maximum allowed value so
128.2918 +     * that default serialization will work properly if this object is streamed
128.2919 +     * out again.
128.2920 +     * </ol>
128.2921 +     *
128.2922 +     * <p>Stream versions older than 2 will not have the affix pattern variables
128.2923 +     * <code>posPrefixPattern</code> etc.  As a result, they will be initialized
128.2924 +     * to <code>null</code>, which means the affix strings will be taken as
128.2925 +     * literal values.  This is exactly what we want, since that corresponds to
128.2926 +     * the pre-version-2 behavior.
128.2927 +     */
128.2928 +    private void readObject(ObjectInputStream stream)
128.2929 +         throws IOException, ClassNotFoundException
128.2930 +    {
128.2931 +        stream.defaultReadObject();
128.2932 +        digitList = new DigitList();
128.2933 +
128.2934 +        if (serialVersionOnStream < 4) {
128.2935 +            setRoundingMode(RoundingMode.HALF_EVEN);
128.2936 +        }
128.2937 +        // We only need to check the maximum counts because NumberFormat
128.2938 +        // .readObject has already ensured that the maximum is greater than the
128.2939 +        // minimum count.
128.2940 +        if (super.getMaximumIntegerDigits() > DOUBLE_INTEGER_DIGITS ||
128.2941 +            super.getMaximumFractionDigits() > DOUBLE_FRACTION_DIGITS) {
128.2942 +            throw new InvalidObjectException("Digit count out of range");
128.2943 +        }
128.2944 +        if (serialVersionOnStream < 3) {
128.2945 +            setMaximumIntegerDigits(super.getMaximumIntegerDigits());
128.2946 +            setMinimumIntegerDigits(super.getMinimumIntegerDigits());
128.2947 +            setMaximumFractionDigits(super.getMaximumFractionDigits());
128.2948 +            setMinimumFractionDigits(super.getMinimumFractionDigits());
128.2949 +        }
128.2950 +        if (serialVersionOnStream < 1) {
128.2951 +            // Didn't have exponential fields
128.2952 +            useExponentialNotation = false;
128.2953 +        }
128.2954 +        serialVersionOnStream = currentSerialVersion;
128.2955 +    }
128.2956 +
128.2957 +    //----------------------------------------------------------------------
128.2958 +    // INSTANCE VARIABLES
128.2959 +    //----------------------------------------------------------------------
128.2960 +
128.2961 +    private transient DigitList digitList = new DigitList();
128.2962 +
128.2963 +    /**
128.2964 +     * The symbol used as a prefix when formatting positive numbers, e.g. "+".
128.2965 +     *
128.2966 +     * @serial
128.2967 +     * @see #getPositivePrefix
128.2968 +     */
128.2969 +    private String  positivePrefix = "";
128.2970 +
128.2971 +    /**
128.2972 +     * The symbol used as a suffix when formatting positive numbers.
128.2973 +     * This is often an empty string.
128.2974 +     *
128.2975 +     * @serial
128.2976 +     * @see #getPositiveSuffix
128.2977 +     */
128.2978 +    private String  positiveSuffix = "";
128.2979 +
128.2980 +    /**
128.2981 +     * The symbol used as a prefix when formatting negative numbers, e.g. "-".
128.2982 +     *
128.2983 +     * @serial
128.2984 +     * @see #getNegativePrefix
128.2985 +     */
128.2986 +    private String  negativePrefix = "-";
128.2987 +
128.2988 +    /**
128.2989 +     * The symbol used as a suffix when formatting negative numbers.
128.2990 +     * This is often an empty string.
128.2991 +     *
128.2992 +     * @serial
128.2993 +     * @see #getNegativeSuffix
128.2994 +     */
128.2995 +    private String  negativeSuffix = "";
128.2996 +
128.2997 +    /**
128.2998 +     * The prefix pattern for non-negative numbers.  This variable corresponds
128.2999 +     * to <code>positivePrefix</code>.
128.3000 +     *
128.3001 +     * <p>This pattern is expanded by the method <code>expandAffix()</code> to
128.3002 +     * <code>positivePrefix</code> to update the latter to reflect changes in
128.3003 +     * <code>symbols</code>.  If this variable is <code>null</code> then
128.3004 +     * <code>positivePrefix</code> is taken as a literal value that does not
128.3005 +     * change when <code>symbols</code> changes.  This variable is always
128.3006 +     * <code>null</code> for <code>DecimalFormat</code> objects older than
128.3007 +     * stream version 2 restored from stream.
128.3008 +     *
128.3009 +     * @serial
128.3010 +     * @since 1.3
128.3011 +     */
128.3012 +    private String posPrefixPattern;
128.3013 +
128.3014 +    /**
128.3015 +     * The suffix pattern for non-negative numbers.  This variable corresponds
128.3016 +     * to <code>positiveSuffix</code>.  This variable is analogous to
128.3017 +     * <code>posPrefixPattern</code>; see that variable for further
128.3018 +     * documentation.
128.3019 +     *
128.3020 +     * @serial
128.3021 +     * @since 1.3
128.3022 +     */
128.3023 +    private String posSuffixPattern;
128.3024 +
128.3025 +    /**
128.3026 +     * The prefix pattern for negative numbers.  This variable corresponds
128.3027 +     * to <code>negativePrefix</code>.  This variable is analogous to
128.3028 +     * <code>posPrefixPattern</code>; see that variable for further
128.3029 +     * documentation.
128.3030 +     *
128.3031 +     * @serial
128.3032 +     * @since 1.3
128.3033 +     */
128.3034 +    private String negPrefixPattern;
128.3035 +
128.3036 +    /**
128.3037 +     * The suffix pattern for negative numbers.  This variable corresponds
128.3038 +     * to <code>negativeSuffix</code>.  This variable is analogous to
128.3039 +     * <code>posPrefixPattern</code>; see that variable for further
128.3040 +     * documentation.
128.3041 +     *
128.3042 +     * @serial
128.3043 +     * @since 1.3
128.3044 +     */
128.3045 +    private String negSuffixPattern;
128.3046 +
128.3047 +    /**
128.3048 +     * The multiplier for use in percent, per mille, etc.
128.3049 +     *
128.3050 +     * @serial
128.3051 +     * @see #getMultiplier
128.3052 +     */
128.3053 +    private int     multiplier = 1;
128.3054 +
128.3055 +    /**
128.3056 +     * The number of digits between grouping separators in the integer
128.3057 +     * portion of a number.  Must be greater than 0 if
128.3058 +     * <code>NumberFormat.groupingUsed</code> is true.
128.3059 +     *
128.3060 +     * @serial
128.3061 +     * @see #getGroupingSize
128.3062 +     * @see java.text.NumberFormat#isGroupingUsed
128.3063 +     */
128.3064 +    private byte    groupingSize = 3;  // invariant, > 0 if useThousands
128.3065 +
128.3066 +    /**
128.3067 +     * If true, forces the decimal separator to always appear in a formatted
128.3068 +     * number, even if the fractional part of the number is zero.
128.3069 +     *
128.3070 +     * @serial
128.3071 +     * @see #isDecimalSeparatorAlwaysShown
128.3072 +     */
128.3073 +    private boolean decimalSeparatorAlwaysShown = false;
128.3074 +
128.3075 +    /**
128.3076 +     * If true, parse returns BigDecimal wherever possible.
128.3077 +     *
128.3078 +     * @serial
128.3079 +     * @see #isParseBigDecimal
128.3080 +     * @since 1.5
128.3081 +     */
128.3082 +    private boolean parseBigDecimal = false;
128.3083 +
128.3084 +
128.3085 +    /**
128.3086 +     * True if this object represents a currency format.  This determines
128.3087 +     * whether the monetary decimal separator is used instead of the normal one.
128.3088 +     */
128.3089 +    private transient boolean isCurrencyFormat = false;
128.3090 +
128.3091 +    /**
128.3092 +     * The <code>DecimalFormatSymbols</code> object used by this format.
128.3093 +     * It contains the symbols used to format numbers, e.g. the grouping separator,
128.3094 +     * decimal separator, and so on.
128.3095 +     *
128.3096 +     * @serial
128.3097 +     * @see #setDecimalFormatSymbols
128.3098 +     * @see java.text.DecimalFormatSymbols
128.3099 +     */
128.3100 +    private DecimalFormatSymbols symbols = null; // LIU new DecimalFormatSymbols();
128.3101 +
128.3102 +    /**
128.3103 +     * True to force the use of exponential (i.e. scientific) notation when formatting
128.3104 +     * numbers.
128.3105 +     *
128.3106 +     * @serial
128.3107 +     * @since 1.2
128.3108 +     */
128.3109 +    private boolean useExponentialNotation;  // Newly persistent in the Java 2 platform v.1.2
128.3110 +
128.3111 +    /**
128.3112 +     * FieldPositions describing the positive prefix String. This is
128.3113 +     * lazily created. Use <code>getPositivePrefixFieldPositions</code>
128.3114 +     * when needed.
128.3115 +     */
128.3116 +    private transient FieldPosition[] positivePrefixFieldPositions;
128.3117 +
128.3118 +    /**
128.3119 +     * FieldPositions describing the positive suffix String. This is
128.3120 +     * lazily created. Use <code>getPositiveSuffixFieldPositions</code>
128.3121 +     * when needed.
128.3122 +     */
128.3123 +    private transient FieldPosition[] positiveSuffixFieldPositions;
128.3124 +
128.3125 +    /**
128.3126 +     * FieldPositions describing the negative prefix String. This is
128.3127 +     * lazily created. Use <code>getNegativePrefixFieldPositions</code>
128.3128 +     * when needed.
128.3129 +     */
128.3130 +    private transient FieldPosition[] negativePrefixFieldPositions;
128.3131 +
128.3132 +    /**
128.3133 +     * FieldPositions describing the negative suffix String. This is
128.3134 +     * lazily created. Use <code>getNegativeSuffixFieldPositions</code>
128.3135 +     * when needed.
128.3136 +     */
128.3137 +    private transient FieldPosition[] negativeSuffixFieldPositions;
128.3138 +
128.3139 +    /**
128.3140 +     * The minimum number of digits used to display the exponent when a number is
128.3141 +     * formatted in exponential notation.  This field is ignored if
128.3142 +     * <code>useExponentialNotation</code> is not true.
128.3143 +     *
128.3144 +     * @serial
128.3145 +     * @since 1.2
128.3146 +     */
128.3147 +    private byte    minExponentDigits;       // Newly persistent in the Java 2 platform v.1.2
128.3148 +
128.3149 +    /**
128.3150 +     * The maximum number of digits allowed in the integer portion of a
128.3151 +     * <code>BigInteger</code> or <code>BigDecimal</code> number.
128.3152 +     * <code>maximumIntegerDigits</code> must be greater than or equal to
128.3153 +     * <code>minimumIntegerDigits</code>.
128.3154 +     *
128.3155 +     * @serial
128.3156 +     * @see #getMaximumIntegerDigits
128.3157 +     * @since 1.5
128.3158 +     */
128.3159 +    private int    maximumIntegerDigits = super.getMaximumIntegerDigits();
128.3160 +
128.3161 +    /**
128.3162 +     * The minimum number of digits allowed in the integer portion of a
128.3163 +     * <code>BigInteger</code> or <code>BigDecimal</code> number.
128.3164 +     * <code>minimumIntegerDigits</code> must be less than or equal to
128.3165 +     * <code>maximumIntegerDigits</code>.
128.3166 +     *
128.3167 +     * @serial
128.3168 +     * @see #getMinimumIntegerDigits
128.3169 +     * @since 1.5
128.3170 +     */
128.3171 +    private int    minimumIntegerDigits = super.getMinimumIntegerDigits();
128.3172 +
128.3173 +    /**
128.3174 +     * The maximum number of digits allowed in the fractional portion of a
128.3175 +     * <code>BigInteger</code> or <code>BigDecimal</code> number.
128.3176 +     * <code>maximumFractionDigits</code> must be greater than or equal to
128.3177 +     * <code>minimumFractionDigits</code>.
128.3178 +     *
128.3179 +     * @serial
128.3180 +     * @see #getMaximumFractionDigits
128.3181 +     * @since 1.5
128.3182 +     */
128.3183 +    private int    maximumFractionDigits = super.getMaximumFractionDigits();
128.3184 +
128.3185 +    /**
128.3186 +     * The minimum number of digits allowed in the fractional portion of a
128.3187 +     * <code>BigInteger</code> or <code>BigDecimal</code> number.
128.3188 +     * <code>minimumFractionDigits</code> must be less than or equal to
128.3189 +     * <code>maximumFractionDigits</code>.
128.3190 +     *
128.3191 +     * @serial
128.3192 +     * @see #getMinimumFractionDigits
128.3193 +     * @since 1.5
128.3194 +     */
128.3195 +    private int    minimumFractionDigits = super.getMinimumFractionDigits();
128.3196 +
128.3197 +    /**
128.3198 +     * The {@link java.math.RoundingMode} used in this DecimalFormat.
128.3199 +     *
128.3200 +     * @serial
128.3201 +     * @since 1.6
128.3202 +     */
128.3203 +    private RoundingMode roundingMode = RoundingMode.HALF_EVEN;
128.3204 +
128.3205 +    //----------------------------------------------------------------------
128.3206 +
128.3207 +    static final int currentSerialVersion = 4;
128.3208 +
128.3209 +    /**
128.3210 +     * The internal serial version which says which version was written.
128.3211 +     * Possible values are:
128.3212 +     * <ul>
128.3213 +     * <li><b>0</b> (default): versions before the Java 2 platform v1.2
128.3214 +     * <li><b>1</b>: version for 1.2, which includes the two new fields
128.3215 +     *      <code>useExponentialNotation</code> and
128.3216 +     *      <code>minExponentDigits</code>.
128.3217 +     * <li><b>2</b>: version for 1.3 and later, which adds four new fields:
128.3218 +     *      <code>posPrefixPattern</code>, <code>posSuffixPattern</code>,
128.3219 +     *      <code>negPrefixPattern</code>, and <code>negSuffixPattern</code>.
128.3220 +     * <li><b>3</b>: version for 1.5 and later, which adds five new fields:
128.3221 +     *      <code>maximumIntegerDigits</code>,
128.3222 +     *      <code>minimumIntegerDigits</code>,
128.3223 +     *      <code>maximumFractionDigits</code>,
128.3224 +     *      <code>minimumFractionDigits</code>, and
128.3225 +     *      <code>parseBigDecimal</code>.
128.3226 +     * <li><b>4</b>: version for 1.6 and later, which adds one new field:
128.3227 +     *      <code>roundingMode</code>.
128.3228 +     * </ul>
128.3229 +     * @since 1.2
128.3230 +     * @serial
128.3231 +     */
128.3232 +    private int serialVersionOnStream = currentSerialVersion;
128.3233 +
128.3234 +    //----------------------------------------------------------------------
128.3235 +    // CONSTANTS
128.3236 +    //----------------------------------------------------------------------
128.3237 +
128.3238 +    // Constants for characters used in programmatic (unlocalized) patterns.
128.3239 +    private static final char       PATTERN_ZERO_DIGIT         = '0';
128.3240 +    private static final char       PATTERN_GROUPING_SEPARATOR = ',';
128.3241 +    private static final char       PATTERN_DECIMAL_SEPARATOR  = '.';
128.3242 +    private static final char       PATTERN_PER_MILLE          = '\u2030';
128.3243 +    private static final char       PATTERN_PERCENT            = '%';
128.3244 +    private static final char       PATTERN_DIGIT              = '#';
128.3245 +    private static final char       PATTERN_SEPARATOR          = ';';
128.3246 +    private static final String     PATTERN_EXPONENT           = "E";
128.3247 +    private static final char       PATTERN_MINUS              = '-';
128.3248 +
128.3249 +    /**
128.3250 +     * The CURRENCY_SIGN is the standard Unicode symbol for currency.  It
128.3251 +     * is used in patterns and substituted with either the currency symbol,
128.3252 +     * or if it is doubled, with the international currency symbol.  If the
128.3253 +     * CURRENCY_SIGN is seen in a pattern, then the decimal separator is
128.3254 +     * replaced with the monetary decimal separator.
128.3255 +     *
128.3256 +     * The CURRENCY_SIGN is not localized.
128.3257 +     */
128.3258 +    private static final char       CURRENCY_SIGN = '\u00A4';
128.3259 +
128.3260 +    private static final char       QUOTE = '\'';
128.3261 +
128.3262 +    private static FieldPosition[] EmptyFieldPositionArray = new FieldPosition[0];
128.3263 +
128.3264 +    // Upper limit on integer and fraction digits for a Java double
128.3265 +    static final int DOUBLE_INTEGER_DIGITS  = 309;
128.3266 +    static final int DOUBLE_FRACTION_DIGITS = 340;
128.3267 +
128.3268 +    // Upper limit on integer and fraction digits for BigDecimal and BigInteger
128.3269 +    static final int MAXIMUM_INTEGER_DIGITS  = Integer.MAX_VALUE;
128.3270 +    static final int MAXIMUM_FRACTION_DIGITS = Integer.MAX_VALUE;
128.3271 +
128.3272 +    // Proclaim JDK 1.1 serial compatibility.
128.3273 +    static final long serialVersionUID = 864413376551465018L;
128.3274 +
128.3275 +    /**
128.3276 +     * Cache to hold the NumberPattern of a Locale.
128.3277 +     */
128.3278 +    private static final ConcurrentMap<Locale, String> cachedLocaleData
128.3279 +        = new ConcurrentHashMap<Locale, String>(3);
128.3280 +}
   129.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   129.2 +++ b/rt/emul/compact/src/main/java/java/text/DecimalFormatSymbols.java	Tue Feb 11 13:31:42 2014 +0100
   129.3 @@ -0,0 +1,834 @@
   129.4 +/*
   129.5 + * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
   129.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   129.7 + *
   129.8 + * This code is free software; you can redistribute it and/or modify it
   129.9 + * under the terms of the GNU General Public License version 2 only, as
  129.10 + * published by the Free Software Foundation.  Oracle designates this
  129.11 + * particular file as subject to the "Classpath" exception as provided
  129.12 + * by Oracle in the LICENSE file that accompanied this code.
  129.13 + *
  129.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  129.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  129.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  129.17 + * version 2 for more details (a copy is included in the LICENSE file that
  129.18 + * accompanied this code).
  129.19 + *
  129.20 + * You should have received a copy of the GNU General Public License version
  129.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  129.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  129.23 + *
  129.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  129.25 + * or visit www.oracle.com if you need additional information or have any
  129.26 + * questions.
  129.27 + */
  129.28 +
  129.29 +/*
  129.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
  129.31 + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
  129.32 + *
  129.33 + *   The original version of this source code and documentation is copyrighted
  129.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
  129.35 + * materials are provided under terms of a License Agreement between Taligent
  129.36 + * and Sun. This technology is protected by multiple US and International
  129.37 + * patents. This notice and attribution to Taligent may not be removed.
  129.38 + *   Taligent is a registered trademark of Taligent, Inc.
  129.39 + *
  129.40 + */
  129.41 +
  129.42 +package java.text;
  129.43 +
  129.44 +import java.io.IOException;
  129.45 +import java.io.ObjectInputStream;
  129.46 +import java.io.Serializable;
  129.47 +import java.util.Currency;
  129.48 +import java.util.Locale;
  129.49 +import java.util.ResourceBundle;
  129.50 +import java.util.concurrent.ConcurrentHashMap;
  129.51 +
  129.52 +/**
  129.53 + * This class represents the set of symbols (such as the decimal separator,
  129.54 + * the grouping separator, and so on) needed by <code>DecimalFormat</code>
  129.55 + * to format numbers. <code>DecimalFormat</code> creates for itself an instance of
  129.56 + * <code>DecimalFormatSymbols</code> from its locale data.  If you need to change any
  129.57 + * of these symbols, you can get the <code>DecimalFormatSymbols</code> object from
  129.58 + * your <code>DecimalFormat</code> and modify it.
  129.59 + *
  129.60 + * @see          java.util.Locale
  129.61 + * @see          DecimalFormat
  129.62 + * @author       Mark Davis
  129.63 + * @author       Alan Liu
  129.64 + */
  129.65 +
  129.66 +public class DecimalFormatSymbols implements Cloneable, Serializable {
  129.67 +
  129.68 +    /**
  129.69 +     * Create a DecimalFormatSymbols object for the default locale.
  129.70 +     * This constructor can only construct instances for the locales
  129.71 +     * supported by the Java runtime environment, not for those
  129.72 +     * supported by installed
  129.73 +     * {@link java.text.spi.DecimalFormatSymbolsProvider DecimalFormatSymbolsProvider}
  129.74 +     * implementations. For full locale coverage, use the
  129.75 +     * {@link #getInstance(Locale) getInstance} method.
  129.76 +     */
  129.77 +    public DecimalFormatSymbols() {
  129.78 +        initialize( Locale.getDefault(Locale.Category.FORMAT) );
  129.79 +    }
  129.80 +
  129.81 +    /**
  129.82 +     * Create a DecimalFormatSymbols object for the given locale.
  129.83 +     * This constructor can only construct instances for the locales
  129.84 +     * supported by the Java runtime environment, not for those
  129.85 +     * supported by installed
  129.86 +     * {@link java.text.spi.DecimalFormatSymbolsProvider DecimalFormatSymbolsProvider}
  129.87 +     * implementations. For full locale coverage, use the
  129.88 +     * {@link #getInstance(Locale) getInstance} method.
  129.89 +     *
  129.90 +     * @exception NullPointerException if <code>locale</code> is null
  129.91 +     */
  129.92 +    public DecimalFormatSymbols( Locale locale ) {
  129.93 +        initialize( locale );
  129.94 +    }
  129.95 +
  129.96 +    /**
  129.97 +     * Returns an array of all locales for which the
  129.98 +     * <code>getInstance</code> methods of this class can return
  129.99 +     * localized instances.
 129.100 +     * The returned array represents the union of locales supported by the Java
 129.101 +     * runtime and by installed
 129.102 +     * {@link java.text.spi.DecimalFormatSymbolsProvider DecimalFormatSymbolsProvider}
 129.103 +     * implementations.  It must contain at least a <code>Locale</code>
 129.104 +     * instance equal to {@link java.util.Locale#US Locale.US}.
 129.105 +     *
 129.106 +     * @return An array of locales for which localized
 129.107 +     *         <code>DecimalFormatSymbols</code> instances are available.
 129.108 +     * @since 1.6
 129.109 +     */
 129.110 +    public static Locale[] getAvailableLocales() {
 129.111 +        return new Locale[] { Locale.US };
 129.112 +//        LocaleServiceProviderPool pool =
 129.113 +//            LocaleServiceProviderPool.getPool(DecimalFormatSymbolsProvider.class);
 129.114 +//        return pool.getAvailableLocales();
 129.115 +    }
 129.116 +
 129.117 +    /**
 129.118 +     * Gets the <code>DecimalFormatSymbols</code> instance for the default
 129.119 +     * locale.  This method provides access to <code>DecimalFormatSymbols</code>
 129.120 +     * instances for locales supported by the Java runtime itself as well
 129.121 +     * as for those supported by installed
 129.122 +     * {@link java.text.spi.DecimalFormatSymbolsProvider
 129.123 +     * DecimalFormatSymbolsProvider} implementations.
 129.124 +     * @return a <code>DecimalFormatSymbols</code> instance.
 129.125 +     * @since 1.6
 129.126 +     */
 129.127 +    public static final DecimalFormatSymbols getInstance() {
 129.128 +        return getInstance(Locale.getDefault(Locale.Category.FORMAT));
 129.129 +    }
 129.130 +
 129.131 +    /**
 129.132 +     * Gets the <code>DecimalFormatSymbols</code> instance for the specified
 129.133 +     * locale.  This method provides access to <code>DecimalFormatSymbols</code>
 129.134 +     * instances for locales supported by the Java runtime itself as well
 129.135 +     * as for those supported by installed
 129.136 +     * {@link java.text.spi.DecimalFormatSymbolsProvider
 129.137 +     * DecimalFormatSymbolsProvider} implementations.
 129.138 +     * @param locale the desired locale.
 129.139 +     * @return a <code>DecimalFormatSymbols</code> instance.
 129.140 +     * @exception NullPointerException if <code>locale</code> is null
 129.141 +     * @since 1.6
 129.142 +     */
 129.143 +    public static final DecimalFormatSymbols getInstance(Locale locale) {
 129.144 +/*
 129.145 +        // Check whether a provider can provide an implementation that's closer
 129.146 +        // to the requested locale than what the Java runtime itself can provide.
 129.147 +        LocaleServiceProviderPool pool =
 129.148 +            LocaleServiceProviderPool.getPool(DecimalFormatSymbolsProvider.class);
 129.149 +        if (pool.hasProviders()) {
 129.150 +            DecimalFormatSymbols providersInstance = pool.getLocalizedObject(
 129.151 +                                DecimalFormatSymbolsGetter.INSTANCE, locale);
 129.152 +            if (providersInstance != null) {
 129.153 +                return providersInstance;
 129.154 +            }
 129.155 +        }
 129.156 +*/
 129.157 +        return new DecimalFormatSymbols(locale);
 129.158 +    }
 129.159 +
 129.160 +    /**
 129.161 +     * Gets the character used for zero. Different for Arabic, etc.
 129.162 +     */
 129.163 +    public char getZeroDigit() {
 129.164 +        return zeroDigit;
 129.165 +    }
 129.166 +
 129.167 +    /**
 129.168 +     * Sets the character used for zero. Different for Arabic, etc.
 129.169 +     */
 129.170 +    public void setZeroDigit(char zeroDigit) {
 129.171 +        this.zeroDigit = zeroDigit;
 129.172 +    }
 129.173 +
 129.174 +    /**
 129.175 +     * Gets the character used for thousands separator. Different for French, etc.
 129.176 +     */
 129.177 +    public char getGroupingSeparator() {
 129.178 +        return groupingSeparator;
 129.179 +    }
 129.180 +
 129.181 +    /**
 129.182 +     * Sets the character used for thousands separator. Different for French, etc.
 129.183 +     */
 129.184 +    public void setGroupingSeparator(char groupingSeparator) {
 129.185 +        this.groupingSeparator = groupingSeparator;
 129.186 +    }
 129.187 +
 129.188 +    /**
 129.189 +     * Gets the character used for decimal sign. Different for French, etc.
 129.190 +     */
 129.191 +    public char getDecimalSeparator() {
 129.192 +        return decimalSeparator;
 129.193 +    }
 129.194 +
 129.195 +    /**
 129.196 +     * Sets the character used for decimal sign. Different for French, etc.
 129.197 +     */
 129.198 +    public void setDecimalSeparator(char decimalSeparator) {
 129.199 +        this.decimalSeparator = decimalSeparator;
 129.200 +    }
 129.201 +
 129.202 +    /**
 129.203 +     * Gets the character used for per mille sign. Different for Arabic, etc.
 129.204 +     */
 129.205 +    public char getPerMill() {
 129.206 +        return perMill;
 129.207 +    }
 129.208 +
 129.209 +    /**
 129.210 +     * Sets the character used for per mille sign. Different for Arabic, etc.
 129.211 +     */
 129.212 +    public void setPerMill(char perMill) {
 129.213 +        this.perMill = perMill;
 129.214 +    }
 129.215 +
 129.216 +    /**
 129.217 +     * Gets the character used for percent sign. Different for Arabic, etc.
 129.218 +     */
 129.219 +    public char getPercent() {
 129.220 +        return percent;
 129.221 +    }
 129.222 +
 129.223 +    /**
 129.224 +     * Sets the character used for percent sign. Different for Arabic, etc.
 129.225 +     */
 129.226 +    public void setPercent(char percent) {
 129.227 +        this.percent = percent;
 129.228 +    }
 129.229 +
 129.230 +    /**
 129.231 +     * Gets the character used for a digit in a pattern.
 129.232 +     */
 129.233 +    public char getDigit() {
 129.234 +        return digit;
 129.235 +    }
 129.236 +
 129.237 +    /**
 129.238 +     * Sets the character used for a digit in a pattern.
 129.239 +     */
 129.240 +    public void setDigit(char digit) {
 129.241 +        this.digit = digit;
 129.242 +    }
 129.243 +
 129.244 +    /**
 129.245 +     * Gets the character used to separate positive and negative subpatterns
 129.246 +     * in a pattern.
 129.247 +     */
 129.248 +    public char getPatternSeparator() {
 129.249 +        return patternSeparator;
 129.250 +    }
 129.251 +
 129.252 +    /**
 129.253 +     * Sets the character used to separate positive and negative subpatterns
 129.254 +     * in a pattern.
 129.255 +     */
 129.256 +    public void setPatternSeparator(char patternSeparator) {
 129.257 +        this.patternSeparator = patternSeparator;
 129.258 +    }
 129.259 +
 129.260 +    /**
 129.261 +     * Gets the string used to represent infinity. Almost always left
 129.262 +     * unchanged.
 129.263 +     */
 129.264 +    public String getInfinity() {
 129.265 +        return infinity;
 129.266 +    }
 129.267 +
 129.268 +    /**
 129.269 +     * Sets the string used to represent infinity. Almost always left
 129.270 +     * unchanged.
 129.271 +     */
 129.272 +    public void setInfinity(String infinity) {
 129.273 +        this.infinity = infinity;
 129.274 +    }
 129.275 +
 129.276 +    /**
 129.277 +     * Gets the string used to represent "not a number". Almost always left
 129.278 +     * unchanged.
 129.279 +     */
 129.280 +    public String getNaN() {
 129.281 +        return NaN;
 129.282 +    }
 129.283 +
 129.284 +    /**
 129.285 +     * Sets the string used to represent "not a number". Almost always left
 129.286 +     * unchanged.
 129.287 +     */
 129.288 +    public void setNaN(String NaN) {
 129.289 +        this.NaN = NaN;
 129.290 +    }
 129.291 +
 129.292 +    /**
 129.293 +     * Gets the character used to represent minus sign. If no explicit
 129.294 +     * negative format is specified, one is formed by prefixing
 129.295 +     * minusSign to the positive format.
 129.296 +     */
 129.297 +    public char getMinusSign() {
 129.298 +        return minusSign;
 129.299 +    }
 129.300 +
 129.301 +    /**
 129.302 +     * Sets the character used to represent minus sign. If no explicit
 129.303 +     * negative format is specified, one is formed by prefixing
 129.304 +     * minusSign to the positive format.
 129.305 +     */
 129.306 +    public void setMinusSign(char minusSign) {
 129.307 +        this.minusSign = minusSign;
 129.308 +    }
 129.309 +
 129.310 +    /**
 129.311 +     * Returns the currency symbol for the currency of these
 129.312 +     * DecimalFormatSymbols in their locale.
 129.313 +     * @since 1.2
 129.314 +     */
 129.315 +    public String getCurrencySymbol()
 129.316 +    {
 129.317 +        return currencySymbol;
 129.318 +    }
 129.319 +
 129.320 +    /**
 129.321 +     * Sets the currency symbol for the currency of these
 129.322 +     * DecimalFormatSymbols in their locale.
 129.323 +     * @since 1.2
 129.324 +     */
 129.325 +    public void setCurrencySymbol(String currency)
 129.326 +    {
 129.327 +        currencySymbol = currency;
 129.328 +    }
 129.329 +
 129.330 +    /**
 129.331 +     * Returns the ISO 4217 currency code of the currency of these
 129.332 +     * DecimalFormatSymbols.
 129.333 +     * @since 1.2
 129.334 +     */
 129.335 +    public String getInternationalCurrencySymbol()
 129.336 +    {
 129.337 +        return intlCurrencySymbol;
 129.338 +    }
 129.339 +
 129.340 +    /**
 129.341 +     * Sets the ISO 4217 currency code of the currency of these
 129.342 +     * DecimalFormatSymbols.
 129.343 +     * If the currency code is valid (as defined by
 129.344 +     * {@link java.util.Currency#getInstance(java.lang.String) Currency.getInstance}),
 129.345 +     * this also sets the currency attribute to the corresponding Currency
 129.346 +     * instance and the currency symbol attribute to the currency's symbol
 129.347 +     * in the DecimalFormatSymbols' locale. If the currency code is not valid,
 129.348 +     * then the currency attribute is set to null and the currency symbol
 129.349 +     * attribute is not modified.
 129.350 +     *
 129.351 +     * @see #setCurrency
 129.352 +     * @see #setCurrencySymbol
 129.353 +     * @since 1.2
 129.354 +     */
 129.355 +    public void setInternationalCurrencySymbol(String currencyCode)
 129.356 +    {
 129.357 +        intlCurrencySymbol = currencyCode;
 129.358 +        currency = null;
 129.359 +        if (currencyCode != null) {
 129.360 +            try {
 129.361 +                currency = Currency.getInstance(currencyCode);
 129.362 +                currencySymbol = currency.getSymbol();
 129.363 +            } catch (IllegalArgumentException e) {
 129.364 +            }
 129.365 +        }
 129.366 +    }
 129.367 +
 129.368 +    /**
 129.369 +     * Gets the currency of these DecimalFormatSymbols. May be null if the
 129.370 +     * currency symbol attribute was previously set to a value that's not
 129.371 +     * a valid ISO 4217 currency code.
 129.372 +     *
 129.373 +     * @return the currency used, or null
 129.374 +     * @since 1.4
 129.375 +     */
 129.376 +    public Currency getCurrency() {
 129.377 +        return currency;
 129.378 +    }
 129.379 +
 129.380 +    /**
 129.381 +     * Sets the currency of these DecimalFormatSymbols.
 129.382 +     * This also sets the currency symbol attribute to the currency's symbol
 129.383 +     * in the DecimalFormatSymbols' locale, and the international currency
 129.384 +     * symbol attribute to the currency's ISO 4217 currency code.
 129.385 +     *
 129.386 +     * @param currency the new currency to be used
 129.387 +     * @exception NullPointerException if <code>currency</code> is null
 129.388 +     * @since 1.4
 129.389 +     * @see #setCurrencySymbol
 129.390 +     * @see #setInternationalCurrencySymbol
 129.391 +     */
 129.392 +    public void setCurrency(Currency currency) {
 129.393 +        if (currency == null) {
 129.394 +            throw new NullPointerException();
 129.395 +        }
 129.396 +        this.currency = currency;
 129.397 +        intlCurrencySymbol = currency.getCurrencyCode();
 129.398 +        currencySymbol = currency.getSymbol(locale);
 129.399 +    }
 129.400 +
 129.401 +
 129.402 +    /**
 129.403 +     * Returns the monetary decimal separator.
 129.404 +     * @since 1.2
 129.405 +     */
 129.406 +    public char getMonetaryDecimalSeparator()
 129.407 +    {
 129.408 +        return monetarySeparator;
 129.409 +    }
 129.410 +
 129.411 +    /**
 129.412 +     * Sets the monetary decimal separator.
 129.413 +     * @since 1.2
 129.414 +     */
 129.415 +    public void setMonetaryDecimalSeparator(char sep)
 129.416 +    {
 129.417 +        monetarySeparator = sep;
 129.418 +    }
 129.419 +
 129.420 +    //------------------------------------------------------------
 129.421 +    // BEGIN   Package Private methods ... to be made public later
 129.422 +    //------------------------------------------------------------
 129.423 +
 129.424 +    /**
 129.425 +     * Returns the character used to separate the mantissa from the exponent.
 129.426 +     */
 129.427 +    char getExponentialSymbol()
 129.428 +    {
 129.429 +        return exponential;
 129.430 +    }
 129.431 +  /**
 129.432 +   * Returns the string used to separate the mantissa from the exponent.
 129.433 +   * Examples: "x10^" for 1.23x10^4, "E" for 1.23E4.
 129.434 +   *
 129.435 +   * @return the exponent separator string
 129.436 +   * @see #setExponentSeparator(java.lang.String)
 129.437 +   * @since 1.6
 129.438 +   */
 129.439 +    public String getExponentSeparator()
 129.440 +    {
 129.441 +        return exponentialSeparator;
 129.442 +    }
 129.443 +
 129.444 +    /**
 129.445 +     * Sets the character used to separate the mantissa from the exponent.
 129.446 +     */
 129.447 +    void setExponentialSymbol(char exp)
 129.448 +    {
 129.449 +        exponential = exp;
 129.450 +    }
 129.451 +
 129.452 +  /**
 129.453 +   * Sets the string used to separate the mantissa from the exponent.
 129.454 +   * Examples: "x10^" for 1.23x10^4, "E" for 1.23E4.
 129.455 +   *
 129.456 +   * @param exp the exponent separator string
 129.457 +   * @exception NullPointerException if <code>exp</code> is null
 129.458 +   * @see #getExponentSeparator()
 129.459 +   * @since 1.6
 129.460 +   */
 129.461 +    public void setExponentSeparator(String exp)
 129.462 +    {
 129.463 +        if (exp == null) {
 129.464 +            throw new NullPointerException();
 129.465 +        }
 129.466 +        exponentialSeparator = exp;
 129.467 +     }
 129.468 +
 129.469 +
 129.470 +    //------------------------------------------------------------
 129.471 +    // END     Package Private methods ... to be made public later
 129.472 +    //------------------------------------------------------------
 129.473 +
 129.474 +    /**
 129.475 +     * Standard override.
 129.476 +     */
 129.477 +    public Object clone() {
 129.478 +        try {
 129.479 +            return (DecimalFormatSymbols)super.clone();
 129.480 +            // other fields are bit-copied
 129.481 +        } catch (CloneNotSupportedException e) {
 129.482 +            throw new InternalError();
 129.483 +        }
 129.484 +    }
 129.485 +
 129.486 +    /**
 129.487 +     * Override equals.
 129.488 +     */
 129.489 +    public boolean equals(Object obj) {
 129.490 +        if (obj == null) return false;
 129.491 +        if (this == obj) return true;
 129.492 +        if (getClass() != obj.getClass()) return false;
 129.493 +        DecimalFormatSymbols other = (DecimalFormatSymbols) obj;
 129.494 +        return (zeroDigit == other.zeroDigit &&
 129.495 +        groupingSeparator == other.groupingSeparator &&
 129.496 +        decimalSeparator == other.decimalSeparator &&
 129.497 +        percent == other.percent &&
 129.498 +        perMill == other.perMill &&
 129.499 +        digit == other.digit &&
 129.500 +        minusSign == other.minusSign &&
 129.501 +        patternSeparator == other.patternSeparator &&
 129.502 +        infinity.equals(other.infinity) &&
 129.503 +        NaN.equals(other.NaN) &&
 129.504 +        currencySymbol.equals(other.currencySymbol) &&
 129.505 +        intlCurrencySymbol.equals(other.intlCurrencySymbol) &&
 129.506 +        currency == other.currency &&
 129.507 +        monetarySeparator == other.monetarySeparator &&
 129.508 +        exponentialSeparator.equals(other.exponentialSeparator) &&
 129.509 +        locale.equals(other.locale));
 129.510 +    }
 129.511 +
 129.512 +    /**
 129.513 +     * Override hashCode.
 129.514 +     */
 129.515 +    public int hashCode() {
 129.516 +            int result = zeroDigit;
 129.517 +            result = result * 37 + groupingSeparator;
 129.518 +            result = result * 37 + decimalSeparator;
 129.519 +            return result;
 129.520 +    }
 129.521 +
 129.522 +    /**
 129.523 +     * Initializes the symbols from the FormatData resource bundle.
 129.524 +     */
 129.525 +    private void initialize( Locale locale ) {
 129.526 +        this.locale = locale;
 129.527 +
 129.528 +        // get resource bundle data - try the cache first
 129.529 +        boolean needCacheUpdate = false;
 129.530 +        Object[] data = cachedLocaleData.get(locale);
 129.531 +        if (data == null) {  /* cache miss */
 129.532 +            // When numbering system is thai (Locale's extension contains u-nu-thai),
 129.533 +            // we read the data from th_TH_TH.
 129.534 +            Locale lookupLocale = locale;
 129.535 +            String numberType = locale.getUnicodeLocaleType("nu");
 129.536 +            if (numberType != null && numberType.equals("thai")) {
 129.537 +                lookupLocale = new Locale("th", "TH", "TH");
 129.538 +            }
 129.539 +            data = new Object[3];
 129.540 +//            ResourceBundle rb = LocaleData.getNumberFormatData(lookupLocale);
 129.541 +//            data[0] = rb.getStringArray("NumberElements");
 129.542 +            needCacheUpdate = true;
 129.543 +        }
 129.544 +
 129.545 +        String[] numberElements = (String[]) data[0];
 129.546 +
 129.547 +        decimalSeparator = numberElements[0].charAt(0);
 129.548 +        groupingSeparator = numberElements[1].charAt(0);
 129.549 +        patternSeparator = numberElements[2].charAt(0);
 129.550 +        percent = numberElements[3].charAt(0);
 129.551 +        zeroDigit = numberElements[4].charAt(0); //different for Arabic,etc.
 129.552 +        digit = numberElements[5].charAt(0);
 129.553 +        minusSign = numberElements[6].charAt(0);
 129.554 +        exponential = numberElements[7].charAt(0);
 129.555 +        exponentialSeparator = numberElements[7]; //string representation new since 1.6
 129.556 +        perMill = numberElements[8].charAt(0);
 129.557 +        infinity  = numberElements[9];
 129.558 +        NaN = numberElements[10];
 129.559 +
 129.560 +        // Try to obtain the currency used in the locale's country.
 129.561 +        // Check for empty country string separately because it's a valid
 129.562 +        // country ID for Locale (and used for the C locale), but not a valid
 129.563 +        // ISO 3166 country code, and exceptions are expensive.
 129.564 +        if (!"".equals(locale.getCountry())) {
 129.565 +            try {
 129.566 +                currency = Currency.getInstance(locale);
 129.567 +            } catch (IllegalArgumentException e) {
 129.568 +                // use default values below for compatibility
 129.569 +            }
 129.570 +        }
 129.571 +        if (currency != null) {
 129.572 +            intlCurrencySymbol = currency.getCurrencyCode();
 129.573 +            if (data[1] != null && data[1] == intlCurrencySymbol) {
 129.574 +                currencySymbol = (String) data[2];
 129.575 +            } else {
 129.576 +                currencySymbol = currency.getSymbol(locale);
 129.577 +                data[1] = intlCurrencySymbol;
 129.578 +                data[2] = currencySymbol;
 129.579 +                needCacheUpdate = true;
 129.580 +            }
 129.581 +        } else {
 129.582 +            // default values
 129.583 +            intlCurrencySymbol = "XXX";
 129.584 +            try {
 129.585 +                currency = Currency.getInstance(intlCurrencySymbol);
 129.586 +            } catch (IllegalArgumentException e) {
 129.587 +            }
 129.588 +            currencySymbol = "\u00A4";
 129.589 +        }
 129.590 +        // Currently the monetary decimal separator is the same as the
 129.591 +        // standard decimal separator for all locales that we support.
 129.592 +        // If that changes, add a new entry to NumberElements.
 129.593 +        monetarySeparator = decimalSeparator;
 129.594 +
 129.595 +        if (needCacheUpdate) {
 129.596 +            cachedLocaleData.putIfAbsent(locale, data);
 129.597 +        }
 129.598 +    }
 129.599 +
 129.600 +    /**
 129.601 +     * Reads the default serializable fields, provides default values for objects
 129.602 +     * in older serial versions, and initializes non-serializable fields.
 129.603 +     * If <code>serialVersionOnStream</code>
 129.604 +     * is less than 1, initializes <code>monetarySeparator</code> to be
 129.605 +     * the same as <code>decimalSeparator</code> and <code>exponential</code>
 129.606 +     * to be 'E'.
 129.607 +     * If <code>serialVersionOnStream</code> is less than 2,
 129.608 +     * initializes <code>locale</code>to the root locale, and initializes
 129.609 +     * If <code>serialVersionOnStream</code> is less than 3, it initializes
 129.610 +     * <code>exponentialSeparator</code> using <code>exponential</code>.
 129.611 +     * Sets <code>serialVersionOnStream</code> back to the maximum allowed value so that
 129.612 +     * default serialization will work properly if this object is streamed out again.
 129.613 +     * Initializes the currency from the intlCurrencySymbol field.
 129.614 +     *
 129.615 +     * @since JDK 1.1.6
 129.616 +     */
 129.617 +    private void readObject(ObjectInputStream stream)
 129.618 +            throws IOException, ClassNotFoundException {
 129.619 +        stream.defaultReadObject();
 129.620 +        if (serialVersionOnStream < 1) {
 129.621 +            // Didn't have monetarySeparator or exponential field;
 129.622 +            // use defaults.
 129.623 +            monetarySeparator = decimalSeparator;
 129.624 +            exponential       = 'E';
 129.625 +        }
 129.626 +        if (serialVersionOnStream < 2) {
 129.627 +            // didn't have locale; use root locale
 129.628 +            locale = Locale.ROOT;
 129.629 +        }
 129.630 +        if (serialVersionOnStream < 3) {
 129.631 +            // didn't have exponentialSeparator. Create one using exponential
 129.632 +            exponentialSeparator = Character.toString(exponential);
 129.633 +        }
 129.634 +        serialVersionOnStream = currentSerialVersion;
 129.635 +
 129.636 +        if (intlCurrencySymbol != null) {
 129.637 +            try {
 129.638 +                 currency = Currency.getInstance(intlCurrencySymbol);
 129.639 +            } catch (IllegalArgumentException e) {
 129.640 +            }
 129.641 +        }
 129.642 +    }
 129.643 +
 129.644 +    /**
 129.645 +     * Character used for zero.
 129.646 +     *
 129.647 +     * @serial
 129.648 +     * @see #getZeroDigit
 129.649 +     */
 129.650 +    private  char    zeroDigit;
 129.651 +
 129.652 +    /**
 129.653 +     * Character used for thousands separator.
 129.654 +     *
 129.655 +     * @serial
 129.656 +     * @see #getGroupingSeparator
 129.657 +     */
 129.658 +    private  char    groupingSeparator;
 129.659 +
 129.660 +    /**
 129.661 +     * Character used for decimal sign.
 129.662 +     *
 129.663 +     * @serial
 129.664 +     * @see #getDecimalSeparator
 129.665 +     */
 129.666 +    private  char    decimalSeparator;
 129.667 +
 129.668 +    /**
 129.669 +     * Character used for per mille sign.
 129.670 +     *
 129.671 +     * @serial
 129.672 +     * @see #getPerMill
 129.673 +     */
 129.674 +    private  char    perMill;
 129.675 +
 129.676 +    /**
 129.677 +     * Character used for percent sign.
 129.678 +     * @serial
 129.679 +     * @see #getPercent
 129.680 +     */
 129.681 +    private  char    percent;
 129.682 +
 129.683 +    /**
 129.684 +     * Character used for a digit in a pattern.
 129.685 +     *
 129.686 +     * @serial
 129.687 +     * @see #getDigit
 129.688 +     */
 129.689 +    private  char    digit;
 129.690 +
 129.691 +    /**
 129.692 +     * Character used to separate positive and negative subpatterns
 129.693 +     * in a pattern.
 129.694 +     *
 129.695 +     * @serial
 129.696 +     * @see #getPatternSeparator
 129.697 +     */
 129.698 +    private  char    patternSeparator;
 129.699 +
 129.700 +    /**
 129.701 +     * String used to represent infinity.
 129.702 +     * @serial
 129.703 +     * @see #getInfinity
 129.704 +     */
 129.705 +    private  String  infinity;
 129.706 +
 129.707 +    /**
 129.708 +     * String used to represent "not a number".
 129.709 +     * @serial
 129.710 +     * @see #getNaN
 129.711 +     */
 129.712 +    private  String  NaN;
 129.713 +
 129.714 +    /**
 129.715 +     * Character used to represent minus sign.
 129.716 +     * @serial
 129.717 +     * @see #getMinusSign
 129.718 +     */
 129.719 +    private  char    minusSign;
 129.720 +
 129.721 +    /**
 129.722 +     * String denoting the local currency, e.g. "$".
 129.723 +     * @serial
 129.724 +     * @see #getCurrencySymbol
 129.725 +     */
 129.726 +    private  String  currencySymbol;
 129.727 +
 129.728 +    /**
 129.729 +     * ISO 4217 currency code denoting the local currency, e.g. "USD".
 129.730 +     * @serial
 129.731 +     * @see #getInternationalCurrencySymbol
 129.732 +     */
 129.733 +    private  String  intlCurrencySymbol;
 129.734 +
 129.735 +    /**
 129.736 +     * The decimal separator used when formatting currency values.
 129.737 +     * @serial
 129.738 +     * @since JDK 1.1.6
 129.739 +     * @see #getMonetaryDecimalSeparator
 129.740 +     */
 129.741 +    private  char    monetarySeparator; // Field new in JDK 1.1.6
 129.742 +
 129.743 +    /**
 129.744 +     * The character used to distinguish the exponent in a number formatted
 129.745 +     * in exponential notation, e.g. 'E' for a number such as "1.23E45".
 129.746 +     * <p>
 129.747 +     * Note that the public API provides no way to set this field,
 129.748 +     * even though it is supported by the implementation and the stream format.
 129.749 +     * The intent is that this will be added to the API in the future.
 129.750 +     *
 129.751 +     * @serial
 129.752 +     * @since JDK 1.1.6
 129.753 +     */
 129.754 +    private  char    exponential;       // Field new in JDK 1.1.6
 129.755 +
 129.756 +  /**
 129.757 +   * The string used to separate the mantissa from the exponent.
 129.758 +   * Examples: "x10^" for 1.23x10^4, "E" for 1.23E4.
 129.759 +   * <p>
 129.760 +   * If both <code>exponential</code> and <code>exponentialSeparator</code>
 129.761 +   * exist, this <code>exponentialSeparator</code> has the precedence.
 129.762 +   *
 129.763 +   * @serial
 129.764 +   * @since 1.6
 129.765 +   */
 129.766 +    private  String    exponentialSeparator;       // Field new in JDK 1.6
 129.767 +
 129.768 +    /**
 129.769 +     * The locale of these currency format symbols.
 129.770 +     *
 129.771 +     * @serial
 129.772 +     * @since 1.4
 129.773 +     */
 129.774 +    private Locale locale;
 129.775 +
 129.776 +    // currency; only the ISO code is serialized.
 129.777 +    private transient Currency currency;
 129.778 +
 129.779 +    // Proclaim JDK 1.1 FCS compatibility
 129.780 +    static final long serialVersionUID = 5772796243397350300L;
 129.781 +
 129.782 +    // The internal serial version which says which version was written
 129.783 +    // - 0 (default) for version up to JDK 1.1.5
 129.784 +    // - 1 for version from JDK 1.1.6, which includes two new fields:
 129.785 +    //     monetarySeparator and exponential.
 129.786 +    // - 2 for version from J2SE 1.4, which includes locale field.
 129.787 +    // - 3 for version from J2SE 1.6, which includes exponentialSeparator field.
 129.788 +    private static final int currentSerialVersion = 3;
 129.789 +
 129.790 +    /**
 129.791 +     * Describes the version of <code>DecimalFormatSymbols</code> present on the stream.
 129.792 +     * Possible values are:
 129.793 +     * <ul>
 129.794 +     * <li><b>0</b> (or uninitialized): versions prior to JDK 1.1.6.
 129.795 +     *
 129.796 +     * <li><b>1</b>: Versions written by JDK 1.1.6 or later, which include
 129.797 +     *      two new fields: <code>monetarySeparator</code> and <code>exponential</code>.
 129.798 +     * <li><b>2</b>: Versions written by J2SE 1.4 or later, which include a
 129.799 +     *      new <code>locale</code> field.
 129.800 +     * <li><b>3</b>: Versions written by J2SE 1.6 or later, which include a
 129.801 +     *      new <code>exponentialSeparator</code> field.
 129.802 +     * </ul>
 129.803 +     * When streaming out a <code>DecimalFormatSymbols</code>, the most recent format
 129.804 +     * (corresponding to the highest allowable <code>serialVersionOnStream</code>)
 129.805 +     * is always written.
 129.806 +     *
 129.807 +     * @serial
 129.808 +     * @since JDK 1.1.6
 129.809 +     */
 129.810 +    private int serialVersionOnStream = currentSerialVersion;
 129.811 +
 129.812 +    /**
 129.813 +     * cache to hold the NumberElements and the Currency
 129.814 +     * of a Locale.
 129.815 +     */
 129.816 +    private static final ConcurrentHashMap<Locale, Object[]> cachedLocaleData = new ConcurrentHashMap<Locale, Object[]>(3);
 129.817 +
 129.818 +    /**
 129.819 +     * Obtains a DecimalFormatSymbols instance from a DecimalFormatSymbolsProvider
 129.820 +     * implementation.
 129.821 +    private static class DecimalFormatSymbolsGetter
 129.822 +        implements LocaleServiceProviderPool.LocalizedObjectGetter<DecimalFormatSymbolsProvider,
 129.823 +                                                                   DecimalFormatSymbols> {
 129.824 +        private static final DecimalFormatSymbolsGetter INSTANCE =
 129.825 +            new DecimalFormatSymbolsGetter();
 129.826 +
 129.827 +        public DecimalFormatSymbols getObject(
 129.828 +                                DecimalFormatSymbolsProvider decimalFormatSymbolsProvider,
 129.829 +                                Locale locale,
 129.830 +                                String key,
 129.831 +                                Object... params) {
 129.832 +            assert params.length == 0;
 129.833 +            return decimalFormatSymbolsProvider.getInstance(locale);
 129.834 +        }
 129.835 +    }
 129.836 +     */
 129.837 +}
   130.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   130.2 +++ b/rt/emul/compact/src/main/java/java/text/DigitList.java	Tue Feb 11 13:31:42 2014 +0100
   130.3 @@ -0,0 +1,715 @@
   130.4 +/*
   130.5 + * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
   130.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   130.7 + *
   130.8 + * This code is free software; you can redistribute it and/or modify it
   130.9 + * under the terms of the GNU General Public License version 2 only, as
  130.10 + * published by the Free Software Foundation.  Oracle designates this
  130.11 + * particular file as subject to the "Classpath" exception as provided
  130.12 + * by Oracle in the LICENSE file that accompanied this code.
  130.13 + *
  130.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  130.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  130.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  130.17 + * version 2 for more details (a copy is included in the LICENSE file that
  130.18 + * accompanied this code).
  130.19 + *
  130.20 + * You should have received a copy of the GNU General Public License version
  130.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  130.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  130.23 + *
  130.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  130.25 + * or visit www.oracle.com if you need additional information or have any
  130.26 + * questions.
  130.27 + */
  130.28 +
  130.29 +/*
  130.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
  130.31 + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
  130.32 + *
  130.33 + *   The original version of this source code and documentation is copyrighted
  130.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
  130.35 + * materials are provided under terms of a License Agreement between Taligent
  130.36 + * and Sun. This technology is protected by multiple US and International
  130.37 + * patents. This notice and attribution to Taligent may not be removed.
  130.38 + *   Taligent is a registered trademark of Taligent, Inc.
  130.39 + *
  130.40 + */
  130.41 +
  130.42 +package java.text;
  130.43 +
  130.44 +import java.math.BigDecimal;
  130.45 +import java.math.BigInteger;
  130.46 +import java.math.RoundingMode;
  130.47 +
  130.48 +/**
  130.49 + * Digit List. Private to DecimalFormat.
  130.50 + * Handles the transcoding
  130.51 + * between numeric values and strings of characters.  Only handles
  130.52 + * non-negative numbers.  The division of labor between DigitList and
  130.53 + * DecimalFormat is that DigitList handles the radix 10 representation
  130.54 + * issues; DecimalFormat handles the locale-specific issues such as
  130.55 + * positive/negative, grouping, decimal point, currency, and so on.
  130.56 + *
  130.57 + * A DigitList is really a representation of a floating point value.
  130.58 + * It may be an integer value; we assume that a double has sufficient
  130.59 + * precision to represent all digits of a long.
  130.60 + *
  130.61 + * The DigitList representation consists of a string of characters,
  130.62 + * which are the digits radix 10, from '0' to '9'.  It also has a radix
  130.63 + * 10 exponent associated with it.  The value represented by a DigitList
  130.64 + * object can be computed by mulitplying the fraction f, where 0 <= f < 1,
  130.65 + * derived by placing all the digits of the list to the right of the
  130.66 + * decimal point, by 10^exponent.
  130.67 + *
  130.68 + * @see  Locale
  130.69 + * @see  Format
  130.70 + * @see  NumberFormat
  130.71 + * @see  DecimalFormat
  130.72 + * @see  ChoiceFormat
  130.73 + * @see  MessageFormat
  130.74 + * @author       Mark Davis, Alan Liu
  130.75 + */
  130.76 +final class DigitList implements Cloneable {
  130.77 +    /**
  130.78 +     * The maximum number of significant digits in an IEEE 754 double, that
  130.79 +     * is, in a Java double.  This must not be increased, or garbage digits
  130.80 +     * will be generated, and should not be decreased, or accuracy will be lost.
  130.81 +     */
  130.82 +    public static final int MAX_COUNT = 19; // == Long.toString(Long.MAX_VALUE).length()
  130.83 +
  130.84 +    /**
  130.85 +     * These data members are intentionally public and can be set directly.
  130.86 +     *
  130.87 +     * The value represented is given by placing the decimal point before
  130.88 +     * digits[decimalAt].  If decimalAt is < 0, then leading zeros between
  130.89 +     * the decimal point and the first nonzero digit are implied.  If decimalAt
  130.90 +     * is > count, then trailing zeros between the digits[count-1] and the
  130.91 +     * decimal point are implied.
  130.92 +     *
  130.93 +     * Equivalently, the represented value is given by f * 10^decimalAt.  Here
  130.94 +     * f is a value 0.1 <= f < 1 arrived at by placing the digits in Digits to
  130.95 +     * the right of the decimal.
  130.96 +     *
  130.97 +     * DigitList is normalized, so if it is non-zero, figits[0] is non-zero.  We
  130.98 +     * don't allow denormalized numbers because our exponent is effectively of
  130.99 +     * unlimited magnitude.  The count value contains the number of significant
 130.100 +     * digits present in digits[].
 130.101 +     *
 130.102 +     * Zero is represented by any DigitList with count == 0 or with each digits[i]
 130.103 +     * for all i <= count == '0'.
 130.104 +     */
 130.105 +    public int decimalAt = 0;
 130.106 +    public int count = 0;
 130.107 +    public char[] digits = new char[MAX_COUNT];
 130.108 +
 130.109 +    private char[] data;
 130.110 +    private RoundingMode roundingMode = RoundingMode.HALF_EVEN;
 130.111 +    private boolean isNegative = false;
 130.112 +
 130.113 +    /**
 130.114 +     * Return true if the represented number is zero.
 130.115 +     */
 130.116 +    boolean isZero() {
 130.117 +        for (int i=0; i < count; ++i) {
 130.118 +            if (digits[i] != '0') {
 130.119 +                return false;
 130.120 +            }
 130.121 +        }
 130.122 +        return true;
 130.123 +    }
 130.124 +
 130.125 +    /**
 130.126 +     * Set the rounding mode
 130.127 +     */
 130.128 +    void setRoundingMode(RoundingMode r) {
 130.129 +        roundingMode = r;
 130.130 +    }
 130.131 +
 130.132 +    /**
 130.133 +     * Clears out the digits.
 130.134 +     * Use before appending them.
 130.135 +     * Typically, you set a series of digits with append, then at the point
 130.136 +     * you hit the decimal point, you set myDigitList.decimalAt = myDigitList.count;
 130.137 +     * then go on appending digits.
 130.138 +     */
 130.139 +    public void clear () {
 130.140 +        decimalAt = 0;
 130.141 +        count = 0;
 130.142 +    }
 130.143 +
 130.144 +    /**
 130.145 +     * Appends a digit to the list, extending the list when necessary.
 130.146 +     */
 130.147 +    public void append(char digit) {
 130.148 +        if (count == digits.length) {
 130.149 +            char[] data = new char[count + 100];
 130.150 +            System.arraycopy(digits, 0, data, 0, count);
 130.151 +            digits = data;
 130.152 +        }
 130.153 +        digits[count++] = digit;
 130.154 +    }
 130.155 +
 130.156 +    /**
 130.157 +     * Utility routine to get the value of the digit list
 130.158 +     * If (count == 0) this throws a NumberFormatException, which
 130.159 +     * mimics Long.parseLong().
 130.160 +     */
 130.161 +    public final double getDouble() {
 130.162 +        if (count == 0) {
 130.163 +            return 0.0;
 130.164 +        }
 130.165 +
 130.166 +        StringBuffer temp = getStringBuffer();
 130.167 +        temp.append('.');
 130.168 +        temp.append(digits, 0, count);
 130.169 +        temp.append('E');
 130.170 +        temp.append(decimalAt);
 130.171 +        return Double.parseDouble(temp.toString());
 130.172 +    }
 130.173 +
 130.174 +    /**
 130.175 +     * Utility routine to get the value of the digit list.
 130.176 +     * If (count == 0) this returns 0, unlike Long.parseLong().
 130.177 +     */
 130.178 +    public final long getLong() {
 130.179 +        // for now, simple implementation; later, do proper IEEE native stuff
 130.180 +
 130.181 +        if (count == 0) {
 130.182 +            return 0;
 130.183 +        }
 130.184 +
 130.185 +        // We have to check for this, because this is the one NEGATIVE value
 130.186 +        // we represent.  If we tried to just pass the digits off to parseLong,
 130.187 +        // we'd get a parse failure.
 130.188 +        if (isLongMIN_VALUE()) {
 130.189 +            return Long.MIN_VALUE;
 130.190 +        }
 130.191 +
 130.192 +        StringBuffer temp = getStringBuffer();
 130.193 +        temp.append(digits, 0, count);
 130.194 +        for (int i = count; i < decimalAt; ++i) {
 130.195 +            temp.append('0');
 130.196 +        }
 130.197 +        return Long.parseLong(temp.toString());
 130.198 +    }
 130.199 +
 130.200 +    public final BigDecimal getBigDecimal() {
 130.201 +        if (count == 0) {
 130.202 +            if (decimalAt == 0) {
 130.203 +                return BigDecimal.ZERO;
 130.204 +            } else {
 130.205 +                return new BigDecimal("0E" + decimalAt);
 130.206 +            }
 130.207 +        }
 130.208 +
 130.209 +       if (decimalAt == count) {
 130.210 +           return new BigDecimal(digits, 0, count);
 130.211 +       } else {
 130.212 +           return new BigDecimal(digits, 0, count).scaleByPowerOfTen(decimalAt - count);
 130.213 +       }
 130.214 +    }
 130.215 +
 130.216 +    /**
 130.217 +     * Return true if the number represented by this object can fit into
 130.218 +     * a long.
 130.219 +     * @param isPositive true if this number should be regarded as positive
 130.220 +     * @param ignoreNegativeZero true if -0 should be regarded as identical to
 130.221 +     * +0; otherwise they are considered distinct
 130.222 +     * @return true if this number fits into a Java long
 130.223 +     */
 130.224 +    boolean fitsIntoLong(boolean isPositive, boolean ignoreNegativeZero) {
 130.225 +        // Figure out if the result will fit in a long.  We have to
 130.226 +        // first look for nonzero digits after the decimal point;
 130.227 +        // then check the size.  If the digit count is 18 or less, then
 130.228 +        // the value can definitely be represented as a long.  If it is 19
 130.229 +        // then it may be too large.
 130.230 +
 130.231 +        // Trim trailing zeros.  This does not change the represented value.
 130.232 +        while (count > 0 && digits[count - 1] == '0') {
 130.233 +            --count;
 130.234 +        }
 130.235 +
 130.236 +        if (count == 0) {
 130.237 +            // Positive zero fits into a long, but negative zero can only
 130.238 +            // be represented as a double. - bug 4162852
 130.239 +            return isPositive || ignoreNegativeZero;
 130.240 +        }
 130.241 +
 130.242 +        if (decimalAt < count || decimalAt > MAX_COUNT) {
 130.243 +            return false;
 130.244 +        }
 130.245 +
 130.246 +        if (decimalAt < MAX_COUNT) return true;
 130.247 +
 130.248 +        // At this point we have decimalAt == count, and count == MAX_COUNT.
 130.249 +        // The number will overflow if it is larger than 9223372036854775807
 130.250 +        // or smaller than -9223372036854775808.
 130.251 +        for (int i=0; i<count; ++i) {
 130.252 +            char dig = digits[i], max = LONG_MIN_REP[i];
 130.253 +            if (dig > max) return false;
 130.254 +            if (dig < max) return true;
 130.255 +        }
 130.256 +
 130.257 +        // At this point the first count digits match.  If decimalAt is less
 130.258 +        // than count, then the remaining digits are zero, and we return true.
 130.259 +        if (count < decimalAt) return true;
 130.260 +
 130.261 +        // Now we have a representation of Long.MIN_VALUE, without the leading
 130.262 +        // negative sign.  If this represents a positive value, then it does
 130.263 +        // not fit; otherwise it fits.
 130.264 +        return !isPositive;
 130.265 +    }
 130.266 +
 130.267 +    /**
 130.268 +     * Set the digit list to a representation of the given double value.
 130.269 +     * This method supports fixed-point notation.
 130.270 +     * @param isNegative Boolean value indicating whether the number is negative.
 130.271 +     * @param source Value to be converted; must not be Inf, -Inf, Nan,
 130.272 +     * or a value <= 0.
 130.273 +     * @param maximumFractionDigits The most fractional digits which should
 130.274 +     * be converted.
 130.275 +     */
 130.276 +    public final void set(boolean isNegative, double source, int maximumFractionDigits) {
 130.277 +        set(isNegative, source, maximumFractionDigits, true);
 130.278 +    }
 130.279 +
 130.280 +    /**
 130.281 +     * Set the digit list to a representation of the given double value.
 130.282 +     * This method supports both fixed-point and exponential notation.
 130.283 +     * @param isNegative Boolean value indicating whether the number is negative.
 130.284 +     * @param source Value to be converted; must not be Inf, -Inf, Nan,
 130.285 +     * or a value <= 0.
 130.286 +     * @param maximumDigits The most fractional or total digits which should
 130.287 +     * be converted.
 130.288 +     * @param fixedPoint If true, then maximumDigits is the maximum
 130.289 +     * fractional digits to be converted.  If false, total digits.
 130.290 +     */
 130.291 +    final void set(boolean isNegative, double source, int maximumDigits, boolean fixedPoint) {
 130.292 +        set(isNegative, Double.toString(source), maximumDigits, fixedPoint);
 130.293 +    }
 130.294 +
 130.295 +    /**
 130.296 +     * Generate a representation of the form DDDDD, DDDDD.DDDDD, or
 130.297 +     * DDDDDE+/-DDDDD.
 130.298 +     */
 130.299 +    final void set(boolean isNegative, String s, int maximumDigits, boolean fixedPoint) {
 130.300 +        this.isNegative = isNegative;
 130.301 +        int len = s.length();
 130.302 +        char[] source = getDataChars(len);
 130.303 +        s.getChars(0, len, source, 0);
 130.304 +
 130.305 +        decimalAt = -1;
 130.306 +        count = 0;
 130.307 +        int exponent = 0;
 130.308 +        // Number of zeros between decimal point and first non-zero digit after
 130.309 +        // decimal point, for numbers < 1.
 130.310 +        int leadingZerosAfterDecimal = 0;
 130.311 +        boolean nonZeroDigitSeen = false;
 130.312 +
 130.313 +        for (int i = 0; i < len; ) {
 130.314 +            char c = source[i++];
 130.315 +            if (c == '.') {
 130.316 +                decimalAt = count;
 130.317 +            } else if (c == 'e' || c == 'E') {
 130.318 +                exponent = parseInt(source, i, len);
 130.319 +                break;
 130.320 +            } else {
 130.321 +                if (!nonZeroDigitSeen) {
 130.322 +                    nonZeroDigitSeen = (c != '0');
 130.323 +                    if (!nonZeroDigitSeen && decimalAt != -1)
 130.324 +                        ++leadingZerosAfterDecimal;
 130.325 +                }
 130.326 +                if (nonZeroDigitSeen) {
 130.327 +                    digits[count++] = c;
 130.328 +                }
 130.329 +            }
 130.330 +        }
 130.331 +        if (decimalAt == -1) {
 130.332 +            decimalAt = count;
 130.333 +        }
 130.334 +        if (nonZeroDigitSeen) {
 130.335 +            decimalAt += exponent - leadingZerosAfterDecimal;
 130.336 +        }
 130.337 +
 130.338 +        if (fixedPoint) {
 130.339 +            // The negative of the exponent represents the number of leading
 130.340 +            // zeros between the decimal and the first non-zero digit, for
 130.341 +            // a value < 0.1 (e.g., for 0.00123, -decimalAt == 2).  If this
 130.342 +            // is more than the maximum fraction digits, then we have an underflow
 130.343 +            // for the printed representation.
 130.344 +            if (-decimalAt > maximumDigits) {
 130.345 +                // Handle an underflow to zero when we round something like
 130.346 +                // 0.0009 to 2 fractional digits.
 130.347 +                count = 0;
 130.348 +                return;
 130.349 +            } else if (-decimalAt == maximumDigits) {
 130.350 +                // If we round 0.0009 to 3 fractional digits, then we have to
 130.351 +                // create a new one digit in the least significant location.
 130.352 +                if (shouldRoundUp(0)) {
 130.353 +                    count = 1;
 130.354 +                    ++decimalAt;
 130.355 +                    digits[0] = '1';
 130.356 +                } else {
 130.357 +                    count = 0;
 130.358 +                }
 130.359 +                return;
 130.360 +            }
 130.361 +            // else fall through
 130.362 +        }
 130.363 +
 130.364 +        // Eliminate trailing zeros.
 130.365 +        while (count > 1 && digits[count - 1] == '0') {
 130.366 +            --count;
 130.367 +        }
 130.368 +
 130.369 +        // Eliminate digits beyond maximum digits to be displayed.
 130.370 +        // Round up if appropriate.
 130.371 +        round(fixedPoint ? (maximumDigits + decimalAt) : maximumDigits);
 130.372 +    }
 130.373 +
 130.374 +    /**
 130.375 +     * Round the representation to the given number of digits.
 130.376 +     * @param maximumDigits The maximum number of digits to be shown.
 130.377 +     * Upon return, count will be less than or equal to maximumDigits.
 130.378 +     */
 130.379 +    private final void round(int maximumDigits) {
 130.380 +        // Eliminate digits beyond maximum digits to be displayed.
 130.381 +        // Round up if appropriate.
 130.382 +        if (maximumDigits >= 0 && maximumDigits < count) {
 130.383 +            if (shouldRoundUp(maximumDigits)) {
 130.384 +                // Rounding up involved incrementing digits from LSD to MSD.
 130.385 +                // In most cases this is simple, but in a worst case situation
 130.386 +                // (9999..99) we have to adjust the decimalAt value.
 130.387 +                for (;;) {
 130.388 +                    --maximumDigits;
 130.389 +                    if (maximumDigits < 0) {
 130.390 +                        // We have all 9's, so we increment to a single digit
 130.391 +                        // of one and adjust the exponent.
 130.392 +                        digits[0] = '1';
 130.393 +                        ++decimalAt;
 130.394 +                        maximumDigits = 0; // Adjust the count
 130.395 +                        break;
 130.396 +                    }
 130.397 +
 130.398 +                    ++digits[maximumDigits];
 130.399 +                    if (digits[maximumDigits] <= '9') break;
 130.400 +                    // digits[maximumDigits] = '0'; // Unnecessary since we'll truncate this
 130.401 +                }
 130.402 +                ++maximumDigits; // Increment for use as count
 130.403 +            }
 130.404 +            count = maximumDigits;
 130.405 +
 130.406 +            // Eliminate trailing zeros.
 130.407 +            while (count > 1 && digits[count-1] == '0') {
 130.408 +                --count;
 130.409 +            }
 130.410 +        }
 130.411 +    }
 130.412 +
 130.413 +
 130.414 +    /**
 130.415 +     * Return true if truncating the representation to the given number
 130.416 +     * of digits will result in an increment to the last digit.  This
 130.417 +     * method implements the rounding modes defined in the
 130.418 +     * java.math.RoundingMode class.
 130.419 +     * [bnf]
 130.420 +     * @param maximumDigits the number of digits to keep, from 0 to
 130.421 +     * <code>count-1</code>.  If 0, then all digits are rounded away, and
 130.422 +     * this method returns true if a one should be generated (e.g., formatting
 130.423 +     * 0.09 with "#.#").
 130.424 +     * @exception ArithmeticException if rounding is needed with rounding
 130.425 +     *            mode being set to RoundingMode.UNNECESSARY
 130.426 +     * @return true if digit <code>maximumDigits-1</code> should be
 130.427 +     * incremented
 130.428 +     */
 130.429 +    private boolean shouldRoundUp(int maximumDigits) {
 130.430 +        if (maximumDigits < count) {
 130.431 +            switch(roundingMode) {
 130.432 +            case UP:
 130.433 +                for (int i=maximumDigits; i<count; ++i) {
 130.434 +                    if (digits[i] != '0') {
 130.435 +                        return true;
 130.436 +                    }
 130.437 +                }
 130.438 +                break;
 130.439 +            case DOWN:
 130.440 +                break;
 130.441 +            case CEILING:
 130.442 +                for (int i=maximumDigits; i<count; ++i) {
 130.443 +                    if (digits[i] != '0') {
 130.444 +                        return !isNegative;
 130.445 +                    }
 130.446 +                }
 130.447 +                break;
 130.448 +            case FLOOR:
 130.449 +                for (int i=maximumDigits; i<count; ++i) {
 130.450 +                    if (digits[i] != '0') {
 130.451 +                        return isNegative;
 130.452 +                    }
 130.453 +                }
 130.454 +                break;
 130.455 +            case HALF_UP:
 130.456 +                if (digits[maximumDigits] >= '5') {
 130.457 +                    return true;
 130.458 +                }
 130.459 +                break;
 130.460 +            case HALF_DOWN:
 130.461 +                if (digits[maximumDigits] > '5') {
 130.462 +                    return true;
 130.463 +                } else if (digits[maximumDigits] == '5' ) {
 130.464 +                    for (int i=maximumDigits+1; i<count; ++i) {
 130.465 +                        if (digits[i] != '0') {
 130.466 +                            return true;
 130.467 +                        }
 130.468 +                    }
 130.469 +                }
 130.470 +                break;
 130.471 +            case HALF_EVEN:
 130.472 +                // Implement IEEE half-even rounding
 130.473 +                if (digits[maximumDigits] > '5') {
 130.474 +                    return true;
 130.475 +                } else if (digits[maximumDigits] == '5' ) {
 130.476 +                    for (int i=maximumDigits+1; i<count; ++i) {
 130.477 +                        if (digits[i] != '0') {
 130.478 +                            return true;
 130.479 +                        }
 130.480 +                    }
 130.481 +                    return maximumDigits > 0 && (digits[maximumDigits-1] % 2 != 0);
 130.482 +                }
 130.483 +                break;
 130.484 +            case UNNECESSARY:
 130.485 +                for (int i=maximumDigits; i<count; ++i) {
 130.486 +                    if (digits[i] != '0') {
 130.487 +                        throw new ArithmeticException(
 130.488 +                            "Rounding needed with the rounding mode being set to RoundingMode.UNNECESSARY");
 130.489 +                    }
 130.490 +                }
 130.491 +                break;
 130.492 +            default:
 130.493 +                assert false;
 130.494 +            }
 130.495 +        }
 130.496 +        return false;
 130.497 +    }
 130.498 +
 130.499 +    /**
 130.500 +     * Utility routine to set the value of the digit list from a long
 130.501 +     */
 130.502 +    public final void set(boolean isNegative, long source) {
 130.503 +        set(isNegative, source, 0);
 130.504 +    }
 130.505 +
 130.506 +    /**
 130.507 +     * Set the digit list to a representation of the given long value.
 130.508 +     * @param isNegative Boolean value indicating whether the number is negative.
 130.509 +     * @param source Value to be converted; must be >= 0 or ==
 130.510 +     * Long.MIN_VALUE.
 130.511 +     * @param maximumDigits The most digits which should be converted.
 130.512 +     * If maximumDigits is lower than the number of significant digits
 130.513 +     * in source, the representation will be rounded.  Ignored if <= 0.
 130.514 +     */
 130.515 +    public final void set(boolean isNegative, long source, int maximumDigits) {
 130.516 +        this.isNegative = isNegative;
 130.517 +
 130.518 +        // This method does not expect a negative number. However,
 130.519 +        // "source" can be a Long.MIN_VALUE (-9223372036854775808),
 130.520 +        // if the number being formatted is a Long.MIN_VALUE.  In that
 130.521 +        // case, it will be formatted as -Long.MIN_VALUE, a number
 130.522 +        // which is outside the legal range of a long, but which can
 130.523 +        // be represented by DigitList.
 130.524 +        if (source <= 0) {
 130.525 +            if (source == Long.MIN_VALUE) {
 130.526 +                decimalAt = count = MAX_COUNT;
 130.527 +                System.arraycopy(LONG_MIN_REP, 0, digits, 0, count);
 130.528 +            } else {
 130.529 +                decimalAt = count = 0; // Values <= 0 format as zero
 130.530 +            }
 130.531 +        } else {
 130.532 +            // Rewritten to improve performance.  I used to call
 130.533 +            // Long.toString(), which was about 4x slower than this code.
 130.534 +            int left = MAX_COUNT;
 130.535 +            int right;
 130.536 +            while (source > 0) {
 130.537 +                digits[--left] = (char)('0' + (source % 10));
 130.538 +                source /= 10;
 130.539 +            }
 130.540 +            decimalAt = MAX_COUNT - left;
 130.541 +            // Don't copy trailing zeros.  We are guaranteed that there is at
 130.542 +            // least one non-zero digit, so we don't have to check lower bounds.
 130.543 +            for (right = MAX_COUNT - 1; digits[right] == '0'; --right)
 130.544 +                ;
 130.545 +            count = right - left + 1;
 130.546 +            System.arraycopy(digits, left, digits, 0, count);
 130.547 +        }
 130.548 +        if (maximumDigits > 0) round(maximumDigits);
 130.549 +    }
 130.550 +
 130.551 +    /**
 130.552 +     * Set the digit list to a representation of the given BigDecimal value.
 130.553 +     * This method supports both fixed-point and exponential notation.
 130.554 +     * @param isNegative Boolean value indicating whether the number is negative.
 130.555 +     * @param source Value to be converted; must not be a value <= 0.
 130.556 +     * @param maximumDigits The most fractional or total digits which should
 130.557 +     * be converted.
 130.558 +     * @param fixedPoint If true, then maximumDigits is the maximum
 130.559 +     * fractional digits to be converted.  If false, total digits.
 130.560 +     */
 130.561 +    final void set(boolean isNegative, BigDecimal source, int maximumDigits, boolean fixedPoint) {
 130.562 +        String s = source.toString();
 130.563 +        extendDigits(s.length());
 130.564 +
 130.565 +        set(isNegative, s, maximumDigits, fixedPoint);
 130.566 +    }
 130.567 +
 130.568 +    /**
 130.569 +     * Set the digit list to a representation of the given BigInteger value.
 130.570 +     * @param isNegative Boolean value indicating whether the number is negative.
 130.571 +     * @param source Value to be converted; must be >= 0.
 130.572 +     * @param maximumDigits The most digits which should be converted.
 130.573 +     * If maximumDigits is lower than the number of significant digits
 130.574 +     * in source, the representation will be rounded.  Ignored if <= 0.
 130.575 +     */
 130.576 +    final void set(boolean isNegative, BigInteger source, int maximumDigits) {
 130.577 +        this.isNegative = isNegative;
 130.578 +        String s = source.toString();
 130.579 +        int len = s.length();
 130.580 +        extendDigits(len);
 130.581 +        s.getChars(0, len, digits, 0);
 130.582 +
 130.583 +        decimalAt = len;
 130.584 +        int right;
 130.585 +        for (right = len - 1; right >= 0 && digits[right] == '0'; --right)
 130.586 +            ;
 130.587 +        count = right + 1;
 130.588 +
 130.589 +        if (maximumDigits > 0) {
 130.590 +            round(maximumDigits);
 130.591 +        }
 130.592 +    }
 130.593 +
 130.594 +    /**
 130.595 +     * equality test between two digit lists.
 130.596 +     */
 130.597 +    public boolean equals(Object obj) {
 130.598 +        if (this == obj)                      // quick check
 130.599 +            return true;
 130.600 +        if (!(obj instanceof DigitList))         // (1) same object?
 130.601 +            return false;
 130.602 +        DigitList other = (DigitList) obj;
 130.603 +        if (count != other.count ||
 130.604 +        decimalAt != other.decimalAt)
 130.605 +            return false;
 130.606 +        for (int i = 0; i < count; i++)
 130.607 +            if (digits[i] != other.digits[i])
 130.608 +                return false;
 130.609 +        return true;
 130.610 +    }
 130.611 +
 130.612 +    /**
 130.613 +     * Generates the hash code for the digit list.
 130.614 +     */
 130.615 +    public int hashCode() {
 130.616 +        int hashcode = decimalAt;
 130.617 +
 130.618 +        for (int i = 0; i < count; i++) {
 130.619 +            hashcode = hashcode * 37 + digits[i];
 130.620 +        }
 130.621 +
 130.622 +        return hashcode;
 130.623 +    }
 130.624 +
 130.625 +    /**
 130.626 +     * Creates a copy of this object.
 130.627 +     * @return a clone of this instance.
 130.628 +     */
 130.629 +    public Object clone() {
 130.630 +        try {
 130.631 +            DigitList other = (DigitList) super.clone();
 130.632 +            char[] newDigits = new char[digits.length];
 130.633 +            System.arraycopy(digits, 0, newDigits, 0, digits.length);
 130.634 +            other.digits = newDigits;
 130.635 +            other.tempBuffer = null;
 130.636 +            return other;
 130.637 +        } catch (CloneNotSupportedException e) {
 130.638 +            throw new InternalError();
 130.639 +        }
 130.640 +    }
 130.641 +
 130.642 +    /**
 130.643 +     * Returns true if this DigitList represents Long.MIN_VALUE;
 130.644 +     * false, otherwise.  This is required so that getLong() works.
 130.645 +     */
 130.646 +    private boolean isLongMIN_VALUE() {
 130.647 +        if (decimalAt != count || count != MAX_COUNT) {
 130.648 +            return false;
 130.649 +        }
 130.650 +
 130.651 +        for (int i = 0; i < count; ++i) {
 130.652 +            if (digits[i] != LONG_MIN_REP[i]) return false;
 130.653 +        }
 130.654 +
 130.655 +        return true;
 130.656 +    }
 130.657 +
 130.658 +    private static final int parseInt(char[] str, int offset, int strLen) {
 130.659 +        char c;
 130.660 +        boolean positive = true;
 130.661 +        if ((c = str[offset]) == '-') {
 130.662 +            positive = false;
 130.663 +            offset++;
 130.664 +        } else if (c == '+') {
 130.665 +            offset++;
 130.666 +        }
 130.667 +
 130.668 +        int value = 0;
 130.669 +        while (offset < strLen) {
 130.670 +            c = str[offset++];
 130.671 +            if (c >= '0' && c <= '9') {
 130.672 +                value = value * 10 + (c - '0');
 130.673 +            } else {
 130.674 +                break;
 130.675 +            }
 130.676 +        }
 130.677 +        return positive ? value : -value;
 130.678 +    }
 130.679 +
 130.680 +    // The digit part of -9223372036854775808L
 130.681 +    private static final char[] LONG_MIN_REP = "9223372036854775808".toCharArray();
 130.682 +
 130.683 +    public String toString() {
 130.684 +        if (isZero()) {
 130.685 +            return "0";
 130.686 +        }
 130.687 +        StringBuffer buf = getStringBuffer();
 130.688 +        buf.append("0.");
 130.689 +        buf.append(digits, 0, count);
 130.690 +        buf.append("x10^");
 130.691 +        buf.append(decimalAt);
 130.692 +        return buf.toString();
 130.693 +    }
 130.694 +
 130.695 +    private StringBuffer tempBuffer;
 130.696 +
 130.697 +    private StringBuffer getStringBuffer() {
 130.698 +        if (tempBuffer == null) {
 130.699 +            tempBuffer = new StringBuffer(MAX_COUNT);
 130.700 +        } else {
 130.701 +            tempBuffer.setLength(0);
 130.702 +        }
 130.703 +        return tempBuffer;
 130.704 +    }
 130.705 +
 130.706 +    private void extendDigits(int len) {
 130.707 +        if (len > digits.length) {
 130.708 +            digits = new char[len];
 130.709 +        }
 130.710 +    }
 130.711 +
 130.712 +    private final char[] getDataChars(int length) {
 130.713 +        if (data == null || data.length < length) {
 130.714 +            data = new char[length];
 130.715 +        }
 130.716 +        return data;
 130.717 +    }
 130.718 +}
   131.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   131.2 +++ b/rt/emul/compact/src/main/java/java/text/DontCareFieldPosition.java	Tue Feb 11 13:31:42 2014 +0100
   131.3 @@ -0,0 +1,53 @@
   131.4 +/*
   131.5 + * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved.
   131.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   131.7 + *
   131.8 + * This code is free software; you can redistribute it and/or modify it
   131.9 + * under the terms of the GNU General Public License version 2 only, as
  131.10 + * published by the Free Software Foundation.  Oracle designates this
  131.11 + * particular file as subject to the "Classpath" exception as provided
  131.12 + * by Oracle in the LICENSE file that accompanied this code.
  131.13 + *
  131.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  131.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  131.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  131.17 + * version 2 for more details (a copy is included in the LICENSE file that
  131.18 + * accompanied this code).
  131.19 + *
  131.20 + * You should have received a copy of the GNU General Public License version
  131.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  131.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  131.23 + *
  131.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  131.25 + * or visit www.oracle.com if you need additional information or have any
  131.26 + * questions.
  131.27 + */
  131.28 +
  131.29 +package java.text;
  131.30 +
  131.31 +/**
  131.32 + * DontCareFieldPosition defines no-op FieldDelegate. Its
  131.33 + * singleton is used for the format methods that don't take a
  131.34 + * FieldPosition.
  131.35 + */
  131.36 +class DontCareFieldPosition extends FieldPosition {
  131.37 +    // The singleton of DontCareFieldPosition.
  131.38 +    static final FieldPosition INSTANCE = new DontCareFieldPosition();
  131.39 +
  131.40 +    private final Format.FieldDelegate noDelegate = new Format.FieldDelegate() {
  131.41 +        public void formatted(Format.Field attr, Object value, int start,
  131.42 +                              int end, StringBuffer buffer) {
  131.43 +        }
  131.44 +        public void formatted(int fieldID, Format.Field attr, Object value,
  131.45 +                              int start, int end, StringBuffer buffer) {
  131.46 +        }
  131.47 +    };
  131.48 +
  131.49 +    private DontCareFieldPosition() {
  131.50 +        super(0);
  131.51 +    }
  131.52 +
  131.53 +    Format.FieldDelegate getFieldDelegate() {
  131.54 +        return noDelegate;
  131.55 +    }
  131.56 +}
   132.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   132.2 +++ b/rt/emul/compact/src/main/java/java/text/FieldPosition.java	Tue Feb 11 13:31:42 2014 +0100
   132.3 @@ -0,0 +1,303 @@
   132.4 +/*
   132.5 + * Copyright (c) 1996, 2002, Oracle and/or its affiliates. All rights reserved.
   132.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   132.7 + *
   132.8 + * This code is free software; you can redistribute it and/or modify it
   132.9 + * under the terms of the GNU General Public License version 2 only, as
  132.10 + * published by the Free Software Foundation.  Oracle designates this
  132.11 + * particular file as subject to the "Classpath" exception as provided
  132.12 + * by Oracle in the LICENSE file that accompanied this code.
  132.13 + *
  132.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  132.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  132.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  132.17 + * version 2 for more details (a copy is included in the LICENSE file that
  132.18 + * accompanied this code).
  132.19 + *
  132.20 + * You should have received a copy of the GNU General Public License version
  132.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  132.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  132.23 + *
  132.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  132.25 + * or visit www.oracle.com if you need additional information or have any
  132.26 + * questions.
  132.27 + */
  132.28 +
  132.29 +/*
  132.30 + * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
  132.31 + * (C) Copyright IBM Corp. 1996 - All Rights Reserved
  132.32 + *
  132.33 + *   The original version of this source code and documentation is copyrighted
  132.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
  132.35 + * materials are provided under terms of a License Agreement between Taligent
  132.36 + * and Sun. This technology is protected by multiple US and International
  132.37 + * patents. This notice and attribution to Taligent may not be removed.
  132.38 + *   Taligent is a registered trademark of Taligent, Inc.
  132.39 + *
  132.40 + */
  132.41 +
  132.42 +package java.text;
  132.43 +
  132.44 +/**
  132.45 + * <code>FieldPosition</code> is a simple class used by <code>Format</code>
  132.46 + * and its subclasses to identify fields in formatted output. Fields can
  132.47 + * be identified in two ways:
  132.48 + * <ul>
  132.49 + *  <li>By an integer constant, whose names typically end with
  132.50 + *      <code>_FIELD</code>. The constants are defined in the various
  132.51 + *      subclasses of <code>Format</code>.
  132.52 + *  <li>By a <code>Format.Field</code> constant, see <code>ERA_FIELD</code>
  132.53 + *      and its friends in <code>DateFormat</code> for an example.
  132.54 + * </ul>
  132.55 + * <p>
  132.56 + * <code>FieldPosition</code> keeps track of the position of the
  132.57 + * field within the formatted output with two indices: the index
  132.58 + * of the first character of the field and the index of the last
  132.59 + * character of the field.
  132.60 + *
  132.61 + * <p>
  132.62 + * One version of the <code>format</code> method in the various
  132.63 + * <code>Format</code> classes requires a <code>FieldPosition</code>
  132.64 + * object as an argument. You use this <code>format</code> method
  132.65 + * to perform partial formatting or to get information about the
  132.66 + * formatted output (such as the position of a field).
  132.67 + *
  132.68 + * <p>
  132.69 + * If you are interested in the positions of all attributes in the
  132.70 + * formatted string use the <code>Format</code> method
  132.71 + * <code>formatToCharacterIterator</code>.
  132.72 + *
  132.73 + * @author      Mark Davis
  132.74 + * @see         java.text.Format
  132.75 + */
  132.76 +public class FieldPosition {
  132.77 +
  132.78 +    /**
  132.79 +     * Input: Desired field to determine start and end offsets for.
  132.80 +     * The meaning depends on the subclass of Format.
  132.81 +     */
  132.82 +    int field = 0;
  132.83 +
  132.84 +    /**
  132.85 +     * Output: End offset of field in text.
  132.86 +     * If the field does not occur in the text, 0 is returned.
  132.87 +     */
  132.88 +    int endIndex = 0;
  132.89 +
  132.90 +    /**
  132.91 +     * Output: Start offset of field in text.
  132.92 +     * If the field does not occur in the text, 0 is returned.
  132.93 +     */
  132.94 +    int beginIndex = 0;
  132.95 +
  132.96 +    /**
  132.97 +     * Desired field this FieldPosition is for.
  132.98 +     */
  132.99 +    private Format.Field attribute;
 132.100 +
 132.101 +    /**
 132.102 +     * Creates a FieldPosition object for the given field.  Fields are
 132.103 +     * identified by constants, whose names typically end with _FIELD,
 132.104 +     * in the various subclasses of Format.
 132.105 +     *
 132.106 +     * @see java.text.NumberFormat#INTEGER_FIELD
 132.107 +     * @see java.text.NumberFormat#FRACTION_FIELD
 132.108 +     * @see java.text.DateFormat#YEAR_FIELD
 132.109 +     * @see java.text.DateFormat#MONTH_FIELD
 132.110 +     */
 132.111 +    public FieldPosition(int field) {
 132.112 +        this.field = field;
 132.113 +    }
 132.114 +
 132.115 +    /**
 132.116 +     * Creates a FieldPosition object for the given field constant. Fields are
 132.117 +     * identified by constants defined in the various <code>Format</code>
 132.118 +     * subclasses. This is equivalent to calling
 132.119 +     * <code>new FieldPosition(attribute, -1)</code>.
 132.120 +     *
 132.121 +     * @param attribute Format.Field constant identifying a field
 132.122 +     * @since 1.4
 132.123 +     */
 132.124 +    public FieldPosition(Format.Field attribute) {
 132.125 +        this(attribute, -1);
 132.126 +    }
 132.127 +
 132.128 +    /**
 132.129 +     * Creates a <code>FieldPosition</code> object for the given field.
 132.130 +     * The field is identified by an attribute constant from one of the
 132.131 +     * <code>Field</code> subclasses as well as an integer field ID
 132.132 +     * defined by the <code>Format</code> subclasses. <code>Format</code>
 132.133 +     * subclasses that are aware of <code>Field</code> should give precedence
 132.134 +     * to <code>attribute</code> and ignore <code>fieldID</code> if
 132.135 +     * <code>attribute</code> is not null. However, older <code>Format</code>
 132.136 +     * subclasses may not be aware of <code>Field</code> and rely on
 132.137 +     * <code>fieldID</code>. If the field has no corresponding integer
 132.138 +     * constant, <code>fieldID</code> should be -1.
 132.139 +     *
 132.140 +     * @param attribute Format.Field constant identifying a field
 132.141 +     * @param fieldID integer constantce identifying a field
 132.142 +     * @since 1.4
 132.143 +     */
 132.144 +    public FieldPosition(Format.Field attribute, int fieldID) {
 132.145 +        this.attribute = attribute;
 132.146 +        this.field = fieldID;
 132.147 +    }
 132.148 +
 132.149 +    /**
 132.150 +     * Returns the field identifier as an attribute constant
 132.151 +     * from one of the <code>Field</code> subclasses. May return null if
 132.152 +     * the field is specified only by an integer field ID.
 132.153 +     *
 132.154 +     * @return Identifier for the field
 132.155 +     * @since 1.4
 132.156 +     */
 132.157 +    public Format.Field getFieldAttribute() {
 132.158 +        return attribute;
 132.159 +    }
 132.160 +
 132.161 +    /**
 132.162 +     * Retrieves the field identifier.
 132.163 +     */
 132.164 +    public int getField() {
 132.165 +        return field;
 132.166 +    }
 132.167 +
 132.168 +    /**
 132.169 +     * Retrieves the index of the first character in the requested field.
 132.170 +     */
 132.171 +    public int getBeginIndex() {
 132.172 +        return beginIndex;
 132.173 +    }
 132.174 +
 132.175 +    /**
 132.176 +     * Retrieves the index of the character following the last character in the
 132.177 +     * requested field.
 132.178 +     */
 132.179 +    public int getEndIndex() {
 132.180 +        return endIndex;
 132.181 +    }
 132.182 +
 132.183 +    /**
 132.184 +     * Sets the begin index.  For use by subclasses of Format.
 132.185 +     * @since 1.2
 132.186 +     */
 132.187 +    public void setBeginIndex(int bi) {
 132.188 +        beginIndex = bi;
 132.189 +    }
 132.190 +
 132.191 +    /**
 132.192 +     * Sets the end index.  For use by subclasses of Format.
 132.193 +     * @since 1.2
 132.194 +     */
 132.195 +    public void setEndIndex(int ei) {
 132.196 +        endIndex = ei;
 132.197 +    }
 132.198 +
 132.199 +    /**
 132.200 +     * Returns a <code>Format.FieldDelegate</code> instance that is associated
 132.201 +     * with the FieldPosition. When the delegate is notified of the same
 132.202 +     * field the FieldPosition is associated with, the begin/end will be
 132.203 +     * adjusted.
 132.204 +     */
 132.205 +    Format.FieldDelegate getFieldDelegate() {
 132.206 +        return new Delegate();
 132.207 +    }
 132.208 +
 132.209 +    /**
 132.210 +     * Overrides equals
 132.211 +     */
 132.212 +    public boolean equals(Object obj)
 132.213 +    {
 132.214 +        if (obj == null) return false;
 132.215 +        if (!(obj instanceof FieldPosition))
 132.216 +            return false;
 132.217 +        FieldPosition other = (FieldPosition) obj;
 132.218 +        if (attribute == null) {
 132.219 +            if (other.attribute != null) {
 132.220 +                return false;
 132.221 +            }
 132.222 +        }
 132.223 +        else if (!attribute.equals(other.attribute)) {
 132.224 +            return false;
 132.225 +        }
 132.226 +        return (beginIndex == other.beginIndex
 132.227 +            && endIndex == other.endIndex
 132.228 +            && field == other.field);
 132.229 +    }
 132.230 +
 132.231 +    /**
 132.232 +     * Returns a hash code for this FieldPosition.
 132.233 +     * @return a hash code value for this object
 132.234 +     */
 132.235 +    public int hashCode() {
 132.236 +        return (field << 24) | (beginIndex << 16) | endIndex;
 132.237 +    }
 132.238 +
 132.239 +    /**
 132.240 +     * Return a string representation of this FieldPosition.
 132.241 +     * @return  a string representation of this object
 132.242 +     */
 132.243 +    public String toString() {
 132.244 +        return getClass().getName() +
 132.245 +            "[field=" + field + ",attribute=" + attribute +
 132.246 +            ",beginIndex=" + beginIndex +
 132.247 +            ",endIndex=" + endIndex + ']';
 132.248 +    }
 132.249 +
 132.250 +
 132.251 +    /**
 132.252 +     * Return true if the receiver wants a <code>Format.Field</code> value and
 132.253 +     * <code>attribute</code> is equal to it.
 132.254 +     */
 132.255 +    private boolean matchesField(Format.Field attribute) {
 132.256 +        if (this.attribute != null) {
 132.257 +            return this.attribute.equals(attribute);
 132.258 +        }
 132.259 +        return false;
 132.260 +    }
 132.261 +
 132.262 +    /**
 132.263 +     * Return true if the receiver wants a <code>Format.Field</code> value and
 132.264 +     * <code>attribute</code> is equal to it, or true if the receiver
 132.265 +     * represents an inteter constant and <code>field</code> equals it.
 132.266 +     */
 132.267 +    private boolean matchesField(Format.Field attribute, int field) {
 132.268 +        if (this.attribute != null) {
 132.269 +            return this.attribute.equals(attribute);
 132.270 +        }
 132.271 +        return (field == this.field);
 132.272 +    }
 132.273 +
 132.274 +
 132.275 +    /**
 132.276 +     * An implementation of FieldDelegate that will adjust the begin/end
 132.277 +     * of the FieldPosition if the arguments match the field of
 132.278 +     * the FieldPosition.
 132.279 +     */
 132.280 +    private class Delegate implements Format.FieldDelegate {
 132.281 +        /**
 132.282 +         * Indicates whether the field has been  encountered before. If this
 132.283 +         * is true, and <code>formatted</code> is invoked, the begin/end
 132.284 +         * are not updated.
 132.285 +         */
 132.286 +        private boolean encounteredField;
 132.287 +
 132.288 +        public void formatted(Format.Field attr, Object value, int start,
 132.289 +                              int end, StringBuffer buffer) {
 132.290 +            if (!encounteredField && matchesField(attr)) {
 132.291 +                setBeginIndex(start);
 132.292 +                setEndIndex(end);
 132.293 +                encounteredField = (start != end);
 132.294 +            }
 132.295 +        }
 132.296 +
 132.297 +        public void formatted(int fieldID, Format.Field attr, Object value,
 132.298 +                              int start, int end, StringBuffer buffer) {
 132.299 +            if (!encounteredField && matchesField(attr, fieldID)) {
 132.300 +                setBeginIndex(start);
 132.301 +                setEndIndex(end);
 132.302 +                encounteredField = (start != end);
 132.303 +            }
 132.304 +        }
 132.305 +    }
 132.306 +}
   133.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   133.2 +++ b/rt/emul/compact/src/main/java/java/text/Format.java	Tue Feb 11 13:31:42 2014 +0100
   133.3 @@ -0,0 +1,406 @@
   133.4 +/*
   133.5 + * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
   133.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   133.7 + *
   133.8 + * This code is free software; you can redistribute it and/or modify it
   133.9 + * under the terms of the GNU General Public License version 2 only, as
  133.10 + * published by the Free Software Foundation.  Oracle designates this
  133.11 + * particular file as subject to the "Classpath" exception as provided
  133.12 + * by Oracle in the LICENSE file that accompanied this code.
  133.13 + *
  133.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  133.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  133.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  133.17 + * version 2 for more details (a copy is included in the LICENSE file that
  133.18 + * accompanied this code).
  133.19 + *
  133.20 + * You should have received a copy of the GNU General Public License version
  133.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  133.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  133.23 + *
  133.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  133.25 + * or visit www.oracle.com if you need additional information or have any
  133.26 + * questions.
  133.27 + */
  133.28 +
  133.29 +/*
  133.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
  133.31 + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
  133.32 + *
  133.33 + *   The original version of this source code and documentation is copyrighted
  133.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
  133.35 + * materials are provided under terms of a License Agreement between Taligent
  133.36 + * and Sun. This technology is protected by multiple US and International
  133.37 + * patents. This notice and attribution to Taligent may not be removed.
  133.38 + *   Taligent is a registered trademark of Taligent, Inc.
  133.39 + *
  133.40 + */
  133.41 +
  133.42 +package java.text;
  133.43 +
  133.44 +import java.io.Serializable;
  133.45 +
  133.46 +/**
  133.47 + * <code>Format</code> is an abstract base class for formatting locale-sensitive
  133.48 + * information such as dates, messages, and numbers.
  133.49 + *
  133.50 + * <p>
  133.51 + * <code>Format</code> defines the programming interface for formatting
  133.52 + * locale-sensitive objects into <code>String</code>s (the
  133.53 + * <code>format</code> method) and for parsing <code>String</code>s back
  133.54 + * into objects (the <code>parseObject</code> method).
  133.55 + *
  133.56 + * <p>
  133.57 + * Generally, a format's <code>parseObject</code> method must be able to parse
  133.58 + * any string formatted by its <code>format</code> method. However, there may
  133.59 + * be exceptional cases where this is not possible. For example, a
  133.60 + * <code>format</code> method might create two adjacent integer numbers with
  133.61 + * no separator in between, and in this case the <code>parseObject</code> could
  133.62 + * not tell which digits belong to which number.
  133.63 + *
  133.64 + * <h4>Subclassing</h4>
  133.65 + *
  133.66 + * <p>
  133.67 + * The Java Platform provides three specialized subclasses of <code>Format</code>--
  133.68 + * <code>DateFormat</code>, <code>MessageFormat</code>, and
  133.69 + * <code>NumberFormat</code>--for formatting dates, messages, and numbers,
  133.70 + * respectively.
  133.71 + * <p>
  133.72 + * Concrete subclasses must implement three methods:
  133.73 + * <ol>
  133.74 + * <li> <code>format(Object obj, StringBuffer toAppendTo, FieldPosition pos)</code>
  133.75 + * <li> <code>formatToCharacterIterator(Object obj)</code>
  133.76 + * <li> <code>parseObject(String source, ParsePosition pos)</code>
  133.77 + * </ol>
  133.78 + * These general methods allow polymorphic parsing and formatting of objects
  133.79 + * and are used, for example, by <code>MessageFormat</code>.
  133.80 + * Subclasses often also provide additional <code>format</code> methods for
  133.81 + * specific input types as well as <code>parse</code> methods for specific
  133.82 + * result types. Any <code>parse</code> method that does not take a
  133.83 + * <code>ParsePosition</code> argument should throw <code>ParseException</code>
  133.84 + * when no text in the required format is at the beginning of the input text.
  133.85 + *
  133.86 + * <p>
  133.87 + * Most subclasses will also implement the following factory methods:
  133.88 + * <ol>
  133.89 + * <li>
  133.90 + * <code>getInstance</code> for getting a useful format object appropriate
  133.91 + * for the current locale
  133.92 + * <li>
  133.93 + * <code>getInstance(Locale)</code> for getting a useful format
  133.94 + * object appropriate for the specified locale
  133.95 + * </ol>
  133.96 + * In addition, some subclasses may also implement other
  133.97 + * <code>getXxxxInstance</code> methods for more specialized control. For
  133.98 + * example, the <code>NumberFormat</code> class provides
  133.99 + * <code>getPercentInstance</code> and <code>getCurrencyInstance</code>
 133.100 + * methods for getting specialized number formatters.
 133.101 + *
 133.102 + * <p>
 133.103 + * Subclasses of <code>Format</code> that allow programmers to create objects
 133.104 + * for locales (with <code>getInstance(Locale)</code> for example)
 133.105 + * must also implement the following class method:
 133.106 + * <blockquote>
 133.107 + * <pre>
 133.108 + * public static Locale[] getAvailableLocales()
 133.109 + * </pre>
 133.110 + * </blockquote>
 133.111 + *
 133.112 + * <p>
 133.113 + * And finally subclasses may define a set of constants to identify the various
 133.114 + * fields in the formatted output. These constants are used to create a FieldPosition
 133.115 + * object which identifies what information is contained in the field and its
 133.116 + * position in the formatted result. These constants should be named
 133.117 + * <code><em>item</em>_FIELD</code> where <code><em>item</em></code> identifies
 133.118 + * the field. For examples of these constants, see <code>ERA_FIELD</code> and its
 133.119 + * friends in {@link DateFormat}.
 133.120 + *
 133.121 + * <h4><a name="synchronization">Synchronization</a></h4>
 133.122 + *
 133.123 + * <p>
 133.124 + * Formats are generally not synchronized.
 133.125 + * It is recommended to create separate format instances for each thread.
 133.126 + * If multiple threads access a format concurrently, it must be synchronized
 133.127 + * externally.
 133.128 + *
 133.129 + * @see          java.text.ParsePosition
 133.130 + * @see          java.text.FieldPosition
 133.131 + * @see          java.text.NumberFormat
 133.132 + * @see          java.text.DateFormat
 133.133 + * @see          java.text.MessageFormat
 133.134 + * @author       Mark Davis
 133.135 + */
 133.136 +public abstract class Format implements Serializable, Cloneable {
 133.137 +
 133.138 +    private static final long serialVersionUID = -299282585814624189L;
 133.139 +
 133.140 +    /**
 133.141 +     * Sole constructor.  (For invocation by subclass constructors, typically
 133.142 +     * implicit.)
 133.143 +     */
 133.144 +    protected Format() {
 133.145 +    }
 133.146 +
 133.147 +    /**
 133.148 +     * Formats an object to produce a string. This is equivalent to
 133.149 +     * <blockquote>
 133.150 +     * {@link #format(Object, StringBuffer, FieldPosition) format}<code>(obj,
 133.151 +     *         new StringBuffer(), new FieldPosition(0)).toString();</code>
 133.152 +     * </blockquote>
 133.153 +     *
 133.154 +     * @param obj    The object to format
 133.155 +     * @return       Formatted string.
 133.156 +     * @exception IllegalArgumentException if the Format cannot format the given
 133.157 +     *            object
 133.158 +     */
 133.159 +    public final String format (Object obj) {
 133.160 +        return format(obj, new StringBuffer(), new FieldPosition(0)).toString();
 133.161 +    }
 133.162 +
 133.163 +    /**
 133.164 +     * Formats an object and appends the resulting text to a given string
 133.165 +     * buffer.
 133.166 +     * If the <code>pos</code> argument identifies a field used by the format,
 133.167 +     * then its indices are set to the beginning and end of the first such
 133.168 +     * field encountered.
 133.169 +     *
 133.170 +     * @param obj    The object to format
 133.171 +     * @param toAppendTo    where the text is to be appended
 133.172 +     * @param pos    A <code>FieldPosition</code> identifying a field
 133.173 +     *               in the formatted text
 133.174 +     * @return       the string buffer passed in as <code>toAppendTo</code>,
 133.175 +     *               with formatted text appended
 133.176 +     * @exception NullPointerException if <code>toAppendTo</code> or
 133.177 +     *            <code>pos</code> is null
 133.178 +     * @exception IllegalArgumentException if the Format cannot format the given
 133.179 +     *            object
 133.180 +     */
 133.181 +    public abstract StringBuffer format(Object obj,
 133.182 +                    StringBuffer toAppendTo,
 133.183 +                    FieldPosition pos);
 133.184 +
 133.185 +    /**
 133.186 +     * Formats an Object producing an <code>AttributedCharacterIterator</code>.
 133.187 +     * You can use the returned <code>AttributedCharacterIterator</code>
 133.188 +     * to build the resulting String, as well as to determine information
 133.189 +     * about the resulting String.
 133.190 +     * <p>
 133.191 +     * Each attribute key of the AttributedCharacterIterator will be of type
 133.192 +     * <code>Field</code>. It is up to each <code>Format</code> implementation
 133.193 +     * to define what the legal values are for each attribute in the
 133.194 +     * <code>AttributedCharacterIterator</code>, but typically the attribute
 133.195 +     * key is also used as the attribute value.
 133.196 +     * <p>The default implementation creates an
 133.197 +     * <code>AttributedCharacterIterator</code> with no attributes. Subclasses
 133.198 +     * that support fields should override this and create an
 133.199 +     * <code>AttributedCharacterIterator</code> with meaningful attributes.
 133.200 +     *
 133.201 +     * @exception NullPointerException if obj is null.
 133.202 +     * @exception IllegalArgumentException when the Format cannot format the
 133.203 +     *            given object.
 133.204 +     * @param obj The object to format
 133.205 +     * @return AttributedCharacterIterator describing the formatted value.
 133.206 +     * @since 1.4
 133.207 +     */
 133.208 +    public AttributedCharacterIterator formatToCharacterIterator(Object obj) {
 133.209 +        return createAttributedCharacterIterator(format(obj));
 133.210 +    }
 133.211 +
 133.212 +    /**
 133.213 +     * Parses text from a string to produce an object.
 133.214 +     * <p>
 133.215 +     * The method attempts to parse text starting at the index given by
 133.216 +     * <code>pos</code>.
 133.217 +     * If parsing succeeds, then the index of <code>pos</code> is updated
 133.218 +     * to the index after the last character used (parsing does not necessarily
 133.219 +     * use all characters up to the end of the string), and the parsed
 133.220 +     * object is returned. The updated <code>pos</code> can be used to
 133.221 +     * indicate the starting point for the next call to this method.
 133.222 +     * If an error occurs, then the index of <code>pos</code> is not
 133.223 +     * changed, the error index of <code>pos</code> is set to the index of
 133.224 +     * the character where the error occurred, and null is returned.
 133.225 +     *
 133.226 +     * @param source A <code>String</code>, part of which should be parsed.
 133.227 +     * @param pos A <code>ParsePosition</code> object with index and error
 133.228 +     *            index information as described above.
 133.229 +     * @return An <code>Object</code> parsed from the string. In case of
 133.230 +     *         error, returns null.
 133.231 +     * @exception NullPointerException if <code>pos</code> is null.
 133.232 +     */
 133.233 +    public abstract Object parseObject (String source, ParsePosition pos);
 133.234 +
 133.235 +    /**
 133.236 +     * Parses text from the beginning of the given string to produce an object.
 133.237 +     * The method may not use the entire text of the given string.
 133.238 +     *
 133.239 +     * @param source A <code>String</code> whose beginning should be parsed.
 133.240 +     * @return An <code>Object</code> parsed from the string.
 133.241 +     * @exception ParseException if the beginning of the specified string
 133.242 +     *            cannot be parsed.
 133.243 +     */
 133.244 +    public Object parseObject(String source) throws ParseException {
 133.245 +        ParsePosition pos = new ParsePosition(0);
 133.246 +        Object result = parseObject(source, pos);
 133.247 +        if (pos.index == 0) {
 133.248 +            throw new ParseException("Format.parseObject(String) failed",
 133.249 +                pos.errorIndex);
 133.250 +        }
 133.251 +        return result;
 133.252 +    }
 133.253 +
 133.254 +    /**
 133.255 +     * Creates and returns a copy of this object.
 133.256 +     *
 133.257 +     * @return a clone of this instance.
 133.258 +     */
 133.259 +    public Object clone() {
 133.260 +        try {
 133.261 +            return super.clone();
 133.262 +        } catch (CloneNotSupportedException e) {
 133.263 +            // will never happen
 133.264 +            return null;
 133.265 +        }
 133.266 +    }
 133.267 +
 133.268 +    //
 133.269 +    // Convenience methods for creating AttributedCharacterIterators from
 133.270 +    // different parameters.
 133.271 +    //
 133.272 +
 133.273 +    /**
 133.274 +     * Creates an <code>AttributedCharacterIterator</code> for the String
 133.275 +     * <code>s</code>.
 133.276 +     *
 133.277 +     * @param s String to create AttributedCharacterIterator from
 133.278 +     * @return AttributedCharacterIterator wrapping s
 133.279 +     */
 133.280 +    AttributedCharacterIterator createAttributedCharacterIterator(String s) {
 133.281 +        AttributedString as = new AttributedString(s);
 133.282 +
 133.283 +        return as.getIterator();
 133.284 +    }
 133.285 +
 133.286 +    /**
 133.287 +     * Creates an <code>AttributedCharacterIterator</code> containg the
 133.288 +     * concatenated contents of the passed in
 133.289 +     * <code>AttributedCharacterIterator</code>s.
 133.290 +     *
 133.291 +     * @param iterators AttributedCharacterIterators used to create resulting
 133.292 +     *                  AttributedCharacterIterators
 133.293 +     * @return AttributedCharacterIterator wrapping passed in
 133.294 +     *         AttributedCharacterIterators
 133.295 +     */
 133.296 +    AttributedCharacterIterator createAttributedCharacterIterator(
 133.297 +                       AttributedCharacterIterator[] iterators) {
 133.298 +        AttributedString as = new AttributedString(iterators);
 133.299 +
 133.300 +        return as.getIterator();
 133.301 +    }
 133.302 +
 133.303 +    /**
 133.304 +     * Returns an AttributedCharacterIterator with the String
 133.305 +     * <code>string</code> and additional key/value pair <code>key</code>,
 133.306 +     * <code>value</code>.
 133.307 +     *
 133.308 +     * @param string String to create AttributedCharacterIterator from
 133.309 +     * @param key Key for AttributedCharacterIterator
 133.310 +     * @param value Value associated with key in AttributedCharacterIterator
 133.311 +     * @return AttributedCharacterIterator wrapping args
 133.312 +     */
 133.313 +    AttributedCharacterIterator createAttributedCharacterIterator(
 133.314 +                      String string, AttributedCharacterIterator.Attribute key,
 133.315 +                      Object value) {
 133.316 +        AttributedString as = new AttributedString(string);
 133.317 +
 133.318 +        as.addAttribute(key, value);
 133.319 +        return as.getIterator();
 133.320 +    }
 133.321 +
 133.322 +    /**
 133.323 +     * Creates an AttributedCharacterIterator with the contents of
 133.324 +     * <code>iterator</code> and the additional attribute <code>key</code>
 133.325 +     * <code>value</code>.
 133.326 +     *
 133.327 +     * @param iterator Initial AttributedCharacterIterator to add arg to
 133.328 +     * @param key Key for AttributedCharacterIterator
 133.329 +     * @param value Value associated with key in AttributedCharacterIterator
 133.330 +     * @return AttributedCharacterIterator wrapping args
 133.331 +     */
 133.332 +    AttributedCharacterIterator createAttributedCharacterIterator(
 133.333 +              AttributedCharacterIterator iterator,
 133.334 +              AttributedCharacterIterator.Attribute key, Object value) {
 133.335 +        AttributedString as = new AttributedString(iterator);
 133.336 +
 133.337 +        as.addAttribute(key, value);
 133.338 +        return as.getIterator();
 133.339 +    }
 133.340 +
 133.341 +
 133.342 +    /**
 133.343 +     * Defines constants that are used as attribute keys in the
 133.344 +     * <code>AttributedCharacterIterator</code> returned
 133.345 +     * from <code>Format.formatToCharacterIterator</code> and as
 133.346 +     * field identifiers in <code>FieldPosition</code>.
 133.347 +     *
 133.348 +     * @since 1.4
 133.349 +     */
 133.350 +    public static class Field extends AttributedCharacterIterator.Attribute {
 133.351 +
 133.352 +        // Proclaim serial compatibility with 1.4 FCS
 133.353 +        private static final long serialVersionUID = 276966692217360283L;
 133.354 +
 133.355 +        /**
 133.356 +         * Creates a Field with the specified name.
 133.357 +         *
 133.358 +         * @param name Name of the attribute
 133.359 +         */
 133.360 +        protected Field(String name) {
 133.361 +            super(name);
 133.362 +        }
 133.363 +    }
 133.364 +
 133.365 +
 133.366 +    /**
 133.367 +     * FieldDelegate is notified by the various <code>Format</code>
 133.368 +     * implementations as they are formatting the Objects. This allows for
 133.369 +     * storage of the individual sections of the formatted String for
 133.370 +     * later use, such as in a <code>FieldPosition</code> or for an
 133.371 +     * <code>AttributedCharacterIterator</code>.
 133.372 +     * <p>
 133.373 +     * Delegates should NOT assume that the <code>Format</code> will notify
 133.374 +     * the delegate of fields in any particular order.
 133.375 +     *
 133.376 +     * @see FieldPosition.Delegate
 133.377 +     * @see CharacterIteratorFieldDelegate
 133.378 +     */
 133.379 +    interface FieldDelegate {
 133.380 +        /**
 133.381 +         * Notified when a particular region of the String is formatted. This
 133.382 +         * method will be invoked if there is no corresponding integer field id
 133.383 +         * matching <code>attr</code>.
 133.384 +         *
 133.385 +         * @param attr Identifies the field matched
 133.386 +         * @param value Value associated with the field
 133.387 +         * @param start Beginning location of the field, will be >= 0
 133.388 +         * @param end End of the field, will be >= start and <= buffer.length()
 133.389 +         * @param buffer Contains current formatted value, receiver should
 133.390 +         *        NOT modify it.
 133.391 +         */
 133.392 +        public void formatted(Format.Field attr, Object value, int start,
 133.393 +                              int end, StringBuffer buffer);
 133.394 +
 133.395 +        /**
 133.396 +         * Notified when a particular region of the String is formatted.
 133.397 +         *
 133.398 +         * @param fieldID Identifies the field by integer
 133.399 +         * @param attr Identifies the field matched
 133.400 +         * @param value Value associated with the field
 133.401 +         * @param start Beginning location of the field, will be >= 0
 133.402 +         * @param end End of the field, will be >= start and <= buffer.length()
 133.403 +         * @param buffer Contains current formatted value, receiver should
 133.404 +         *        NOT modify it.
 133.405 +         */
 133.406 +        public void formatted(int fieldID, Format.Field attr, Object value,
 133.407 +                              int start, int end, StringBuffer buffer);
 133.408 +    }
 133.409 +}
   134.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   134.2 +++ b/rt/emul/compact/src/main/java/java/text/MessageFormat.java	Tue Feb 11 13:31:42 2014 +0100
   134.3 @@ -0,0 +1,1594 @@
   134.4 +/*
   134.5 + * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
   134.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   134.7 + *
   134.8 + * This code is free software; you can redistribute it and/or modify it
   134.9 + * under the terms of the GNU General Public License version 2 only, as
  134.10 + * published by the Free Software Foundation.  Oracle designates this
  134.11 + * particular file as subject to the "Classpath" exception as provided
  134.12 + * by Oracle in the LICENSE file that accompanied this code.
  134.13 + *
  134.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  134.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  134.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  134.17 + * version 2 for more details (a copy is included in the LICENSE file that
  134.18 + * accompanied this code).
  134.19 + *
  134.20 + * You should have received a copy of the GNU General Public License version
  134.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  134.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  134.23 + *
  134.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  134.25 + * or visit www.oracle.com if you need additional information or have any
  134.26 + * questions.
  134.27 + */
  134.28 +
  134.29 +/*
  134.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
  134.31 + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
  134.32 + *
  134.33 + *   The original version of this source code and documentation is copyrighted
  134.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
  134.35 + * materials are provided under terms of a License Agreement between Taligent
  134.36 + * and Sun. This technology is protected by multiple US and International
  134.37 + * patents. This notice and attribution to Taligent may not be removed.
  134.38 + *   Taligent is a registered trademark of Taligent, Inc.
  134.39 + *
  134.40 + */
  134.41 +
  134.42 +package java.text;
  134.43 +
  134.44 +import java.io.InvalidObjectException;
  134.45 +import java.io.IOException;
  134.46 +import java.io.ObjectInputStream;
  134.47 +import java.text.DecimalFormat;
  134.48 +import java.util.ArrayList;
  134.49 +import java.util.Arrays;
  134.50 +import java.util.Date;
  134.51 +import java.util.List;
  134.52 +import java.util.Locale;
  134.53 +
  134.54 +
  134.55 +/**
  134.56 + * <code>MessageFormat</code> provides a means to produce concatenated
  134.57 + * messages in a language-neutral way. Use this to construct messages
  134.58 + * displayed for end users.
  134.59 + *
  134.60 + * <p>
  134.61 + * <code>MessageFormat</code> takes a set of objects, formats them, then
  134.62 + * inserts the formatted strings into the pattern at the appropriate places.
  134.63 + *
  134.64 + * <p>
  134.65 + * <strong>Note:</strong>
  134.66 + * <code>MessageFormat</code> differs from the other <code>Format</code>
  134.67 + * classes in that you create a <code>MessageFormat</code> object with one
  134.68 + * of its constructors (not with a <code>getInstance</code> style factory
  134.69 + * method). The factory methods aren't necessary because <code>MessageFormat</code>
  134.70 + * itself doesn't implement locale specific behavior. Any locale specific
  134.71 + * behavior is defined by the pattern that you provide as well as the
  134.72 + * subformats used for inserted arguments.
  134.73 + *
  134.74 + * <h4><a name="patterns">Patterns and Their Interpretation</a></h4>
  134.75 + *
  134.76 + * <code>MessageFormat</code> uses patterns of the following form:
  134.77 + * <blockquote><pre>
  134.78 + * <i>MessageFormatPattern:</i>
  134.79 + *         <i>String</i>
  134.80 + *         <i>MessageFormatPattern</i> <i>FormatElement</i> <i>String</i>
  134.81 + *
  134.82 + * <i>FormatElement:</i>
  134.83 + *         { <i>ArgumentIndex</i> }
  134.84 + *         { <i>ArgumentIndex</i> , <i>FormatType</i> }
  134.85 + *         { <i>ArgumentIndex</i> , <i>FormatType</i> , <i>FormatStyle</i> }
  134.86 + *
  134.87 + * <i>FormatType: one of </i>
  134.88 + *         number date time choice
  134.89 + *
  134.90 + * <i>FormatStyle:</i>
  134.91 + *         short
  134.92 + *         medium
  134.93 + *         long
  134.94 + *         full
  134.95 + *         integer
  134.96 + *         currency
  134.97 + *         percent
  134.98 + *         <i>SubformatPattern</i>
  134.99 + * </pre></blockquote>
 134.100 + *
 134.101 + * <p>Within a <i>String</i>, a pair of single quotes can be used to
 134.102 + * quote any arbitrary characters except single quotes. For example,
 134.103 + * pattern string <code>"'{0}'"</code> represents string
 134.104 + * <code>"{0}"</code>, not a <i>FormatElement</i>. A single quote itself
 134.105 + * must be represented by doubled single quotes {@code ''} throughout a
 134.106 + * <i>String</i>.  For example, pattern string <code>"'{''}'"</code> is
 134.107 + * interpreted as a sequence of <code>'{</code> (start of quoting and a
 134.108 + * left curly brace), <code>''</code> (a single quote), and
 134.109 + * <code>}'</code> (a right curly brace and end of quoting),
 134.110 + * <em>not</em> <code>'{'</code> and <code>'}'</code> (quoted left and
 134.111 + * right curly braces): representing string <code>"{'}"</code>,
 134.112 + * <em>not</em> <code>"{}"</code>.
 134.113 + *
 134.114 + * <p>A <i>SubformatPattern</i> is interpreted by its corresponding
 134.115 + * subformat, and subformat-dependent pattern rules apply. For example,
 134.116 + * pattern string <code>"{1,number,<u>$'#',##</u>}"</code>
 134.117 + * (<i>SubformatPattern</i> with underline) will produce a number format
 134.118 + * with the pound-sign quoted, with a result such as: {@code
 134.119 + * "$#31,45"}. Refer to each {@code Format} subclass documentation for
 134.120 + * details.
 134.121 + *
 134.122 + * <p>Any unmatched quote is treated as closed at the end of the given
 134.123 + * pattern. For example, pattern string {@code "'{0}"} is treated as
 134.124 + * pattern {@code "'{0}'"}.
 134.125 + *
 134.126 + * <p>Any curly braces within an unquoted pattern must be balanced. For
 134.127 + * example, <code>"ab {0} de"</code> and <code>"ab '}' de"</code> are
 134.128 + * valid patterns, but <code>"ab {0'}' de"</code>, <code>"ab } de"</code>
 134.129 + * and <code>"''{''"</code> are not.
 134.130 + *
 134.131 + * <p>
 134.132 + * <dl><dt><b>Warning:</b><dd>The rules for using quotes within message
 134.133 + * format patterns unfortunately have shown to be somewhat confusing.
 134.134 + * In particular, it isn't always obvious to localizers whether single
 134.135 + * quotes need to be doubled or not. Make sure to inform localizers about
 134.136 + * the rules, and tell them (for example, by using comments in resource
 134.137 + * bundle source files) which strings will be processed by {@code MessageFormat}.
 134.138 + * Note that localizers may need to use single quotes in translated
 134.139 + * strings where the original version doesn't have them.
 134.140 + * </dl>
 134.141 + * <p>
 134.142 + * The <i>ArgumentIndex</i> value is a non-negative integer written
 134.143 + * using the digits {@code '0'} through {@code '9'}, and represents an index into the
 134.144 + * {@code arguments} array passed to the {@code format} methods
 134.145 + * or the result array returned by the {@code parse} methods.
 134.146 + * <p>
 134.147 + * The <i>FormatType</i> and <i>FormatStyle</i> values are used to create
 134.148 + * a {@code Format} instance for the format element. The following
 134.149 + * table shows how the values map to {@code Format} instances. Combinations not
 134.150 + * shown in the table are illegal. A <i>SubformatPattern</i> must
 134.151 + * be a valid pattern string for the {@code Format} subclass used.
 134.152 + * <p>
 134.153 + * <table border=1 summary="Shows how FormatType and FormatStyle values map to Format instances">
 134.154 + *    <tr>
 134.155 + *       <th id="ft" class="TableHeadingColor">FormatType
 134.156 + *       <th id="fs" class="TableHeadingColor">FormatStyle
 134.157 + *       <th id="sc" class="TableHeadingColor">Subformat Created
 134.158 + *    <tr>
 134.159 + *       <td headers="ft"><i>(none)</i>
 134.160 + *       <td headers="fs"><i>(none)</i>
 134.161 + *       <td headers="sc"><code>null</code>
 134.162 + *    <tr>
 134.163 + *       <td headers="ft" rowspan=5><code>number</code>
 134.164 + *       <td headers="fs"><i>(none)</i>
 134.165 + *       <td headers="sc">{@link NumberFormat#getInstance(Locale) NumberFormat.getInstance}{@code (getLocale())}
 134.166 + *    <tr>
 134.167 + *       <td headers="fs"><code>integer</code>
 134.168 + *       <td headers="sc">{@link NumberFormat#getIntegerInstance(Locale) NumberFormat.getIntegerInstance}{@code (getLocale())}
 134.169 + *    <tr>
 134.170 + *       <td headers="fs"><code>currency</code>
 134.171 + *       <td headers="sc">{@link NumberFormat#getCurrencyInstance(Locale) NumberFormat.getCurrencyInstance}{@code (getLocale())}
 134.172 + *    <tr>
 134.173 + *       <td headers="fs"><code>percent</code>
 134.174 + *       <td headers="sc">{@link NumberFormat#getPercentInstance(Locale) NumberFormat.getPercentInstance}{@code (getLocale())}
 134.175 + *    <tr>
 134.176 + *       <td headers="fs"><i>SubformatPattern</i>
 134.177 + *       <td headers="sc">{@code new} {@link DecimalFormat#DecimalFormat(String,DecimalFormatSymbols) DecimalFormat}{@code (subformatPattern,} {@link DecimalFormatSymbols#getInstance(Locale) DecimalFormatSymbols.getInstance}{@code (getLocale()))}
 134.178 + *    <tr>
 134.179 + *       <td headers="ft" rowspan=6><code>date</code>
 134.180 + *       <td headers="fs"><i>(none)</i>
 134.181 + *       <td headers="sc">{@link DateFormat#getDateInstance(int,Locale) DateFormat.getDateInstance}{@code (}{@link DateFormat#DEFAULT}{@code , getLocale())}
 134.182 + *    <tr>
 134.183 + *       <td headers="fs"><code>short</code>
 134.184 + *       <td headers="sc">{@link DateFormat#getDateInstance(int,Locale) DateFormat.getDateInstance}{@code (}{@link DateFormat#SHORT}{@code , getLocale())}
 134.185 + *    <tr>
 134.186 + *       <td headers="fs"><code>medium</code>
 134.187 + *       <td headers="sc">{@link DateFormat#getDateInstance(int,Locale) DateFormat.getDateInstance}{@code (}{@link DateFormat#DEFAULT}{@code , getLocale())}
 134.188 + *    <tr>
 134.189 + *       <td headers="fs"><code>long</code>
 134.190 + *       <td headers="sc">{@link DateFormat#getDateInstance(int,Locale) DateFormat.getDateInstance}{@code (}{@link DateFormat#LONG}{@code , getLocale())}
 134.191 + *    <tr>
 134.192 + *       <td headers="fs"><code>full</code>
 134.193 + *       <td headers="sc">{@link DateFormat#getDateInstance(int,Locale) DateFormat.getDateInstance}{@code (}{@link DateFormat#FULL}{@code , getLocale())}
 134.194 + *    <tr>
 134.195 + *       <td headers="fs"><i>SubformatPattern</i>
 134.196 + *       <td headers="sc">{@code new} {@link SimpleDateFormat#SimpleDateFormat(String,Locale) SimpleDateFormat}{@code (subformatPattern, getLocale())}
 134.197 + *    <tr>
 134.198 + *       <td headers="ft" rowspan=6><code>time</code>
 134.199 + *       <td headers="fs"><i>(none)</i>
 134.200 + *       <td headers="sc">{@link DateFormat#getTimeInstance(int,Locale) DateFormat.getTimeInstance}{@code (}{@link DateFormat#DEFAULT}{@code , getLocale())}
 134.201 + *    <tr>
 134.202 + *       <td headers="fs"><code>short</code>
 134.203 + *       <td headers="sc">{@link DateFormat#getTimeInstance(int,Locale) DateFormat.getTimeInstance}{@code (}{@link DateFormat#SHORT}{@code , getLocale())}
 134.204 + *    <tr>
 134.205 + *       <td headers="fs"><code>medium</code>
 134.206 + *       <td headers="sc">{@link DateFormat#getTimeInstance(int,Locale) DateFormat.getTimeInstance}{@code (}{@link DateFormat#DEFAULT}{@code , getLocale())}
 134.207 + *    <tr>
 134.208 + *       <td headers="fs"><code>long</code>
 134.209 + *       <td headers="sc">{@link DateFormat#getTimeInstance(int,Locale) DateFormat.getTimeInstance}{@code (}{@link DateFormat#LONG}{@code , getLocale())}
 134.210 + *    <tr>
 134.211 + *       <td headers="fs"><code>full</code>
 134.212 + *       <td headers="sc">{@link DateFormat#getTimeInstance(int,Locale) DateFormat.getTimeInstance}{@code (}{@link DateFormat#FULL}{@code , getLocale())}
 134.213 + *    <tr>
 134.214 + *       <td headers="fs"><i>SubformatPattern</i>
 134.215 + *       <td headers="sc">{@code new} {@link SimpleDateFormat#SimpleDateFormat(String,Locale) SimpleDateFormat}{@code (subformatPattern, getLocale())}
 134.216 + *    <tr>
 134.217 + *       <td headers="ft"><code>choice</code>
 134.218 + *       <td headers="fs"><i>SubformatPattern</i>
 134.219 + *       <td headers="sc">{@code new} {@link ChoiceFormat#ChoiceFormat(String) ChoiceFormat}{@code (subformatPattern)}
 134.220 + * </table>
 134.221 + * <p>
 134.222 + *
 134.223 + * <h4>Usage Information</h4>
 134.224 + *
 134.225 + * <p>
 134.226 + * Here are some examples of usage.
 134.227 + * In real internationalized programs, the message format pattern and other
 134.228 + * static strings will, of course, be obtained from resource bundles.
 134.229 + * Other parameters will be dynamically determined at runtime.
 134.230 + * <p>
 134.231 + * The first example uses the static method <code>MessageFormat.format</code>,
 134.232 + * which internally creates a <code>MessageFormat</code> for one-time use:
 134.233 + * <blockquote><pre>
 134.234 + * int planet = 7;
 134.235 + * String event = "a disturbance in the Force";
 134.236 + *
 134.237 + * String result = MessageFormat.format(
 134.238 + *     "At {1,time} on {1,date}, there was {2} on planet {0,number,integer}.",
 134.239 + *     planet, new Date(), event);
 134.240 + * </pre></blockquote>
 134.241 + * The output is:
 134.242 + * <blockquote><pre>
 134.243 + * At 12:30 PM on Jul 3, 2053, there was a disturbance in the Force on planet 7.
 134.244 + * </pre></blockquote>
 134.245 + *
 134.246 + * <p>
 134.247 + * The following example creates a <code>MessageFormat</code> instance that
 134.248 + * can be used repeatedly:
 134.249 + * <blockquote><pre>
 134.250 + * int fileCount = 1273;
 134.251 + * String diskName = "MyDisk";
 134.252 + * Object[] testArgs = {new Long(fileCount), diskName};
 134.253 + *
 134.254 + * MessageFormat form = new MessageFormat(
 134.255 + *     "The disk \"{1}\" contains {0} file(s).");
 134.256 + *
 134.257 + * System.out.println(form.format(testArgs));
 134.258 + * </pre></blockquote>
 134.259 + * The output with different values for <code>fileCount</code>:
 134.260 + * <blockquote><pre>
 134.261 + * The disk "MyDisk" contains 0 file(s).
 134.262 + * The disk "MyDisk" contains 1 file(s).
 134.263 + * The disk "MyDisk" contains 1,273 file(s).
 134.264 + * </pre></blockquote>
 134.265 + *
 134.266 + * <p>
 134.267 + * For more sophisticated patterns, you can use a <code>ChoiceFormat</code>
 134.268 + * to produce correct forms for singular and plural:
 134.269 + * <blockquote><pre>
 134.270 + * MessageFormat form = new MessageFormat("The disk \"{1}\" contains {0}.");
 134.271 + * double[] filelimits = {0,1,2};
 134.272 + * String[] filepart = {"no files","one file","{0,number} files"};
 134.273 + * ChoiceFormat fileform = new ChoiceFormat(filelimits, filepart);
 134.274 + * form.setFormatByArgumentIndex(0, fileform);
 134.275 + *
 134.276 + * int fileCount = 1273;
 134.277 + * String diskName = "MyDisk";
 134.278 + * Object[] testArgs = {new Long(fileCount), diskName};
 134.279 + *
 134.280 + * System.out.println(form.format(testArgs));
 134.281 + * </pre></blockquote>
 134.282 + * The output with different values for <code>fileCount</code>:
 134.283 + * <blockquote><pre>
 134.284 + * The disk "MyDisk" contains no files.
 134.285 + * The disk "MyDisk" contains one file.
 134.286 + * The disk "MyDisk" contains 1,273 files.
 134.287 + * </pre></blockquote>
 134.288 + *
 134.289 + * <p>
 134.290 + * You can create the <code>ChoiceFormat</code> programmatically, as in the
 134.291 + * above example, or by using a pattern. See {@link ChoiceFormat}
 134.292 + * for more information.
 134.293 + * <blockquote><pre>
 134.294 + * form.applyPattern(
 134.295 + *    "There {0,choice,0#are no files|1#is one file|1&lt;are {0,number,integer} files}.");
 134.296 + * </pre></blockquote>
 134.297 + *
 134.298 + * <p>
 134.299 + * <strong>Note:</strong> As we see above, the string produced
 134.300 + * by a <code>ChoiceFormat</code> in <code>MessageFormat</code> is treated as special;
 134.301 + * occurrences of '{' are used to indicate subformats, and cause recursion.
 134.302 + * If you create both a <code>MessageFormat</code> and <code>ChoiceFormat</code>
 134.303 + * programmatically (instead of using the string patterns), then be careful not to
 134.304 + * produce a format that recurses on itself, which will cause an infinite loop.
 134.305 + * <p>
 134.306 + * When a single argument is parsed more than once in the string, the last match
 134.307 + * will be the final result of the parsing.  For example,
 134.308 + * <blockquote><pre>
 134.309 + * MessageFormat mf = new MessageFormat("{0,number,#.##}, {0,number,#.#}");
 134.310 + * Object[] objs = {new Double(3.1415)};
 134.311 + * String result = mf.format( objs );
 134.312 + * // result now equals "3.14, 3.1"
 134.313 + * objs = null;
 134.314 + * objs = mf.parse(result, new ParsePosition(0));
 134.315 + * // objs now equals {new Double(3.1)}
 134.316 + * </pre></blockquote>
 134.317 + *
 134.318 + * <p>
 134.319 + * Likewise, parsing with a {@code MessageFormat} object using patterns containing
 134.320 + * multiple occurrences of the same argument would return the last match.  For
 134.321 + * example,
 134.322 + * <blockquote><pre>
 134.323 + * MessageFormat mf = new MessageFormat("{0}, {0}, {0}");
 134.324 + * String forParsing = "x, y, z";
 134.325 + * Object[] objs = mf.parse(forParsing, new ParsePosition(0));
 134.326 + * // result now equals {new String("z")}
 134.327 + * </pre></blockquote>
 134.328 + *
 134.329 + * <h4><a name="synchronization">Synchronization</a></h4>
 134.330 + *
 134.331 + * <p>
 134.332 + * Message formats are not synchronized.
 134.333 + * It is recommended to create separate format instances for each thread.
 134.334 + * If multiple threads access a format concurrently, it must be synchronized
 134.335 + * externally.
 134.336 + *
 134.337 + * @see          java.util.Locale
 134.338 + * @see          Format
 134.339 + * @see          NumberFormat
 134.340 + * @see          DecimalFormat
 134.341 + * @see          DecimalFormatSymbols
 134.342 + * @see          ChoiceFormat
 134.343 + * @see          DateFormat
 134.344 + * @see          SimpleDateFormat
 134.345 + *
 134.346 + * @author       Mark Davis
 134.347 + */
 134.348 +
 134.349 +public class MessageFormat extends Format {
 134.350 +
 134.351 +    private static final long serialVersionUID = 6479157306784022952L;
 134.352 +
 134.353 +    /**
 134.354 +     * Constructs a MessageFormat for the default locale and the
 134.355 +     * specified pattern.
 134.356 +     * The constructor first sets the locale, then parses the pattern and
 134.357 +     * creates a list of subformats for the format elements contained in it.
 134.358 +     * Patterns and their interpretation are specified in the
 134.359 +     * <a href="#patterns">class description</a>.
 134.360 +     *
 134.361 +     * @param pattern the pattern for this message format
 134.362 +     * @exception IllegalArgumentException if the pattern is invalid
 134.363 +     */
 134.364 +    public MessageFormat(String pattern) {
 134.365 +        this.locale = Locale.getDefault(Locale.Category.FORMAT);
 134.366 +        applyPattern(pattern);
 134.367 +    }
 134.368 +
 134.369 +    /**
 134.370 +     * Constructs a MessageFormat for the specified locale and
 134.371 +     * pattern.
 134.372 +     * The constructor first sets the locale, then parses the pattern and
 134.373 +     * creates a list of subformats for the format elements contained in it.
 134.374 +     * Patterns and their interpretation are specified in the
 134.375 +     * <a href="#patterns">class description</a>.
 134.376 +     *
 134.377 +     * @param pattern the pattern for this message format
 134.378 +     * @param locale the locale for this message format
 134.379 +     * @exception IllegalArgumentException if the pattern is invalid
 134.380 +     * @since 1.4
 134.381 +     */
 134.382 +    public MessageFormat(String pattern, Locale locale) {
 134.383 +        this.locale = locale;
 134.384 +        applyPattern(pattern);
 134.385 +    }
 134.386 +
 134.387 +    /**
 134.388 +     * Sets the locale to be used when creating or comparing subformats.
 134.389 +     * This affects subsequent calls
 134.390 +     * <ul>
 134.391 +     * <li>to the {@link #applyPattern applyPattern}
 134.392 +     *     and {@link #toPattern toPattern} methods if format elements specify
 134.393 +     *     a format type and therefore have the subformats created in the
 134.394 +     *     <code>applyPattern</code> method, as well as
 134.395 +     * <li>to the <code>format</code> and
 134.396 +     *     {@link #formatToCharacterIterator formatToCharacterIterator} methods
 134.397 +     *     if format elements do not specify a format type and therefore have
 134.398 +     *     the subformats created in the formatting methods.
 134.399 +     * </ul>
 134.400 +     * Subformats that have already been created are not affected.
 134.401 +     *
 134.402 +     * @param locale the locale to be used when creating or comparing subformats
 134.403 +     */
 134.404 +    public void setLocale(Locale locale) {
 134.405 +        this.locale = locale;
 134.406 +    }
 134.407 +
 134.408 +    /**
 134.409 +     * Gets the locale that's used when creating or comparing subformats.
 134.410 +     *
 134.411 +     * @return the locale used when creating or comparing subformats
 134.412 +     */
 134.413 +    public Locale getLocale() {
 134.414 +        return locale;
 134.415 +    }
 134.416 +
 134.417 +
 134.418 +    /**
 134.419 +     * Sets the pattern used by this message format.
 134.420 +     * The method parses the pattern and creates a list of subformats
 134.421 +     * for the format elements contained in it.
 134.422 +     * Patterns and their interpretation are specified in the
 134.423 +     * <a href="#patterns">class description</a>.
 134.424 +     *
 134.425 +     * @param pattern the pattern for this message format
 134.426 +     * @exception IllegalArgumentException if the pattern is invalid
 134.427 +     */
 134.428 +    public void applyPattern(String pattern) {
 134.429 +            StringBuilder[] segments = new StringBuilder[4];
 134.430 +            // Allocate only segments[SEG_RAW] here. The rest are
 134.431 +            // allocated on demand.
 134.432 +            segments[SEG_RAW] = new StringBuilder();
 134.433 +
 134.434 +            int part = SEG_RAW;
 134.435 +            int formatNumber = 0;
 134.436 +            boolean inQuote = false;
 134.437 +            int braceStack = 0;
 134.438 +            maxOffset = -1;
 134.439 +            for (int i = 0; i < pattern.length(); ++i) {
 134.440 +                char ch = pattern.charAt(i);
 134.441 +                if (part == SEG_RAW) {
 134.442 +                    if (ch == '\'') {
 134.443 +                        if (i + 1 < pattern.length()
 134.444 +                            && pattern.charAt(i+1) == '\'') {
 134.445 +                            segments[part].append(ch);  // handle doubles
 134.446 +                            ++i;
 134.447 +                        } else {
 134.448 +                            inQuote = !inQuote;
 134.449 +                        }
 134.450 +                    } else if (ch == '{' && !inQuote) {
 134.451 +                        part = SEG_INDEX;
 134.452 +                        if (segments[SEG_INDEX] == null) {
 134.453 +                            segments[SEG_INDEX] = new StringBuilder();
 134.454 +                        }
 134.455 +                    } else {
 134.456 +                        segments[part].append(ch);
 134.457 +                    }
 134.458 +                } else  {
 134.459 +                    if (inQuote) {              // just copy quotes in parts
 134.460 +                        segments[part].append(ch);
 134.461 +                        if (ch == '\'') {
 134.462 +                            inQuote = false;
 134.463 +                        }
 134.464 +                    } else {
 134.465 +                        switch (ch) {
 134.466 +                        case ',':
 134.467 +                            if (part < SEG_MODIFIER) {
 134.468 +                                if (segments[++part] == null) {
 134.469 +                                    segments[part] = new StringBuilder();
 134.470 +                                }
 134.471 +                            } else {
 134.472 +                                segments[part].append(ch);
 134.473 +                            }
 134.474 +                            break;
 134.475 +                        case '{':
 134.476 +                            ++braceStack;
 134.477 +                            segments[part].append(ch);
 134.478 +                            break;
 134.479 +                        case '}':
 134.480 +                            if (braceStack == 0) {
 134.481 +                                part = SEG_RAW;
 134.482 +                                makeFormat(i, formatNumber, segments);
 134.483 +                                formatNumber++;
 134.484 +                                // throw away other segments
 134.485 +                                segments[SEG_INDEX] = null;
 134.486 +                                segments[SEG_TYPE] = null;
 134.487 +                                segments[SEG_MODIFIER] = null;
 134.488 +                            } else {
 134.489 +                                --braceStack;
 134.490 +                                segments[part].append(ch);
 134.491 +                            }
 134.492 +                            break;
 134.493 +                        case ' ':
 134.494 +                            // Skip any leading space chars for SEG_TYPE.
 134.495 +                            if (part != SEG_TYPE || segments[SEG_TYPE].length() > 0) {
 134.496 +                                segments[part].append(ch);
 134.497 +                            }
 134.498 +                            break;
 134.499 +                        case '\'':
 134.500 +                            inQuote = true;
 134.501 +                            // fall through, so we keep quotes in other parts
 134.502 +                        default:
 134.503 +                            segments[part].append(ch);
 134.504 +                            break;
 134.505 +                        }
 134.506 +                    }
 134.507 +                }
 134.508 +            }
 134.509 +            if (braceStack == 0 && part != 0) {
 134.510 +                maxOffset = -1;
 134.511 +                throw new IllegalArgumentException("Unmatched braces in the pattern.");
 134.512 +            }
 134.513 +            this.pattern = segments[0].toString();
 134.514 +    }
 134.515 +
 134.516 +
 134.517 +    /**
 134.518 +     * Returns a pattern representing the current state of the message format.
 134.519 +     * The string is constructed from internal information and therefore
 134.520 +     * does not necessarily equal the previously applied pattern.
 134.521 +     *
 134.522 +     * @return a pattern representing the current state of the message format
 134.523 +     */
 134.524 +    public String toPattern() {
 134.525 +        // later, make this more extensible
 134.526 +        int lastOffset = 0;
 134.527 +        StringBuilder result = new StringBuilder();
 134.528 +        for (int i = 0; i <= maxOffset; ++i) {
 134.529 +            copyAndFixQuotes(pattern, lastOffset, offsets[i], result);
 134.530 +            lastOffset = offsets[i];
 134.531 +            result.append('{').append(argumentNumbers[i]);
 134.532 +            Format fmt = formats[i];
 134.533 +            if (fmt == null) {
 134.534 +                // do nothing, string format
 134.535 +            } else if (fmt instanceof NumberFormat) {
 134.536 +                if (fmt.equals(NumberFormat.getInstance(locale))) {
 134.537 +                    result.append(",number");
 134.538 +                } else if (fmt.equals(NumberFormat.getCurrencyInstance(locale))) {
 134.539 +                    result.append(",number,currency");
 134.540 +                } else if (fmt.equals(NumberFormat.getPercentInstance(locale))) {
 134.541 +                    result.append(",number,percent");
 134.542 +                } else if (fmt.equals(NumberFormat.getIntegerInstance(locale))) {
 134.543 +                    result.append(",number,integer");
 134.544 +                } else {
 134.545 +                    if (fmt instanceof DecimalFormat) {
 134.546 +                        result.append(",number,").append(((DecimalFormat)fmt).toPattern());
 134.547 +                    } else if (fmt instanceof ChoiceFormat) {
 134.548 +                        result.append(",choice,").append(((ChoiceFormat)fmt).toPattern());
 134.549 +                    } else {
 134.550 +                        // UNKNOWN
 134.551 +                    }
 134.552 +                }
 134.553 +            } else if (fmt instanceof DateFormat) {
 134.554 +                int index;
 134.555 +                for (index = MODIFIER_DEFAULT; index < DATE_TIME_MODIFIERS.length; index++) {
 134.556 +                    DateFormat df = DateFormat.getDateInstance(DATE_TIME_MODIFIERS[index],
 134.557 +                                                               locale);
 134.558 +                    if (fmt.equals(df)) {
 134.559 +                        result.append(",date");
 134.560 +                        break;
 134.561 +                    }
 134.562 +                    df = DateFormat.getTimeInstance(DATE_TIME_MODIFIERS[index],
 134.563 +                                                    locale);
 134.564 +                    if (fmt.equals(df)) {
 134.565 +                        result.append(",time");
 134.566 +                        break;
 134.567 +                    }
 134.568 +                }
 134.569 +                if (index >= DATE_TIME_MODIFIERS.length) {
 134.570 +                    if (fmt instanceof SimpleDateFormat) {
 134.571 +                        result.append(",date,").append(((SimpleDateFormat)fmt).toPattern());
 134.572 +                    } else {
 134.573 +                        // UNKNOWN
 134.574 +                    }
 134.575 +                } else if (index != MODIFIER_DEFAULT) {
 134.576 +                    result.append(',').append(DATE_TIME_MODIFIER_KEYWORDS[index]);
 134.577 +                }
 134.578 +            } else {
 134.579 +                //result.append(", unknown");
 134.580 +            }
 134.581 +            result.append('}');
 134.582 +        }
 134.583 +        copyAndFixQuotes(pattern, lastOffset, pattern.length(), result);
 134.584 +        return result.toString();
 134.585 +    }
 134.586 +
 134.587 +    /**
 134.588 +     * Sets the formats to use for the values passed into
 134.589 +     * <code>format</code> methods or returned from <code>parse</code>
 134.590 +     * methods. The indices of elements in <code>newFormats</code>
 134.591 +     * correspond to the argument indices used in the previously set
 134.592 +     * pattern string.
 134.593 +     * The order of formats in <code>newFormats</code> thus corresponds to
 134.594 +     * the order of elements in the <code>arguments</code> array passed
 134.595 +     * to the <code>format</code> methods or the result array returned
 134.596 +     * by the <code>parse</code> methods.
 134.597 +     * <p>
 134.598 +     * If an argument index is used for more than one format element
 134.599 +     * in the pattern string, then the corresponding new format is used
 134.600 +     * for all such format elements. If an argument index is not used
 134.601 +     * for any format element in the pattern string, then the
 134.602 +     * corresponding new format is ignored. If fewer formats are provided
 134.603 +     * than needed, then only the formats for argument indices less
 134.604 +     * than <code>newFormats.length</code> are replaced.
 134.605 +     *
 134.606 +     * @param newFormats the new formats to use
 134.607 +     * @exception NullPointerException if <code>newFormats</code> is null
 134.608 +     * @since 1.4
 134.609 +     */
 134.610 +    public void setFormatsByArgumentIndex(Format[] newFormats) {
 134.611 +        for (int i = 0; i <= maxOffset; i++) {
 134.612 +            int j = argumentNumbers[i];
 134.613 +            if (j < newFormats.length) {
 134.614 +                formats[i] = newFormats[j];
 134.615 +            }
 134.616 +        }
 134.617 +    }
 134.618 +
 134.619 +    /**
 134.620 +     * Sets the formats to use for the format elements in the
 134.621 +     * previously set pattern string.
 134.622 +     * The order of formats in <code>newFormats</code> corresponds to
 134.623 +     * the order of format elements in the pattern string.
 134.624 +     * <p>
 134.625 +     * If more formats are provided than needed by the pattern string,
 134.626 +     * the remaining ones are ignored. If fewer formats are provided
 134.627 +     * than needed, then only the first <code>newFormats.length</code>
 134.628 +     * formats are replaced.
 134.629 +     * <p>
 134.630 +     * Since the order of format elements in a pattern string often
 134.631 +     * changes during localization, it is generally better to use the
 134.632 +     * {@link #setFormatsByArgumentIndex setFormatsByArgumentIndex}
 134.633 +     * method, which assumes an order of formats corresponding to the
 134.634 +     * order of elements in the <code>arguments</code> array passed to
 134.635 +     * the <code>format</code> methods or the result array returned by
 134.636 +     * the <code>parse</code> methods.
 134.637 +     *
 134.638 +     * @param newFormats the new formats to use
 134.639 +     * @exception NullPointerException if <code>newFormats</code> is null
 134.640 +     */
 134.641 +    public void setFormats(Format[] newFormats) {
 134.642 +        int runsToCopy = newFormats.length;
 134.643 +        if (runsToCopy > maxOffset + 1) {
 134.644 +            runsToCopy = maxOffset + 1;
 134.645 +        }
 134.646 +        for (int i = 0; i < runsToCopy; i++) {
 134.647 +            formats[i] = newFormats[i];
 134.648 +        }
 134.649 +    }
 134.650 +
 134.651 +    /**
 134.652 +     * Sets the format to use for the format elements within the
 134.653 +     * previously set pattern string that use the given argument
 134.654 +     * index.
 134.655 +     * The argument index is part of the format element definition and
 134.656 +     * represents an index into the <code>arguments</code> array passed
 134.657 +     * to the <code>format</code> methods or the result array returned
 134.658 +     * by the <code>parse</code> methods.
 134.659 +     * <p>
 134.660 +     * If the argument index is used for more than one format element
 134.661 +     * in the pattern string, then the new format is used for all such
 134.662 +     * format elements. If the argument index is not used for any format
 134.663 +     * element in the pattern string, then the new format is ignored.
 134.664 +     *
 134.665 +     * @param argumentIndex the argument index for which to use the new format
 134.666 +     * @param newFormat the new format to use
 134.667 +     * @since 1.4
 134.668 +     */
 134.669 +    public void setFormatByArgumentIndex(int argumentIndex, Format newFormat) {
 134.670 +        for (int j = 0; j <= maxOffset; j++) {
 134.671 +            if (argumentNumbers[j] == argumentIndex) {
 134.672 +                formats[j] = newFormat;
 134.673 +            }
 134.674 +        }
 134.675 +    }
 134.676 +
 134.677 +    /**
 134.678 +     * Sets the format to use for the format element with the given
 134.679 +     * format element index within the previously set pattern string.
 134.680 +     * The format element index is the zero-based number of the format
 134.681 +     * element counting from the start of the pattern string.
 134.682 +     * <p>
 134.683 +     * Since the order of format elements in a pattern string often
 134.684 +     * changes during localization, it is generally better to use the
 134.685 +     * {@link #setFormatByArgumentIndex setFormatByArgumentIndex}
 134.686 +     * method, which accesses format elements based on the argument
 134.687 +     * index they specify.
 134.688 +     *
 134.689 +     * @param formatElementIndex the index of a format element within the pattern
 134.690 +     * @param newFormat the format to use for the specified format element
 134.691 +     * @exception ArrayIndexOutOfBoundsException if {@code formatElementIndex} is equal to or
 134.692 +     *            larger than the number of format elements in the pattern string
 134.693 +     */
 134.694 +    public void setFormat(int formatElementIndex, Format newFormat) {
 134.695 +        formats[formatElementIndex] = newFormat;
 134.696 +    }
 134.697 +
 134.698 +    /**
 134.699 +     * Gets the formats used for the values passed into
 134.700 +     * <code>format</code> methods or returned from <code>parse</code>
 134.701 +     * methods. The indices of elements in the returned array
 134.702 +     * correspond to the argument indices used in the previously set
 134.703 +     * pattern string.
 134.704 +     * The order of formats in the returned array thus corresponds to
 134.705 +     * the order of elements in the <code>arguments</code> array passed
 134.706 +     * to the <code>format</code> methods or the result array returned
 134.707 +     * by the <code>parse</code> methods.
 134.708 +     * <p>
 134.709 +     * If an argument index is used for more than one format element
 134.710 +     * in the pattern string, then the format used for the last such
 134.711 +     * format element is returned in the array. If an argument index
 134.712 +     * is not used for any format element in the pattern string, then
 134.713 +     * null is returned in the array.
 134.714 +     *
 134.715 +     * @return the formats used for the arguments within the pattern
 134.716 +     * @since 1.4
 134.717 +     */
 134.718 +    public Format[] getFormatsByArgumentIndex() {
 134.719 +        int maximumArgumentNumber = -1;
 134.720 +        for (int i = 0; i <= maxOffset; i++) {
 134.721 +            if (argumentNumbers[i] > maximumArgumentNumber) {
 134.722 +                maximumArgumentNumber = argumentNumbers[i];
 134.723 +            }
 134.724 +        }
 134.725 +        Format[] resultArray = new Format[maximumArgumentNumber + 1];
 134.726 +        for (int i = 0; i <= maxOffset; i++) {
 134.727 +            resultArray[argumentNumbers[i]] = formats[i];
 134.728 +        }
 134.729 +        return resultArray;
 134.730 +    }
 134.731 +
 134.732 +    /**
 134.733 +     * Gets the formats used for the format elements in the
 134.734 +     * previously set pattern string.
 134.735 +     * The order of formats in the returned array corresponds to
 134.736 +     * the order of format elements in the pattern string.
 134.737 +     * <p>
 134.738 +     * Since the order of format elements in a pattern string often
 134.739 +     * changes during localization, it's generally better to use the
 134.740 +     * {@link #getFormatsByArgumentIndex getFormatsByArgumentIndex}
 134.741 +     * method, which assumes an order of formats corresponding to the
 134.742 +     * order of elements in the <code>arguments</code> array passed to
 134.743 +     * the <code>format</code> methods or the result array returned by
 134.744 +     * the <code>parse</code> methods.
 134.745 +     *
 134.746 +     * @return the formats used for the format elements in the pattern
 134.747 +     */
 134.748 +    public Format[] getFormats() {
 134.749 +        Format[] resultArray = new Format[maxOffset + 1];
 134.750 +        System.arraycopy(formats, 0, resultArray, 0, maxOffset + 1);
 134.751 +        return resultArray;
 134.752 +    }
 134.753 +
 134.754 +    /**
 134.755 +     * Formats an array of objects and appends the <code>MessageFormat</code>'s
 134.756 +     * pattern, with format elements replaced by the formatted objects, to the
 134.757 +     * provided <code>StringBuffer</code>.
 134.758 +     * <p>
 134.759 +     * The text substituted for the individual format elements is derived from
 134.760 +     * the current subformat of the format element and the
 134.761 +     * <code>arguments</code> element at the format element's argument index
 134.762 +     * as indicated by the first matching line of the following table. An
 134.763 +     * argument is <i>unavailable</i> if <code>arguments</code> is
 134.764 +     * <code>null</code> or has fewer than argumentIndex+1 elements.
 134.765 +     * <p>
 134.766 +     * <table border=1 summary="Examples of subformat,argument,and formatted text">
 134.767 +     *    <tr>
 134.768 +     *       <th>Subformat
 134.769 +     *       <th>Argument
 134.770 +     *       <th>Formatted Text
 134.771 +     *    <tr>
 134.772 +     *       <td><i>any</i>
 134.773 +     *       <td><i>unavailable</i>
 134.774 +     *       <td><code>"{" + argumentIndex + "}"</code>
 134.775 +     *    <tr>
 134.776 +     *       <td><i>any</i>
 134.777 +     *       <td><code>null</code>
 134.778 +     *       <td><code>"null"</code>
 134.779 +     *    <tr>
 134.780 +     *       <td><code>instanceof ChoiceFormat</code>
 134.781 +     *       <td><i>any</i>
 134.782 +     *       <td><code>subformat.format(argument).indexOf('{') >= 0 ?<br>
 134.783 +     *           (new MessageFormat(subformat.format(argument), getLocale())).format(argument) :
 134.784 +     *           subformat.format(argument)</code>
 134.785 +     *    <tr>
 134.786 +     *       <td><code>!= null</code>
 134.787 +     *       <td><i>any</i>
 134.788 +     *       <td><code>subformat.format(argument)</code>
 134.789 +     *    <tr>
 134.790 +     *       <td><code>null</code>
 134.791 +     *       <td><code>instanceof Number</code>
 134.792 +     *       <td><code>NumberFormat.getInstance(getLocale()).format(argument)</code>
 134.793 +     *    <tr>
 134.794 +     *       <td><code>null</code>
 134.795 +     *       <td><code>instanceof Date</code>
 134.796 +     *       <td><code>DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, getLocale()).format(argument)</code>
 134.797 +     *    <tr>
 134.798 +     *       <td><code>null</code>
 134.799 +     *       <td><code>instanceof String</code>
 134.800 +     *       <td><code>argument</code>
 134.801 +     *    <tr>
 134.802 +     *       <td><code>null</code>
 134.803 +     *       <td><i>any</i>
 134.804 +     *       <td><code>argument.toString()</code>
 134.805 +     * </table>
 134.806 +     * <p>
 134.807 +     * If <code>pos</code> is non-null, and refers to
 134.808 +     * <code>Field.ARGUMENT</code>, the location of the first formatted
 134.809 +     * string will be returned.
 134.810 +     *
 134.811 +     * @param arguments an array of objects to be formatted and substituted.
 134.812 +     * @param result where text is appended.
 134.813 +     * @param pos On input: an alignment field, if desired.
 134.814 +     *            On output: the offsets of the alignment field.
 134.815 +     * @exception IllegalArgumentException if an argument in the
 134.816 +     *            <code>arguments</code> array is not of the type
 134.817 +     *            expected by the format element(s) that use it.
 134.818 +     */
 134.819 +    public final StringBuffer format(Object[] arguments, StringBuffer result,
 134.820 +                                     FieldPosition pos)
 134.821 +    {
 134.822 +        return subformat(arguments, result, pos, null);
 134.823 +    }
 134.824 +
 134.825 +    /**
 134.826 +     * Creates a MessageFormat with the given pattern and uses it
 134.827 +     * to format the given arguments. This is equivalent to
 134.828 +     * <blockquote>
 134.829 +     *     <code>(new {@link #MessageFormat(String) MessageFormat}(pattern)).{@link #format(java.lang.Object[], java.lang.StringBuffer, java.text.FieldPosition) format}(arguments, new StringBuffer(), null).toString()</code>
 134.830 +     * </blockquote>
 134.831 +     *
 134.832 +     * @exception IllegalArgumentException if the pattern is invalid,
 134.833 +     *            or if an argument in the <code>arguments</code> array
 134.834 +     *            is not of the type expected by the format element(s)
 134.835 +     *            that use it.
 134.836 +     */
 134.837 +    public static String format(String pattern, Object ... arguments) {
 134.838 +        MessageFormat temp = new MessageFormat(pattern);
 134.839 +        return temp.format(arguments);
 134.840 +    }
 134.841 +
 134.842 +    // Overrides
 134.843 +    /**
 134.844 +     * Formats an array of objects and appends the <code>MessageFormat</code>'s
 134.845 +     * pattern, with format elements replaced by the formatted objects, to the
 134.846 +     * provided <code>StringBuffer</code>.
 134.847 +     * This is equivalent to
 134.848 +     * <blockquote>
 134.849 +     *     <code>{@link #format(java.lang.Object[], java.lang.StringBuffer, java.text.FieldPosition) format}((Object[]) arguments, result, pos)</code>
 134.850 +     * </blockquote>
 134.851 +     *
 134.852 +     * @param arguments an array of objects to be formatted and substituted.
 134.853 +     * @param result where text is appended.
 134.854 +     * @param pos On input: an alignment field, if desired.
 134.855 +     *            On output: the offsets of the alignment field.
 134.856 +     * @exception IllegalArgumentException if an argument in the
 134.857 +     *            <code>arguments</code> array is not of the type
 134.858 +     *            expected by the format element(s) that use it.
 134.859 +     */
 134.860 +    public final StringBuffer format(Object arguments, StringBuffer result,
 134.861 +                                     FieldPosition pos)
 134.862 +    {
 134.863 +        return subformat((Object[]) arguments, result, pos, null);
 134.864 +    }
 134.865 +
 134.866 +    /**
 134.867 +     * Formats an array of objects and inserts them into the
 134.868 +     * <code>MessageFormat</code>'s pattern, producing an
 134.869 +     * <code>AttributedCharacterIterator</code>.
 134.870 +     * You can use the returned <code>AttributedCharacterIterator</code>
 134.871 +     * to build the resulting String, as well as to determine information
 134.872 +     * about the resulting String.
 134.873 +     * <p>
 134.874 +     * The text of the returned <code>AttributedCharacterIterator</code> is
 134.875 +     * the same that would be returned by
 134.876 +     * <blockquote>
 134.877 +     *     <code>{@link #format(java.lang.Object[], java.lang.StringBuffer, java.text.FieldPosition) format}(arguments, new StringBuffer(), null).toString()</code>
 134.878 +     * </blockquote>
 134.879 +     * <p>
 134.880 +     * In addition, the <code>AttributedCharacterIterator</code> contains at
 134.881 +     * least attributes indicating where text was generated from an
 134.882 +     * argument in the <code>arguments</code> array. The keys of these attributes are of
 134.883 +     * type <code>MessageFormat.Field</code>, their values are
 134.884 +     * <code>Integer</code> objects indicating the index in the <code>arguments</code>
 134.885 +     * array of the argument from which the text was generated.
 134.886 +     * <p>
 134.887 +     * The attributes/value from the underlying <code>Format</code>
 134.888 +     * instances that <code>MessageFormat</code> uses will also be
 134.889 +     * placed in the resulting <code>AttributedCharacterIterator</code>.
 134.890 +     * This allows you to not only find where an argument is placed in the
 134.891 +     * resulting String, but also which fields it contains in turn.
 134.892 +     *
 134.893 +     * @param arguments an array of objects to be formatted and substituted.
 134.894 +     * @return AttributedCharacterIterator describing the formatted value.
 134.895 +     * @exception NullPointerException if <code>arguments</code> is null.
 134.896 +     * @exception IllegalArgumentException if an argument in the
 134.897 +     *            <code>arguments</code> array is not of the type
 134.898 +     *            expected by the format element(s) that use it.
 134.899 +     * @since 1.4
 134.900 +     */
 134.901 +    public AttributedCharacterIterator formatToCharacterIterator(Object arguments) {
 134.902 +        StringBuffer result = new StringBuffer();
 134.903 +        ArrayList iterators = new ArrayList();
 134.904 +
 134.905 +        if (arguments == null) {
 134.906 +            throw new NullPointerException(
 134.907 +                   "formatToCharacterIterator must be passed non-null object");
 134.908 +        }
 134.909 +        subformat((Object[]) arguments, result, null, iterators);
 134.910 +        if (iterators.size() == 0) {
 134.911 +            return createAttributedCharacterIterator("");
 134.912 +        }
 134.913 +        return createAttributedCharacterIterator(
 134.914 +                     (AttributedCharacterIterator[])iterators.toArray(
 134.915 +                     new AttributedCharacterIterator[iterators.size()]));
 134.916 +    }
 134.917 +
 134.918 +    /**
 134.919 +     * Parses the string.
 134.920 +     *
 134.921 +     * <p>Caveats: The parse may fail in a number of circumstances.
 134.922 +     * For example:
 134.923 +     * <ul>
 134.924 +     * <li>If one of the arguments does not occur in the pattern.
 134.925 +     * <li>If the format of an argument loses information, such as
 134.926 +     *     with a choice format where a large number formats to "many".
 134.927 +     * <li>Does not yet handle recursion (where
 134.928 +     *     the substituted strings contain {n} references.)
 134.929 +     * <li>Will not always find a match (or the correct match)
 134.930 +     *     if some part of the parse is ambiguous.
 134.931 +     *     For example, if the pattern "{1},{2}" is used with the
 134.932 +     *     string arguments {"a,b", "c"}, it will format as "a,b,c".
 134.933 +     *     When the result is parsed, it will return {"a", "b,c"}.
 134.934 +     * <li>If a single argument is parsed more than once in the string,
 134.935 +     *     then the later parse wins.
 134.936 +     * </ul>
 134.937 +     * When the parse fails, use ParsePosition.getErrorIndex() to find out
 134.938 +     * where in the string the parsing failed.  The returned error
 134.939 +     * index is the starting offset of the sub-patterns that the string
 134.940 +     * is comparing with.  For example, if the parsing string "AAA {0} BBB"
 134.941 +     * is comparing against the pattern "AAD {0} BBB", the error index is
 134.942 +     * 0. When an error occurs, the call to this method will return null.
 134.943 +     * If the source is null, return an empty array.
 134.944 +     */
 134.945 +    public Object[] parse(String source, ParsePosition pos) {
 134.946 +        if (source == null) {
 134.947 +            Object[] empty = {};
 134.948 +            return empty;
 134.949 +        }
 134.950 +
 134.951 +        int maximumArgumentNumber = -1;
 134.952 +        for (int i = 0; i <= maxOffset; i++) {
 134.953 +            if (argumentNumbers[i] > maximumArgumentNumber) {
 134.954 +                maximumArgumentNumber = argumentNumbers[i];
 134.955 +            }
 134.956 +        }
 134.957 +        Object[] resultArray = new Object[maximumArgumentNumber + 1];
 134.958 +
 134.959 +        int patternOffset = 0;
 134.960 +        int sourceOffset = pos.index;
 134.961 +        ParsePosition tempStatus = new ParsePosition(0);
 134.962 +        for (int i = 0; i <= maxOffset; ++i) {
 134.963 +            // match up to format
 134.964 +            int len = offsets[i] - patternOffset;
 134.965 +            if (len == 0 || pattern.regionMatches(patternOffset,
 134.966 +                                                  source, sourceOffset, len)) {
 134.967 +                sourceOffset += len;
 134.968 +                patternOffset += len;
 134.969 +            } else {
 134.970 +                pos.errorIndex = sourceOffset;
 134.971 +                return null; // leave index as is to signal error
 134.972 +            }
 134.973 +
 134.974 +            // now use format
 134.975 +            if (formats[i] == null) {   // string format
 134.976 +                // if at end, use longest possible match
 134.977 +                // otherwise uses first match to intervening string
 134.978 +                // does NOT recursively try all possibilities
 134.979 +                int tempLength = (i != maxOffset) ? offsets[i+1] : pattern.length();
 134.980 +
 134.981 +                int next;
 134.982 +                if (patternOffset >= tempLength) {
 134.983 +                    next = source.length();
 134.984 +                }else{
 134.985 +                    next = source.indexOf(pattern.substring(patternOffset, tempLength),
 134.986 +                                          sourceOffset);
 134.987 +                }
 134.988 +
 134.989 +                if (next < 0) {
 134.990 +                    pos.errorIndex = sourceOffset;
 134.991 +                    return null; // leave index as is to signal error
 134.992 +                } else {
 134.993 +                    String strValue= source.substring(sourceOffset,next);
 134.994 +                    if (!strValue.equals("{"+argumentNumbers[i]+"}"))
 134.995 +                        resultArray[argumentNumbers[i]]
 134.996 +                            = source.substring(sourceOffset,next);
 134.997 +                    sourceOffset = next;
 134.998 +                }
 134.999 +            } else {
134.1000 +                tempStatus.index = sourceOffset;
134.1001 +                resultArray[argumentNumbers[i]]
134.1002 +                    = formats[i].parseObject(source,tempStatus);
134.1003 +                if (tempStatus.index == sourceOffset) {
134.1004 +                    pos.errorIndex = sourceOffset;
134.1005 +                    return null; // leave index as is to signal error
134.1006 +                }
134.1007 +                sourceOffset = tempStatus.index; // update
134.1008 +            }
134.1009 +        }
134.1010 +        int len = pattern.length() - patternOffset;
134.1011 +        if (len == 0 || pattern.regionMatches(patternOffset,
134.1012 +                                              source, sourceOffset, len)) {
134.1013 +            pos.index = sourceOffset + len;
134.1014 +        } else {
134.1015 +            pos.errorIndex = sourceOffset;
134.1016 +            return null; // leave index as is to signal error
134.1017 +        }
134.1018 +        return resultArray;
134.1019 +    }
134.1020 +
134.1021 +    /**
134.1022 +     * Parses text from the beginning of the given string to produce an object
134.1023 +     * array.
134.1024 +     * The method may not use the entire text of the given string.
134.1025 +     * <p>
134.1026 +     * See the {@link #parse(String, ParsePosition)} method for more information
134.1027 +     * on message parsing.
134.1028 +     *
134.1029 +     * @param source A <code>String</code> whose beginning should be parsed.
134.1030 +     * @return An <code>Object</code> array parsed from the string.
134.1031 +     * @exception ParseException if the beginning of the specified string
134.1032 +     *            cannot be parsed.
134.1033 +     */
134.1034 +    public Object[] parse(String source) throws ParseException {
134.1035 +        ParsePosition pos  = new ParsePosition(0);
134.1036 +        Object[] result = parse(source, pos);
134.1037 +        if (pos.index == 0)  // unchanged, returned object is null
134.1038 +            throw new ParseException("MessageFormat parse error!", pos.errorIndex);
134.1039 +
134.1040 +        return result;
134.1041 +    }
134.1042 +
134.1043 +    /**
134.1044 +     * Parses text from a string to produce an object array.
134.1045 +     * <p>
134.1046 +     * The method attempts to parse text starting at the index given by
134.1047 +     * <code>pos</code>.
134.1048 +     * If parsing succeeds, then the index of <code>pos</code> is updated
134.1049 +     * to the index after the last character used (parsing does not necessarily
134.1050 +     * use all characters up to the end of the string), and the parsed
134.1051 +     * object array is returned. The updated <code>pos</code> can be used to
134.1052 +     * indicate the starting point for the next call to this method.
134.1053 +     * If an error occurs, then the index of <code>pos</code> is not
134.1054 +     * changed, the error index of <code>pos</code> is set to the index of
134.1055 +     * the character where the error occurred, and null is returned.
134.1056 +     * <p>
134.1057 +     * See the {@link #parse(String, ParsePosition)} method for more information
134.1058 +     * on message parsing.
134.1059 +     *
134.1060 +     * @param source A <code>String</code>, part of which should be parsed.
134.1061 +     * @param pos A <code>ParsePosition</code> object with index and error
134.1062 +     *            index information as described above.
134.1063 +     * @return An <code>Object</code> array parsed from the string. In case of
134.1064 +     *         error, returns null.
134.1065 +     * @exception NullPointerException if <code>pos</code> is null.
134.1066 +     */
134.1067 +    public Object parseObject(String source, ParsePosition pos) {
134.1068 +        return parse(source, pos);
134.1069 +    }
134.1070 +
134.1071 +    /**
134.1072 +     * Creates and returns a copy of this object.
134.1073 +     *
134.1074 +     * @return a clone of this instance.
134.1075 +     */
134.1076 +    public Object clone() {
134.1077 +        MessageFormat other = (MessageFormat) super.clone();
134.1078 +
134.1079 +        // clone arrays. Can't do with utility because of bug in Cloneable
134.1080 +        other.formats = (Format[]) formats.clone(); // shallow clone
134.1081 +        for (int i = 0; i < formats.length; ++i) {
134.1082 +            if (formats[i] != null)
134.1083 +                other.formats[i] = (Format)formats[i].clone();
134.1084 +        }
134.1085 +        // for primitives or immutables, shallow clone is enough
134.1086 +        other.offsets = (int[]) offsets.clone();
134.1087 +        other.argumentNumbers = (int[]) argumentNumbers.clone();
134.1088 +
134.1089 +        return other;
134.1090 +    }
134.1091 +
134.1092 +    /**
134.1093 +     * Equality comparison between two message format objects
134.1094 +     */
134.1095 +    public boolean equals(Object obj) {
134.1096 +        if (this == obj)                      // quick check
134.1097 +            return true;
134.1098 +        if (obj == null || getClass() != obj.getClass())
134.1099 +            return false;
134.1100 +        MessageFormat other = (MessageFormat) obj;
134.1101 +        return (maxOffset == other.maxOffset
134.1102 +                && pattern.equals(other.pattern)
134.1103 +                && ((locale != null && locale.equals(other.locale))
134.1104 +                 || (locale == null && other.locale == null))
134.1105 +                && Arrays.equals(offsets,other.offsets)
134.1106 +                && Arrays.equals(argumentNumbers,other.argumentNumbers)
134.1107 +                && Arrays.equals(formats,other.formats));
134.1108 +    }
134.1109 +
134.1110 +    /**
134.1111 +     * Generates a hash code for the message format object.
134.1112 +     */
134.1113 +    public int hashCode() {
134.1114 +        return pattern.hashCode(); // enough for reasonable distribution
134.1115 +    }
134.1116 +
134.1117 +
134.1118 +    /**
134.1119 +     * Defines constants that are used as attribute keys in the
134.1120 +     * <code>AttributedCharacterIterator</code> returned
134.1121 +     * from <code>MessageFormat.formatToCharacterIterator</code>.
134.1122 +     *
134.1123 +     * @since 1.4
134.1124 +     */
134.1125 +    public static class Field extends Format.Field {
134.1126 +
134.1127 +        // Proclaim serial compatibility with 1.4 FCS
134.1128 +        private static final long serialVersionUID = 7899943957617360810L;
134.1129 +
134.1130 +        /**
134.1131 +         * Creates a Field with the specified name.
134.1132 +         *
134.1133 +         * @param name Name of the attribute
134.1134 +         */
134.1135 +        protected Field(String name) {
134.1136 +            super(name);
134.1137 +        }
134.1138 +
134.1139 +        /**
134.1140 +         * Resolves instances being deserialized to the predefined constants.
134.1141 +         *
134.1142 +         * @throws InvalidObjectException if the constant could not be
134.1143 +         *         resolved.
134.1144 +         * @return resolved MessageFormat.Field constant
134.1145 +         */
134.1146 +        protected Object readResolve() throws InvalidObjectException {
134.1147 +            if (this.getClass() != MessageFormat.Field.class) {
134.1148 +                throw new InvalidObjectException("subclass didn't correctly implement readResolve");
134.1149 +            }
134.1150 +
134.1151 +            return ARGUMENT;
134.1152 +        }
134.1153 +
134.1154 +        //
134.1155 +        // The constants
134.1156 +        //
134.1157 +
134.1158 +        /**
134.1159 +         * Constant identifying a portion of a message that was generated
134.1160 +         * from an argument passed into <code>formatToCharacterIterator</code>.
134.1161 +         * The value associated with the key will be an <code>Integer</code>
134.1162 +         * indicating the index in the <code>arguments</code> array of the
134.1163 +         * argument from which the text was generated.
134.1164 +         */
134.1165 +        public final static Field ARGUMENT =
134.1166 +                           new Field("message argument field");
134.1167 +    }
134.1168 +
134.1169 +    // ===========================privates============================
134.1170 +
134.1171 +    /**
134.1172 +     * The locale to use for formatting numbers and dates.
134.1173 +     * @serial
134.1174 +     */
134.1175 +    private Locale locale;
134.1176 +
134.1177 +    /**
134.1178 +     * The string that the formatted values are to be plugged into.  In other words, this
134.1179 +     * is the pattern supplied on construction with all of the {} expressions taken out.
134.1180 +     * @serial
134.1181 +     */
134.1182 +    private String pattern = "";
134.1183 +
134.1184 +    /** The initially expected number of subformats in the format */
134.1185 +    private static final int INITIAL_FORMATS = 10;
134.1186 +
134.1187 +    /**
134.1188 +     * An array of formatters, which are used to format the arguments.
134.1189 +     * @serial
134.1190 +     */
134.1191 +    private Format[] formats = new Format[INITIAL_FORMATS];
134.1192 +
134.1193 +    /**
134.1194 +     * The positions where the results of formatting each argument are to be inserted
134.1195 +     * into the pattern.
134.1196 +     * @serial
134.1197 +     */
134.1198 +    private int[] offsets = new int[INITIAL_FORMATS];
134.1199 +
134.1200 +    /**
134.1201 +     * The argument numbers corresponding to each formatter.  (The formatters are stored
134.1202 +     * in the order they occur in the pattern, not in the order in which the arguments
134.1203 +     * are specified.)
134.1204 +     * @serial
134.1205 +     */
134.1206 +    private int[] argumentNumbers = new int[INITIAL_FORMATS];
134.1207 +
134.1208 +    /**
134.1209 +     * One less than the number of entries in <code>offsets</code>.  Can also be thought of
134.1210 +     * as the index of the highest-numbered element in <code>offsets</code> that is being used.
134.1211 +     * All of these arrays should have the same number of elements being used as <code>offsets</code>
134.1212 +     * does, and so this variable suffices to tell us how many entries are in all of them.
134.1213 +     * @serial
134.1214 +     */
134.1215 +    private int maxOffset = -1;
134.1216 +
134.1217 +    /**
134.1218 +     * Internal routine used by format. If <code>characterIterators</code> is
134.1219 +     * non-null, AttributedCharacterIterator will be created from the
134.1220 +     * subformats as necessary. If <code>characterIterators</code> is null
134.1221 +     * and <code>fp</code> is non-null and identifies
134.1222 +     * <code>Field.MESSAGE_ARGUMENT</code>, the location of
134.1223 +     * the first replaced argument will be set in it.
134.1224 +     *
134.1225 +     * @exception IllegalArgumentException if an argument in the
134.1226 +     *            <code>arguments</code> array is not of the type
134.1227 +     *            expected by the format element(s) that use it.
134.1228 +     */
134.1229 +    private StringBuffer subformat(Object[] arguments, StringBuffer result,
134.1230 +                                   FieldPosition fp, List characterIterators) {
134.1231 +        // note: this implementation assumes a fast substring & index.
134.1232 +        // if this is not true, would be better to append chars one by one.
134.1233 +        int lastOffset = 0;
134.1234 +        int last = result.length();
134.1235 +        for (int i = 0; i <= maxOffset; ++i) {
134.1236 +            result.append(pattern.substring(lastOffset, offsets[i]));
134.1237 +            lastOffset = offsets[i];
134.1238 +            int argumentNumber = argumentNumbers[i];
134.1239 +            if (arguments == null || argumentNumber >= arguments.length) {
134.1240 +                result.append('{').append(argumentNumber).append('}');
134.1241 +                continue;
134.1242 +            }
134.1243 +            // int argRecursion = ((recursionProtection >> (argumentNumber*2)) & 0x3);
134.1244 +            if (false) { // if (argRecursion == 3){
134.1245 +                // prevent loop!!!
134.1246 +                result.append('\uFFFD');
134.1247 +            } else {
134.1248 +                Object obj = arguments[argumentNumber];
134.1249 +                String arg = null;
134.1250 +                Format subFormatter = null;
134.1251 +                if (obj == null) {
134.1252 +                    arg = "null";
134.1253 +                } else if (formats[i] != null) {
134.1254 +                    subFormatter = formats[i];
134.1255 +                    if (subFormatter instanceof ChoiceFormat) {
134.1256 +                        arg = formats[i].format(obj);
134.1257 +                        if (arg.indexOf('{') >= 0) {
134.1258 +                            subFormatter = new MessageFormat(arg, locale);
134.1259 +                            obj = arguments;
134.1260 +                            arg = null;
134.1261 +                        }
134.1262 +                    }
134.1263 +                } else if (obj instanceof Number) {
134.1264 +                    // format number if can
134.1265 +                    subFormatter = NumberFormat.getInstance(locale);
134.1266 +                } else if (obj instanceof Date) {
134.1267 +                    // format a Date if can
134.1268 +                    subFormatter = DateFormat.getDateTimeInstance(
134.1269 +                             DateFormat.SHORT, DateFormat.SHORT, locale);//fix
134.1270 +                } else if (obj instanceof String) {
134.1271 +                    arg = (String) obj;
134.1272 +
134.1273 +                } else {
134.1274 +                    arg = obj.toString();
134.1275 +                    if (arg == null) arg = "null";
134.1276 +                }
134.1277 +
134.1278 +                // At this point we are in two states, either subFormatter
134.1279 +                // is non-null indicating we should format obj using it,
134.1280 +                // or arg is non-null and we should use it as the value.
134.1281 +
134.1282 +                if (characterIterators != null) {
134.1283 +                    // If characterIterators is non-null, it indicates we need
134.1284 +                    // to get the CharacterIterator from the child formatter.
134.1285 +                    if (last != result.length()) {
134.1286 +                        characterIterators.add(
134.1287 +                            createAttributedCharacterIterator(result.substring
134.1288 +                                                              (last)));
134.1289 +                        last = result.length();
134.1290 +                    }
134.1291 +                    if (subFormatter != null) {
134.1292 +                        AttributedCharacterIterator subIterator =
134.1293 +                                   subFormatter.formatToCharacterIterator(obj);
134.1294 +
134.1295 +                        append(result, subIterator);
134.1296 +                        if (last != result.length()) {
134.1297 +                            characterIterators.add(
134.1298 +                                         createAttributedCharacterIterator(
134.1299 +                                         subIterator, Field.ARGUMENT,
134.1300 +                                         Integer.valueOf(argumentNumber)));
134.1301 +                            last = result.length();
134.1302 +                        }
134.1303 +                        arg = null;
134.1304 +                    }
134.1305 +                    if (arg != null && arg.length() > 0) {
134.1306 +                        result.append(arg);
134.1307 +                        characterIterators.add(
134.1308 +                                 createAttributedCharacterIterator(
134.1309 +                                 arg, Field.ARGUMENT,
134.1310 +                                 Integer.valueOf(argumentNumber)));
134.1311 +                        last = result.length();
134.1312 +                    }
134.1313 +                }
134.1314 +                else {
134.1315 +                    if (subFormatter != null) {
134.1316 +                        arg = subFormatter.format(obj);
134.1317 +                    }
134.1318 +                    last = result.length();
134.1319 +                    result.append(arg);
134.1320 +                    if (i == 0 && fp != null && Field.ARGUMENT.equals(
134.1321 +                                  fp.getFieldAttribute())) {
134.1322 +                        fp.setBeginIndex(last);
134.1323 +                        fp.setEndIndex(result.length());
134.1324 +                    }
134.1325 +                    last = result.length();
134.1326 +                }
134.1327 +            }
134.1328 +        }
134.1329 +        result.append(pattern.substring(lastOffset, pattern.length()));
134.1330 +        if (characterIterators != null && last != result.length()) {
134.1331 +            characterIterators.add(createAttributedCharacterIterator(
134.1332 +                                   result.substring(last)));
134.1333 +        }
134.1334 +        return result;
134.1335 +    }
134.1336 +
134.1337 +    /**
134.1338 +     * Convenience method to append all the characters in
134.1339 +     * <code>iterator</code> to the StringBuffer <code>result</code>.
134.1340 +     */
134.1341 +    private void append(StringBuffer result, CharacterIterator iterator) {
134.1342 +        if (iterator.first() != CharacterIterator.DONE) {
134.1343 +            char aChar;
134.1344 +
134.1345 +            result.append(iterator.first());
134.1346 +            while ((aChar = iterator.next()) != CharacterIterator.DONE) {
134.1347 +                result.append(aChar);
134.1348 +            }
134.1349 +        }
134.1350 +    }
134.1351 +
134.1352 +    // Indices for segments
134.1353 +    private static final int SEG_RAW      = 0;
134.1354 +    private static final int SEG_INDEX    = 1;
134.1355 +    private static final int SEG_TYPE     = 2;
134.1356 +    private static final int SEG_MODIFIER = 3; // modifier or subformat
134.1357 +
134.1358 +    // Indices for type keywords
134.1359 +    private static final int TYPE_NULL    = 0;
134.1360 +    private static final int TYPE_NUMBER  = 1;
134.1361 +    private static final int TYPE_DATE    = 2;
134.1362 +    private static final int TYPE_TIME    = 3;
134.1363 +    private static final int TYPE_CHOICE  = 4;
134.1364 +
134.1365 +    private static final String[] TYPE_KEYWORDS = {
134.1366 +        "",
134.1367 +        "number",
134.1368 +        "date",
134.1369 +        "time",
134.1370 +        "choice"
134.1371 +    };
134.1372 +
134.1373 +    // Indices for number modifiers
134.1374 +    private static final int MODIFIER_DEFAULT  = 0; // common in number and date-time
134.1375 +    private static final int MODIFIER_CURRENCY = 1;
134.1376 +    private static final int MODIFIER_PERCENT  = 2;
134.1377 +    private static final int MODIFIER_INTEGER  = 3;
134.1378 +
134.1379 +    private static final String[] NUMBER_MODIFIER_KEYWORDS = {
134.1380 +        "",
134.1381 +        "currency",
134.1382 +        "percent",
134.1383 +        "integer"
134.1384 +    };
134.1385 +
134.1386 +    // Indices for date-time modifiers
134.1387 +    private static final int MODIFIER_SHORT   = 1;
134.1388 +    private static final int MODIFIER_MEDIUM  = 2;
134.1389 +    private static final int MODIFIER_LONG    = 3;
134.1390 +    private static final int MODIFIER_FULL    = 4;
134.1391 +
134.1392 +    private static final String[] DATE_TIME_MODIFIER_KEYWORDS = {
134.1393 +        "",
134.1394 +        "short",
134.1395 +        "medium",
134.1396 +        "long",
134.1397 +        "full"
134.1398 +    };
134.1399 +
134.1400 +    // Date-time style values corresponding to the date-time modifiers.
134.1401 +    private static final int[] DATE_TIME_MODIFIERS = {
134.1402 +        DateFormat.DEFAULT,
134.1403 +        DateFormat.SHORT,
134.1404 +        DateFormat.MEDIUM,
134.1405 +        DateFormat.LONG,
134.1406 +        DateFormat.FULL,
134.1407 +    };
134.1408 +
134.1409 +    private void makeFormat(int position, int offsetNumber,
134.1410 +                            StringBuilder[] textSegments)
134.1411 +    {
134.1412 +        String[] segments = new String[textSegments.length];
134.1413 +        for (int i = 0; i < textSegments.length; i++) {
134.1414 +            StringBuilder oneseg = textSegments[i];
134.1415 +            segments[i] = (oneseg != null) ? oneseg.toString() : "";
134.1416 +        }
134.1417 +
134.1418 +        // get the argument number
134.1419 +        int argumentNumber;
134.1420 +        try {
134.1421 +            argumentNumber = Integer.parseInt(segments[SEG_INDEX]); // always unlocalized!
134.1422 +        } catch (NumberFormatException e) {
134.1423 +            throw new IllegalArgumentException("can't parse argument number: "
134.1424 +                                               + segments[SEG_INDEX], e);
134.1425 +        }
134.1426 +        if (argumentNumber < 0) {
134.1427 +            throw new IllegalArgumentException("negative argument number: "
134.1428 +                                               + argumentNumber);
134.1429 +        }
134.1430 +
134.1431 +        // resize format information arrays if necessary
134.1432 +        if (offsetNumber >= formats.length) {
134.1433 +            int newLength = formats.length * 2;
134.1434 +            Format[] newFormats = new Format[newLength];
134.1435 +            int[] newOffsets = new int[newLength];
134.1436 +            int[] newArgumentNumbers = new int[newLength];
134.1437 +            System.arraycopy(formats, 0, newFormats, 0, maxOffset + 1);
134.1438 +            System.arraycopy(offsets, 0, newOffsets, 0, maxOffset + 1);
134.1439 +            System.arraycopy(argumentNumbers, 0, newArgumentNumbers, 0, maxOffset + 1);
134.1440 +            formats = newFormats;
134.1441 +            offsets = newOffsets;
134.1442 +            argumentNumbers = newArgumentNumbers;
134.1443 +        }
134.1444 +        int oldMaxOffset = maxOffset;
134.1445 +        maxOffset = offsetNumber;
134.1446 +        offsets[offsetNumber] = segments[SEG_RAW].length();
134.1447 +        argumentNumbers[offsetNumber] = argumentNumber;
134.1448 +
134.1449 +        // now get the format
134.1450 +        Format newFormat = null;
134.1451 +        if (segments[SEG_TYPE].length() != 0) {
134.1452 +            int type = findKeyword(segments[SEG_TYPE], TYPE_KEYWORDS);
134.1453 +            switch (type) {
134.1454 +            case TYPE_NULL:
134.1455 +                // Type "" is allowed. e.g., "{0,}", "{0,,}", and "{0,,#}"
134.1456 +                // are treated as "{0}".
134.1457 +                break;
134.1458 +
134.1459 +            case TYPE_NUMBER:
134.1460 +                switch (findKeyword(segments[SEG_MODIFIER], NUMBER_MODIFIER_KEYWORDS)) {
134.1461 +                case MODIFIER_DEFAULT:
134.1462 +                    newFormat = NumberFormat.getInstance(locale);
134.1463 +                    break;
134.1464 +                case MODIFIER_CURRENCY:
134.1465 +                    newFormat = NumberFormat.getCurrencyInstance(locale);
134.1466 +                    break;
134.1467 +                case MODIFIER_PERCENT:
134.1468 +                    newFormat = NumberFormat.getPercentInstance(locale);
134.1469 +                    break;
134.1470 +                case MODIFIER_INTEGER:
134.1471 +                    newFormat = NumberFormat.getIntegerInstance(locale);
134.1472 +                    break;
134.1473 +                default: // DecimalFormat pattern
134.1474 +                    try {
134.1475 +                        newFormat = new DecimalFormat(segments[SEG_MODIFIER],
134.1476 +                                                      DecimalFormatSymbols.getInstance(locale));
134.1477 +                    } catch (IllegalArgumentException e) {
134.1478 +                        maxOffset = oldMaxOffset;
134.1479 +                        throw e;
134.1480 +                    }
134.1481 +                    break;
134.1482 +                }
134.1483 +                break;
134.1484 +
134.1485 +            case TYPE_DATE:
134.1486 +            case TYPE_TIME:
134.1487 +                int mod = findKeyword(segments[SEG_MODIFIER], DATE_TIME_MODIFIER_KEYWORDS);
134.1488 +                if (mod >= 0 && mod < DATE_TIME_MODIFIER_KEYWORDS.length) {
134.1489 +                    if (type == TYPE_DATE) {
134.1490 +                        newFormat = DateFormat.getDateInstance(DATE_TIME_MODIFIERS[mod],
134.1491 +                                                               locale);
134.1492 +                    } else {
134.1493 +                        newFormat = DateFormat.getTimeInstance(DATE_TIME_MODIFIERS[mod],
134.1494 +                                                               locale);
134.1495 +                    }
134.1496 +                } else {
134.1497 +                    // SimpleDateFormat pattern
134.1498 +                    try {
134.1499 +                        newFormat = new SimpleDateFormat(segments[SEG_MODIFIER], locale);
134.1500 +                    } catch (IllegalArgumentException e) {
134.1501 +                        maxOffset = oldMaxOffset;
134.1502 +                        throw e;
134.1503 +                    }
134.1504 +                }
134.1505 +                break;
134.1506 +
134.1507 +            case TYPE_CHOICE:
134.1508 +                try {
134.1509 +                    // ChoiceFormat pattern
134.1510 +                    newFormat = new ChoiceFormat(segments[SEG_MODIFIER]);
134.1511 +                } catch (Exception e) {
134.1512 +                    maxOffset = oldMaxOffset;
134.1513 +                    throw new IllegalArgumentException("Choice Pattern incorrect: "
134.1514 +                                                       + segments[SEG_MODIFIER], e);
134.1515 +                }
134.1516 +                break;
134.1517 +
134.1518 +            default:
134.1519 +                maxOffset = oldMaxOffset;
134.1520 +                throw new IllegalArgumentException("unknown format type: " +
134.1521 +                                                   segments[SEG_TYPE]);
134.1522 +            }
134.1523 +        }
134.1524 +        formats[offsetNumber] = newFormat;
134.1525 +    }
134.1526 +
134.1527 +    private static final int findKeyword(String s, String[] list) {
134.1528 +        for (int i = 0; i < list.length; ++i) {
134.1529 +            if (s.equals(list[i]))
134.1530 +                return i;
134.1531 +        }
134.1532 +
134.1533 +        // Try trimmed lowercase.
134.1534 +        String ls = s.trim().toLowerCase(Locale.ROOT);
134.1535 +        if (ls != s) {
134.1536 +            for (int i = 0; i < list.length; ++i) {
134.1537 +                if (ls.equals(list[i]))
134.1538 +                    return i;
134.1539 +            }
134.1540 +        }
134.1541 +        return -1;
134.1542 +    }
134.1543 +
134.1544 +    private static final void copyAndFixQuotes(String source, int start, int end,
134.1545 +                                               StringBuilder target) {
134.1546 +        boolean quoted = false;
134.1547 +
134.1548 +        for (int i = start; i < end; ++i) {
134.1549 +            char ch = source.charAt(i);
134.1550 +            if (ch == '{') {
134.1551 +                if (!quoted) {
134.1552 +                    target.append('\'');
134.1553 +                    quoted = true;
134.1554 +                }
134.1555 +                target.append(ch);
134.1556 +            } else if (ch == '\'') {
134.1557 +                target.append("''");
134.1558 +            } else {
134.1559 +                if (quoted) {
134.1560 +                    target.append('\'');
134.1561 +                    quoted = false;
134.1562 +                }
134.1563 +                target.append(ch);
134.1564 +            }
134.1565 +        }
134.1566 +        if (quoted) {
134.1567 +            target.append('\'');
134.1568 +        }
134.1569 +    }
134.1570 +
134.1571 +    /**
134.1572 +     * After reading an object from the input stream, do a simple verification
134.1573 +     * to maintain class invariants.
134.1574 +     * @throws InvalidObjectException if the objects read from the stream is invalid.
134.1575 +     */
134.1576 +    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
134.1577 +        in.defaultReadObject();
134.1578 +        boolean isValid = maxOffset >= -1
134.1579 +                && formats.length > maxOffset
134.1580 +                && offsets.length > maxOffset
134.1581 +                && argumentNumbers.length > maxOffset;
134.1582 +        if (isValid) {
134.1583 +            int lastOffset = pattern.length() + 1;
134.1584 +            for (int i = maxOffset; i >= 0; --i) {
134.1585 +                if ((offsets[i] < 0) || (offsets[i] > lastOffset)) {
134.1586 +                    isValid = false;
134.1587 +                    break;
134.1588 +                } else {
134.1589 +                    lastOffset = offsets[i];
134.1590 +                }
134.1591 +            }
134.1592 +        }
134.1593 +        if (!isValid) {
134.1594 +            throw new InvalidObjectException("Could not reconstruct MessageFormat from corrupt stream.");
134.1595 +        }
134.1596 +    }
134.1597 +}
   135.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   135.2 +++ b/rt/emul/compact/src/main/java/java/text/NumberFormat.java	Tue Feb 11 13:31:42 2014 +0100
   135.3 @@ -0,0 +1,1159 @@
   135.4 +/*
   135.5 + * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
   135.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   135.7 + *
   135.8 + * This code is free software; you can redistribute it and/or modify it
   135.9 + * under the terms of the GNU General Public License version 2 only, as
  135.10 + * published by the Free Software Foundation.  Oracle designates this
  135.11 + * particular file as subject to the "Classpath" exception as provided
  135.12 + * by Oracle in the LICENSE file that accompanied this code.
  135.13 + *
  135.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  135.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  135.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  135.17 + * version 2 for more details (a copy is included in the LICENSE file that
  135.18 + * accompanied this code).
  135.19 + *
  135.20 + * You should have received a copy of the GNU General Public License version
  135.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  135.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  135.23 + *
  135.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  135.25 + * or visit www.oracle.com if you need additional information or have any
  135.26 + * questions.
  135.27 + */
  135.28 +
  135.29 +/*
  135.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
  135.31 + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
  135.32 + *
  135.33 + *   The original version of this source code and documentation is copyrighted
  135.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
  135.35 + * materials are provided under terms of a License Agreement between Taligent
  135.36 + * and Sun. This technology is protected by multiple US and International
  135.37 + * patents. This notice and attribution to Taligent may not be removed.
  135.38 + *   Taligent is a registered trademark of Taligent, Inc.
  135.39 + *
  135.40 + */
  135.41 +
  135.42 +package java.text;
  135.43 +
  135.44 +import java.io.InvalidObjectException;
  135.45 +import java.io.IOException;
  135.46 +import java.io.ObjectInputStream;
  135.47 +import java.io.ObjectOutputStream;
  135.48 +import java.math.BigInteger;
  135.49 +import java.math.RoundingMode;
  135.50 +import java.util.Currency;
  135.51 +import java.util.HashMap;
  135.52 +import java.util.Hashtable;
  135.53 +import java.util.Locale;
  135.54 +import java.util.Map;
  135.55 +import java.util.ResourceBundle;
  135.56 +import java.util.concurrent.atomic.AtomicInteger;
  135.57 +import java.util.concurrent.atomic.AtomicLong;
  135.58 +
  135.59 +/**
  135.60 + * <code>NumberFormat</code> is the abstract base class for all number
  135.61 + * formats. This class provides the interface for formatting and parsing
  135.62 + * numbers. <code>NumberFormat</code> also provides methods for determining
  135.63 + * which locales have number formats, and what their names are.
  135.64 + *
  135.65 + * <p>
  135.66 + * <code>NumberFormat</code> helps you to format and parse numbers for any locale.
  135.67 + * Your code can be completely independent of the locale conventions for
  135.68 + * decimal points, thousands-separators, or even the particular decimal
  135.69 + * digits used, or whether the number format is even decimal.
  135.70 + *
  135.71 + * <p>
  135.72 + * To format a number for the current Locale, use one of the factory
  135.73 + * class methods:
  135.74 + * <blockquote>
  135.75 + * <pre>
  135.76 + *  myString = NumberFormat.getInstance().format(myNumber);
  135.77 + * </pre>
  135.78 + * </blockquote>
  135.79 + * If you are formatting multiple numbers, it is
  135.80 + * more efficient to get the format and use it multiple times so that
  135.81 + * the system doesn't have to fetch the information about the local
  135.82 + * language and country conventions multiple times.
  135.83 + * <blockquote>
  135.84 + * <pre>
  135.85 + * NumberFormat nf = NumberFormat.getInstance();
  135.86 + * for (int i = 0; i < myNumber.length; ++i) {
  135.87 + *     output.println(nf.format(myNumber[i]) + "; ");
  135.88 + * }
  135.89 + * </pre>
  135.90 + * </blockquote>
  135.91 + * To format a number for a different Locale, specify it in the
  135.92 + * call to <code>getInstance</code>.
  135.93 + * <blockquote>
  135.94 + * <pre>
  135.95 + * NumberFormat nf = NumberFormat.getInstance(Locale.FRENCH);
  135.96 + * </pre>
  135.97 + * </blockquote>
  135.98 + * You can also use a <code>NumberFormat</code> to parse numbers:
  135.99 + * <blockquote>
 135.100 + * <pre>
 135.101 + * myNumber = nf.parse(myString);
 135.102 + * </pre>
 135.103 + * </blockquote>
 135.104 + * Use <code>getInstance</code> or <code>getNumberInstance</code> to get the
 135.105 + * normal number format. Use <code>getIntegerInstance</code> to get an
 135.106 + * integer number format. Use <code>getCurrencyInstance</code> to get the
 135.107 + * currency number format. And use <code>getPercentInstance</code> to get a
 135.108 + * format for displaying percentages. With this format, a fraction like
 135.109 + * 0.53 is displayed as 53%.
 135.110 + *
 135.111 + * <p>
 135.112 + * You can also control the display of numbers with such methods as
 135.113 + * <code>setMinimumFractionDigits</code>.
 135.114 + * If you want even more control over the format or parsing,
 135.115 + * or want to give your users more control,
 135.116 + * you can try casting the <code>NumberFormat</code> you get from the factory methods
 135.117 + * to a <code>DecimalFormat</code>. This will work for the vast majority
 135.118 + * of locales; just remember to put it in a <code>try</code> block in case you
 135.119 + * encounter an unusual one.
 135.120 + *
 135.121 + * <p>
 135.122 + * NumberFormat and DecimalFormat are designed such that some controls
 135.123 + * work for formatting and others work for parsing.  The following is
 135.124 + * the detailed description for each these control methods,
 135.125 + * <p>
 135.126 + * setParseIntegerOnly : only affects parsing, e.g.
 135.127 + * if true,  "3456.78" -> 3456 (and leaves the parse position just after index 6)
 135.128 + * if false, "3456.78" -> 3456.78 (and leaves the parse position just after index 8)
 135.129 + * This is independent of formatting.  If you want to not show a decimal point
 135.130 + * where there might be no digits after the decimal point, use
 135.131 + * setDecimalSeparatorAlwaysShown.
 135.132 + * <p>
 135.133 + * setDecimalSeparatorAlwaysShown : only affects formatting, and only where
 135.134 + * there might be no digits after the decimal point, such as with a pattern
 135.135 + * like "#,##0.##", e.g.,
 135.136 + * if true,  3456.00 -> "3,456."
 135.137 + * if false, 3456.00 -> "3456"
 135.138 + * This is independent of parsing.  If you want parsing to stop at the decimal
 135.139 + * point, use setParseIntegerOnly.
 135.140 + *
 135.141 + * <p>
 135.142 + * You can also use forms of the <code>parse</code> and <code>format</code>
 135.143 + * methods with <code>ParsePosition</code> and <code>FieldPosition</code> to
 135.144 + * allow you to:
 135.145 + * <ul>
 135.146 + * <li> progressively parse through pieces of a string
 135.147 + * <li> align the decimal point and other areas
 135.148 + * </ul>
 135.149 + * For example, you can align numbers in two ways:
 135.150 + * <ol>
 135.151 + * <li> If you are using a monospaced font with spacing for alignment,
 135.152 + *      you can pass the <code>FieldPosition</code> in your format call, with
 135.153 + *      <code>field</code> = <code>INTEGER_FIELD</code>. On output,
 135.154 + *      <code>getEndIndex</code> will be set to the offset between the
 135.155 + *      last character of the integer and the decimal. Add
 135.156 + *      (desiredSpaceCount - getEndIndex) spaces at the front of the string.
 135.157 + *
 135.158 + * <li> If you are using proportional fonts,
 135.159 + *      instead of padding with spaces, measure the width
 135.160 + *      of the string in pixels from the start to <code>getEndIndex</code>.
 135.161 + *      Then move the pen by
 135.162 + *      (desiredPixelWidth - widthToAlignmentPoint) before drawing the text.
 135.163 + *      It also works where there is no decimal, but possibly additional
 135.164 + *      characters at the end, e.g., with parentheses in negative
 135.165 + *      numbers: "(12)" for -12.
 135.166 + * </ol>
 135.167 + *
 135.168 + * <h4><a name="synchronization">Synchronization</a></h4>
 135.169 + *
 135.170 + * <p>
 135.171 + * Number formats are generally not synchronized.
 135.172 + * It is recommended to create separate format instances for each thread.
 135.173 + * If multiple threads access a format concurrently, it must be synchronized
 135.174 + * externally.
 135.175 + *
 135.176 + * @see          DecimalFormat
 135.177 + * @see          ChoiceFormat
 135.178 + * @author       Mark Davis
 135.179 + * @author       Helena Shih
 135.180 + */
 135.181 +public abstract class NumberFormat extends Format  {
 135.182 +
 135.183 +    /**
 135.184 +     * Field constant used to construct a FieldPosition object. Signifies that
 135.185 +     * the position of the integer part of a formatted number should be returned.
 135.186 +     * @see java.text.FieldPosition
 135.187 +     */
 135.188 +    public static final int INTEGER_FIELD = 0;
 135.189 +
 135.190 +    /**
 135.191 +     * Field constant used to construct a FieldPosition object. Signifies that
 135.192 +     * the position of the fraction part of a formatted number should be returned.
 135.193 +     * @see java.text.FieldPosition
 135.194 +     */
 135.195 +    public static final int FRACTION_FIELD = 1;
 135.196 +
 135.197 +    /**
 135.198 +     * Sole constructor.  (For invocation by subclass constructors, typically
 135.199 +     * implicit.)
 135.200 +     */
 135.201 +    protected NumberFormat() {
 135.202 +    }
 135.203 +
 135.204 +    /**
 135.205 +     * Formats a number and appends the resulting text to the given string
 135.206 +     * buffer.
 135.207 +     * The number can be of any subclass of {@link java.lang.Number}.
 135.208 +     * <p>
 135.209 +     * This implementation extracts the number's value using
 135.210 +     * {@link java.lang.Number#longValue()} for all integral type values that
 135.211 +     * can be converted to <code>long</code> without loss of information,
 135.212 +     * including <code>BigInteger</code> values with a
 135.213 +     * {@link java.math.BigInteger#bitLength() bit length} of less than 64,
 135.214 +     * and {@link java.lang.Number#doubleValue()} for all other types. It
 135.215 +     * then calls
 135.216 +     * {@link #format(long,java.lang.StringBuffer,java.text.FieldPosition)}
 135.217 +     * or {@link #format(double,java.lang.StringBuffer,java.text.FieldPosition)}.
 135.218 +     * This may result in loss of magnitude information and precision for
 135.219 +     * <code>BigInteger</code> and <code>BigDecimal</code> values.
 135.220 +     * @param number     the number to format
 135.221 +     * @param toAppendTo the <code>StringBuffer</code> to which the formatted
 135.222 +     *                   text is to be appended
 135.223 +     * @param pos        On input: an alignment field, if desired.
 135.224 +     *                   On output: the offsets of the alignment field.
 135.225 +     * @return           the value passed in as <code>toAppendTo</code>
 135.226 +     * @exception        IllegalArgumentException if <code>number</code> is
 135.227 +     *                   null or not an instance of <code>Number</code>.
 135.228 +     * @exception        NullPointerException if <code>toAppendTo</code> or
 135.229 +     *                   <code>pos</code> is null
 135.230 +     * @exception        ArithmeticException if rounding is needed with rounding
 135.231 +     *                   mode being set to RoundingMode.UNNECESSARY
 135.232 +     * @see              java.text.FieldPosition
 135.233 +     */
 135.234 +    public StringBuffer format(Object number,
 135.235 +                               StringBuffer toAppendTo,
 135.236 +                               FieldPosition pos) {
 135.237 +        if (number instanceof Long || number instanceof Integer ||
 135.238 +            number instanceof Short || number instanceof Byte ||
 135.239 +            number instanceof AtomicInteger || number instanceof AtomicLong ||
 135.240 +            (number instanceof BigInteger &&
 135.241 +             ((BigInteger)number).bitLength() < 64)) {
 135.242 +            return format(((Number)number).longValue(), toAppendTo, pos);
 135.243 +        } else if (number instanceof Number) {
 135.244 +            return format(((Number)number).doubleValue(), toAppendTo, pos);
 135.245 +        } else {
 135.246 +            throw new IllegalArgumentException("Cannot format given Object as a Number");
 135.247 +        }
 135.248 +    }
 135.249 +
 135.250 +    /**
 135.251 +     * Parses text from a string to produce a <code>Number</code>.
 135.252 +     * <p>
 135.253 +     * The method attempts to parse text starting at the index given by
 135.254 +     * <code>pos</code>.
 135.255 +     * If parsing succeeds, then the index of <code>pos</code> is updated
 135.256 +     * to the index after the last character used (parsing does not necessarily
 135.257 +     * use all characters up to the end of the string), and the parsed
 135.258 +     * number is returned. The updated <code>pos</code> can be used to
 135.259 +     * indicate the starting point for the next call to this method.
 135.260 +     * If an error occurs, then the index of <code>pos</code> is not
 135.261 +     * changed, the error index of <code>pos</code> is set to the index of
 135.262 +     * the character where the error occurred, and null is returned.
 135.263 +     * <p>
 135.264 +     * See the {@link #parse(String, ParsePosition)} method for more information
 135.265 +     * on number parsing.
 135.266 +     *
 135.267 +     * @param source A <code>String</code>, part of which should be parsed.
 135.268 +     * @param pos A <code>ParsePosition</code> object with index and error
 135.269 +     *            index information as described above.
 135.270 +     * @return A <code>Number</code> parsed from the string. In case of
 135.271 +     *         error, returns null.
 135.272 +     * @exception NullPointerException if <code>pos</code> is null.
 135.273 +     */
 135.274 +    public final Object parseObject(String source, ParsePosition pos) {
 135.275 +        return parse(source, pos);
 135.276 +    }
 135.277 +
 135.278 +   /**
 135.279 +     * Specialization of format.
 135.280 +     * @exception        ArithmeticException if rounding is needed with rounding
 135.281 +     *                   mode being set to RoundingMode.UNNECESSARY
 135.282 +     * @see java.text.Format#format
 135.283 +     */
 135.284 +    public final String format(double number) {
 135.285 +        return format(number, new StringBuffer(),
 135.286 +                      DontCareFieldPosition.INSTANCE).toString();
 135.287 +    }
 135.288 +
 135.289 +   /**
 135.290 +     * Specialization of format.
 135.291 +     * @exception        ArithmeticException if rounding is needed with rounding
 135.292 +     *                   mode being set to RoundingMode.UNNECESSARY
 135.293 +     * @see java.text.Format#format
 135.294 +     */
 135.295 +    public final String format(long number) {
 135.296 +        return format(number, new StringBuffer(),
 135.297 +                      DontCareFieldPosition.INSTANCE).toString();
 135.298 +    }
 135.299 +
 135.300 +   /**
 135.301 +     * Specialization of format.
 135.302 +     * @exception        ArithmeticException if rounding is needed with rounding
 135.303 +     *                   mode being set to RoundingMode.UNNECESSARY
 135.304 +     * @see java.text.Format#format
 135.305 +     */
 135.306 +    public abstract StringBuffer format(double number,
 135.307 +                                        StringBuffer toAppendTo,
 135.308 +                                        FieldPosition pos);
 135.309 +
 135.310 +   /**
 135.311 +     * Specialization of format.
 135.312 +     * @exception        ArithmeticException if rounding is needed with rounding
 135.313 +     *                   mode being set to RoundingMode.UNNECESSARY
 135.314 +     * @see java.text.Format#format
 135.315 +     */
 135.316 +    public abstract StringBuffer format(long number,
 135.317 +                                        StringBuffer toAppendTo,
 135.318 +                                        FieldPosition pos);
 135.319 +
 135.320 +   /**
 135.321 +     * Returns a Long if possible (e.g., within the range [Long.MIN_VALUE,
 135.322 +     * Long.MAX_VALUE] and with no decimals), otherwise a Double.
 135.323 +     * If IntegerOnly is set, will stop at a decimal
 135.324 +     * point (or equivalent; e.g., for rational numbers "1 2/3", will stop
 135.325 +     * after the 1).
 135.326 +     * Does not throw an exception; if no object can be parsed, index is
 135.327 +     * unchanged!
 135.328 +     * @see java.text.NumberFormat#isParseIntegerOnly
 135.329 +     * @see java.text.Format#parseObject
 135.330 +     */
 135.331 +    public abstract Number parse(String source, ParsePosition parsePosition);
 135.332 +
 135.333 +    /**
 135.334 +     * Parses text from the beginning of the given string to produce a number.
 135.335 +     * The method may not use the entire text of the given string.
 135.336 +     * <p>
 135.337 +     * See the {@link #parse(String, ParsePosition)} method for more information
 135.338 +     * on number parsing.
 135.339 +     *
 135.340 +     * @param source A <code>String</code> whose beginning should be parsed.
 135.341 +     * @return A <code>Number</code> parsed from the string.
 135.342 +     * @exception ParseException if the beginning of the specified string
 135.343 +     *            cannot be parsed.
 135.344 +     */
 135.345 +    public Number parse(String source) throws ParseException {
 135.346 +        ParsePosition parsePosition = new ParsePosition(0);
 135.347 +        Number result = parse(source, parsePosition);
 135.348 +        if (parsePosition.index == 0) {
 135.349 +            throw new ParseException("Unparseable number: \"" + source + "\"",
 135.350 +                                     parsePosition.errorIndex);
 135.351 +        }
 135.352 +        return result;
 135.353 +    }
 135.354 +
 135.355 +    /**
 135.356 +     * Returns true if this format will parse numbers as integers only.
 135.357 +     * For example in the English locale, with ParseIntegerOnly true, the
 135.358 +     * string "1234." would be parsed as the integer value 1234 and parsing
 135.359 +     * would stop at the "." character.  Of course, the exact format accepted
 135.360 +     * by the parse operation is locale dependant and determined by sub-classes
 135.361 +     * of NumberFormat.
 135.362 +     */
 135.363 +    public boolean isParseIntegerOnly() {
 135.364 +        return parseIntegerOnly;
 135.365 +    }
 135.366 +
 135.367 +    /**
 135.368 +     * Sets whether or not numbers should be parsed as integers only.
 135.369 +     * @see #isParseIntegerOnly
 135.370 +     */
 135.371 +    public void setParseIntegerOnly(boolean value) {
 135.372 +        parseIntegerOnly = value;
 135.373 +    }
 135.374 +
 135.375 +    //============== Locale Stuff =====================
 135.376 +
 135.377 +    /**
 135.378 +     * Returns a general-purpose number format for the current default locale.
 135.379 +     * This is the same as calling
 135.380 +     * {@link #getNumberInstance() getNumberInstance()}.
 135.381 +     */
 135.382 +    public final static NumberFormat getInstance() {
 135.383 +        return getInstance(Locale.getDefault(Locale.Category.FORMAT), NUMBERSTYLE);
 135.384 +    }
 135.385 +
 135.386 +    /**
 135.387 +     * Returns a general-purpose number format for the specified locale.
 135.388 +     * This is the same as calling
 135.389 +     * {@link #getNumberInstance(java.util.Locale) getNumberInstance(inLocale)}.
 135.390 +     */
 135.391 +    public static NumberFormat getInstance(Locale inLocale) {
 135.392 +        return getInstance(inLocale, NUMBERSTYLE);
 135.393 +    }
 135.394 +
 135.395 +    /**     * Returns a general-purpose number format for the current default locale.
 135.396 +     */
 135.397 +    public final static NumberFormat getNumberInstance() {
 135.398 +        return getInstance(Locale.getDefault(Locale.Category.FORMAT), NUMBERSTYLE);
 135.399 +    }
 135.400 +
 135.401 +    /**
 135.402 +     * Returns a general-purpose number format for the specified locale.
 135.403 +     */
 135.404 +    public static NumberFormat getNumberInstance(Locale inLocale) {
 135.405 +        return getInstance(inLocale, NUMBERSTYLE);
 135.406 +    }
 135.407 +
 135.408 +    /**
 135.409 +     * Returns an integer number format for the current default locale. The
 135.410 +     * returned number format is configured to round floating point numbers
 135.411 +     * to the nearest integer using half-even rounding (see {@link
 135.412 +     * java.math.RoundingMode#HALF_EVEN RoundingMode.HALF_EVEN}) for formatting,
 135.413 +     * and to parse only the integer part of an input string (see {@link
 135.414 +     * #isParseIntegerOnly isParseIntegerOnly}).
 135.415 +     *
 135.416 +     * @see #getRoundingMode()
 135.417 +     * @return a number format for integer values
 135.418 +     * @since 1.4
 135.419 +     */
 135.420 +    public final static NumberFormat getIntegerInstance() {
 135.421 +        return getInstance(Locale.getDefault(Locale.Category.FORMAT), INTEGERSTYLE);
 135.422 +    }
 135.423 +
 135.424 +    /**
 135.425 +     * Returns an integer number format for the specified locale. The
 135.426 +     * returned number format is configured to round floating point numbers
 135.427 +     * to the nearest integer using half-even rounding (see {@link
 135.428 +     * java.math.RoundingMode#HALF_EVEN RoundingMode.HALF_EVEN}) for formatting,
 135.429 +     * and to parse only the integer part of an input string (see {@link
 135.430 +     * #isParseIntegerOnly isParseIntegerOnly}).
 135.431 +     *
 135.432 +     * @see #getRoundingMode()
 135.433 +     * @return a number format for integer values
 135.434 +     * @since 1.4
 135.435 +     */
 135.436 +    public static NumberFormat getIntegerInstance(Locale inLocale) {
 135.437 +        return getInstance(inLocale, INTEGERSTYLE);
 135.438 +    }
 135.439 +
 135.440 +    /**
 135.441 +     * Returns a currency format for the current default locale.
 135.442 +     */
 135.443 +    public final static NumberFormat getCurrencyInstance() {
 135.444 +        return getInstance(Locale.getDefault(Locale.Category.FORMAT), CURRENCYSTYLE);
 135.445 +    }
 135.446 +
 135.447 +    /**
 135.448 +     * Returns a currency format for the specified locale.
 135.449 +     */
 135.450 +    public static NumberFormat getCurrencyInstance(Locale inLocale) {
 135.451 +        return getInstance(inLocale, CURRENCYSTYLE);
 135.452 +    }
 135.453 +
 135.454 +    /**
 135.455 +     * Returns a percentage format for the current default locale.
 135.456 +     */
 135.457 +    public final static NumberFormat getPercentInstance() {
 135.458 +        return getInstance(Locale.getDefault(Locale.Category.FORMAT), PERCENTSTYLE);
 135.459 +    }
 135.460 +
 135.461 +    /**
 135.462 +     * Returns a percentage format for the specified locale.
 135.463 +     */
 135.464 +    public static NumberFormat getPercentInstance(Locale inLocale) {
 135.465 +        return getInstance(inLocale, PERCENTSTYLE);
 135.466 +    }
 135.467 +
 135.468 +    /**
 135.469 +     * Returns a scientific format for the current default locale.
 135.470 +     */
 135.471 +    /*public*/ final static NumberFormat getScientificInstance() {
 135.472 +        return getInstance(Locale.getDefault(Locale.Category.FORMAT), SCIENTIFICSTYLE);
 135.473 +    }
 135.474 +
 135.475 +    /**
 135.476 +     * Returns a scientific format for the specified locale.
 135.477 +     */
 135.478 +    /*public*/ static NumberFormat getScientificInstance(Locale inLocale) {
 135.479 +        return getInstance(inLocale, SCIENTIFICSTYLE);
 135.480 +    }
 135.481 +
 135.482 +    /**
 135.483 +     * Returns an array of all locales for which the
 135.484 +     * <code>get*Instance</code> methods of this class can return
 135.485 +     * localized instances.
 135.486 +     * The returned array represents the union of locales supported by the Java
 135.487 +     * runtime and by installed
 135.488 +     * {@link java.text.spi.NumberFormatProvider NumberFormatProvider} implementations.
 135.489 +     * It must contain at least a <code>Locale</code> instance equal to
 135.490 +     * {@link java.util.Locale#US Locale.US}.
 135.491 +     *
 135.492 +     * @return An array of locales for which localized
 135.493 +     *         <code>NumberFormat</code> instances are available.
 135.494 +     */
 135.495 +    public static Locale[] getAvailableLocales() {
 135.496 +        return new Locale[] { Locale.US };
 135.497 +//        LocaleServiceProviderPool pool =
 135.498 +//            LocaleServiceProviderPool.getPool(NumberFormatProvider.class);
 135.499 +//        return pool.getAvailableLocales();
 135.500 +    }
 135.501 +
 135.502 +    /**
 135.503 +     * Overrides hashCode
 135.504 +     */
 135.505 +    public int hashCode() {
 135.506 +        return maximumIntegerDigits * 37 + maxFractionDigits;
 135.507 +        // just enough fields for a reasonable distribution
 135.508 +    }
 135.509 +
 135.510 +    /**
 135.511 +     * Overrides equals
 135.512 +     */
 135.513 +    public boolean equals(Object obj) {
 135.514 +        if (obj == null) {
 135.515 +            return false;
 135.516 +        }
 135.517 +        if (this == obj) {
 135.518 +            return true;
 135.519 +        }
 135.520 +        if (getClass() != obj.getClass()) {
 135.521 +            return false;
 135.522 +        }
 135.523 +        NumberFormat other = (NumberFormat) obj;
 135.524 +        return (maximumIntegerDigits == other.maximumIntegerDigits
 135.525 +            && minimumIntegerDigits == other.minimumIntegerDigits
 135.526 +            && maximumFractionDigits == other.maximumFractionDigits
 135.527 +            && minimumFractionDigits == other.minimumFractionDigits
 135.528 +            && groupingUsed == other.groupingUsed
 135.529 +            && parseIntegerOnly == other.parseIntegerOnly);
 135.530 +    }
 135.531 +
 135.532 +    /**
 135.533 +     * Overrides Cloneable
 135.534 +     */
 135.535 +    public Object clone() {
 135.536 +        NumberFormat other = (NumberFormat) super.clone();
 135.537 +        return other;
 135.538 +    }
 135.539 +
 135.540 +    /**
 135.541 +     * Returns true if grouping is used in this format. For example, in the
 135.542 +     * English locale, with grouping on, the number 1234567 might be formatted
 135.543 +     * as "1,234,567". The grouping separator as well as the size of each group
 135.544 +     * is locale dependant and is determined by sub-classes of NumberFormat.
 135.545 +     * @see #setGroupingUsed
 135.546 +     */
 135.547 +    public boolean isGroupingUsed() {
 135.548 +        return groupingUsed;
 135.549 +    }
 135.550 +
 135.551 +    /**
 135.552 +     * Set whether or not grouping will be used in this format.
 135.553 +     * @see #isGroupingUsed
 135.554 +     */
 135.555 +    public void setGroupingUsed(boolean newValue) {
 135.556 +        groupingUsed = newValue;
 135.557 +    }
 135.558 +
 135.559 +    /**
 135.560 +     * Returns the maximum number of digits allowed in the integer portion of a
 135.561 +     * number.
 135.562 +     * @see #setMaximumIntegerDigits
 135.563 +     */
 135.564 +    public int getMaximumIntegerDigits() {
 135.565 +        return maximumIntegerDigits;
 135.566 +    }
 135.567 +
 135.568 +    /**
 135.569 +     * Sets the maximum number of digits allowed in the integer portion of a
 135.570 +     * number. maximumIntegerDigits must be >= minimumIntegerDigits.  If the
 135.571 +     * new value for maximumIntegerDigits is less than the current value
 135.572 +     * of minimumIntegerDigits, then minimumIntegerDigits will also be set to
 135.573 +     * the new value.
 135.574 +     * @param newValue the maximum number of integer digits to be shown; if
 135.575 +     * less than zero, then zero is used. The concrete subclass may enforce an
 135.576 +     * upper limit to this value appropriate to the numeric type being formatted.
 135.577 +     * @see #getMaximumIntegerDigits
 135.578 +     */
 135.579 +    public void setMaximumIntegerDigits(int newValue) {
 135.580 +        maximumIntegerDigits = Math.max(0,newValue);
 135.581 +        if (minimumIntegerDigits > maximumIntegerDigits) {
 135.582 +            minimumIntegerDigits = maximumIntegerDigits;
 135.583 +        }
 135.584 +    }
 135.585 +
 135.586 +    /**
 135.587 +     * Returns the minimum number of digits allowed in the integer portion of a
 135.588 +     * number.
 135.589 +     * @see #setMinimumIntegerDigits
 135.590 +     */
 135.591 +    public int getMinimumIntegerDigits() {
 135.592 +        return minimumIntegerDigits;
 135.593 +    }
 135.594 +
 135.595 +    /**
 135.596 +     * Sets the minimum number of digits allowed in the integer portion of a
 135.597 +     * number. minimumIntegerDigits must be <= maximumIntegerDigits.  If the
 135.598 +     * new value for minimumIntegerDigits exceeds the current value
 135.599 +     * of maximumIntegerDigits, then maximumIntegerDigits will also be set to
 135.600 +     * the new value
 135.601 +     * @param newValue the minimum number of integer digits to be shown; if
 135.602 +     * less than zero, then zero is used. The concrete subclass may enforce an
 135.603 +     * upper limit to this value appropriate to the numeric type being formatted.
 135.604 +     * @see #getMinimumIntegerDigits
 135.605 +     */
 135.606 +    public void setMinimumIntegerDigits(int newValue) {
 135.607 +        minimumIntegerDigits = Math.max(0,newValue);
 135.608 +        if (minimumIntegerDigits > maximumIntegerDigits) {
 135.609 +            maximumIntegerDigits = minimumIntegerDigits;
 135.610 +        }
 135.611 +    }
 135.612 +
 135.613 +    /**
 135.614 +     * Returns the maximum number of digits allowed in the fraction portion of a
 135.615 +     * number.
 135.616 +     * @see #setMaximumFractionDigits
 135.617 +     */
 135.618 +    public int getMaximumFractionDigits() {
 135.619 +        return maximumFractionDigits;
 135.620 +    }
 135.621 +
 135.622 +    /**
 135.623 +     * Sets the maximum number of digits allowed in the fraction portion of a
 135.624 +     * number. maximumFractionDigits must be >= minimumFractionDigits.  If the
 135.625 +     * new value for maximumFractionDigits is less than the current value
 135.626 +     * of minimumFractionDigits, then minimumFractionDigits will also be set to
 135.627 +     * the new value.
 135.628 +     * @param newValue the maximum number of fraction digits to be shown; if
 135.629 +     * less than zero, then zero is used. The concrete subclass may enforce an
 135.630 +     * upper limit to this value appropriate to the numeric type being formatted.
 135.631 +     * @see #getMaximumFractionDigits
 135.632 +     */
 135.633 +    public void setMaximumFractionDigits(int newValue) {
 135.634 +        maximumFractionDigits = Math.max(0,newValue);
 135.635 +        if (maximumFractionDigits < minimumFractionDigits) {
 135.636 +            minimumFractionDigits = maximumFractionDigits;
 135.637 +        }
 135.638 +    }
 135.639 +
 135.640 +    /**
 135.641 +     * Returns the minimum number of digits allowed in the fraction portion of a
 135.642 +     * number.
 135.643 +     * @see #setMinimumFractionDigits
 135.644 +     */
 135.645 +    public int getMinimumFractionDigits() {
 135.646 +        return minimumFractionDigits;
 135.647 +    }
 135.648 +
 135.649 +    /**
 135.650 +     * Sets the minimum number of digits allowed in the fraction portion of a
 135.651 +     * number. minimumFractionDigits must be <= maximumFractionDigits.  If the
 135.652 +     * new value for minimumFractionDigits exceeds the current value
 135.653 +     * of maximumFractionDigits, then maximumIntegerDigits will also be set to
 135.654 +     * the new value
 135.655 +     * @param newValue the minimum number of fraction digits to be shown; if
 135.656 +     * less than zero, then zero is used. The concrete subclass may enforce an
 135.657 +     * upper limit to this value appropriate to the numeric type being formatted.
 135.658 +     * @see #getMinimumFractionDigits
 135.659 +     */
 135.660 +    public void setMinimumFractionDigits(int newValue) {
 135.661 +        minimumFractionDigits = Math.max(0,newValue);
 135.662 +        if (maximumFractionDigits < minimumFractionDigits) {
 135.663 +            maximumFractionDigits = minimumFractionDigits;
 135.664 +        }
 135.665 +    }
 135.666 +
 135.667 +    /**
 135.668 +     * Gets the currency used by this number format when formatting
 135.669 +     * currency values. The initial value is derived in a locale dependent
 135.670 +     * way. The returned value may be null if no valid
 135.671 +     * currency could be determined and no currency has been set using
 135.672 +     * {@link #setCurrency(java.util.Currency) setCurrency}.
 135.673 +     * <p>
 135.674 +     * The default implementation throws
 135.675 +     * <code>UnsupportedOperationException</code>.
 135.676 +     *
 135.677 +     * @return the currency used by this number format, or <code>null</code>
 135.678 +     * @exception UnsupportedOperationException if the number format class
 135.679 +     * doesn't implement currency formatting
 135.680 +     * @since 1.4
 135.681 +     */
 135.682 +    public Currency getCurrency() {
 135.683 +        throw new UnsupportedOperationException();
 135.684 +    }
 135.685 +
 135.686 +    /**
 135.687 +     * Sets the currency used by this number format when formatting
 135.688 +     * currency values. This does not update the minimum or maximum
 135.689 +     * number of fraction digits used by the number format.
 135.690 +     * <p>
 135.691 +     * The default implementation throws
 135.692 +     * <code>UnsupportedOperationException</code>.
 135.693 +     *
 135.694 +     * @param currency the new currency to be used by this number format
 135.695 +     * @exception UnsupportedOperationException if the number format class
 135.696 +     * doesn't implement currency formatting
 135.697 +     * @exception NullPointerException if <code>currency</code> is null
 135.698 +     * @since 1.4
 135.699 +     */
 135.700 +    public void setCurrency(Currency currency) {
 135.701 +        throw new UnsupportedOperationException();
 135.702 +    }
 135.703 +
 135.704 +    /**
 135.705 +     * Gets the {@link java.math.RoundingMode} used in this NumberFormat.
 135.706 +     * The default implementation of this method in NumberFormat
 135.707 +     * always throws {@link java.lang.UnsupportedOperationException}.
 135.708 +     * Subclasses which handle different rounding modes should override
 135.709 +     * this method.
 135.710 +     *
 135.711 +     * @exception UnsupportedOperationException The default implementation
 135.712 +     *     always throws this exception
 135.713 +     * @return The <code>RoundingMode</code> used for this NumberFormat.
 135.714 +     * @see #setRoundingMode(RoundingMode)
 135.715 +     * @since 1.6
 135.716 +     */
 135.717 +    public RoundingMode getRoundingMode() {
 135.718 +        throw new UnsupportedOperationException();
 135.719 +    }
 135.720 +
 135.721 +    /**
 135.722 +     * Sets the {@link java.math.RoundingMode} used in this NumberFormat.
 135.723 +     * The default implementation of this method in NumberFormat always
 135.724 +     * throws {@link java.lang.UnsupportedOperationException}.
 135.725 +     * Subclasses which handle different rounding modes should override
 135.726 +     * this method.
 135.727 +     *
 135.728 +     * @exception UnsupportedOperationException The default implementation
 135.729 +     *     always throws this exception
 135.730 +     * @exception NullPointerException if <code>roundingMode</code> is null
 135.731 +     * @param roundingMode The <code>RoundingMode</code> to be used
 135.732 +     * @see #getRoundingMode()
 135.733 +     * @since 1.6
 135.734 +     */
 135.735 +    public void setRoundingMode(RoundingMode roundingMode) {
 135.736 +        throw new UnsupportedOperationException();
 135.737 +    }
 135.738 +
 135.739 +    // =======================privates===============================
 135.740 +
 135.741 +    private static NumberFormat getInstance(Locale desiredLocale,
 135.742 +                                           int choice) {
 135.743 +        // Check whether a provider can provide an implementation that's closer
 135.744 +        // to the requested locale than what the Java runtime itself can provide.
 135.745 +//        LocaleServiceProviderPool pool =
 135.746 +//            LocaleServiceProviderPool.getPool(NumberFormatProvider.class);
 135.747 +//        if (pool.hasProviders()) {
 135.748 +//            NumberFormat providersInstance = pool.getLocalizedObject(
 135.749 +//                                    NumberFormatGetter.INSTANCE,
 135.750 +//                                    desiredLocale,
 135.751 +//                                    choice);
 135.752 +//            if (providersInstance != null) {
 135.753 +//                return providersInstance;
 135.754 +//            }
 135.755 +//        }
 135.756 +
 135.757 +        /* try the cache first */
 135.758 +        String[] numberPatterns = (String[])cachedLocaleData.get(desiredLocale);
 135.759 +//        if (numberPatterns == null) { /* cache miss */
 135.760 +//            ResourceBundle resource = LocaleData.getNumberFormatData(desiredLocale);
 135.761 +//            numberPatterns = resource.getStringArray("NumberPatterns");
 135.762 +//            /* update cache */
 135.763 +//            cachedLocaleData.put(desiredLocale, numberPatterns);
 135.764 +//        }
 135.765 +
 135.766 +        DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(desiredLocale);
 135.767 +        int entry = (choice == INTEGERSTYLE) ? NUMBERSTYLE : choice;
 135.768 +        DecimalFormat format = new DecimalFormat(numberPatterns[entry], symbols);
 135.769 +
 135.770 +        if (choice == INTEGERSTYLE) {
 135.771 +            format.setMaximumFractionDigits(0);
 135.772 +            format.setDecimalSeparatorAlwaysShown(false);
 135.773 +            format.setParseIntegerOnly(true);
 135.774 +        } else if (choice == CURRENCYSTYLE) {
 135.775 +            format.adjustForCurrencyDefaultFractionDigits();
 135.776 +        }
 135.777 +
 135.778 +        return format;
 135.779 +    }
 135.780 +
 135.781 +    /**
 135.782 +     * First, read in the default serializable data.
 135.783 +     *
 135.784 +     * Then, if <code>serialVersionOnStream</code> is less than 1, indicating that
 135.785 +     * the stream was written by JDK 1.1,
 135.786 +     * set the <code>int</code> fields such as <code>maximumIntegerDigits</code>
 135.787 +     * to be equal to the <code>byte</code> fields such as <code>maxIntegerDigits</code>,
 135.788 +     * since the <code>int</code> fields were not present in JDK 1.1.
 135.789 +     * Finally, set serialVersionOnStream back to the maximum allowed value so that
 135.790 +     * default serialization will work properly if this object is streamed out again.
 135.791 +     *
 135.792 +     * <p>If <code>minimumIntegerDigits</code> is greater than
 135.793 +     * <code>maximumIntegerDigits</code> or <code>minimumFractionDigits</code>
 135.794 +     * is greater than <code>maximumFractionDigits</code>, then the stream data
 135.795 +     * is invalid and this method throws an <code>InvalidObjectException</code>.
 135.796 +     * In addition, if any of these values is negative, then this method throws
 135.797 +     * an <code>InvalidObjectException</code>.
 135.798 +     *
 135.799 +     * @since 1.2
 135.800 +     */
 135.801 +    private void readObject(ObjectInputStream stream)
 135.802 +         throws IOException, ClassNotFoundException
 135.803 +    {
 135.804 +        stream.defaultReadObject();
 135.805 +        if (serialVersionOnStream < 1) {
 135.806 +            // Didn't have additional int fields, reassign to use them.
 135.807 +            maximumIntegerDigits = maxIntegerDigits;
 135.808 +            minimumIntegerDigits = minIntegerDigits;
 135.809 +            maximumFractionDigits = maxFractionDigits;
 135.810 +            minimumFractionDigits = minFractionDigits;
 135.811 +        }
 135.812 +        if (minimumIntegerDigits > maximumIntegerDigits ||
 135.813 +            minimumFractionDigits > maximumFractionDigits ||
 135.814 +            minimumIntegerDigits < 0 || minimumFractionDigits < 0) {
 135.815 +            throw new InvalidObjectException("Digit count range invalid");
 135.816 +        }
 135.817 +        serialVersionOnStream = currentSerialVersion;
 135.818 +    }
 135.819 +
 135.820 +    /**
 135.821 +     * Write out the default serializable data, after first setting
 135.822 +     * the <code>byte</code> fields such as <code>maxIntegerDigits</code> to be
 135.823 +     * equal to the <code>int</code> fields such as <code>maximumIntegerDigits</code>
 135.824 +     * (or to <code>Byte.MAX_VALUE</code>, whichever is smaller), for compatibility
 135.825 +     * with the JDK 1.1 version of the stream format.
 135.826 +     *
 135.827 +     * @since 1.2
 135.828 +     */
 135.829 +    private void writeObject(ObjectOutputStream stream)
 135.830 +         throws IOException
 135.831 +    {
 135.832 +        maxIntegerDigits = (maximumIntegerDigits > Byte.MAX_VALUE) ?
 135.833 +                           Byte.MAX_VALUE : (byte)maximumIntegerDigits;
 135.834 +        minIntegerDigits = (minimumIntegerDigits > Byte.MAX_VALUE) ?
 135.835 +                           Byte.MAX_VALUE : (byte)minimumIntegerDigits;
 135.836 +        maxFractionDigits = (maximumFractionDigits > Byte.MAX_VALUE) ?
 135.837 +                            Byte.MAX_VALUE : (byte)maximumFractionDigits;
 135.838 +        minFractionDigits = (minimumFractionDigits > Byte.MAX_VALUE) ?
 135.839 +                            Byte.MAX_VALUE : (byte)minimumFractionDigits;
 135.840 +        stream.defaultWriteObject();
 135.841 +    }
 135.842 +
 135.843 +    /**
 135.844 +     * Cache to hold the NumberPatterns of a Locale.
 135.845 +     */
 135.846 +    private static final Hashtable cachedLocaleData = new Hashtable(3);
 135.847 +
 135.848 +    // Constants used by factory methods to specify a style of format.
 135.849 +    private static final int NUMBERSTYLE = 0;
 135.850 +    private static final int CURRENCYSTYLE = 1;
 135.851 +    private static final int PERCENTSTYLE = 2;
 135.852 +    private static final int SCIENTIFICSTYLE = 3;
 135.853 +    private static final int INTEGERSTYLE = 4;
 135.854 +
 135.855 +    /**
 135.856 +     * True if the grouping (i.e. thousands) separator is used when
 135.857 +     * formatting and parsing numbers.
 135.858 +     *
 135.859 +     * @serial
 135.860 +     * @see #isGroupingUsed
 135.861 +     */
 135.862 +    private boolean groupingUsed = true;
 135.863 +
 135.864 +    /**
 135.865 +     * The maximum number of digits allowed in the integer portion of a
 135.866 +     * number.  <code>maxIntegerDigits</code> must be greater than or equal to
 135.867 +     * <code>minIntegerDigits</code>.
 135.868 +     * <p>
 135.869 +     * <strong>Note:</strong> This field exists only for serialization
 135.870 +     * compatibility with JDK 1.1.  In Java platform 2 v1.2 and higher, the new
 135.871 +     * <code>int</code> field <code>maximumIntegerDigits</code> is used instead.
 135.872 +     * When writing to a stream, <code>maxIntegerDigits</code> is set to
 135.873 +     * <code>maximumIntegerDigits</code> or <code>Byte.MAX_VALUE</code>,
 135.874 +     * whichever is smaller.  When reading from a stream, this field is used
 135.875 +     * only if <code>serialVersionOnStream</code> is less than 1.
 135.876 +     *
 135.877 +     * @serial
 135.878 +     * @see #getMaximumIntegerDigits
 135.879 +     */
 135.880 +    private byte    maxIntegerDigits = 40;
 135.881 +
 135.882 +    /**
 135.883 +     * The minimum number of digits allowed in the integer portion of a
 135.884 +     * number.  <code>minimumIntegerDigits</code> must be less than or equal to
 135.885 +     * <code>maximumIntegerDigits</code>.
 135.886 +     * <p>
 135.887 +     * <strong>Note:</strong> This field exists only for serialization
 135.888 +     * compatibility with JDK 1.1.  In Java platform 2 v1.2 and higher, the new
 135.889 +     * <code>int</code> field <code>minimumIntegerDigits</code> is used instead.
 135.890 +     * When writing to a stream, <code>minIntegerDigits</code> is set to
 135.891 +     * <code>minimumIntegerDigits</code> or <code>Byte.MAX_VALUE</code>,
 135.892 +     * whichever is smaller.  When reading from a stream, this field is used
 135.893 +     * only if <code>serialVersionOnStream</code> is less than 1.
 135.894 +     *
 135.895 +     * @serial
 135.896 +     * @see #getMinimumIntegerDigits
 135.897 +     */
 135.898 +    private byte    minIntegerDigits = 1;
 135.899 +
 135.900 +    /**
 135.901 +     * The maximum number of digits allowed in the fractional portion of a
 135.902 +     * number.  <code>maximumFractionDigits</code> must be greater than or equal to
 135.903 +     * <code>minimumFractionDigits</code>.
 135.904 +     * <p>
 135.905 +     * <strong>Note:</strong> This field exists only for serialization
 135.906 +     * compatibility with JDK 1.1.  In Java platform 2 v1.2 and higher, the new
 135.907 +     * <code>int</code> field <code>maximumFractionDigits</code> is used instead.
 135.908 +     * When writing to a stream, <code>maxFractionDigits</code> is set to
 135.909 +     * <code>maximumFractionDigits</code> or <code>Byte.MAX_VALUE</code>,
 135.910 +     * whichever is smaller.  When reading from a stream, this field is used
 135.911 +     * only if <code>serialVersionOnStream</code> is less than 1.
 135.912 +     *
 135.913 +     * @serial
 135.914 +     * @see #getMaximumFractionDigits
 135.915 +     */
 135.916 +    private byte    maxFractionDigits = 3;    // invariant, >= minFractionDigits
 135.917 +
 135.918 +    /**
 135.919 +     * The minimum number of digits allowed in the fractional portion of a
 135.920 +     * number.  <code>minimumFractionDigits</code> must be less than or equal to
 135.921 +     * <code>maximumFractionDigits</code>.
 135.922 +     * <p>
 135.923 +     * <strong>Note:</strong> This field exists only for serialization
 135.924 +     * compatibility with JDK 1.1.  In Java platform 2 v1.2 and higher, the new
 135.925 +     * <code>int</code> field <code>minimumFractionDigits</code> is used instead.
 135.926 +     * When writing to a stream, <code>minFractionDigits</code> is set to
 135.927 +     * <code>minimumFractionDigits</code> or <code>Byte.MAX_VALUE</code>,
 135.928 +     * whichever is smaller.  When reading from a stream, this field is used
 135.929 +     * only if <code>serialVersionOnStream</code> is less than 1.
 135.930 +     *
 135.931 +     * @serial
 135.932 +     * @see #getMinimumFractionDigits
 135.933 +     */
 135.934 +    private byte    minFractionDigits = 0;
 135.935 +
 135.936 +    /**
 135.937 +     * True if this format will parse numbers as integers only.
 135.938 +     *
 135.939 +     * @serial
 135.940 +     * @see #isParseIntegerOnly
 135.941 +     */
 135.942 +    private boolean parseIntegerOnly = false;
 135.943 +
 135.944 +    // new fields for 1.2.  byte is too small for integer digits.
 135.945 +
 135.946 +    /**
 135.947 +     * The maximum number of digits allowed in the integer portion of a
 135.948 +     * number.  <code>maximumIntegerDigits</code> must be greater than or equal to
 135.949 +     * <code>minimumIntegerDigits</code>.
 135.950 +     *
 135.951 +     * @serial
 135.952 +     * @since 1.2
 135.953 +     * @see #getMaximumIntegerDigits
 135.954 +     */
 135.955 +    private int    maximumIntegerDigits = 40;
 135.956 +
 135.957 +    /**
 135.958 +     * The minimum number of digits allowed in the integer portion of a
 135.959 +     * number.  <code>minimumIntegerDigits</code> must be less than or equal to
 135.960 +     * <code>maximumIntegerDigits</code>.
 135.961 +     *
 135.962 +     * @serial
 135.963 +     * @since 1.2
 135.964 +     * @see #getMinimumIntegerDigits
 135.965 +     */
 135.966 +    private int    minimumIntegerDigits = 1;
 135.967 +
 135.968 +    /**
 135.969 +     * The maximum number of digits allowed in the fractional portion of a
 135.970 +     * number.  <code>maximumFractionDigits</code> must be greater than or equal to
 135.971 +     * <code>minimumFractionDigits</code>.
 135.972 +     *
 135.973 +     * @serial
 135.974 +     * @since 1.2
 135.975 +     * @see #getMaximumFractionDigits
 135.976 +     */
 135.977 +    private int    maximumFractionDigits = 3;    // invariant, >= minFractionDigits
 135.978 +
 135.979 +    /**
 135.980 +     * The minimum number of digits allowed in the fractional portion of a
 135.981 +     * number.  <code>minimumFractionDigits</code> must be less than or equal to
 135.982 +     * <code>maximumFractionDigits</code>.
 135.983 +     *
 135.984 +     * @serial
 135.985 +     * @since 1.2
 135.986 +     * @see #getMinimumFractionDigits
 135.987 +     */
 135.988 +    private int    minimumFractionDigits = 0;
 135.989 +
 135.990 +    static final int currentSerialVersion = 1;
 135.991 +
 135.992 +    /**
 135.993 +     * Describes the version of <code>NumberFormat</code> present on the stream.
 135.994 +     * Possible values are:
 135.995 +     * <ul>
 135.996 +     * <li><b>0</b> (or uninitialized): the JDK 1.1 version of the stream format.
 135.997 +     *     In this version, the <code>int</code> fields such as
 135.998 +     *     <code>maximumIntegerDigits</code> were not present, and the <code>byte</code>
 135.999 +     *     fields such as <code>maxIntegerDigits</code> are used instead.
135.1000 +     *
135.1001 +     * <li><b>1</b>: the 1.2 version of the stream format.  The values of the
135.1002 +     *     <code>byte</code> fields such as <code>maxIntegerDigits</code> are ignored,
135.1003 +     *     and the <code>int</code> fields such as <code>maximumIntegerDigits</code>
135.1004 +     *     are used instead.
135.1005 +     * </ul>
135.1006 +     * When streaming out a <code>NumberFormat</code>, the most recent format
135.1007 +     * (corresponding to the highest allowable <code>serialVersionOnStream</code>)
135.1008 +     * is always written.
135.1009 +     *
135.1010 +     * @serial
135.1011 +     * @since 1.2
135.1012 +     */
135.1013 +    private int serialVersionOnStream = currentSerialVersion;
135.1014 +
135.1015 +    // Removed "implements Cloneable" clause.  Needs to update serialization
135.1016 +    // ID for backward compatibility.
135.1017 +    static final long serialVersionUID = -2308460125733713944L;
135.1018 +
135.1019 +
135.1020 +    //
135.1021 +    // class for AttributedCharacterIterator attributes
135.1022 +    //
135.1023 +    /**
135.1024 +     * Defines constants that are used as attribute keys in the
135.1025 +     * <code>AttributedCharacterIterator</code> returned
135.1026 +     * from <code>NumberFormat.formatToCharacterIterator</code> and as
135.1027 +     * field identifiers in <code>FieldPosition</code>.
135.1028 +     *
135.1029 +     * @since 1.4
135.1030 +     */
135.1031 +    public static class Field extends Format.Field {
135.1032 +
135.1033 +        // Proclaim serial compatibility with 1.4 FCS
135.1034 +        private static final long serialVersionUID = 7494728892700160890L;
135.1035 +
135.1036 +        // table of all instances in this class, used by readResolve
135.1037 +        private static final Map instanceMap = new HashMap(11);
135.1038 +
135.1039 +        /**
135.1040 +         * Creates a Field instance with the specified
135.1041 +         * name.
135.1042 +         *
135.1043 +         * @param name Name of the attribute
135.1044 +         */
135.1045 +        protected Field(String name) {
135.1046 +            super(name);
135.1047 +            if (this.getClass() == NumberFormat.Field.class) {
135.1048 +                instanceMap.put(name, this);
135.1049 +            }
135.1050 +        }
135.1051 +
135.1052 +        /**
135.1053 +         * Resolves instances being deserialized to the predefined constants.
135.1054 +         *
135.1055 +         * @throws InvalidObjectException if the constant could not be resolved.
135.1056 +         * @return resolved NumberFormat.Field constant
135.1057 +         */
135.1058 +        protected Object readResolve() throws InvalidObjectException {
135.1059 +            if (this.getClass() != NumberFormat.Field.class) {
135.1060 +                throw new InvalidObjectException("subclass didn't correctly implement readResolve");
135.1061 +            }
135.1062 +
135.1063 +            Object instance = instanceMap.get(getName());
135.1064 +            if (instance != null) {
135.1065 +                return instance;
135.1066 +            } else {
135.1067 +                throw new InvalidObjectException("unknown attribute name");
135.1068 +            }
135.1069 +        }
135.1070 +
135.1071 +        /**
135.1072 +         * Constant identifying the integer field.
135.1073 +         */
135.1074 +        public static final Field INTEGER = new Field("integer");
135.1075 +
135.1076 +        /**
135.1077 +         * Constant identifying the fraction field.
135.1078 +         */
135.1079 +        public static final Field FRACTION = new Field("fraction");
135.1080 +
135.1081 +        /**
135.1082 +         * Constant identifying the exponent field.
135.1083 +         */
135.1084 +        public static final Field EXPONENT = new Field("exponent");
135.1085 +
135.1086 +        /**
135.1087 +         * Constant identifying the decimal separator field.
135.1088 +         */
135.1089 +        public static final Field DECIMAL_SEPARATOR =
135.1090 +                            new Field("decimal separator");
135.1091 +
135.1092 +        /**
135.1093 +         * Constant identifying the sign field.
135.1094 +         */
135.1095 +        public static final Field SIGN = new Field("sign");
135.1096 +
135.1097 +        /**
135.1098 +         * Constant identifying the grouping separator field.
135.1099 +         */
135.1100 +        public static final Field GROUPING_SEPARATOR =
135.1101 +                            new Field("grouping separator");
135.1102 +
135.1103 +        /**
135.1104 +         * Constant identifying the exponent symbol field.
135.1105 +         */
135.1106 +        public static final Field EXPONENT_SYMBOL = new
135.1107 +                            Field("exponent symbol");
135.1108 +
135.1109 +        /**
135.1110 +         * Constant identifying the percent field.
135.1111 +         */
135.1112 +        public static final Field PERCENT = new Field("percent");
135.1113 +
135.1114 +        /**
135.1115 +         * Constant identifying the permille field.
135.1116 +         */
135.1117 +        public static final Field PERMILLE = new Field("per mille");
135.1118 +
135.1119 +        /**
135.1120 +         * Constant identifying the currency field.
135.1121 +         */
135.1122 +        public static final Field CURRENCY = new Field("currency");
135.1123 +
135.1124 +        /**
135.1125 +         * Constant identifying the exponent sign field.
135.1126 +         */
135.1127 +        public static final Field EXPONENT_SIGN = new Field("exponent sign");
135.1128 +    }
135.1129 +
135.1130 +    /**
135.1131 +     * Obtains a NumberFormat instance from a NumberFormatProvider implementation.
135.1132 +     *
135.1133 +    private static class NumberFormatGetter
135.1134 +        implements LocaleServiceProviderPool.LocalizedObjectGetter<NumberFormatProvider,
135.1135 +                                                                   NumberFormat> {
135.1136 +        private static final NumberFormatGetter INSTANCE = new NumberFormatGetter();
135.1137 +
135.1138 +        public NumberFormat getObject(NumberFormatProvider numberFormatProvider,
135.1139 +                                Locale locale,
135.1140 +                                String key,
135.1141 +                                Object... params) {
135.1142 +            assert params.length == 1;
135.1143 +            int choice = (Integer)params[0];
135.1144 +
135.1145 +            switch (choice) {
135.1146 +            case NUMBERSTYLE:
135.1147 +                return numberFormatProvider.getNumberInstance(locale);
135.1148 +            case PERCENTSTYLE:
135.1149 +                return numberFormatProvider.getPercentInstance(locale);
135.1150 +            case CURRENCYSTYLE:
135.1151 +                return numberFormatProvider.getCurrencyInstance(locale);
135.1152 +            case INTEGERSTYLE:
135.1153 +                return numberFormatProvider.getIntegerInstance(locale);
135.1154 +            default:
135.1155 +                assert false : choice;
135.1156 +            }
135.1157 +
135.1158 +            return null;
135.1159 +        }
135.1160 +    }
135.1161 +    */
135.1162 +}
   136.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   136.2 +++ b/rt/emul/compact/src/main/java/java/text/ParseException.java	Tue Feb 11 13:31:42 2014 +0100
   136.3 @@ -0,0 +1,78 @@
   136.4 +/*
   136.5 + * Copyright (c) 1996, 1998, Oracle and/or its affiliates. All rights reserved.
   136.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   136.7 + *
   136.8 + * This code is free software; you can redistribute it and/or modify it
   136.9 + * under the terms of the GNU General Public License version 2 only, as
  136.10 + * published by the Free Software Foundation.  Oracle designates this
  136.11 + * particular file as subject to the "Classpath" exception as provided
  136.12 + * by Oracle in the LICENSE file that accompanied this code.
  136.13 + *
  136.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  136.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  136.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  136.17 + * version 2 for more details (a copy is included in the LICENSE file that
  136.18 + * accompanied this code).
  136.19 + *
  136.20 + * You should have received a copy of the GNU General Public License version
  136.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  136.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  136.23 + *
  136.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  136.25 + * or visit www.oracle.com if you need additional information or have any
  136.26 + * questions.
  136.27 + */
  136.28 +
  136.29 +/*
  136.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
  136.31 + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
  136.32 + *
  136.33 + *   The original version of this source code and documentation is copyrighted
  136.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
  136.35 + * materials are provided under terms of a License Agreement between Taligent
  136.36 + * and Sun. This technology is protected by multiple US and International
  136.37 + * patents. This notice and attribution to Taligent may not be removed.
  136.38 + *   Taligent is a registered trademark of Taligent, Inc.
  136.39 + *
  136.40 + */
  136.41 +
  136.42 +package java.text;
  136.43 +
  136.44 +/**
  136.45 + * Signals that an error has been reached unexpectedly
  136.46 + * while parsing.
  136.47 + * @see java.lang.Exception
  136.48 + * @see java.text.Format
  136.49 + * @see java.text.FieldPosition
  136.50 + * @author      Mark Davis
  136.51 + */
  136.52 +public
  136.53 +class ParseException extends Exception {
  136.54 +
  136.55 +    /**
  136.56 +     * Constructs a ParseException with the specified detail message and
  136.57 +     * offset.
  136.58 +     * A detail message is a String that describes this particular exception.
  136.59 +     * @param s the detail message
  136.60 +     * @param errorOffset the position where the error is found while parsing.
  136.61 +     */
  136.62 +    public ParseException(String s, int errorOffset) {
  136.63 +        super(s);
  136.64 +        this.errorOffset = errorOffset;
  136.65 +    }
  136.66 +
  136.67 +    /**
  136.68 +     * Returns the position where the error was found.
  136.69 +     */
  136.70 +    public int getErrorOffset () {
  136.71 +        return errorOffset;
  136.72 +    }
  136.73 +
  136.74 +    //============ privates ============
  136.75 +    /**
  136.76 +     * The zero-based character offset into the string being parsed at which
  136.77 +     * the error was found during parsing.
  136.78 +     * @serial
  136.79 +     */
  136.80 +    private int errorOffset;
  136.81 +}
   137.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   137.2 +++ b/rt/emul/compact/src/main/java/java/text/ParsePosition.java	Tue Feb 11 13:31:42 2014 +0100
   137.3 @@ -0,0 +1,139 @@
   137.4 +/*
   137.5 + * Copyright (c) 1996, 2002, Oracle and/or its affiliates. All rights reserved.
   137.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   137.7 + *
   137.8 + * This code is free software; you can redistribute it and/or modify it
   137.9 + * under the terms of the GNU General Public License version 2 only, as
  137.10 + * published by the Free Software Foundation.  Oracle designates this
  137.11 + * particular file as subject to the "Classpath" exception as provided
  137.12 + * by Oracle in the LICENSE file that accompanied this code.
  137.13 + *
  137.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  137.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  137.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  137.17 + * version 2 for more details (a copy is included in the LICENSE file that
  137.18 + * accompanied this code).
  137.19 + *
  137.20 + * You should have received a copy of the GNU General Public License version
  137.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  137.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  137.23 + *
  137.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  137.25 + * or visit www.oracle.com if you need additional information or have any
  137.26 + * questions.
  137.27 + */
  137.28 +
  137.29 +/*
  137.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
  137.31 + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
  137.32 + *
  137.33 + *   The original version of this source code and documentation is copyrighted
  137.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
  137.35 + * materials are provided under terms of a License Agreement between Taligent
  137.36 + * and Sun. This technology is protected by multiple US and International
  137.37 + * patents. This notice and attribution to Taligent may not be removed.
  137.38 + *   Taligent is a registered trademark of Taligent, Inc.
  137.39 + *
  137.40 + */
  137.41 +
  137.42 +package java.text;
  137.43 +
  137.44 +
  137.45 +/**
  137.46 + * <code>ParsePosition</code> is a simple class used by <code>Format</code>
  137.47 + * and its subclasses to keep track of the current position during parsing.
  137.48 + * The <code>parseObject</code> method in the various <code>Format</code>
  137.49 + * classes requires a <code>ParsePosition</code> object as an argument.
  137.50 + *
  137.51 + * <p>
  137.52 + * By design, as you parse through a string with different formats,
  137.53 + * you can use the same <code>ParsePosition</code>, since the index parameter
  137.54 + * records the current position.
  137.55 + *
  137.56 + * @author      Mark Davis
  137.57 + * @see         java.text.Format
  137.58 + */
  137.59 +
  137.60 +public class ParsePosition {
  137.61 +
  137.62 +    /**
  137.63 +     * Input: the place you start parsing.
  137.64 +     * <br>Output: position where the parse stopped.
  137.65 +     * This is designed to be used serially,
  137.66 +     * with each call setting index up for the next one.
  137.67 +     */
  137.68 +    int index = 0;
  137.69 +    int errorIndex = -1;
  137.70 +
  137.71 +    /**
  137.72 +     * Retrieve the current parse position.  On input to a parse method, this
  137.73 +     * is the index of the character at which parsing will begin; on output, it
  137.74 +     * is the index of the character following the last character parsed.
  137.75 +     */
  137.76 +    public int getIndex() {
  137.77 +        return index;
  137.78 +    }
  137.79 +
  137.80 +    /**
  137.81 +     * Set the current parse position.
  137.82 +     */
  137.83 +    public void setIndex(int index) {
  137.84 +        this.index = index;
  137.85 +    }
  137.86 +
  137.87 +    /**
  137.88 +     * Create a new ParsePosition with the given initial index.
  137.89 +     */
  137.90 +    public ParsePosition(int index) {
  137.91 +        this.index = index;
  137.92 +    }
  137.93 +    /**
  137.94 +     * Set the index at which a parse error occurred.  Formatters
  137.95 +     * should set this before returning an error code from their
  137.96 +     * parseObject method.  The default value is -1 if this is not set.
  137.97 +     * @since 1.2
  137.98 +     */
  137.99 +    public void setErrorIndex(int ei)
 137.100 +    {
 137.101 +        errorIndex = ei;
 137.102 +    }
 137.103 +
 137.104 +    /**
 137.105 +     * Retrieve the index at which an error occurred, or -1 if the
 137.106 +     * error index has not been set.
 137.107 +     * @since 1.2
 137.108 +     */
 137.109 +    public int getErrorIndex()
 137.110 +    {
 137.111 +        return errorIndex;
 137.112 +    }
 137.113 +    /**
 137.114 +     * Overrides equals
 137.115 +     */
 137.116 +    public boolean equals(Object obj)
 137.117 +    {
 137.118 +        if (obj == null) return false;
 137.119 +        if (!(obj instanceof ParsePosition))
 137.120 +            return false;
 137.121 +        ParsePosition other = (ParsePosition) obj;
 137.122 +        return (index == other.index && errorIndex == other.errorIndex);
 137.123 +    }
 137.124 +
 137.125 +    /**
 137.126 +     * Returns a hash code for this ParsePosition.
 137.127 +     * @return a hash code value for this object
 137.128 +     */
 137.129 +    public int hashCode() {
 137.130 +        return (errorIndex << 16) | index;
 137.131 +    }
 137.132 +
 137.133 +    /**
 137.134 +     * Return a string representation of this ParsePosition.
 137.135 +     * @return  a string representation of this object
 137.136 +     */
 137.137 +    public String toString() {
 137.138 +        return getClass().getName() +
 137.139 +            "[index=" + index +
 137.140 +            ",errorIndex=" + errorIndex + ']';
 137.141 +    }
 137.142 +}
   138.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   138.2 +++ b/rt/emul/compact/src/main/java/java/text/SimpleDateFormat.java	Tue Feb 11 13:31:42 2014 +0100
   138.3 @@ -0,0 +1,2383 @@
   138.4 +/*
   138.5 + * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
   138.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   138.7 + *
   138.8 + * This code is free software; you can redistribute it and/or modify it
   138.9 + * under the terms of the GNU General Public License version 2 only, as
  138.10 + * published by the Free Software Foundation.  Oracle designates this
  138.11 + * particular file as subject to the "Classpath" exception as provided
  138.12 + * by Oracle in the LICENSE file that accompanied this code.
  138.13 + *
  138.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  138.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  138.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  138.17 + * version 2 for more details (a copy is included in the LICENSE file that
  138.18 + * accompanied this code).
  138.19 + *
  138.20 + * You should have received a copy of the GNU General Public License version
  138.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  138.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  138.23 + *
  138.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  138.25 + * or visit www.oracle.com if you need additional information or have any
  138.26 + * questions.
  138.27 + */
  138.28 +
  138.29 +/*
  138.30 + * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
  138.31 + * (C) Copyright IBM Corp. 1996-1998 - All Rights Reserved
  138.32 + *
  138.33 + *   The original version of this source code and documentation is copyrighted
  138.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
  138.35 + * materials are provided under terms of a License Agreement between Taligent
  138.36 + * and Sun. This technology is protected by multiple US and International
  138.37 + * patents. This notice and attribution to Taligent may not be removed.
  138.38 + *   Taligent is a registered trademark of Taligent, Inc.
  138.39 + *
  138.40 + */
  138.41 +
  138.42 +package java.text;
  138.43 +
  138.44 +import java.io.IOException;
  138.45 +import java.io.InvalidObjectException;
  138.46 +import java.io.ObjectInputStream;
  138.47 +import java.util.Calendar;
  138.48 +import java.util.Date;
  138.49 +import java.util.Locale;
  138.50 +import java.util.Map;
  138.51 +import java.util.MissingResourceException;
  138.52 +import java.util.ResourceBundle;
  138.53 +import java.util.SimpleTimeZone;
  138.54 +import java.util.TimeZone;
  138.55 +import java.util.concurrent.ConcurrentHashMap;
  138.56 +import java.util.concurrent.ConcurrentMap;
  138.57 +
  138.58 +import static java.text.DateFormatSymbols.*;
  138.59 +
  138.60 +/**
  138.61 + * <code>SimpleDateFormat</code> is a concrete class for formatting and
  138.62 + * parsing dates in a locale-sensitive manner. It allows for formatting
  138.63 + * (date -> text), parsing (text -> date), and normalization.
  138.64 + *
  138.65 + * <p>
  138.66 + * <code>SimpleDateFormat</code> allows you to start by choosing
  138.67 + * any user-defined patterns for date-time formatting. However, you
  138.68 + * are encouraged to create a date-time formatter with either
  138.69 + * <code>getTimeInstance</code>, <code>getDateInstance</code>, or
  138.70 + * <code>getDateTimeInstance</code> in <code>DateFormat</code>. Each
  138.71 + * of these class methods can return a date/time formatter initialized
  138.72 + * with a default format pattern. You may modify the format pattern
  138.73 + * using the <code>applyPattern</code> methods as desired.
  138.74 + * For more information on using these methods, see
  138.75 + * {@link DateFormat}.
  138.76 + *
  138.77 + * <h4>Date and Time Patterns</h4>
  138.78 + * <p>
  138.79 + * Date and time formats are specified by <em>date and time pattern</em>
  138.80 + * strings.
  138.81 + * Within date and time pattern strings, unquoted letters from
  138.82 + * <code>'A'</code> to <code>'Z'</code> and from <code>'a'</code> to
  138.83 + * <code>'z'</code> are interpreted as pattern letters representing the
  138.84 + * components of a date or time string.
  138.85 + * Text can be quoted using single quotes (<code>'</code>) to avoid
  138.86 + * interpretation.
  138.87 + * <code>"''"</code> represents a single quote.
  138.88 + * All other characters are not interpreted; they're simply copied into the
  138.89 + * output string during formatting or matched against the input string
  138.90 + * during parsing.
  138.91 + * <p>
  138.92 + * The following pattern letters are defined (all other characters from
  138.93 + * <code>'A'</code> to <code>'Z'</code> and from <code>'a'</code> to
  138.94 + * <code>'z'</code> are reserved):
  138.95 + * <blockquote>
  138.96 + * <table border=0 cellspacing=3 cellpadding=0 summary="Chart shows pattern letters, date/time component, presentation, and examples.">
  138.97 + *     <tr bgcolor="#ccccff">
  138.98 + *         <th align=left>Letter
  138.99 + *         <th align=left>Date or Time Component
 138.100 + *         <th align=left>Presentation
 138.101 + *         <th align=left>Examples
 138.102 + *     <tr>
 138.103 + *         <td><code>G</code>
 138.104 + *         <td>Era designator
 138.105 + *         <td><a href="#text">Text</a>
 138.106 + *         <td><code>AD</code>
 138.107 + *     <tr bgcolor="#eeeeff">
 138.108 + *         <td><code>y</code>
 138.109 + *         <td>Year
 138.110 + *         <td><a href="#year">Year</a>
 138.111 + *         <td><code>1996</code>; <code>96</code>
 138.112 + *     <tr>
 138.113 + *         <td><code>Y</code>
 138.114 + *         <td>Week year
 138.115 + *         <td><a href="#year">Year</a>
 138.116 + *         <td><code>2009</code>; <code>09</code>
 138.117 + *     <tr bgcolor="#eeeeff">
 138.118 + *         <td><code>M</code>
 138.119 + *         <td>Month in year
 138.120 + *         <td><a href="#month">Month</a>
 138.121 + *         <td><code>July</code>; <code>Jul</code>; <code>07</code>
 138.122 + *     <tr>
 138.123 + *         <td><code>w</code>
 138.124 + *         <td>Week in year
 138.125 + *         <td><a href="#number">Number</a>
 138.126 + *         <td><code>27</code>
 138.127 + *     <tr bgcolor="#eeeeff">
 138.128 + *         <td><code>W</code>
 138.129 + *         <td>Week in month
 138.130 + *         <td><a href="#number">Number</a>
 138.131 + *         <td><code>2</code>
 138.132 + *     <tr>
 138.133 + *         <td><code>D</code>
 138.134 + *         <td>Day in year
 138.135 + *         <td><a href="#number">Number</a>
 138.136 + *         <td><code>189</code>
 138.137 + *     <tr bgcolor="#eeeeff">
 138.138 + *         <td><code>d</code>
 138.139 + *         <td>Day in month
 138.140 + *         <td><a href="#number">Number</a>
 138.141 + *         <td><code>10</code>
 138.142 + *     <tr>
 138.143 + *         <td><code>F</code>
 138.144 + *         <td>Day of week in month
 138.145 + *         <td><a href="#number">Number</a>
 138.146 + *         <td><code>2</code>
 138.147 + *     <tr bgcolor="#eeeeff">
 138.148 + *         <td><code>E</code>
 138.149 + *         <td>Day name in week
 138.150 + *         <td><a href="#text">Text</a>
 138.151 + *         <td><code>Tuesday</code>; <code>Tue</code>
 138.152 + *     <tr>
 138.153 + *         <td><code>u</code>
 138.154 + *         <td>Day number of week (1 = Monday, ..., 7 = Sunday)
 138.155 + *         <td><a href="#number">Number</a>
 138.156 + *         <td><code>1</code>
 138.157 + *     <tr bgcolor="#eeeeff">
 138.158 + *         <td><code>a</code>
 138.159 + *         <td>Am/pm marker
 138.160 + *         <td><a href="#text">Text</a>
 138.161 + *         <td><code>PM</code>
 138.162 + *     <tr>
 138.163 + *         <td><code>H</code>
 138.164 + *         <td>Hour in day (0-23)
 138.165 + *         <td><a href="#number">Number</a>
 138.166 + *         <td><code>0</code>
 138.167 + *     <tr bgcolor="#eeeeff">
 138.168 + *         <td><code>k</code>
 138.169 + *         <td>Hour in day (1-24)
 138.170 + *         <td><a href="#number">Number</a>
 138.171 + *         <td><code>24</code>
 138.172 + *     <tr>
 138.173 + *         <td><code>K</code>
 138.174 + *         <td>Hour in am/pm (0-11)
 138.175 + *         <td><a href="#number">Number</a>
 138.176 + *         <td><code>0</code>
 138.177 + *     <tr bgcolor="#eeeeff">
 138.178 + *         <td><code>h</code>
 138.179 + *         <td>Hour in am/pm (1-12)
 138.180 + *         <td><a href="#number">Number</a>
 138.181 + *         <td><code>12</code>
 138.182 + *     <tr>
 138.183 + *         <td><code>m</code>
 138.184 + *         <td>Minute in hour
 138.185 + *         <td><a href="#number">Number</a>
 138.186 + *         <td><code>30</code>
 138.187 + *     <tr bgcolor="#eeeeff">
 138.188 + *         <td><code>s</code>
 138.189 + *         <td>Second in minute
 138.190 + *         <td><a href="#number">Number</a>
 138.191 + *         <td><code>55</code>
 138.192 + *     <tr>
 138.193 + *         <td><code>S</code>
 138.194 + *         <td>Millisecond
 138.195 + *         <td><a href="#number">Number</a>
 138.196 + *         <td><code>978</code>
 138.197 + *     <tr bgcolor="#eeeeff">
 138.198 + *         <td><code>z</code>
 138.199 + *         <td>Time zone
 138.200 + *         <td><a href="#timezone">General time zone</a>
 138.201 + *         <td><code>Pacific Standard Time</code>; <code>PST</code>; <code>GMT-08:00</code>
 138.202 + *     <tr>
 138.203 + *         <td><code>Z</code>
 138.204 + *         <td>Time zone
 138.205 + *         <td><a href="#rfc822timezone">RFC 822 time zone</a>
 138.206 + *         <td><code>-0800</code>
 138.207 + *     <tr bgcolor="#eeeeff">
 138.208 + *         <td><code>X</code>
 138.209 + *         <td>Time zone
 138.210 + *         <td><a href="#iso8601timezone">ISO 8601 time zone</a>
 138.211 + *         <td><code>-08</code>; <code>-0800</code>;  <code>-08:00</code>
 138.212 + * </table>
 138.213 + * </blockquote>
 138.214 + * Pattern letters are usually repeated, as their number determines the
 138.215 + * exact presentation:
 138.216 + * <ul>
 138.217 + * <li><strong><a name="text">Text:</a></strong>
 138.218 + *     For formatting, if the number of pattern letters is 4 or more,
 138.219 + *     the full form is used; otherwise a short or abbreviated form
 138.220 + *     is used if available.
 138.221 + *     For parsing, both forms are accepted, independent of the number
 138.222 + *     of pattern letters.<br><br></li>
 138.223 + * <li><strong><a name="number">Number:</a></strong>
 138.224 + *     For formatting, the number of pattern letters is the minimum
 138.225 + *     number of digits, and shorter numbers are zero-padded to this amount.
 138.226 + *     For parsing, the number of pattern letters is ignored unless
 138.227 + *     it's needed to separate two adjacent fields.<br><br></li>
 138.228 + * <li><strong><a name="year">Year:</a></strong>
 138.229 + *     If the formatter's {@link #getCalendar() Calendar} is the Gregorian
 138.230 + *     calendar, the following rules are applied.<br>
 138.231 + *     <ul>
 138.232 + *     <li>For formatting, if the number of pattern letters is 2, the year
 138.233 + *         is truncated to 2 digits; otherwise it is interpreted as a
 138.234 + *         <a href="#number">number</a>.
 138.235 + *     <li>For parsing, if the number of pattern letters is more than 2,
 138.236 + *         the year is interpreted literally, regardless of the number of
 138.237 + *         digits. So using the pattern "MM/dd/yyyy", "01/11/12" parses to
 138.238 + *         Jan 11, 12 A.D.
 138.239 + *     <li>For parsing with the abbreviated year pattern ("y" or "yy"),
 138.240 + *         <code>SimpleDateFormat</code> must interpret the abbreviated year
 138.241 + *         relative to some century.  It does this by adjusting dates to be
 138.242 + *         within 80 years before and 20 years after the time the <code>SimpleDateFormat</code>
 138.243 + *         instance is created. For example, using a pattern of "MM/dd/yy" and a
 138.244 + *         <code>SimpleDateFormat</code> instance created on Jan 1, 1997,  the string
 138.245 + *         "01/11/12" would be interpreted as Jan 11, 2012 while the string "05/04/64"
 138.246 + *         would be interpreted as May 4, 1964.
 138.247 + *         During parsing, only strings consisting of exactly two digits, as defined by
 138.248 + *         {@link Character#isDigit(char)}, will be parsed into the default century.
 138.249 + *         Any other numeric string, such as a one digit string, a three or more digit
 138.250 + *         string, or a two digit string that isn't all digits (for example, "-1"), is
 138.251 + *         interpreted literally.  So "01/02/3" or "01/02/003" are parsed, using the
 138.252 + *         same pattern, as Jan 2, 3 AD.  Likewise, "01/02/-3" is parsed as Jan 2, 4 BC.
 138.253 + *     </ul>
 138.254 + *     Otherwise, calendar system specific forms are applied.
 138.255 + *     For both formatting and parsing, if the number of pattern
 138.256 + *     letters is 4 or more, a calendar specific {@linkplain
 138.257 + *     Calendar#LONG long form} is used. Otherwise, a calendar
 138.258 + *     specific {@linkplain Calendar#SHORT short or abbreviated form}
 138.259 + *     is used.<br>
 138.260 + *     <br>
 138.261 + *     If week year {@code 'Y'} is specified and the {@linkplain
 138.262 + *     #getCalendar() calendar} doesn't support any <a
 138.263 + *     href="../util/GregorianCalendar.html#week_year"> week
 138.264 + *     years</a>, the calendar year ({@code 'y'}) is used instead. The
 138.265 + *     support of week years can be tested with a call to {@link
 138.266 + *     DateFormat#getCalendar() getCalendar()}.{@link
 138.267 + *     java.util.Calendar#isWeekDateSupported()
 138.268 + *     isWeekDateSupported()}.<br><br></li>
 138.269 + * <li><strong><a name="month">Month:</a></strong>
 138.270 + *     If the number of pattern letters is 3 or more, the month is
 138.271 + *     interpreted as <a href="#text">text</a>; otherwise,
 138.272 + *     it is interpreted as a <a href="#number">number</a>.<br><br></li>
 138.273 + * <li><strong><a name="timezone">General time zone:</a></strong>
 138.274 + *     Time zones are interpreted as <a href="#text">text</a> if they have
 138.275 + *     names. For time zones representing a GMT offset value, the
 138.276 + *     following syntax is used:
 138.277 + *     <pre>
 138.278 + *     <a name="GMTOffsetTimeZone"><i>GMTOffsetTimeZone:</i></a>
 138.279 + *             <code>GMT</code> <i>Sign</i> <i>Hours</i> <code>:</code> <i>Minutes</i>
 138.280 + *     <i>Sign:</i> one of
 138.281 + *             <code>+ -</code>
 138.282 + *     <i>Hours:</i>
 138.283 + *             <i>Digit</i>
 138.284 + *             <i>Digit</i> <i>Digit</i>
 138.285 + *     <i>Minutes:</i>
 138.286 + *             <i>Digit</i> <i>Digit</i>
 138.287 + *     <i>Digit:</i> one of
 138.288 + *             <code>0 1 2 3 4 5 6 7 8 9</code></pre>
 138.289 + *     <i>Hours</i> must be between 0 and 23, and <i>Minutes</i> must be between
 138.290 + *     00 and 59. The format is locale independent and digits must be taken
 138.291 + *     from the Basic Latin block of the Unicode standard.
 138.292 + *     <p>For parsing, <a href="#rfc822timezone">RFC 822 time zones</a> are also
 138.293 + *     accepted.<br><br></li>
 138.294 + * <li><strong><a name="rfc822timezone">RFC 822 time zone:</a></strong>
 138.295 + *     For formatting, the RFC 822 4-digit time zone format is used:
 138.296 + *
 138.297 + *     <pre>
 138.298 + *     <i>RFC822TimeZone:</i>
 138.299 + *             <i>Sign</i> <i>TwoDigitHours</i> <i>Minutes</i>
 138.300 + *     <i>TwoDigitHours:</i>
 138.301 + *             <i>Digit Digit</i></pre>
 138.302 + *     <i>TwoDigitHours</i> must be between 00 and 23. Other definitions
 138.303 + *     are as for <a href="#timezone">general time zones</a>.
 138.304 + *
 138.305 + *     <p>For parsing, <a href="#timezone">general time zones</a> are also
 138.306 + *     accepted.
 138.307 + * <li><strong><a name="iso8601timezone">ISO 8601 Time zone:</a></strong>
 138.308 + *     The number of pattern letters designates the format for both formatting
 138.309 + *     and parsing as follows:
 138.310 + *     <pre>
 138.311 + *     <i>ISO8601TimeZone:</i>
 138.312 + *             <i>OneLetterISO8601TimeZone</i>
 138.313 + *             <i>TwoLetterISO8601TimeZone</i>
 138.314 + *             <i>ThreeLetterISO8601TimeZone</i>
 138.315 + *     <i>OneLetterISO8601TimeZone:</i>
 138.316 + *             <i>Sign</i> <i>TwoDigitHours</i>
 138.317 + *             {@code Z}
 138.318 + *     <i>TwoLetterISO8601TimeZone:</i>
 138.319 + *             <i>Sign</i> <i>TwoDigitHours</i> <i>Minutes</i>
 138.320 + *             {@code Z}
 138.321 + *     <i>ThreeLetterISO8601TimeZone:</i>
 138.322 + *             <i>Sign</i> <i>TwoDigitHours</i> {@code :} <i>Minutes</i>
 138.323 + *             {@code Z}</pre>
 138.324 + *     Other definitions are as for <a href="#timezone">general time zones</a> or
 138.325 + *     <a href="#rfc822timezone">RFC 822 time zones</a>.
 138.326 + *
 138.327 + *     <p>For formatting, if the offset value from GMT is 0, {@code "Z"} is
 138.328 + *     produced. If the number of pattern letters is 1, any fraction of an hour
 138.329 + *     is ignored. For example, if the pattern is {@code "X"} and the time zone is
 138.330 + *     {@code "GMT+05:30"}, {@code "+05"} is produced.
 138.331 + *
 138.332 + *     <p>For parsing, {@code "Z"} is parsed as the UTC time zone designator.
 138.333 + *     <a href="#timezone">General time zones</a> are <em>not</em> accepted.
 138.334 + *
 138.335 + *     <p>If the number of pattern letters is 4 or more, {@link
 138.336 + *     IllegalArgumentException} is thrown when constructing a {@code
 138.337 + *     SimpleDateFormat} or {@linkplain #applyPattern(String) applying a
 138.338 + *     pattern}.
 138.339 + * </ul>
 138.340 + * <code>SimpleDateFormat</code> also supports <em>localized date and time
 138.341 + * pattern</em> strings. In these strings, the pattern letters described above
 138.342 + * may be replaced with other, locale dependent, pattern letters.
 138.343 + * <code>SimpleDateFormat</code> does not deal with the localization of text
 138.344 + * other than the pattern letters; that's up to the client of the class.
 138.345 + * <p>
 138.346 + *
 138.347 + * <h4>Examples</h4>
 138.348 + *
 138.349 + * The following examples show how date and time patterns are interpreted in
 138.350 + * the U.S. locale. The given date and time are 2001-07-04 12:08:56 local time
 138.351 + * in the U.S. Pacific Time time zone.
 138.352 + * <blockquote>
 138.353 + * <table border=0 cellspacing=3 cellpadding=0 summary="Examples of date and time patterns interpreted in the U.S. locale">
 138.354 + *     <tr bgcolor="#ccccff">
 138.355 + *         <th align=left>Date and Time Pattern
 138.356 + *         <th align=left>Result
 138.357 + *     <tr>
 138.358 + *         <td><code>"yyyy.MM.dd G 'at' HH:mm:ss z"</code>
 138.359 + *         <td><code>2001.07.04 AD at 12:08:56 PDT</code>
 138.360 + *     <tr bgcolor="#eeeeff">
 138.361 + *         <td><code>"EEE, MMM d, ''yy"</code>
 138.362 + *         <td><code>Wed, Jul 4, '01</code>
 138.363 + *     <tr>
 138.364 + *         <td><code>"h:mm a"</code>
 138.365 + *         <td><code>12:08 PM</code>
 138.366 + *     <tr bgcolor="#eeeeff">
 138.367 + *         <td><code>"hh 'o''clock' a, zzzz"</code>
 138.368 + *         <td><code>12 o'clock PM, Pacific Daylight Time</code>
 138.369 + *     <tr>
 138.370 + *         <td><code>"K:mm a, z"</code>
 138.371 + *         <td><code>0:08 PM, PDT</code>
 138.372 + *     <tr bgcolor="#eeeeff">
 138.373 + *         <td><code>"yyyyy.MMMMM.dd GGG hh:mm aaa"</code>
 138.374 + *         <td><code>02001.July.04 AD 12:08 PM</code>
 138.375 + *     <tr>
 138.376 + *         <td><code>"EEE, d MMM yyyy HH:mm:ss Z"</code>
 138.377 + *         <td><code>Wed, 4 Jul 2001 12:08:56 -0700</code>
 138.378 + *     <tr bgcolor="#eeeeff">
 138.379 + *         <td><code>"yyMMddHHmmssZ"</code>
 138.380 + *         <td><code>010704120856-0700</code>
 138.381 + *     <tr>
 138.382 + *         <td><code>"yyyy-MM-dd'T'HH:mm:ss.SSSZ"</code>
 138.383 + *         <td><code>2001-07-04T12:08:56.235-0700</code>
 138.384 + *     <tr bgcolor="#eeeeff">
 138.385 + *         <td><code>"yyyy-MM-dd'T'HH:mm:ss.SSSXXX"</code>
 138.386 + *         <td><code>2001-07-04T12:08:56.235-07:00</code>
 138.387 + *     <tr>
 138.388 + *         <td><code>"YYYY-'W'ww-u"</code>
 138.389 + *         <td><code>2001-W27-3</code>
 138.390 + * </table>
 138.391 + * </blockquote>
 138.392 + *
 138.393 + * <h4><a name="synchronization">Synchronization</a></h4>
 138.394 + *
 138.395 + * <p>
 138.396 + * Date formats are not synchronized.
 138.397 + * It is recommended to create separate format instances for each thread.
 138.398 + * If multiple threads access a format concurrently, it must be synchronized
 138.399 + * externally.
 138.400 + *
 138.401 + * @see          <a href="http://java.sun.com/docs/books/tutorial/i18n/format/simpleDateFormat.html">Java Tutorial</a>
 138.402 + * @see          java.util.Calendar
 138.403 + * @see          java.util.TimeZone
 138.404 + * @see          DateFormat
 138.405 + * @see          DateFormatSymbols
 138.406 + * @author       Mark Davis, Chen-Lieh Huang, Alan Liu
 138.407 + */
 138.408 +public class SimpleDateFormat extends DateFormat {
 138.409 +
 138.410 +    // the official serial version ID which says cryptically
 138.411 +    // which version we're compatible with
 138.412 +    static final long serialVersionUID = 4774881970558875024L;
 138.413 +
 138.414 +    // the internal serial version which says which version was written
 138.415 +    // - 0 (default) for version up to JDK 1.1.3
 138.416 +    // - 1 for version from JDK 1.1.4, which includes a new field
 138.417 +    static final int currentSerialVersion = 1;
 138.418 +
 138.419 +    /**
 138.420 +     * The version of the serialized data on the stream.  Possible values:
 138.421 +     * <ul>
 138.422 +     * <li><b>0</b> or not present on stream: JDK 1.1.3.  This version
 138.423 +     * has no <code>defaultCenturyStart</code> on stream.
 138.424 +     * <li><b>1</b> JDK 1.1.4 or later.  This version adds
 138.425 +     * <code>defaultCenturyStart</code>.
 138.426 +     * </ul>
 138.427 +     * When streaming out this class, the most recent format
 138.428 +     * and the highest allowable <code>serialVersionOnStream</code>
 138.429 +     * is written.
 138.430 +     * @serial
 138.431 +     * @since JDK1.1.4
 138.432 +     */
 138.433 +    private int serialVersionOnStream = currentSerialVersion;
 138.434 +
 138.435 +    /**
 138.436 +     * The pattern string of this formatter.  This is always a non-localized
 138.437 +     * pattern.  May not be null.  See class documentation for details.
 138.438 +     * @serial
 138.439 +     */
 138.440 +    private String pattern;
 138.441 +
 138.442 +    /**
 138.443 +     * Saved numberFormat and pattern.
 138.444 +     * @see SimpleDateFormat#checkNegativeNumberExpression
 138.445 +     */
 138.446 +    transient private NumberFormat originalNumberFormat;
 138.447 +    transient private String originalNumberPattern;
 138.448 +
 138.449 +    /**
 138.450 +     * The minus sign to be used with format and parse.
 138.451 +     */
 138.452 +    transient private char minusSign = '-';
 138.453 +
 138.454 +    /**
 138.455 +     * True when a negative sign follows a number.
 138.456 +     * (True as default in Arabic.)
 138.457 +     */
 138.458 +    transient private boolean hasFollowingMinusSign = false;
 138.459 +
 138.460 +    /**
 138.461 +     * The compiled pattern.
 138.462 +     */
 138.463 +    transient private char[] compiledPattern;
 138.464 +
 138.465 +    /**
 138.466 +     * Tags for the compiled pattern.
 138.467 +     */
 138.468 +    private final static int TAG_QUOTE_ASCII_CHAR       = 100;
 138.469 +    private final static int TAG_QUOTE_CHARS            = 101;
 138.470 +
 138.471 +    /**
 138.472 +     * Locale dependent digit zero.
 138.473 +     * @see #zeroPaddingNumber
 138.474 +     * @see java.text.DecimalFormatSymbols#getZeroDigit
 138.475 +     */
 138.476 +    transient private char zeroDigit;
 138.477 +
 138.478 +    /**
 138.479 +     * The symbols used by this formatter for week names, month names,
 138.480 +     * etc.  May not be null.
 138.481 +     * @serial
 138.482 +     * @see java.text.DateFormatSymbols
 138.483 +     */
 138.484 +    private DateFormatSymbols formatData;
 138.485 +
 138.486 +    /**
 138.487 +     * We map dates with two-digit years into the century starting at
 138.488 +     * <code>defaultCenturyStart</code>, which may be any date.  May
 138.489 +     * not be null.
 138.490 +     * @serial
 138.491 +     * @since JDK1.1.4
 138.492 +     */
 138.493 +    private Date defaultCenturyStart;
 138.494 +
 138.495 +    transient private int defaultCenturyStartYear;
 138.496 +
 138.497 +    private static final int MILLIS_PER_MINUTE = 60 * 1000;
 138.498 +
 138.499 +    // For time zones that have no names, use strings GMT+minutes and
 138.500 +    // GMT-minutes. For instance, in France the time zone is GMT+60.
 138.501 +    private static final String GMT = "GMT";
 138.502 +
 138.503 +    /**
 138.504 +     * Cache to hold the DateTimePatterns of a Locale.
 138.505 +     */
 138.506 +    private static final ConcurrentMap<Locale, String[]> cachedLocaleData
 138.507 +        = new ConcurrentHashMap<Locale, String[]>(3);
 138.508 +
 138.509 +    /**
 138.510 +     * Cache NumberFormat instances with Locale key.
 138.511 +     */
 138.512 +    private static final ConcurrentMap<Locale, NumberFormat> cachedNumberFormatData
 138.513 +        = new ConcurrentHashMap<Locale, NumberFormat>(3);
 138.514 +
 138.515 +    /**
 138.516 +     * The Locale used to instantiate this
 138.517 +     * <code>SimpleDateFormat</code>. The value may be null if this object
 138.518 +     * has been created by an older <code>SimpleDateFormat</code> and
 138.519 +     * deserialized.
 138.520 +     *
 138.521 +     * @serial
 138.522 +     * @since 1.6
 138.523 +     */
 138.524 +    private Locale locale;
 138.525 +
 138.526 +    /**
 138.527 +     * Indicates whether this <code>SimpleDateFormat</code> should use
 138.528 +     * the DateFormatSymbols. If true, the format and parse methods
 138.529 +     * use the DateFormatSymbols values. If false, the format and
 138.530 +     * parse methods call Calendar.getDisplayName or
 138.531 +     * Calendar.getDisplayNames.
 138.532 +     */
 138.533 +    transient boolean useDateFormatSymbols;
 138.534 +
 138.535 +    /**
 138.536 +     * Constructs a <code>SimpleDateFormat</code> using the default pattern and
 138.537 +     * date format symbols for the default locale.
 138.538 +     * <b>Note:</b> This constructor may not support all locales.
 138.539 +     * For full coverage, use the factory methods in the {@link DateFormat}
 138.540 +     * class.
 138.541 +     */
 138.542 +    public SimpleDateFormat() {
 138.543 +        this(SHORT, SHORT, Locale.getDefault(Locale.Category.FORMAT));
 138.544 +    }
 138.545 +
 138.546 +    /**
 138.547 +     * Constructs a <code>SimpleDateFormat</code> using the given pattern and
 138.548 +     * the default date format symbols for the default locale.
 138.549 +     * <b>Note:</b> This constructor may not support all locales.
 138.550 +     * For full coverage, use the factory methods in the {@link DateFormat}
 138.551 +     * class.
 138.552 +     *
 138.553 +     * @param pattern the pattern describing the date and time format
 138.554 +     * @exception NullPointerException if the given pattern is null
 138.555 +     * @exception IllegalArgumentException if the given pattern is invalid
 138.556 +     */
 138.557 +    public SimpleDateFormat(String pattern)
 138.558 +    {
 138.559 +        this(pattern, Locale.getDefault(Locale.Category.FORMAT));
 138.560 +    }
 138.561 +
 138.562 +    /**
 138.563 +     * Constructs a <code>SimpleDateFormat</code> using the given pattern and
 138.564 +     * the default date format symbols for the given locale.
 138.565 +     * <b>Note:</b> This constructor may not support all locales.
 138.566 +     * For full coverage, use the factory methods in the {@link DateFormat}
 138.567 +     * class.
 138.568 +     *
 138.569 +     * @param pattern the pattern describing the date and time format
 138.570 +     * @param locale the locale whose date format symbols should be used
 138.571 +     * @exception NullPointerException if the given pattern or locale is null
 138.572 +     * @exception IllegalArgumentException if the given pattern is invalid
 138.573 +     */
 138.574 +    public SimpleDateFormat(String pattern, Locale locale)
 138.575 +    {
 138.576 +        if (pattern == null || locale == null) {
 138.577 +            throw new NullPointerException();
 138.578 +        }
 138.579 +
 138.580 +        initializeCalendar(locale);
 138.581 +        this.pattern = pattern;
 138.582 +        this.formatData = DateFormatSymbols.getInstanceRef(locale);
 138.583 +        this.locale = locale;
 138.584 +        initialize(locale);
 138.585 +    }
 138.586 +
 138.587 +    /**
 138.588 +     * Constructs a <code>SimpleDateFormat</code> using the given pattern and
 138.589 +     * date format symbols.
 138.590 +     *
 138.591 +     * @param pattern the pattern describing the date and time format
 138.592 +     * @param formatSymbols the date format symbols to be used for formatting
 138.593 +     * @exception NullPointerException if the given pattern or formatSymbols is null
 138.594 +     * @exception IllegalArgumentException if the given pattern is invalid
 138.595 +     */
 138.596 +    public SimpleDateFormat(String pattern, DateFormatSymbols formatSymbols)
 138.597 +    {
 138.598 +        if (pattern == null || formatSymbols == null) {
 138.599 +            throw new NullPointerException();
 138.600 +        }
 138.601 +
 138.602 +        this.pattern = pattern;
 138.603 +        this.formatData = (DateFormatSymbols) formatSymbols.clone();
 138.604 +        this.locale = Locale.getDefault(Locale.Category.FORMAT);
 138.605 +        initializeCalendar(this.locale);
 138.606 +        initialize(this.locale);
 138.607 +        useDateFormatSymbols = true;
 138.608 +    }
 138.609 +
 138.610 +    /* Package-private, called by DateFormat factory methods */
 138.611 +    SimpleDateFormat(int timeStyle, int dateStyle, Locale loc) {
 138.612 +        if (loc == null) {
 138.613 +            throw new NullPointerException();
 138.614 +        }
 138.615 +
 138.616 +        this.locale = loc;
 138.617 +        // initialize calendar and related fields
 138.618 +        initializeCalendar(loc);
 138.619 +
 138.620 +        /* try the cache first */
 138.621 +        String[] dateTimePatterns = cachedLocaleData.get(loc);
 138.622 +        if (dateTimePatterns == null) { /* cache miss */
 138.623 +            ResourceBundle r = null; // LocaleData.getDateFormatData(loc);
 138.624 +            if (!isGregorianCalendar()) {
 138.625 +                try {
 138.626 +                    dateTimePatterns = r.getStringArray(getCalendarName() + ".DateTimePatterns");
 138.627 +                } catch (MissingResourceException e) {
 138.628 +                }
 138.629 +            }
 138.630 +            if (dateTimePatterns == null) {
 138.631 +                dateTimePatterns = r.getStringArray("DateTimePatterns");
 138.632 +            }
 138.633 +            /* update cache */
 138.634 +            cachedLocaleData.putIfAbsent(loc, dateTimePatterns);
 138.635 +        }
 138.636 +        formatData = DateFormatSymbols.getInstanceRef(loc);
 138.637 +        if ((timeStyle >= 0) && (dateStyle >= 0)) {
 138.638 +            Object[] dateTimeArgs = {dateTimePatterns[timeStyle],
 138.639 +                                     dateTimePatterns[dateStyle + 4]};
 138.640 +            pattern = MessageFormat.format(dateTimePatterns[8], dateTimeArgs);
 138.641 +        }
 138.642 +        else if (timeStyle >= 0) {
 138.643 +            pattern = dateTimePatterns[timeStyle];
 138.644 +        }
 138.645 +        else if (dateStyle >= 0) {
 138.646 +            pattern = dateTimePatterns[dateStyle + 4];
 138.647 +        }
 138.648 +        else {
 138.649 +            throw new IllegalArgumentException("No date or time style specified");
 138.650 +        }
 138.651 +
 138.652 +        initialize(loc);
 138.653 +    }
 138.654 +
 138.655 +    /* Initialize compiledPattern and numberFormat fields */
 138.656 +    private void initialize(Locale loc) {
 138.657 +        // Verify and compile the given pattern.
 138.658 +        compiledPattern = compile(pattern);
 138.659 +
 138.660 +        /* try the cache first */
 138.661 +        numberFormat = cachedNumberFormatData.get(loc);
 138.662 +        if (numberFormat == null) { /* cache miss */
 138.663 +            numberFormat = NumberFormat.getIntegerInstance(loc);
 138.664 +            numberFormat.setGroupingUsed(false);
 138.665 +
 138.666 +            /* update cache */
 138.667 +            cachedNumberFormatData.putIfAbsent(loc, numberFormat);
 138.668 +        }
 138.669 +        numberFormat = (NumberFormat) numberFormat.clone();
 138.670 +
 138.671 +        initializeDefaultCentury();
 138.672 +    }
 138.673 +
 138.674 +    private void initializeCalendar(Locale loc) {
 138.675 +        if (calendar == null) {
 138.676 +            assert loc != null;
 138.677 +            // The format object must be constructed using the symbols for this zone.
 138.678 +            // However, the calendar should use the current default TimeZone.
 138.679 +            // If this is not contained in the locale zone strings, then the zone
 138.680 +            // will be formatted using generic GMT+/-H:MM nomenclature.
 138.681 +            calendar = Calendar.getInstance(TimeZone.getDefault(), loc);
 138.682 +        }
 138.683 +    }
 138.684 +
 138.685 +    /**
 138.686 +     * Returns the compiled form of the given pattern. The syntax of
 138.687 +     * the compiled pattern is:
 138.688 +     * <blockquote>
 138.689 +     * CompiledPattern:
 138.690 +     *     EntryList
 138.691 +     * EntryList:
 138.692 +     *     Entry
 138.693 +     *     EntryList Entry
 138.694 +     * Entry:
 138.695 +     *     TagField
 138.696 +     *     TagField data
 138.697 +     * TagField:
 138.698 +     *     Tag Length
 138.699 +     *     TaggedData
 138.700 +     * Tag:
 138.701 +     *     pattern_char_index
 138.702 +     *     TAG_QUOTE_CHARS
 138.703 +     * Length:
 138.704 +     *     short_length
 138.705 +     *     long_length
 138.706 +     * TaggedData:
 138.707 +     *     TAG_QUOTE_ASCII_CHAR ascii_char
 138.708 +     *
 138.709 +     * </blockquote>
 138.710 +     *
 138.711 +     * where `short_length' is an 8-bit unsigned integer between 0 and
 138.712 +     * 254.  `long_length' is a sequence of an 8-bit integer 255 and a
 138.713 +     * 32-bit signed integer value which is split into upper and lower
 138.714 +     * 16-bit fields in two char's. `pattern_char_index' is an 8-bit
 138.715 +     * integer between 0 and 18. `ascii_char' is an 7-bit ASCII
 138.716 +     * character value. `data' depends on its Tag value.
 138.717 +     * <p>
 138.718 +     * If Length is short_length, Tag and short_length are packed in a
 138.719 +     * single char, as illustrated below.
 138.720 +     * <blockquote>
 138.721 +     *     char[0] = (Tag << 8) | short_length;
 138.722 +     * </blockquote>
 138.723 +     *
 138.724 +     * If Length is long_length, Tag and 255 are packed in the first
 138.725 +     * char and a 32-bit integer, as illustrated below.
 138.726 +     * <blockquote>
 138.727 +     *     char[0] = (Tag << 8) | 255;
 138.728 +     *     char[1] = (char) (long_length >>> 16);
 138.729 +     *     char[2] = (char) (long_length & 0xffff);
 138.730 +     * </blockquote>
 138.731 +     * <p>
 138.732 +     * If Tag is a pattern_char_index, its Length is the number of
 138.733 +     * pattern characters. For example, if the given pattern is
 138.734 +     * "yyyy", Tag is 1 and Length is 4, followed by no data.
 138.735 +     * <p>
 138.736 +     * If Tag is TAG_QUOTE_CHARS, its Length is the number of char's
 138.737 +     * following the TagField. For example, if the given pattern is
 138.738 +     * "'o''clock'", Length is 7 followed by a char sequence of
 138.739 +     * <code>o&nbs;'&nbs;c&nbs;l&nbs;o&nbs;c&nbs;k</code>.
 138.740 +     * <p>
 138.741 +     * TAG_QUOTE_ASCII_CHAR is a special tag and has an ASCII
 138.742 +     * character in place of Length. For example, if the given pattern
 138.743 +     * is "'o'", the TaggedData entry is
 138.744 +     * <code>((TAG_QUOTE_ASCII_CHAR&nbs;<<&nbs;8)&nbs;|&nbs;'o')</code>.
 138.745 +     *
 138.746 +     * @exception NullPointerException if the given pattern is null
 138.747 +     * @exception IllegalArgumentException if the given pattern is invalid
 138.748 +     */
 138.749 +    private char[] compile(String pattern) {
 138.750 +        int length = pattern.length();
 138.751 +        boolean inQuote = false;
 138.752 +        StringBuilder compiledPattern = new StringBuilder(length * 2);
 138.753 +        StringBuilder tmpBuffer = null;
 138.754 +        int count = 0;
 138.755 +        int lastTag = -1;
 138.756 +
 138.757 +        for (int i = 0; i < length; i++) {
 138.758 +            char c = pattern.charAt(i);
 138.759 +
 138.760 +            if (c == '\'') {
 138.761 +                // '' is treated as a single quote regardless of being
 138.762 +                // in a quoted section.
 138.763 +                if ((i + 1) < length) {
 138.764 +                    c = pattern.charAt(i + 1);
 138.765 +                    if (c == '\'') {
 138.766 +                        i++;
 138.767 +                        if (count != 0) {
 138.768 +                            encode(lastTag, count, compiledPattern);
 138.769 +                            lastTag = -1;
 138.770 +                            count = 0;
 138.771 +                        }
 138.772 +                        if (inQuote) {
 138.773 +                            tmpBuffer.append(c);
 138.774 +                        } else {
 138.775 +                            compiledPattern.append((char)(TAG_QUOTE_ASCII_CHAR << 8 | c));
 138.776 +                        }
 138.777 +                        continue;
 138.778 +                    }
 138.779 +                }
 138.780 +                if (!inQuote) {
 138.781 +                    if (count != 0) {
 138.782 +                        encode(lastTag, count, compiledPattern);
 138.783 +                        lastTag = -1;
 138.784 +                        count = 0;
 138.785 +                    }
 138.786 +                    if (tmpBuffer == null) {
 138.787 +                        tmpBuffer = new StringBuilder(length);
 138.788 +                    } else {
 138.789 +                        tmpBuffer.setLength(0);
 138.790 +                    }
 138.791 +                    inQuote = true;
 138.792 +                } else {
 138.793 +                    int len = tmpBuffer.length();
 138.794 +                    if (len == 1) {
 138.795 +                        char ch = tmpBuffer.charAt(0);
 138.796 +                        if (ch < 128) {
 138.797 +                            compiledPattern.append((char)(TAG_QUOTE_ASCII_CHAR << 8 | ch));
 138.798 +                        } else {
 138.799 +                            compiledPattern.append((char)(TAG_QUOTE_CHARS << 8 | 1));
 138.800 +                            compiledPattern.append(ch);
 138.801 +                        }
 138.802 +                    } else {
 138.803 +                        encode(TAG_QUOTE_CHARS, len, compiledPattern);
 138.804 +                        compiledPattern.append(tmpBuffer);
 138.805 +                    }
 138.806 +                    inQuote = false;
 138.807 +                }
 138.808 +                continue;
 138.809 +            }
 138.810 +            if (inQuote) {
 138.811 +                tmpBuffer.append(c);
 138.812 +                continue;
 138.813 +            }
 138.814 +            if (!(c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z')) {
 138.815 +                if (count != 0) {
 138.816 +                    encode(lastTag, count, compiledPattern);
 138.817 +                    lastTag = -1;
 138.818 +                    count = 0;
 138.819 +                }
 138.820 +                if (c < 128) {
 138.821 +                    // In most cases, c would be a delimiter, such as ':'.
 138.822 +                    compiledPattern.append((char)(TAG_QUOTE_ASCII_CHAR << 8 | c));
 138.823 +                } else {
 138.824 +                    // Take any contiguous non-ASCII alphabet characters and
 138.825 +                    // put them in a single TAG_QUOTE_CHARS.
 138.826 +                    int j;
 138.827 +                    for (j = i + 1; j < length; j++) {
 138.828 +                        char d = pattern.charAt(j);
 138.829 +                        if (d == '\'' || (d >= 'a' && d <= 'z' || d >= 'A' && d <= 'Z')) {
 138.830 +                            break;
 138.831 +                        }
 138.832 +                    }
 138.833 +                    compiledPattern.append((char)(TAG_QUOTE_CHARS << 8 | (j - i)));
 138.834 +                    for (; i < j; i++) {
 138.835 +                        compiledPattern.append(pattern.charAt(i));
 138.836 +                    }
 138.837 +                    i--;
 138.838 +                }
 138.839 +                continue;
 138.840 +            }
 138.841 +
 138.842 +            int tag;
 138.843 +            if ((tag = DateFormatSymbols.patternChars.indexOf(c)) == -1) {
 138.844 +                throw new IllegalArgumentException("Illegal pattern character " +
 138.845 +                                                   "'" + c + "'");
 138.846 +            }
 138.847 +            if (lastTag == -1 || lastTag == tag) {
 138.848 +                lastTag = tag;
 138.849 +                count++;
 138.850 +                continue;
 138.851 +            }
 138.852 +            encode(lastTag, count, compiledPattern);
 138.853 +            lastTag = tag;
 138.854 +            count = 1;
 138.855 +        }
 138.856 +
 138.857 +        if (inQuote) {
 138.858 +            throw new IllegalArgumentException("Unterminated quote");
 138.859 +        }
 138.860 +
 138.861 +        if (count != 0) {
 138.862 +            encode(lastTag, count, compiledPattern);
 138.863 +        }
 138.864 +
 138.865 +        // Copy the compiled pattern to a char array
 138.866 +        int len = compiledPattern.length();
 138.867 +        char[] r = new char[len];
 138.868 +        compiledPattern.getChars(0, len, r, 0);
 138.869 +        return r;
 138.870 +    }
 138.871 +
 138.872 +    /**
 138.873 +     * Encodes the given tag and length and puts encoded char(s) into buffer.
 138.874 +     */
 138.875 +    private static final void encode(int tag, int length, StringBuilder buffer) {
 138.876 +        if (tag == PATTERN_ISO_ZONE && length >= 4) {
 138.877 +            throw new IllegalArgumentException("invalid ISO 8601 format: length=" + length);
 138.878 +        }
 138.879 +        if (length < 255) {
 138.880 +            buffer.append((char)(tag << 8 | length));
 138.881 +        } else {
 138.882 +            buffer.append((char)((tag << 8) | 0xff));
 138.883 +            buffer.append((char)(length >>> 16));
 138.884 +            buffer.append((char)(length & 0xffff));
 138.885 +        }
 138.886 +    }
 138.887 +
 138.888 +    /* Initialize the fields we use to disambiguate ambiguous years. Separate
 138.889 +     * so we can call it from readObject().
 138.890 +     */
 138.891 +    private void initializeDefaultCentury() {
 138.892 +        calendar.setTimeInMillis(System.currentTimeMillis());
 138.893 +        calendar.add( Calendar.YEAR, -80 );
 138.894 +        parseAmbiguousDatesAsAfter(calendar.getTime());
 138.895 +    }
 138.896 +
 138.897 +    /* Define one-century window into which to disambiguate dates using
 138.898 +     * two-digit years.
 138.899 +     */
 138.900 +    private void parseAmbiguousDatesAsAfter(Date startDate) {
 138.901 +        defaultCenturyStart = startDate;
 138.902 +        calendar.setTime(startDate);
 138.903 +        defaultCenturyStartYear = calendar.get(Calendar.YEAR);
 138.904 +    }
 138.905 +
 138.906 +    /**
 138.907 +     * Sets the 100-year period 2-digit years will be interpreted as being in
 138.908 +     * to begin on the date the user specifies.
 138.909 +     *
 138.910 +     * @param startDate During parsing, two digit years will be placed in the range
 138.911 +     * <code>startDate</code> to <code>startDate + 100 years</code>.
 138.912 +     * @see #get2DigitYearStart
 138.913 +     * @since 1.2
 138.914 +     */
 138.915 +    public void set2DigitYearStart(Date startDate) {
 138.916 +        parseAmbiguousDatesAsAfter(new Date(startDate.getTime()));
 138.917 +    }
 138.918 +
 138.919 +    /**
 138.920 +     * Returns the beginning date of the 100-year period 2-digit years are interpreted
 138.921 +     * as being within.
 138.922 +     *
 138.923 +     * @return the start of the 100-year period into which two digit years are
 138.924 +     * parsed
 138.925 +     * @see #set2DigitYearStart
 138.926 +     * @since 1.2
 138.927 +     */
 138.928 +    public Date get2DigitYearStart() {
 138.929 +        return (Date) defaultCenturyStart.clone();
 138.930 +    }
 138.931 +
 138.932 +    /**
 138.933 +     * Formats the given <code>Date</code> into a date/time string and appends
 138.934 +     * the result to the given <code>StringBuffer</code>.
 138.935 +     *
 138.936 +     * @param date the date-time value to be formatted into a date-time string.
 138.937 +     * @param toAppendTo where the new date-time text is to be appended.
 138.938 +     * @param pos the formatting position. On input: an alignment field,
 138.939 +     * if desired. On output: the offsets of the alignment field.
 138.940 +     * @return the formatted date-time string.
 138.941 +     * @exception NullPointerException if the given {@code date} is {@code null}.
 138.942 +     */
 138.943 +    public StringBuffer format(Date date, StringBuffer toAppendTo,
 138.944 +                               FieldPosition pos)
 138.945 +    {
 138.946 +        pos.beginIndex = pos.endIndex = 0;
 138.947 +        return format(date, toAppendTo, pos.getFieldDelegate());
 138.948 +    }
 138.949 +
 138.950 +    // Called from Format after creating a FieldDelegate
 138.951 +    private StringBuffer format(Date date, StringBuffer toAppendTo,
 138.952 +                                FieldDelegate delegate) {
 138.953 +        // Convert input date to time field list
 138.954 +        calendar.setTime(date);
 138.955 +
 138.956 +        boolean useDateFormatSymbols = useDateFormatSymbols();
 138.957 +
 138.958 +        for (int i = 0; i < compiledPattern.length; ) {
 138.959 +            int tag = compiledPattern[i] >>> 8;
 138.960 +            int count = compiledPattern[i++] & 0xff;
 138.961 +            if (count == 255) {
 138.962 +                count = compiledPattern[i++] << 16;
 138.963 +                count |= compiledPattern[i++];
 138.964 +            }
 138.965 +
 138.966 +            switch (tag) {
 138.967 +            case TAG_QUOTE_ASCII_CHAR:
 138.968 +                toAppendTo.append((char)count);
 138.969 +                break;
 138.970 +
 138.971 +            case TAG_QUOTE_CHARS:
 138.972 +                toAppendTo.append(compiledPattern, i, count);
 138.973 +                i += count;
 138.974 +                break;
 138.975 +
 138.976 +            default:
 138.977 +                subFormat(tag, count, delegate, toAppendTo, useDateFormatSymbols);
 138.978 +                break;
 138.979 +            }
 138.980 +        }
 138.981 +        return toAppendTo;
 138.982 +    }
 138.983 +
 138.984 +    /**
 138.985 +     * Formats an Object producing an <code>AttributedCharacterIterator</code>.
 138.986 +     * You can use the returned <code>AttributedCharacterIterator</code>
 138.987 +     * to build the resulting String, as well as to determine information
 138.988 +     * about the resulting String.
 138.989 +     * <p>
 138.990 +     * Each attribute key of the AttributedCharacterIterator will be of type
 138.991 +     * <code>DateFormat.Field</code>, with the corresponding attribute value
 138.992 +     * being the same as the attribute key.
 138.993 +     *
 138.994 +     * @exception NullPointerException if obj is null.
 138.995 +     * @exception IllegalArgumentException if the Format cannot format the
 138.996 +     *            given object, or if the Format's pattern string is invalid.
 138.997 +     * @param obj The object to format
 138.998 +     * @return AttributedCharacterIterator describing the formatted value.
 138.999 +     * @since 1.4
138.1000 +     */
138.1001 +    public AttributedCharacterIterator formatToCharacterIterator(Object obj) {
138.1002 +        StringBuffer sb = new StringBuffer();
138.1003 +        CharacterIteratorFieldDelegate delegate = new
138.1004 +                         CharacterIteratorFieldDelegate();
138.1005 +
138.1006 +        if (obj instanceof Date) {
138.1007 +            format((Date)obj, sb, delegate);
138.1008 +        }
138.1009 +        else if (obj instanceof Number) {
138.1010 +            format(new Date(((Number)obj).longValue()), sb, delegate);
138.1011 +        }
138.1012 +        else if (obj == null) {
138.1013 +            throw new NullPointerException(
138.1014 +                   "formatToCharacterIterator must be passed non-null object");
138.1015 +        }
138.1016 +        else {
138.1017 +            throw new IllegalArgumentException(
138.1018 +                             "Cannot format given Object as a Date");
138.1019 +        }
138.1020 +        return delegate.getIterator(sb.toString());
138.1021 +    }
138.1022 +
138.1023 +    // Map index into pattern character string to Calendar field number
138.1024 +    private static final int[] PATTERN_INDEX_TO_CALENDAR_FIELD =
138.1025 +    {
138.1026 +        Calendar.ERA, Calendar.YEAR, Calendar.MONTH, Calendar.DATE,
138.1027 +        Calendar.HOUR_OF_DAY, Calendar.HOUR_OF_DAY, Calendar.MINUTE,
138.1028 +        Calendar.SECOND, Calendar.MILLISECOND, Calendar.DAY_OF_WEEK,
138.1029 +        Calendar.DAY_OF_YEAR, Calendar.DAY_OF_WEEK_IN_MONTH,
138.1030 +        Calendar.WEEK_OF_YEAR, Calendar.WEEK_OF_MONTH,
138.1031 +        Calendar.AM_PM, Calendar.HOUR, Calendar.HOUR, Calendar.ZONE_OFFSET,
138.1032 +        Calendar.ZONE_OFFSET,
138.1033 +        // Pseudo Calendar fields
138.1034 +        CalendarBuilder.WEEK_YEAR,
138.1035 +        CalendarBuilder.ISO_DAY_OF_WEEK,
138.1036 +        Calendar.ZONE_OFFSET
138.1037 +    };
138.1038 +
138.1039 +    // Map index into pattern character string to DateFormat field number
138.1040 +    private static final int[] PATTERN_INDEX_TO_DATE_FORMAT_FIELD = {
138.1041 +        DateFormat.ERA_FIELD, DateFormat.YEAR_FIELD, DateFormat.MONTH_FIELD,
138.1042 +        DateFormat.DATE_FIELD, DateFormat.HOUR_OF_DAY1_FIELD,
138.1043 +        DateFormat.HOUR_OF_DAY0_FIELD, DateFormat.MINUTE_FIELD,
138.1044 +        DateFormat.SECOND_FIELD, DateFormat.MILLISECOND_FIELD,
138.1045 +        DateFormat.DAY_OF_WEEK_FIELD, DateFormat.DAY_OF_YEAR_FIELD,
138.1046 +        DateFormat.DAY_OF_WEEK_IN_MONTH_FIELD, DateFormat.WEEK_OF_YEAR_FIELD,
138.1047 +        DateFormat.WEEK_OF_MONTH_FIELD, DateFormat.AM_PM_FIELD,
138.1048 +        DateFormat.HOUR1_FIELD, DateFormat.HOUR0_FIELD,
138.1049 +        DateFormat.TIMEZONE_FIELD, DateFormat.TIMEZONE_FIELD,
138.1050 +        DateFormat.YEAR_FIELD, DateFormat.DAY_OF_WEEK_FIELD,
138.1051 +        DateFormat.TIMEZONE_FIELD
138.1052 +    };
138.1053 +
138.1054 +    // Maps from DecimalFormatSymbols index to Field constant
138.1055 +    private static final Field[] PATTERN_INDEX_TO_DATE_FORMAT_FIELD_ID = {
138.1056 +        Field.ERA, Field.YEAR, Field.MONTH, Field.DAY_OF_MONTH,
138.1057 +        Field.HOUR_OF_DAY1, Field.HOUR_OF_DAY0, Field.MINUTE,
138.1058 +        Field.SECOND, Field.MILLISECOND, Field.DAY_OF_WEEK,
138.1059 +        Field.DAY_OF_YEAR, Field.DAY_OF_WEEK_IN_MONTH,
138.1060 +        Field.WEEK_OF_YEAR, Field.WEEK_OF_MONTH,
138.1061 +        Field.AM_PM, Field.HOUR1, Field.HOUR0, Field.TIME_ZONE,
138.1062 +        Field.TIME_ZONE,
138.1063 +        Field.YEAR, Field.DAY_OF_WEEK,
138.1064 +        Field.TIME_ZONE
138.1065 +    };
138.1066 +
138.1067 +    /**
138.1068 +     * Private member function that does the real date/time formatting.
138.1069 +     */
138.1070 +    private void subFormat(int patternCharIndex, int count,
138.1071 +                           FieldDelegate delegate, StringBuffer buffer,
138.1072 +                           boolean useDateFormatSymbols)
138.1073 +    {
138.1074 +        int     maxIntCount = Integer.MAX_VALUE;
138.1075 +        String  current = null;
138.1076 +        int     beginOffset = buffer.length();
138.1077 +
138.1078 +        int field = PATTERN_INDEX_TO_CALENDAR_FIELD[patternCharIndex];
138.1079 +        int value;
138.1080 +        if (field == CalendarBuilder.WEEK_YEAR) {
138.1081 +            if (calendar.isWeekDateSupported()) {
138.1082 +                value = calendar.getWeekYear();
138.1083 +            } else {
138.1084 +                // use calendar year 'y' instead
138.1085 +                patternCharIndex = PATTERN_YEAR;
138.1086 +                field = PATTERN_INDEX_TO_CALENDAR_FIELD[patternCharIndex];
138.1087 +                value = calendar.get(field);
138.1088 +            }
138.1089 +        } else if (field == CalendarBuilder.ISO_DAY_OF_WEEK) {
138.1090 +            value = CalendarBuilder.toISODayOfWeek(calendar.get(Calendar.DAY_OF_WEEK));
138.1091 +        } else {
138.1092 +            value = calendar.get(field);
138.1093 +        }
138.1094 +
138.1095 +        int style = (count >= 4) ? Calendar.LONG : Calendar.SHORT;
138.1096 +        if (!useDateFormatSymbols && field != CalendarBuilder.ISO_DAY_OF_WEEK) {
138.1097 +            current = calendar.getDisplayName(field, style, locale);
138.1098 +        }
138.1099 +
138.1100 +        // Note: zeroPaddingNumber() assumes that maxDigits is either
138.1101 +        // 2 or maxIntCount. If we make any changes to this,
138.1102 +        // zeroPaddingNumber() must be fixed.
138.1103 +
138.1104 +        switch (patternCharIndex) {
138.1105 +        case PATTERN_ERA: // 'G'
138.1106 +            if (useDateFormatSymbols) {
138.1107 +                String[] eras = formatData.getEras();
138.1108 +                if (value < eras.length)
138.1109 +                    current = eras[value];
138.1110 +            }
138.1111 +            if (current == null)
138.1112 +                current = "";
138.1113 +            break;
138.1114 +
138.1115 +        case PATTERN_WEEK_YEAR: // 'Y'
138.1116 +        case PATTERN_YEAR:      // 'y'
138.1117 +            if (calendar instanceof GregorianCalendar) {
138.1118 +                if (count != 2)
138.1119 +                    zeroPaddingNumber(value, count, maxIntCount, buffer);
138.1120 +                else // count == 2
138.1121 +                    zeroPaddingNumber(value, 2, 2, buffer); // clip 1996 to 96
138.1122 +            } else {
138.1123 +                if (current == null) {
138.1124 +                    zeroPaddingNumber(value, style == Calendar.LONG ? 1 : count,
138.1125 +                                      maxIntCount, buffer);
138.1126 +                }
138.1127 +            }
138.1128 +            break;
138.1129 +
138.1130 +        case PATTERN_MONTH: // 'M'
138.1131 +            if (useDateFormatSymbols) {
138.1132 +                String[] months;
138.1133 +                if (count >= 4) {
138.1134 +                    months = formatData.getMonths();
138.1135 +                    current = months[value];
138.1136 +                } else if (count == 3) {
138.1137 +                    months = formatData.getShortMonths();
138.1138 +                    current = months[value];
138.1139 +                }
138.1140 +            } else {
138.1141 +                if (count < 3) {
138.1142 +                    current = null;
138.1143 +                }
138.1144 +            }
138.1145 +            if (current == null) {
138.1146 +                zeroPaddingNumber(value+1, count, maxIntCount, buffer);
138.1147 +            }
138.1148 +            break;
138.1149 +
138.1150 +        case PATTERN_HOUR_OF_DAY1: // 'k' 1-based.  eg, 23:59 + 1 hour =>> 24:59
138.1151 +            if (current == null) {
138.1152 +                if (value == 0)
138.1153 +                    zeroPaddingNumber(calendar.getMaximum(Calendar.HOUR_OF_DAY)+1,
138.1154 +                                      count, maxIntCount, buffer);
138.1155 +                else
138.1156 +                    zeroPaddingNumber(value, count, maxIntCount, buffer);
138.1157 +            }
138.1158 +            break;
138.1159 +
138.1160 +        case PATTERN_DAY_OF_WEEK: // 'E'
138.1161 +            if (useDateFormatSymbols) {
138.1162 +                String[] weekdays;
138.1163 +                if (count >= 4) {
138.1164 +                    weekdays = formatData.getWeekdays();
138.1165 +                    current = weekdays[value];
138.1166 +                } else { // count < 4, use abbreviated form if exists
138.1167 +                    weekdays = formatData.getShortWeekdays();
138.1168 +                    current = weekdays[value];
138.1169 +                }
138.1170 +            }
138.1171 +            break;
138.1172 +
138.1173 +        case PATTERN_AM_PM:    // 'a'
138.1174 +            if (useDateFormatSymbols) {
138.1175 +                String[] ampm = formatData.getAmPmStrings();
138.1176 +                current = ampm[value];
138.1177 +            }
138.1178 +            break;
138.1179 +
138.1180 +        case PATTERN_HOUR1:    // 'h' 1-based.  eg, 11PM + 1 hour =>> 12 AM
138.1181 +            if (current == null) {
138.1182 +                if (value == 0)
138.1183 +                    zeroPaddingNumber(calendar.getLeastMaximum(Calendar.HOUR)+1,
138.1184 +                                      count, maxIntCount, buffer);
138.1185 +                else
138.1186 +                    zeroPaddingNumber(value, count, maxIntCount, buffer);
138.1187 +            }
138.1188 +            break;
138.1189 +
138.1190 +        case PATTERN_ZONE_NAME: // 'z'
138.1191 +            if (current == null) {
138.1192 +                if (formatData.locale == null || formatData.isZoneStringsSet) {
138.1193 +                    int zoneIndex =
138.1194 +                        formatData.getZoneIndex(calendar.getTimeZone().getID());
138.1195 +                    if (zoneIndex == -1) {
138.1196 +                        value = calendar.get(Calendar.ZONE_OFFSET) +
138.1197 +                            calendar.get(Calendar.DST_OFFSET);
138.1198 +//                        buffer.append(ZoneInfoFile.toCustomID(value));
138.1199 +                    } else {
138.1200 +                        int index = (calendar.get(Calendar.DST_OFFSET) == 0) ? 1: 3;
138.1201 +                        if (count < 4) {
138.1202 +                            // Use the short name
138.1203 +                            index++;
138.1204 +                        }
138.1205 +                        String[][] zoneStrings = formatData.getZoneStringsWrapper();
138.1206 +                        buffer.append(zoneStrings[zoneIndex][index]);
138.1207 +                    }
138.1208 +                } else {
138.1209 +                    TimeZone tz = calendar.getTimeZone();
138.1210 +                    boolean daylight = (calendar.get(Calendar.DST_OFFSET) != 0);
138.1211 +                    int tzstyle = (count < 4 ? TimeZone.SHORT : TimeZone.LONG);
138.1212 +                    buffer.append(tz.getDisplayName(daylight, tzstyle, formatData.locale));
138.1213 +                }
138.1214 +            }
138.1215 +            break;
138.1216 +
138.1217 +        case PATTERN_ZONE_VALUE: // 'Z' ("-/+hhmm" form)
138.1218 +            value = (calendar.get(Calendar.ZONE_OFFSET) +
138.1219 +                     calendar.get(Calendar.DST_OFFSET)) / 60000;
138.1220 +
138.1221 +            int width = 4;
138.1222 +            if (value >= 0) {
138.1223 +                buffer.append('+');
138.1224 +            } else {
138.1225 +                width++;
138.1226 +            }
138.1227 +
138.1228 +            int num = (value / 60) * 100 + (value % 60);
138.1229 +//            CalendarUtils.sprintf0d(buffer, num, width);
138.1230 +            break;
138.1231 +
138.1232 +        case PATTERN_ISO_ZONE:   // 'X'
138.1233 +            value = calendar.get(Calendar.ZONE_OFFSET)
138.1234 +                    + calendar.get(Calendar.DST_OFFSET);
138.1235 +
138.1236 +            if (value == 0) {
138.1237 +                buffer.append('Z');
138.1238 +                break;
138.1239 +            }
138.1240 +
138.1241 +            value /=  60000;
138.1242 +            if (value >= 0) {
138.1243 +                buffer.append('+');
138.1244 +            } else {
138.1245 +                buffer.append('-');
138.1246 +                value = -value;
138.1247 +            }
138.1248 +
138.1249 +//            CalendarUtils.sprintf0d(buffer, value / 60, 2);
138.1250 +            if (count == 1) {
138.1251 +                break;
138.1252 +            }
138.1253 +
138.1254 +            if (count == 3) {
138.1255 +                buffer.append(':');
138.1256 +            }
138.1257 +//            CalendarUtils.sprintf0d(buffer, value % 60, 2);
138.1258 +            break;
138.1259 +
138.1260 +        default:
138.1261 +     // case PATTERN_DAY_OF_MONTH:         // 'd'
138.1262 +     // case PATTERN_HOUR_OF_DAY0:         // 'H' 0-based.  eg, 23:59 + 1 hour =>> 00:59
138.1263 +     // case PATTERN_MINUTE:               // 'm'
138.1264 +     // case PATTERN_SECOND:               // 's'
138.1265 +     // case PATTERN_MILLISECOND:          // 'S'
138.1266 +     // case PATTERN_DAY_OF_YEAR:          // 'D'
138.1267 +     // case PATTERN_DAY_OF_WEEK_IN_MONTH: // 'F'
138.1268 +     // case PATTERN_WEEK_OF_YEAR:         // 'w'
138.1269 +     // case PATTERN_WEEK_OF_MONTH:        // 'W'
138.1270 +     // case PATTERN_HOUR0:                // 'K' eg, 11PM + 1 hour =>> 0 AM
138.1271 +     // case PATTERN_ISO_DAY_OF_WEEK:      // 'u' pseudo field, Monday = 1, ..., Sunday = 7
138.1272 +            if (current == null) {
138.1273 +                zeroPaddingNumber(value, count, maxIntCount, buffer);
138.1274 +            }
138.1275 +            break;
138.1276 +        } // switch (patternCharIndex)
138.1277 +
138.1278 +        if (current != null) {
138.1279 +            buffer.append(current);
138.1280 +        }
138.1281 +
138.1282 +        int fieldID = PATTERN_INDEX_TO_DATE_FORMAT_FIELD[patternCharIndex];
138.1283 +        Field f = PATTERN_INDEX_TO_DATE_FORMAT_FIELD_ID[patternCharIndex];
138.1284 +
138.1285 +        delegate.formatted(fieldID, f, f, beginOffset, buffer.length(), buffer);
138.1286 +    }
138.1287 +
138.1288 +    /**
138.1289 +     * Formats a number with the specified minimum and maximum number of digits.
138.1290 +     */
138.1291 +    private final void zeroPaddingNumber(int value, int minDigits, int maxDigits, StringBuffer buffer)
138.1292 +    {
138.1293 +        // Optimization for 1, 2 and 4 digit numbers. This should
138.1294 +        // cover most cases of formatting date/time related items.
138.1295 +        // Note: This optimization code assumes that maxDigits is
138.1296 +        // either 2 or Integer.MAX_VALUE (maxIntCount in format()).
138.1297 +        try {
138.1298 +            if (zeroDigit == 0) {
138.1299 +                zeroDigit = ((DecimalFormat)numberFormat).getDecimalFormatSymbols().getZeroDigit();
138.1300 +            }
138.1301 +            if (value >= 0) {
138.1302 +                if (value < 100 && minDigits >= 1 && minDigits <= 2) {
138.1303 +                    if (value < 10) {
138.1304 +                        if (minDigits == 2) {
138.1305 +                            buffer.append(zeroDigit);
138.1306 +                        }
138.1307 +                        buffer.append((char)(zeroDigit + value));
138.1308 +                    } else {
138.1309 +                        buffer.append((char)(zeroDigit + value / 10));
138.1310 +                        buffer.append((char)(zeroDigit + value % 10));
138.1311 +                    }
138.1312 +                    return;
138.1313 +                } else if (value >= 1000 && value < 10000) {
138.1314 +                    if (minDigits == 4) {
138.1315 +                        buffer.append((char)(zeroDigit + value / 1000));
138.1316 +                        value %= 1000;
138.1317 +                        buffer.append((char)(zeroDigit + value / 100));
138.1318 +                        value %= 100;
138.1319 +                        buffer.append((char)(zeroDigit + value / 10));
138.1320 +                        buffer.append((char)(zeroDigit + value % 10));
138.1321 +                        return;
138.1322 +                    }
138.1323 +                    if (minDigits == 2 && maxDigits == 2) {
138.1324 +                        zeroPaddingNumber(value % 100, 2, 2, buffer);
138.1325 +                        return;
138.1326 +                    }
138.1327 +                }
138.1328 +            }
138.1329 +        } catch (Exception e) {
138.1330 +        }
138.1331 +
138.1332 +        numberFormat.setMinimumIntegerDigits(minDigits);
138.1333 +        numberFormat.setMaximumIntegerDigits(maxDigits);
138.1334 +        numberFormat.format((long)value, buffer, DontCareFieldPosition.INSTANCE);
138.1335 +    }
138.1336 +
138.1337 +
138.1338 +    /**
138.1339 +     * Parses text from a string to produce a <code>Date</code>.
138.1340 +     * <p>
138.1341 +     * The method attempts to parse text starting at the index given by
138.1342 +     * <code>pos</code>.
138.1343 +     * If parsing succeeds, then the index of <code>pos</code> is updated
138.1344 +     * to the index after the last character used (parsing does not necessarily
138.1345 +     * use all characters up to the end of the string), and the parsed
138.1346 +     * date is returned. The updated <code>pos</code> can be used to
138.1347 +     * indicate the starting point for the next call to this method.
138.1348 +     * If an error occurs, then the index of <code>pos</code> is not
138.1349 +     * changed, the error index of <code>pos</code> is set to the index of
138.1350 +     * the character where the error occurred, and null is returned.
138.1351 +     *
138.1352 +     * <p>This parsing operation uses the {@link DateFormat#calendar
138.1353 +     * calendar} to produce a {@code Date}. All of the {@code
138.1354 +     * calendar}'s date-time fields are {@linkplain Calendar#clear()
138.1355 +     * cleared} before parsing, and the {@code calendar}'s default
138.1356 +     * values of the date-time fields are used for any missing
138.1357 +     * date-time information. For example, the year value of the
138.1358 +     * parsed {@code Date} is 1970 with {@link GregorianCalendar} if
138.1359 +     * no year value is given from the parsing operation.  The {@code
138.1360 +     * TimeZone} value may be overwritten, depending on the given
138.1361 +     * pattern and the time zone value in {@code text}. Any {@code
138.1362 +     * TimeZone} value that has previously been set by a call to
138.1363 +     * {@link #setTimeZone(java.util.TimeZone) setTimeZone} may need
138.1364 +     * to be restored for further operations.
138.1365 +     *
138.1366 +     * @param text  A <code>String</code>, part of which should be parsed.
138.1367 +     * @param pos   A <code>ParsePosition</code> object with index and error
138.1368 +     *              index information as described above.
138.1369 +     * @return A <code>Date</code> parsed from the string. In case of
138.1370 +     *         error, returns null.
138.1371 +     * @exception NullPointerException if <code>text</code> or <code>pos</code> is null.
138.1372 +     */
138.1373 +    public Date parse(String text, ParsePosition pos)
138.1374 +    {
138.1375 +        checkNegativeNumberExpression();
138.1376 +
138.1377 +        int start = pos.index;
138.1378 +        int oldStart = start;
138.1379 +        int textLength = text.length();
138.1380 +
138.1381 +        boolean[] ambiguousYear = {false};
138.1382 +
138.1383 +        CalendarBuilder calb = new CalendarBuilder();
138.1384 +
138.1385 +        for (int i = 0; i < compiledPattern.length; ) {
138.1386 +            int tag = compiledPattern[i] >>> 8;
138.1387 +            int count = compiledPattern[i++] & 0xff;
138.1388 +            if (count == 255) {
138.1389 +                count = compiledPattern[i++] << 16;
138.1390 +                count |= compiledPattern[i++];
138.1391 +            }
138.1392 +
138.1393 +            switch (tag) {
138.1394 +            case TAG_QUOTE_ASCII_CHAR:
138.1395 +                if (start >= textLength || text.charAt(start) != (char)count) {
138.1396 +                    pos.index = oldStart;
138.1397 +                    pos.errorIndex = start;
138.1398 +                    return null;
138.1399 +                }
138.1400 +                start++;
138.1401 +                break;
138.1402 +
138.1403 +            case TAG_QUOTE_CHARS:
138.1404 +                while (count-- > 0) {
138.1405 +                    if (start >= textLength || text.charAt(start) != compiledPattern[i++]) {
138.1406 +                        pos.index = oldStart;
138.1407 +                        pos.errorIndex = start;
138.1408 +                        return null;
138.1409 +                    }
138.1410 +                    start++;
138.1411 +                }
138.1412 +                break;
138.1413 +
138.1414 +            default:
138.1415 +                // Peek the next pattern to determine if we need to
138.1416 +                // obey the number of pattern letters for
138.1417 +                // parsing. It's required when parsing contiguous
138.1418 +                // digit text (e.g., "20010704") with a pattern which
138.1419 +                // has no delimiters between fields, like "yyyyMMdd".
138.1420 +                boolean obeyCount = false;
138.1421 +
138.1422 +                // In Arabic, a minus sign for a negative number is put after
138.1423 +                // the number. Even in another locale, a minus sign can be
138.1424 +                // put after a number using DateFormat.setNumberFormat().
138.1425 +                // If both the minus sign and the field-delimiter are '-',
138.1426 +                // subParse() needs to determine whether a '-' after a number
138.1427 +                // in the given text is a delimiter or is a minus sign for the
138.1428 +                // preceding number. We give subParse() a clue based on the
138.1429 +                // information in compiledPattern.
138.1430 +                boolean useFollowingMinusSignAsDelimiter = false;
138.1431 +
138.1432 +                if (i < compiledPattern.length) {
138.1433 +                    int nextTag = compiledPattern[i] >>> 8;
138.1434 +                    if (!(nextTag == TAG_QUOTE_ASCII_CHAR ||
138.1435 +                          nextTag == TAG_QUOTE_CHARS)) {
138.1436 +                        obeyCount = true;
138.1437 +                    }
138.1438 +
138.1439 +                    if (hasFollowingMinusSign &&
138.1440 +                        (nextTag == TAG_QUOTE_ASCII_CHAR ||
138.1441 +                         nextTag == TAG_QUOTE_CHARS)) {
138.1442 +                        int c;
138.1443 +                        if (nextTag == TAG_QUOTE_ASCII_CHAR) {
138.1444 +                            c = compiledPattern[i] & 0xff;
138.1445 +                        } else {
138.1446 +                            c = compiledPattern[i+1];
138.1447 +                        }
138.1448 +
138.1449 +                        if (c == minusSign) {
138.1450 +                            useFollowingMinusSignAsDelimiter = true;
138.1451 +                        }
138.1452 +                    }
138.1453 +                }
138.1454 +                start = subParse(text, start, tag, count, obeyCount,
138.1455 +                                 ambiguousYear, pos,
138.1456 +                                 useFollowingMinusSignAsDelimiter, calb);
138.1457 +                if (start < 0) {
138.1458 +                    pos.index = oldStart;
138.1459 +                    return null;
138.1460 +                }
138.1461 +            }
138.1462 +        }
138.1463 +
138.1464 +        // At this point the fields of Calendar have been set.  Calendar
138.1465 +        // will fill in default values for missing fields when the time
138.1466 +        // is computed.
138.1467 +
138.1468 +        pos.index = start;
138.1469 +
138.1470 +        Date parsedDate;
138.1471 +        try {
138.1472 +            parsedDate = calb.establish(calendar).getTime();
138.1473 +            // If the year value is ambiguous,
138.1474 +            // then the two-digit year == the default start year
138.1475 +            if (ambiguousYear[0]) {
138.1476 +                if (parsedDate.before(defaultCenturyStart)) {
138.1477 +                    parsedDate = calb.addYear(100).establish(calendar).getTime();
138.1478 +                }
138.1479 +            }
138.1480 +        }
138.1481 +        // An IllegalArgumentException will be thrown by Calendar.getTime()
138.1482 +        // if any fields are out of range, e.g., MONTH == 17.
138.1483 +        catch (IllegalArgumentException e) {
138.1484 +            pos.errorIndex = start;
138.1485 +            pos.index = oldStart;
138.1486 +            return null;
138.1487 +        }
138.1488 +
138.1489 +        return parsedDate;
138.1490 +    }
138.1491 +
138.1492 +    /**
138.1493 +     * Private code-size reduction function used by subParse.
138.1494 +     * @param text the time text being parsed.
138.1495 +     * @param start where to start parsing.
138.1496 +     * @param field the date field being parsed.
138.1497 +     * @param data the string array to parsed.
138.1498 +     * @return the new start position if matching succeeded; a negative number
138.1499 +     * indicating matching failure, otherwise.
138.1500 +     */
138.1501 +    private int matchString(String text, int start, int field, String[] data, CalendarBuilder calb)
138.1502 +    {
138.1503 +        int i = 0;
138.1504 +        int count = data.length;
138.1505 +
138.1506 +        if (field == Calendar.DAY_OF_WEEK) i = 1;
138.1507 +
138.1508 +        // There may be multiple strings in the data[] array which begin with
138.1509 +        // the same prefix (e.g., Cerven and Cervenec (June and July) in Czech).
138.1510 +        // We keep track of the longest match, and return that.  Note that this
138.1511 +        // unfortunately requires us to test all array elements.
138.1512 +        int bestMatchLength = 0, bestMatch = -1;
138.1513 +        for (; i<count; ++i)
138.1514 +        {
138.1515 +            int length = data[i].length();
138.1516 +            // Always compare if we have no match yet; otherwise only compare
138.1517 +            // against potentially better matches (longer strings).
138.1518 +            if (length > bestMatchLength &&
138.1519 +                text.regionMatches(true, start, data[i], 0, length))
138.1520 +            {
138.1521 +                bestMatch = i;
138.1522 +                bestMatchLength = length;
138.1523 +            }
138.1524 +        }
138.1525 +        if (bestMatch >= 0)
138.1526 +        {
138.1527 +            calb.set(field, bestMatch);
138.1528 +            return start + bestMatchLength;
138.1529 +        }
138.1530 +        return -start;
138.1531 +    }
138.1532 +
138.1533 +    /**
138.1534 +     * Performs the same thing as matchString(String, int, int,
138.1535 +     * String[]). This method takes a Map<String, Integer> instead of
138.1536 +     * String[].
138.1537 +     */
138.1538 +    private int matchString(String text, int start, int field,
138.1539 +                            Map<String,Integer> data, CalendarBuilder calb) {
138.1540 +        if (data != null) {
138.1541 +            String bestMatch = null;
138.1542 +
138.1543 +            for (String name : data.keySet()) {
138.1544 +                int length = name.length();
138.1545 +                if (bestMatch == null || length > bestMatch.length()) {
138.1546 +                    if (text.regionMatches(true, start, name, 0, length)) {
138.1547 +                        bestMatch = name;
138.1548 +                    }
138.1549 +                }
138.1550 +            }
138.1551 +
138.1552 +            if (bestMatch != null) {
138.1553 +                calb.set(field, data.get(bestMatch));
138.1554 +                return start + bestMatch.length();
138.1555 +            }
138.1556 +        }
138.1557 +        return -start;
138.1558 +    }
138.1559 +
138.1560 +    private int matchZoneString(String text, int start, String[] zoneNames) {
138.1561 +        for (int i = 1; i <= 4; ++i) {
138.1562 +            // Checking long and short zones [1 & 2],
138.1563 +            // and long and short daylight [3 & 4].
138.1564 +            String zoneName = zoneNames[i];
138.1565 +            if (text.regionMatches(true, start,
138.1566 +                                   zoneName, 0, zoneName.length())) {
138.1567 +                return i;
138.1568 +            }
138.1569 +        }
138.1570 +        return -1;
138.1571 +    }
138.1572 +
138.1573 +    private boolean matchDSTString(String text, int start, int zoneIndex, int standardIndex,
138.1574 +                                   String[][] zoneStrings) {
138.1575 +        int index = standardIndex + 2;
138.1576 +        String zoneName  = zoneStrings[zoneIndex][index];
138.1577 +        if (text.regionMatches(true, start,
138.1578 +                               zoneName, 0, zoneName.length())) {
138.1579 +            return true;
138.1580 +        }
138.1581 +        return false;
138.1582 +    }
138.1583 +
138.1584 +    /**
138.1585 +     * find time zone 'text' matched zoneStrings and set to internal
138.1586 +     * calendar.
138.1587 +     */
138.1588 +    private int subParseZoneString(String text, int start, CalendarBuilder calb) {
138.1589 +        boolean useSameName = false; // true if standard and daylight time use the same abbreviation.
138.1590 +        TimeZone currentTimeZone = getTimeZone();
138.1591 +
138.1592 +        // At this point, check for named time zones by looking through
138.1593 +        // the locale data from the TimeZoneNames strings.
138.1594 +        // Want to be able to parse both short and long forms.
138.1595 +        int zoneIndex = formatData.getZoneIndex(currentTimeZone.getID());
138.1596 +        TimeZone tz = null;
138.1597 +        String[][] zoneStrings = formatData.getZoneStringsWrapper();
138.1598 +        String[] zoneNames = null;
138.1599 +        int nameIndex = 0;
138.1600 +        if (zoneIndex != -1) {
138.1601 +            zoneNames = zoneStrings[zoneIndex];
138.1602 +            if ((nameIndex = matchZoneString(text, start, zoneNames)) > 0) {
138.1603 +                if (nameIndex <= 2) {
138.1604 +                    // Check if the standard name (abbr) and the daylight name are the same.
138.1605 +                    useSameName = zoneNames[nameIndex].equalsIgnoreCase(zoneNames[nameIndex + 2]);
138.1606 +                }
138.1607 +                tz = TimeZone.getTimeZone(zoneNames[0]);
138.1608 +            }
138.1609 +        }
138.1610 +        if (tz == null) {
138.1611 +            zoneIndex = formatData.getZoneIndex(TimeZone.getDefault().getID());
138.1612 +            if (zoneIndex != -1) {
138.1613 +                zoneNames = zoneStrings[zoneIndex];
138.1614 +                if ((nameIndex = matchZoneString(text, start, zoneNames)) > 0) {
138.1615 +                    if (nameIndex <= 2) {
138.1616 +                        useSameName = zoneNames[nameIndex].equalsIgnoreCase(zoneNames[nameIndex + 2]);
138.1617 +                    }
138.1618 +                    tz = TimeZone.getTimeZone(zoneNames[0]);
138.1619 +                }
138.1620 +            }
138.1621 +        }
138.1622 +
138.1623 +        if (tz == null) {
138.1624 +            int len = zoneStrings.length;
138.1625 +            for (int i = 0; i < len; i++) {
138.1626 +                zoneNames = zoneStrings[i];
138.1627 +                if ((nameIndex = matchZoneString(text, start, zoneNames)) > 0) {
138.1628 +                    if (nameIndex <= 2) {
138.1629 +                        useSameName = zoneNames[nameIndex].equalsIgnoreCase(zoneNames[nameIndex + 2]);
138.1630 +                    }
138.1631 +                    tz = TimeZone.getTimeZone(zoneNames[0]);
138.1632 +                    break;
138.1633 +                }
138.1634 +            }
138.1635 +        }
138.1636 +        if (tz != null) { // Matched any ?
138.1637 +            if (!tz.equals(currentTimeZone)) {
138.1638 +                setTimeZone(tz);
138.1639 +            }
138.1640 +            // If the time zone matched uses the same name
138.1641 +            // (abbreviation) for both standard and daylight time,
138.1642 +            // let the time zone in the Calendar decide which one.
138.1643 +            //
138.1644 +            // Also if tz.getDSTSaving() returns 0 for DST, use tz to
138.1645 +            // determine the local time. (6645292)
138.1646 +            int dstAmount = (nameIndex >= 3) ? tz.getDSTSavings() : 0;
138.1647 +            if (!(useSameName || (nameIndex >= 3 && dstAmount == 0))) {
138.1648 +                calb.set(Calendar.ZONE_OFFSET, tz.getRawOffset())
138.1649 +                    .set(Calendar.DST_OFFSET, dstAmount);
138.1650 +            }
138.1651 +            return (start + zoneNames[nameIndex].length());
138.1652 +        }
138.1653 +        return 0;
138.1654 +    }
138.1655 +
138.1656 +    /**
138.1657 +     * Parses numeric forms of time zone offset, such as "hh:mm", and
138.1658 +     * sets calb to the parsed value.
138.1659 +     *
138.1660 +     * @param text  the text to be parsed
138.1661 +     * @param start the character position to start parsing
138.1662 +     * @param sign  1: positive; -1: negative
138.1663 +     * @param count 0: 'Z' or "GMT+hh:mm" parsing; 1 - 3: the number of 'X's
138.1664 +     * @param colon true - colon required between hh and mm; false - no colon required
138.1665 +     * @param calb  a CalendarBuilder in which the parsed value is stored
138.1666 +     * @return updated parsed position, or its negative value to indicate a parsing error
138.1667 +     */
138.1668 +    private int subParseNumericZone(String text, int start, int sign, int count,
138.1669 +                                    boolean colon, CalendarBuilder calb) {
138.1670 +        int index = start;
138.1671 +
138.1672 +      parse:
138.1673 +        try {
138.1674 +            char c = text.charAt(index++);
138.1675 +            // Parse hh
138.1676 +            int hours;
138.1677 +            if (!isDigit(c)) {
138.1678 +                break parse;
138.1679 +            }
138.1680 +            hours = c - '0';
138.1681 +            c = text.charAt(index++);
138.1682 +            if (isDigit(c)) {
138.1683 +                hours = hours * 10 + (c - '0');
138.1684 +            } else {
138.1685 +                // If no colon in RFC 822 or 'X' (ISO), two digits are
138.1686 +                // required.
138.1687 +                if (count > 0 || !colon) {
138.1688 +                    break parse;
138.1689 +                }
138.1690 +                --index;
138.1691 +            }
138.1692 +            if (hours > 23) {
138.1693 +                break parse;
138.1694 +            }
138.1695 +            int minutes = 0;
138.1696 +            if (count != 1) {
138.1697 +                // Proceed with parsing mm
138.1698 +                c = text.charAt(index++);
138.1699 +                if (colon) {
138.1700 +                    if (c != ':') {
138.1701 +                        break parse;
138.1702 +                    }
138.1703 +                    c = text.charAt(index++);
138.1704 +                }
138.1705 +                if (!isDigit(c)) {
138.1706 +                    break parse;
138.1707 +                }
138.1708 +                minutes = c - '0';
138.1709 +                c = text.charAt(index++);
138.1710 +                if (!isDigit(c)) {
138.1711 +                    break parse;
138.1712 +                }
138.1713 +                minutes = minutes * 10 + (c - '0');
138.1714 +                if (minutes > 59) {
138.1715 +                    break parse;
138.1716 +                }
138.1717 +            }
138.1718 +            minutes += hours * 60;
138.1719 +            calb.set(Calendar.ZONE_OFFSET, minutes * MILLIS_PER_MINUTE * sign)
138.1720 +                .set(Calendar.DST_OFFSET, 0);
138.1721 +            return index;
138.1722 +        } catch (IndexOutOfBoundsException e) {
138.1723 +        }
138.1724 +        return  1 - index; // -(index - 1)
138.1725 +    }
138.1726 +
138.1727 +    private boolean isDigit(char c) {
138.1728 +        return c >= '0' && c <= '9';
138.1729 +    }
138.1730 +
138.1731 +    /**
138.1732 +     * Private member function that converts the parsed date strings into
138.1733 +     * timeFields. Returns -start (for ParsePosition) if failed.
138.1734 +     * @param text the time text to be parsed.
138.1735 +     * @param start where to start parsing.
138.1736 +     * @param ch the pattern character for the date field text to be parsed.
138.1737 +     * @param count the count of a pattern character.
138.1738 +     * @param obeyCount if true, then the next field directly abuts this one,
138.1739 +     * and we should use the count to know when to stop parsing.
138.1740 +     * @param ambiguousYear return parameter; upon return, if ambiguousYear[0]
138.1741 +     * is true, then a two-digit year was parsed and may need to be readjusted.
138.1742 +     * @param origPos origPos.errorIndex is used to return an error index
138.1743 +     * at which a parse error occurred, if matching failure occurs.
138.1744 +     * @return the new start position if matching succeeded; -1 indicating
138.1745 +     * matching failure, otherwise. In case matching failure occurred,
138.1746 +     * an error index is set to origPos.errorIndex.
138.1747 +     */
138.1748 +    private int subParse(String text, int start, int patternCharIndex, int count,
138.1749 +                         boolean obeyCount, boolean[] ambiguousYear,
138.1750 +                         ParsePosition origPos,
138.1751 +                         boolean useFollowingMinusSignAsDelimiter, CalendarBuilder calb) {
138.1752 +        Number number = null;
138.1753 +        int value = 0;
138.1754 +        ParsePosition pos = new ParsePosition(0);
138.1755 +        pos.index = start;
138.1756 +        if (patternCharIndex == PATTERN_WEEK_YEAR && !calendar.isWeekDateSupported()) {
138.1757 +            // use calendar year 'y' instead
138.1758 +            patternCharIndex = PATTERN_YEAR;
138.1759 +        }
138.1760 +        int field = PATTERN_INDEX_TO_CALENDAR_FIELD[patternCharIndex];
138.1761 +
138.1762 +        // If there are any spaces here, skip over them.  If we hit the end
138.1763 +        // of the string, then fail.
138.1764 +        for (;;) {
138.1765 +            if (pos.index >= text.length()) {
138.1766 +                origPos.errorIndex = start;
138.1767 +                return -1;
138.1768 +            }
138.1769 +            char c = text.charAt(pos.index);
138.1770 +            if (c != ' ' && c != '\t') break;
138.1771 +            ++pos.index;
138.1772 +        }
138.1773 +
138.1774 +      parsing:
138.1775 +        {
138.1776 +            // We handle a few special cases here where we need to parse
138.1777 +            // a number value.  We handle further, more generic cases below.  We need
138.1778 +            // to handle some of them here because some fields require extra processing on
138.1779 +            // the parsed value.
138.1780 +            if (patternCharIndex == PATTERN_HOUR_OF_DAY1 ||
138.1781 +                patternCharIndex == PATTERN_HOUR1 ||
138.1782 +                (patternCharIndex == PATTERN_MONTH && count <= 2) ||
138.1783 +                patternCharIndex == PATTERN_YEAR ||
138.1784 +                patternCharIndex == PATTERN_WEEK_YEAR) {
138.1785 +                // It would be good to unify this with the obeyCount logic below,
138.1786 +                // but that's going to be difficult.
138.1787 +                if (obeyCount) {
138.1788 +                    if ((start+count) > text.length()) {
138.1789 +                        break parsing;
138.1790 +                    }
138.1791 +                    number = numberFormat.parse(text.substring(0, start+count), pos);
138.1792 +                } else {
138.1793 +                    number = numberFormat.parse(text, pos);
138.1794 +                }
138.1795 +                if (number == null) {
138.1796 +                    if (patternCharIndex != PATTERN_YEAR || calendar instanceof GregorianCalendar) {
138.1797 +                        break parsing;
138.1798 +                    }
138.1799 +                } else {
138.1800 +                    value = number.intValue();
138.1801 +
138.1802 +                    if (useFollowingMinusSignAsDelimiter && (value < 0) &&
138.1803 +                        (((pos.index < text.length()) &&
138.1804 +                         (text.charAt(pos.index) != minusSign)) ||
138.1805 +                         ((pos.index == text.length()) &&
138.1806 +                          (text.charAt(pos.index-1) == minusSign)))) {
138.1807 +                        value = -value;
138.1808 +                        pos.index--;
138.1809 +                    }
138.1810 +                }
138.1811 +            }
138.1812 +
138.1813 +            boolean useDateFormatSymbols = useDateFormatSymbols();
138.1814 +
138.1815 +            int index;
138.1816 +            switch (patternCharIndex) {
138.1817 +            case PATTERN_ERA: // 'G'
138.1818 +                if (useDateFormatSymbols) {
138.1819 +                    if ((index = matchString(text, start, Calendar.ERA, formatData.getEras(), calb)) > 0) {
138.1820 +                        return index;
138.1821 +                    }
138.1822 +                } else {
138.1823 +                    Map<String, Integer> map = calendar.getDisplayNames(field,
138.1824 +                                                                        Calendar.ALL_STYLES,
138.1825 +                                                                        locale);
138.1826 +                    if ((index = matchString(text, start, field, map, calb)) > 0) {
138.1827 +                        return index;
138.1828 +                    }
138.1829 +                }
138.1830 +                break parsing;
138.1831 +
138.1832 +            case PATTERN_WEEK_YEAR: // 'Y'
138.1833 +            case PATTERN_YEAR:      // 'y'
138.1834 +                if (!(calendar instanceof GregorianCalendar)) {
138.1835 +                    // calendar might have text representations for year values,
138.1836 +                    // such as "\u5143" in JapaneseImperialCalendar.
138.1837 +                    int style = (count >= 4) ? Calendar.LONG : Calendar.SHORT;
138.1838 +                    Map<String, Integer> map = calendar.getDisplayNames(field, style, locale);
138.1839 +                    if (map != null) {
138.1840 +                        if ((index = matchString(text, start, field, map, calb)) > 0) {
138.1841 +                            return index;
138.1842 +                        }
138.1843 +                    }
138.1844 +                    calb.set(field, value);
138.1845 +                    return pos.index;
138.1846 +                }
138.1847 +
138.1848 +                // If there are 3 or more YEAR pattern characters, this indicates
138.1849 +                // that the year value is to be treated literally, without any
138.1850 +                // two-digit year adjustments (e.g., from "01" to 2001).  Otherwise
138.1851 +                // we made adjustments to place the 2-digit year in the proper
138.1852 +                // century, for parsed strings from "00" to "99".  Any other string
138.1853 +                // is treated literally:  "2250", "-1", "1", "002".
138.1854 +                if (count <= 2 && (pos.index - start) == 2
138.1855 +                    && Character.isDigit(text.charAt(start))
138.1856 +                    && Character.isDigit(text.charAt(start+1))) {
138.1857 +                    // Assume for example that the defaultCenturyStart is 6/18/1903.
138.1858 +                    // This means that two-digit years will be forced into the range
138.1859 +                    // 6/18/1903 to 6/17/2003.  As a result, years 00, 01, and 02
138.1860 +                    // correspond to 2000, 2001, and 2002.  Years 04, 05, etc. correspond
138.1861 +                    // to 1904, 1905, etc.  If the year is 03, then it is 2003 if the
138.1862 +                    // other fields specify a date before 6/18, or 1903 if they specify a
138.1863 +                    // date afterwards.  As a result, 03 is an ambiguous year.  All other
138.1864 +                    // two-digit years are unambiguous.
138.1865 +                    int ambiguousTwoDigitYear = defaultCenturyStartYear % 100;
138.1866 +                    ambiguousYear[0] = value == ambiguousTwoDigitYear;
138.1867 +                    value += (defaultCenturyStartYear/100)*100 +
138.1868 +                        (value < ambiguousTwoDigitYear ? 100 : 0);
138.1869 +                }
138.1870 +                calb.set(field, value);
138.1871 +                return pos.index;
138.1872 +
138.1873 +            case PATTERN_MONTH: // 'M'
138.1874 +                if (count <= 2) // i.e., M or MM.
138.1875 +                {
138.1876 +                    // Don't want to parse the month if it is a string
138.1877 +                    // while pattern uses numeric style: M or MM.
138.1878 +                    // [We computed 'value' above.]
138.1879 +                    calb.set(Calendar.MONTH, value - 1);
138.1880 +                    return pos.index;
138.1881 +                }
138.1882 +
138.1883 +                if (useDateFormatSymbols) {
138.1884 +                    // count >= 3 // i.e., MMM or MMMM
138.1885 +                    // Want to be able to parse both short and long forms.
138.1886 +                    // Try count == 4 first:
138.1887 +                    int newStart = 0;
138.1888 +                    if ((newStart = matchString(text, start, Calendar.MONTH,
138.1889 +                                                formatData.getMonths(), calb)) > 0) {
138.1890 +                        return newStart;
138.1891 +                    }
138.1892 +                    // count == 4 failed, now try count == 3
138.1893 +                    if ((index = matchString(text, start, Calendar.MONTH,
138.1894 +                                             formatData.getShortMonths(), calb)) > 0) {
138.1895 +                        return index;
138.1896 +                    }
138.1897 +                } else {
138.1898 +                    Map<String, Integer> map = calendar.getDisplayNames(field,
138.1899 +                                                                        Calendar.ALL_STYLES,
138.1900 +                                                                        locale);
138.1901 +                    if ((index = matchString(text, start, field, map, calb)) > 0) {
138.1902 +                        return index;
138.1903 +                    }
138.1904 +                }
138.1905 +                break parsing;
138.1906 +
138.1907 +            case PATTERN_HOUR_OF_DAY1: // 'k' 1-based.  eg, 23:59 + 1 hour =>> 24:59
138.1908 +                if (!isLenient()) {
138.1909 +                    // Validate the hour value in non-lenient
138.1910 +                    if (value < 1 || value > 24) {
138.1911 +                        break parsing;
138.1912 +                    }
138.1913 +                }
138.1914 +                // [We computed 'value' above.]
138.1915 +                if (value == calendar.getMaximum(Calendar.HOUR_OF_DAY)+1)
138.1916 +                    value = 0;
138.1917 +                calb.set(Calendar.HOUR_OF_DAY, value);
138.1918 +                return pos.index;
138.1919 +
138.1920 +            case PATTERN_DAY_OF_WEEK:  // 'E'
138.1921 +                {
138.1922 +                    if (useDateFormatSymbols) {
138.1923 +                        // Want to be able to parse both short and long forms.
138.1924 +                        // Try count == 4 (DDDD) first:
138.1925 +                        int newStart = 0;
138.1926 +                        if ((newStart=matchString(text, start, Calendar.DAY_OF_WEEK,
138.1927 +                                                  formatData.getWeekdays(), calb)) > 0) {
138.1928 +                            return newStart;
138.1929 +                        }
138.1930 +                        // DDDD failed, now try DDD
138.1931 +                        if ((index = matchString(text, start, Calendar.DAY_OF_WEEK,
138.1932 +                                                 formatData.getShortWeekdays(), calb)) > 0) {
138.1933 +                            return index;
138.1934 +                        }
138.1935 +                    } else {
138.1936 +                        int[] styles = { Calendar.LONG, Calendar.SHORT };
138.1937 +                        for (int style : styles) {
138.1938 +                            Map<String,Integer> map = calendar.getDisplayNames(field, style, locale);
138.1939 +                            if ((index = matchString(text, start, field, map, calb)) > 0) {
138.1940 +                                return index;
138.1941 +                            }
138.1942 +                        }
138.1943 +                    }
138.1944 +                }
138.1945 +                break parsing;
138.1946 +
138.1947 +            case PATTERN_AM_PM:    // 'a'
138.1948 +                if (useDateFormatSymbols) {
138.1949 +                    if ((index = matchString(text, start, Calendar.AM_PM,
138.1950 +                                             formatData.getAmPmStrings(), calb)) > 0) {
138.1951 +                        return index;
138.1952 +                    }
138.1953 +                } else {
138.1954 +                    Map<String,Integer> map = calendar.getDisplayNames(field, Calendar.ALL_STYLES, locale);
138.1955 +                    if ((index = matchString(text, start, field, map, calb)) > 0) {
138.1956 +                        return index;
138.1957 +                    }
138.1958 +                }
138.1959 +                break parsing;
138.1960 +
138.1961 +            case PATTERN_HOUR1: // 'h' 1-based.  eg, 11PM + 1 hour =>> 12 AM
138.1962 +                if (!isLenient()) {
138.1963 +                    // Validate the hour value in non-lenient
138.1964 +                    if (value < 1 || value > 12) {
138.1965 +                        break parsing;
138.1966 +                    }
138.1967 +                }
138.1968 +                // [We computed 'value' above.]
138.1969 +                if (value == calendar.getLeastMaximum(Calendar.HOUR)+1)
138.1970 +                    value = 0;
138.1971 +                calb.set(Calendar.HOUR, value);
138.1972 +                return pos.index;
138.1973 +
138.1974 +            case PATTERN_ZONE_NAME:  // 'z'
138.1975 +            case PATTERN_ZONE_VALUE: // 'Z'
138.1976 +                {
138.1977 +                    int sign = 0;
138.1978 +                    try {
138.1979 +                        char c = text.charAt(pos.index);
138.1980 +                        if (c == '+') {
138.1981 +                            sign = 1;
138.1982 +                        } else if (c == '-') {
138.1983 +                            sign = -1;
138.1984 +                        }
138.1985 +                        if (sign == 0) {
138.1986 +                            // Try parsing a custom time zone "GMT+hh:mm" or "GMT".
138.1987 +                            if ((c == 'G' || c == 'g')
138.1988 +                                && (text.length() - start) >= GMT.length()
138.1989 +                                && text.regionMatches(true, start, GMT, 0, GMT.length())) {
138.1990 +                                pos.index = start + GMT.length();
138.1991 +
138.1992 +                                if ((text.length() - pos.index) > 0) {
138.1993 +                                    c = text.charAt(pos.index);
138.1994 +                                    if (c == '+') {
138.1995 +                                        sign = 1;
138.1996 +                                    } else if (c == '-') {
138.1997 +                                        sign = -1;
138.1998 +                                    }
138.1999 +                                }
138.2000 +
138.2001 +                                if (sign == 0) {    /* "GMT" without offset */
138.2002 +                                    calb.set(Calendar.ZONE_OFFSET, 0)
138.2003 +                                        .set(Calendar.DST_OFFSET, 0);
138.2004 +                                    return pos.index;
138.2005 +                                }
138.2006 +
138.2007 +                                // Parse the rest as "hh:mm"
138.2008 +                                int i = subParseNumericZone(text, ++pos.index,
138.2009 +                                                            sign, 0, true, calb);
138.2010 +                                if (i > 0) {
138.2011 +                                    return i;
138.2012 +                                }
138.2013 +                                pos.index = -i;
138.2014 +                            } else {
138.2015 +                                // Try parsing the text as a time zone
138.2016 +                                // name or abbreviation.
138.2017 +                                int i = subParseZoneString(text, pos.index, calb);
138.2018 +                                if (i > 0) {
138.2019 +                                    return i;
138.2020 +                                }
138.2021 +                                pos.index = -i;
138.2022 +                            }
138.2023 +                        } else {
138.2024 +                            // Parse the rest as "hhmm" (RFC 822)
138.2025 +                            int i = subParseNumericZone(text, ++pos.index,
138.2026 +                                                        sign, 0, false, calb);
138.2027 +                            if (i > 0) {
138.2028 +                                return i;
138.2029 +                            }
138.2030 +                            pos.index = -i;
138.2031 +                        }
138.2032 +                    } catch (IndexOutOfBoundsException e) {
138.2033 +                    }
138.2034 +                }
138.2035 +                break parsing;
138.2036 +
138.2037 +            case PATTERN_ISO_ZONE:   // 'X'
138.2038 +                {
138.2039 +                    if ((text.length() - pos.index) <= 0) {
138.2040 +                        break parsing;
138.2041 +                    }
138.2042 +
138.2043 +                    int sign = 0;
138.2044 +                    char c = text.charAt(pos.index);
138.2045 +                    if (c == 'Z') {
138.2046 +                        calb.set(Calendar.ZONE_OFFSET, 0).set(Calendar.DST_OFFSET, 0);
138.2047 +                        return ++pos.index;
138.2048 +                    }
138.2049 +
138.2050 +                    // parse text as "+/-hh[[:]mm]" based on count
138.2051 +                    if (c == '+') {
138.2052 +                        sign = 1;
138.2053 +                    } else if (c == '-') {
138.2054 +                        sign = -1;
138.2055 +                    } else {
138.2056 +                        ++pos.index;
138.2057 +                        break parsing;
138.2058 +                    }
138.2059 +                    int i = subParseNumericZone(text, ++pos.index, sign, count,
138.2060 +                                                count == 3, calb);
138.2061 +                    if (i > 0) {
138.2062 +                        return i;
138.2063 +                    }
138.2064 +                    pos.index = -i;
138.2065 +                }
138.2066 +                break parsing;
138.2067 +
138.2068 +            default:
138.2069 +         // case PATTERN_DAY_OF_MONTH:         // 'd'
138.2070 +         // case PATTERN_HOUR_OF_DAY0:         // 'H' 0-based.  eg, 23:59 + 1 hour =>> 00:59
138.2071 +         // case PATTERN_MINUTE:               // 'm'
138.2072 +         // case PATTERN_SECOND:               // 's'
138.2073 +         // case PATTERN_MILLISECOND:          // 'S'
138.2074 +         // case PATTERN_DAY_OF_YEAR:          // 'D'
138.2075 +         // case PATTERN_DAY_OF_WEEK_IN_MONTH: // 'F'
138.2076 +         // case PATTERN_WEEK_OF_YEAR:         // 'w'
138.2077 +         // case PATTERN_WEEK_OF_MONTH:        // 'W'
138.2078 +         // case PATTERN_HOUR0:                // 'K' 0-based.  eg, 11PM + 1 hour =>> 0 AM
138.2079 +         // case PATTERN_ISO_DAY_OF_WEEK:      // 'u' (pseudo field);
138.2080 +
138.2081 +                // Handle "generic" fields
138.2082 +                if (obeyCount) {
138.2083 +                    if ((start+count) > text.length()) {
138.2084 +                        break parsing;
138.2085 +                    }
138.2086 +                    number = numberFormat.parse(text.substring(0, start+count), pos);
138.2087 +                } else {
138.2088 +                    number = numberFormat.parse(text, pos);
138.2089 +                }
138.2090 +                if (number != null) {
138.2091 +                    value = number.intValue();
138.2092 +
138.2093 +                    if (useFollowingMinusSignAsDelimiter && (value < 0) &&
138.2094 +                        (((pos.index < text.length()) &&
138.2095 +                         (text.charAt(pos.index) != minusSign)) ||
138.2096 +                         ((pos.index == text.length()) &&
138.2097 +                          (text.charAt(pos.index-1) == minusSign)))) {
138.2098 +                        value = -value;
138.2099 +                        pos.index--;
138.2100 +                    }
138.2101 +
138.2102 +                    calb.set(field, value);
138.2103 +                    return pos.index;
138.2104 +                }
138.2105 +                break parsing;
138.2106 +            }
138.2107 +        }
138.2108 +
138.2109 +        // Parsing failed.
138.2110 +        origPos.errorIndex = pos.index;
138.2111 +        return -1;
138.2112 +    }
138.2113 +
138.2114 +    private final String getCalendarName() {
138.2115 +        return calendar.getClass().getName();
138.2116 +    }
138.2117 +
138.2118 +    private boolean useDateFormatSymbols() {
138.2119 +        if (useDateFormatSymbols) {
138.2120 +            return true;
138.2121 +        }
138.2122 +        return isGregorianCalendar() || locale == null;
138.2123 +    }
138.2124 +
138.2125 +    private boolean isGregorianCalendar() {
138.2126 +        return "java.util.GregorianCalendar".equals(getCalendarName());
138.2127 +    }
138.2128 +
138.2129 +    /**
138.2130 +     * Translates a pattern, mapping each character in the from string to the
138.2131 +     * corresponding character in the to string.
138.2132 +     *
138.2133 +     * @exception IllegalArgumentException if the given pattern is invalid
138.2134 +     */
138.2135 +    private String translatePattern(String pattern, String from, String to) {
138.2136 +        StringBuilder result = new StringBuilder();
138.2137 +        boolean inQuote = false;
138.2138 +        for (int i = 0; i < pattern.length(); ++i) {
138.2139 +            char c = pattern.charAt(i);
138.2140 +            if (inQuote) {
138.2141 +                if (c == '\'')
138.2142 +                    inQuote = false;
138.2143 +            }
138.2144 +            else {
138.2145 +                if (c == '\'')
138.2146 +                    inQuote = true;
138.2147 +                else if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
138.2148 +                    int ci = from.indexOf(c);
138.2149 +                    if (ci >= 0) {
138.2150 +                        // patternChars is longer than localPatternChars due
138.2151 +                        // to serialization compatibility. The pattern letters
138.2152 +                        // unsupported by localPatternChars pass through.
138.2153 +                        if (ci < to.length()) {
138.2154 +                            c = to.charAt(ci);
138.2155 +                        }
138.2156 +                    } else {
138.2157 +                        throw new IllegalArgumentException("Illegal pattern " +
138.2158 +                                                           " character '" +
138.2159 +                                                           c + "'");
138.2160 +                    }
138.2161 +                }
138.2162 +            }
138.2163 +            result.append(c);
138.2164 +        }
138.2165 +        if (inQuote)
138.2166 +            throw new IllegalArgumentException("Unfinished quote in pattern");
138.2167 +        return result.toString();
138.2168 +    }
138.2169 +
138.2170 +    /**
138.2171 +     * Returns a pattern string describing this date format.
138.2172 +     *
138.2173 +     * @return a pattern string describing this date format.
138.2174 +     */
138.2175 +    public String toPattern() {
138.2176 +        return pattern;
138.2177 +    }
138.2178 +
138.2179 +    /**
138.2180 +     * Returns a localized pattern string describing this date format.
138.2181 +     *
138.2182 +     * @return a localized pattern string describing this date format.
138.2183 +     */
138.2184 +    public String toLocalizedPattern() {
138.2185 +        return translatePattern(pattern,
138.2186 +                                DateFormatSymbols.patternChars,
138.2187 +                                formatData.getLocalPatternChars());
138.2188 +    }
138.2189 +
138.2190 +    /**
138.2191 +     * Applies the given pattern string to this date format.
138.2192 +     *
138.2193 +     * @param pattern the new date and time pattern for this date format
138.2194 +     * @exception NullPointerException if the given pattern is null
138.2195 +     * @exception IllegalArgumentException if the given pattern is invalid
138.2196 +     */
138.2197 +    public void applyPattern(String pattern)
138.2198 +    {
138.2199 +        compiledPattern = compile(pattern);
138.2200 +        this.pattern = pattern;
138.2201 +    }
138.2202 +
138.2203 +    /**
138.2204 +     * Applies the given localized pattern string to this date format.
138.2205 +     *
138.2206 +     * @param pattern a String to be mapped to the new date and time format
138.2207 +     *        pattern for this format
138.2208 +     * @exception NullPointerException if the given pattern is null
138.2209 +     * @exception IllegalArgumentException if the given pattern is invalid
138.2210 +     */
138.2211 +    public void applyLocalizedPattern(String pattern) {
138.2212 +         String p = translatePattern(pattern,
138.2213 +                                     formatData.getLocalPatternChars(),
138.2214 +                                     DateFormatSymbols.patternChars);
138.2215 +         compiledPattern = compile(p);
138.2216 +         this.pattern = p;
138.2217 +    }
138.2218 +
138.2219 +    /**
138.2220 +     * Gets a copy of the date and time format symbols of this date format.
138.2221 +     *
138.2222 +     * @return the date and time format symbols of this date format
138.2223 +     * @see #setDateFormatSymbols
138.2224 +     */
138.2225 +    public DateFormatSymbols getDateFormatSymbols()
138.2226 +    {
138.2227 +        return (DateFormatSymbols)formatData.clone();
138.2228 +    }
138.2229 +
138.2230 +    /**
138.2231 +     * Sets the date and time format symbols of this date format.
138.2232 +     *
138.2233 +     * @param newFormatSymbols the new date and time format symbols
138.2234 +     * @exception NullPointerException if the given newFormatSymbols is null
138.2235 +     * @see #getDateFormatSymbols
138.2236 +     */
138.2237 +    public void setDateFormatSymbols(DateFormatSymbols newFormatSymbols)
138.2238 +    {
138.2239 +        this.formatData = (DateFormatSymbols)newFormatSymbols.clone();
138.2240 +        useDateFormatSymbols = true;
138.2241 +    }
138.2242 +
138.2243 +    /**
138.2244 +     * Creates a copy of this <code>SimpleDateFormat</code>. This also
138.2245 +     * clones the format's date format symbols.
138.2246 +     *
138.2247 +     * @return a clone of this <code>SimpleDateFormat</code>
138.2248 +     */
138.2249 +    public Object clone() {
138.2250 +        SimpleDateFormat other = (SimpleDateFormat) super.clone();
138.2251 +        other.formatData = (DateFormatSymbols) formatData.clone();
138.2252 +        return other;
138.2253 +    }
138.2254 +
138.2255 +    /**
138.2256 +     * Returns the hash code value for this <code>SimpleDateFormat</code> object.
138.2257 +     *
138.2258 +     * @return the hash code value for this <code>SimpleDateFormat</code> object.
138.2259 +     */
138.2260 +    public int hashCode()
138.2261 +    {
138.2262 +        return pattern.hashCode();
138.2263 +        // just enough fields for a reasonable distribution
138.2264 +    }
138.2265 +
138.2266 +    /**
138.2267 +     * Compares the given object with this <code>SimpleDateFormat</code> for
138.2268 +     * equality.
138.2269 +     *
138.2270 +     * @return true if the given object is equal to this
138.2271 +     * <code>SimpleDateFormat</code>
138.2272 +     */
138.2273 +    public boolean equals(Object obj)
138.2274 +    {
138.2275 +        if (!super.equals(obj)) return false; // super does class check
138.2276 +        SimpleDateFormat that = (SimpleDateFormat) obj;
138.2277 +        return (pattern.equals(that.pattern)
138.2278 +                && formatData.equals(that.formatData));
138.2279 +    }
138.2280 +
138.2281 +    /**
138.2282 +     * After reading an object from the input stream, the format
138.2283 +     * pattern in the object is verified.
138.2284 +     * <p>
138.2285 +     * @exception InvalidObjectException if the pattern is invalid
138.2286 +     */
138.2287 +    private void readObject(ObjectInputStream stream)
138.2288 +                         throws IOException, ClassNotFoundException {
138.2289 +        stream.defaultReadObject();
138.2290 +
138.2291 +        try {
138.2292 +            compiledPattern = compile(pattern);
138.2293 +        } catch (Exception e) {
138.2294 +            throw new InvalidObjectException("invalid pattern");
138.2295 +        }
138.2296 +
138.2297 +        if (serialVersionOnStream < 1) {
138.2298 +            // didn't have defaultCenturyStart field
138.2299 +            initializeDefaultCentury();
138.2300 +        }
138.2301 +        else {
138.2302 +            // fill in dependent transient field
138.2303 +            parseAmbiguousDatesAsAfter(defaultCenturyStart);
138.2304 +        }
138.2305 +        serialVersionOnStream = currentSerialVersion;
138.2306 +
138.2307 +        // If the deserialized object has a SimpleTimeZone, try
138.2308 +        // to replace it with a ZoneInfo equivalent in order to
138.2309 +        // be compatible with the SimpleTimeZone-based
138.2310 +        // implementation as much as possible.
138.2311 +        TimeZone tz = getTimeZone();
138.2312 +        if (tz instanceof SimpleTimeZone) {
138.2313 +            String id = tz.getID();
138.2314 +            TimeZone zi = TimeZone.getTimeZone(id);
138.2315 +            if (zi != null && zi.hasSameRules(tz) && zi.getID().equals(id)) {
138.2316 +                setTimeZone(zi);
138.2317 +            }
138.2318 +        }
138.2319 +    }
138.2320 +
138.2321 +    /**
138.2322 +     * Analyze the negative subpattern of DecimalFormat and set/update values
138.2323 +     * as necessary.
138.2324 +     */
138.2325 +    private void checkNegativeNumberExpression() {
138.2326 +        if ((numberFormat instanceof DecimalFormat) &&
138.2327 +            !numberFormat.equals(originalNumberFormat)) {
138.2328 +            String numberPattern = ((DecimalFormat)numberFormat).toPattern();
138.2329 +            if (!numberPattern.equals(originalNumberPattern)) {
138.2330 +                hasFollowingMinusSign = false;
138.2331 +
138.2332 +                int separatorIndex = numberPattern.indexOf(';');
138.2333 +                // If the negative subpattern is not absent, we have to analayze
138.2334 +                // it in order to check if it has a following minus sign.
138.2335 +                if (separatorIndex > -1) {
138.2336 +                    int minusIndex = numberPattern.indexOf('-', separatorIndex);
138.2337 +                    if ((minusIndex > numberPattern.lastIndexOf('0')) &&
138.2338 +                        (minusIndex > numberPattern.lastIndexOf('#'))) {
138.2339 +                        hasFollowingMinusSign = true;
138.2340 +                        minusSign = ((DecimalFormat)numberFormat).getDecimalFormatSymbols().getMinusSign();
138.2341 +                    }
138.2342 +                }
138.2343 +                originalNumberPattern = numberPattern;
138.2344 +            }
138.2345 +            originalNumberFormat = numberFormat;
138.2346 +        }
138.2347 +    }
138.2348 +
138.2349 +    private static final class GregorianCalendar extends Calendar {
138.2350 +        @Override
138.2351 +        protected void computeTime() {
138.2352 +        }
138.2353 +
138.2354 +        @Override
138.2355 +        protected void computeFields() {
138.2356 +        }
138.2357 +
138.2358 +        @Override
138.2359 +        public void add(int field, int amount) {
138.2360 +        }
138.2361 +
138.2362 +        @Override
138.2363 +        public void roll(int field, boolean up) {
138.2364 +        }
138.2365 +
138.2366 +        @Override
138.2367 +        public int getMinimum(int field) {
138.2368 +            return 0;
138.2369 +        }
138.2370 +
138.2371 +        @Override
138.2372 +        public int getMaximum(int field) {
138.2373 +            return 0;
138.2374 +        }
138.2375 +
138.2376 +        @Override
138.2377 +        public int getGreatestMinimum(int field) {
138.2378 +            return 0;
138.2379 +        }
138.2380 +
138.2381 +        @Override
138.2382 +        public int getLeastMaximum(int field) {
138.2383 +            return 0;
138.2384 +        }
138.2385 +    }
138.2386 +}
   139.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   139.2 +++ b/rt/emul/compact/src/main/java/java/util/BitSet.java	Tue Feb 11 13:31:42 2014 +0100
   139.3 @@ -0,0 +1,1188 @@
   139.4 +/*
   139.5 + * Copyright (c) 1995, 2007, Oracle and/or its affiliates. All rights reserved.
   139.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   139.7 + *
   139.8 + * This code is free software; you can redistribute it and/or modify it
   139.9 + * under the terms of the GNU General Public License version 2 only, as
  139.10 + * published by the Free Software Foundation.  Oracle designates this
  139.11 + * particular file as subject to the "Classpath" exception as provided
  139.12 + * by Oracle in the LICENSE file that accompanied this code.
  139.13 + *
  139.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  139.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  139.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  139.17 + * version 2 for more details (a copy is included in the LICENSE file that
  139.18 + * accompanied this code).
  139.19 + *
  139.20 + * You should have received a copy of the GNU General Public License version
  139.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  139.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  139.23 + *
  139.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  139.25 + * or visit www.oracle.com if you need additional information or have any
  139.26 + * questions.
  139.27 + */
  139.28 +
  139.29 +package java.util;
  139.30 +
  139.31 +import java.io.*;
  139.32 +
  139.33 +/**
  139.34 + * This class implements a vector of bits that grows as needed. Each
  139.35 + * component of the bit set has a {@code boolean} value. The
  139.36 + * bits of a {@code BitSet} are indexed by nonnegative integers.
  139.37 + * Individual indexed bits can be examined, set, or cleared. One
  139.38 + * {@code BitSet} may be used to modify the contents of another
  139.39 + * {@code BitSet} through logical AND, logical inclusive OR, and
  139.40 + * logical exclusive OR operations.
  139.41 + *
  139.42 + * <p>By default, all bits in the set initially have the value
  139.43 + * {@code false}.
  139.44 + *
  139.45 + * <p>Every bit set has a current size, which is the number of bits
  139.46 + * of space currently in use by the bit set. Note that the size is
  139.47 + * related to the implementation of a bit set, so it may change with
  139.48 + * implementation. The length of a bit set relates to logical length
  139.49 + * of a bit set and is defined independently of implementation.
  139.50 + *
  139.51 + * <p>Unless otherwise noted, passing a null parameter to any of the
  139.52 + * methods in a {@code BitSet} will result in a
  139.53 + * {@code NullPointerException}.
  139.54 + *
  139.55 + * <p>A {@code BitSet} is not safe for multithreaded use without
  139.56 + * external synchronization.
  139.57 + *
  139.58 + * @author  Arthur van Hoff
  139.59 + * @author  Michael McCloskey
  139.60 + * @author  Martin Buchholz
  139.61 + * @since   JDK1.0
  139.62 + */
  139.63 +public class BitSet implements Cloneable, java.io.Serializable {
  139.64 +    /*
  139.65 +     * BitSets are packed into arrays of "words."  Currently a word is
  139.66 +     * a long, which consists of 64 bits, requiring 6 address bits.
  139.67 +     * The choice of word size is determined purely by performance concerns.
  139.68 +     */
  139.69 +    private final static int ADDRESS_BITS_PER_WORD = 6;
  139.70 +    private final static int BITS_PER_WORD = 1 << ADDRESS_BITS_PER_WORD;
  139.71 +    private final static int BIT_INDEX_MASK = BITS_PER_WORD - 1;
  139.72 +
  139.73 +    /* Used to shift left or right for a partial word mask */
  139.74 +    private static final long WORD_MASK = 0xffffffffffffffffL;
  139.75 +
  139.76 +    /**
  139.77 +     * @serialField bits long[]
  139.78 +     *
  139.79 +     * The bits in this BitSet.  The ith bit is stored in bits[i/64] at
  139.80 +     * bit position i % 64 (where bit position 0 refers to the least
  139.81 +     * significant bit and 63 refers to the most significant bit).
  139.82 +     */
  139.83 +    private static final ObjectStreamField[] serialPersistentFields = {
  139.84 +        new ObjectStreamField("bits", long[].class),
  139.85 +    };
  139.86 +
  139.87 +    /**
  139.88 +     * The internal field corresponding to the serialField "bits".
  139.89 +     */
  139.90 +    private long[] words;
  139.91 +
  139.92 +    /**
  139.93 +     * The number of words in the logical size of this BitSet.
  139.94 +     */
  139.95 +    private transient int wordsInUse = 0;
  139.96 +
  139.97 +    /**
  139.98 +     * Whether the size of "words" is user-specified.  If so, we assume
  139.99 +     * the user knows what he's doing and try harder to preserve it.
 139.100 +     */
 139.101 +    private transient boolean sizeIsSticky = false;
 139.102 +
 139.103 +    /* use serialVersionUID from JDK 1.0.2 for interoperability */
 139.104 +    private static final long serialVersionUID = 7997698588986878753L;
 139.105 +
 139.106 +    /**
 139.107 +     * Given a bit index, return word index containing it.
 139.108 +     */
 139.109 +    private static int wordIndex(int bitIndex) {
 139.110 +        return bitIndex >> ADDRESS_BITS_PER_WORD;
 139.111 +    }
 139.112 +
 139.113 +    /**
 139.114 +     * Every public method must preserve these invariants.
 139.115 +     */
 139.116 +    private void checkInvariants() {
 139.117 +        assert(wordsInUse == 0 || words[wordsInUse - 1] != 0);
 139.118 +        assert(wordsInUse >= 0 && wordsInUse <= words.length);
 139.119 +        assert(wordsInUse == words.length || words[wordsInUse] == 0);
 139.120 +    }
 139.121 +
 139.122 +    /**
 139.123 +     * Sets the field wordsInUse to the logical size in words of the bit set.
 139.124 +     * WARNING:This method assumes that the number of words actually in use is
 139.125 +     * less than or equal to the current value of wordsInUse!
 139.126 +     */
 139.127 +    private void recalculateWordsInUse() {
 139.128 +        // Traverse the bitset until a used word is found
 139.129 +        int i;
 139.130 +        for (i = wordsInUse-1; i >= 0; i--)
 139.131 +            if (words[i] != 0)
 139.132 +                break;
 139.133 +
 139.134 +        wordsInUse = i+1; // The new logical size
 139.135 +    }
 139.136 +
 139.137 +    /**
 139.138 +     * Creates a new bit set. All bits are initially {@code false}.
 139.139 +     */
 139.140 +    public BitSet() {
 139.141 +        initWords(BITS_PER_WORD);
 139.142 +        sizeIsSticky = false;
 139.143 +    }
 139.144 +
 139.145 +    /**
 139.146 +     * Creates a bit set whose initial size is large enough to explicitly
 139.147 +     * represent bits with indices in the range {@code 0} through
 139.148 +     * {@code nbits-1}. All bits are initially {@code false}.
 139.149 +     *
 139.150 +     * @param  nbits the initial size of the bit set
 139.151 +     * @throws NegativeArraySizeException if the specified initial size
 139.152 +     *         is negative
 139.153 +     */
 139.154 +    public BitSet(int nbits) {
 139.155 +        // nbits can't be negative; size 0 is OK
 139.156 +        if (nbits < 0)
 139.157 +            throw new NegativeArraySizeException("nbits < 0: " + nbits);
 139.158 +
 139.159 +        initWords(nbits);
 139.160 +        sizeIsSticky = true;
 139.161 +    }
 139.162 +
 139.163 +    private void initWords(int nbits) {
 139.164 +        words = new long[wordIndex(nbits-1) + 1];
 139.165 +    }
 139.166 +
 139.167 +    /**
 139.168 +     * Creates a bit set using words as the internal representation.
 139.169 +     * The last word (if there is one) must be non-zero.
 139.170 +     */
 139.171 +    private BitSet(long[] words) {
 139.172 +        this.words = words;
 139.173 +        this.wordsInUse = words.length;
 139.174 +        checkInvariants();
 139.175 +    }
 139.176 +
 139.177 +    /**
 139.178 +     * Returns a new bit set containing all the bits in the given long array.
 139.179 +     *
 139.180 +     * <p>More precisely,
 139.181 +     * <br>{@code BitSet.valueOf(longs).get(n) == ((longs[n/64] & (1L<<(n%64))) != 0)}
 139.182 +     * <br>for all {@code n < 64 * longs.length}.
 139.183 +     *
 139.184 +     * <p>This method is equivalent to
 139.185 +     * {@code BitSet.valueOf(LongBuffer.wrap(longs))}.
 139.186 +     *
 139.187 +     * @param longs a long array containing a little-endian representation
 139.188 +     *        of a sequence of bits to be used as the initial bits of the
 139.189 +     *        new bit set
 139.190 +     * @since 1.7
 139.191 +     */
 139.192 +    public static BitSet valueOf(long[] longs) {
 139.193 +        int n;
 139.194 +        for (n = longs.length; n > 0 && longs[n - 1] == 0; n--)
 139.195 +            ;
 139.196 +        return new BitSet(Arrays.copyOf(longs, n));
 139.197 +    }
 139.198 +
 139.199 +    /**
 139.200 +     * Returns a new bit set containing all the bits in the given long
 139.201 +     * buffer between its position and limit.
 139.202 +     *
 139.203 +     * <p>More precisely,
 139.204 +     * <br>{@code BitSet.valueOf(lb).get(n) == ((lb.get(lb.position()+n/64) & (1L<<(n%64))) != 0)}
 139.205 +     * <br>for all {@code n < 64 * lb.remaining()}.
 139.206 +     *
 139.207 +     * <p>The long buffer is not modified by this method, and no
 139.208 +     * reference to the buffer is retained by the bit set.
 139.209 +     *
 139.210 +     * @param lb a long buffer containing a little-endian representation
 139.211 +     *        of a sequence of bits between its position and limit, to be
 139.212 +     *        used as the initial bits of the new bit set
 139.213 +     * @since 1.7
 139.214 +     */
 139.215 +//    public static BitSet valueOf(LongBuffer lb) {
 139.216 +//        lb = lb.slice();
 139.217 +//        int n;
 139.218 +//        for (n = lb.remaining(); n > 0 && lb.get(n - 1) == 0; n--)
 139.219 +//            ;
 139.220 +//        long[] words = new long[n];
 139.221 +//        lb.get(words);
 139.222 +//        return new BitSet(words);
 139.223 +//    }
 139.224 +
 139.225 +    /**
 139.226 +     * Returns a new bit set containing all the bits in the given byte array.
 139.227 +     *
 139.228 +     * <p>More precisely,
 139.229 +     * <br>{@code BitSet.valueOf(bytes).get(n) == ((bytes[n/8] & (1<<(n%8))) != 0)}
 139.230 +     * <br>for all {@code n <  8 * bytes.length}.
 139.231 +     *
 139.232 +     * <p>This method is equivalent to
 139.233 +     * {@code BitSet.valueOf(ByteBuffer.wrap(bytes))}.
 139.234 +     *
 139.235 +     * @param bytes a byte array containing a little-endian
 139.236 +     *        representation of a sequence of bits to be used as the
 139.237 +     *        initial bits of the new bit set
 139.238 +     * @since 1.7
 139.239 +     */
 139.240 +//    public static BitSet valueOf(byte[] bytes) {
 139.241 +//        return BitSet.valueOf(ByteBuffer.wrap(bytes));
 139.242 +//    }
 139.243 +
 139.244 +    /**
 139.245 +     * Returns a new bit set containing all the bits in the given byte
 139.246 +     * buffer between its position and limit.
 139.247 +     *
 139.248 +     * <p>More precisely,
 139.249 +     * <br>{@code BitSet.valueOf(bb).get(n) == ((bb.get(bb.position()+n/8) & (1<<(n%8))) != 0)}
 139.250 +     * <br>for all {@code n < 8 * bb.remaining()}.
 139.251 +     *
 139.252 +     * <p>The byte buffer is not modified by this method, and no
 139.253 +     * reference to the buffer is retained by the bit set.
 139.254 +     *
 139.255 +     * @param bb a byte buffer containing a little-endian representation
 139.256 +     *        of a sequence of bits between its position and limit, to be
 139.257 +     *        used as the initial bits of the new bit set
 139.258 +     * @since 1.7
 139.259 +     */
 139.260 +//    public static BitSet valueOf(ByteBuffer bb) {
 139.261 +//        bb = bb.slice().order(ByteOrder.LITTLE_ENDIAN);
 139.262 +//        int n;
 139.263 +//        for (n = bb.remaining(); n > 0 && bb.get(n - 1) == 0; n--)
 139.264 +//            ;
 139.265 +//        long[] words = new long[(n + 7) / 8];
 139.266 +//        bb.limit(n);
 139.267 +//        int i = 0;
 139.268 +//        while (bb.remaining() >= 8)
 139.269 +//            words[i++] = bb.getLong();
 139.270 +//        for (int remaining = bb.remaining(), j = 0; j < remaining; j++)
 139.271 +//            words[i] |= (bb.get() & 0xffL) << (8 * j);
 139.272 +//        return new BitSet(words);
 139.273 +//    }
 139.274 +
 139.275 +    /**
 139.276 +     * Returns a new byte array containing all the bits in this bit set.
 139.277 +     *
 139.278 +     * <p>More precisely, if
 139.279 +     * <br>{@code byte[] bytes = s.toByteArray();}
 139.280 +     * <br>then {@code bytes.length == (s.length()+7)/8} and
 139.281 +     * <br>{@code s.get(n) == ((bytes[n/8] & (1<<(n%8))) != 0)}
 139.282 +     * <br>for all {@code n < 8 * bytes.length}.
 139.283 +     *
 139.284 +     * @return a byte array containing a little-endian representation
 139.285 +     *         of all the bits in this bit set
 139.286 +     * @since 1.7
 139.287 +    */
 139.288 +//    public byte[] toByteArray() {
 139.289 +//        int n = wordsInUse;
 139.290 +//        if (n == 0)
 139.291 +//            return new byte[0];
 139.292 +//        int len = 8 * (n-1);
 139.293 +//        for (long x = words[n - 1]; x != 0; x >>>= 8)
 139.294 +//            len++;
 139.295 +//        byte[] bytes = new byte[len];
 139.296 +//        ByteBuffer bb = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN);
 139.297 +//        for (int i = 0; i < n - 1; i++)
 139.298 +//            bb.putLong(words[i]);
 139.299 +//        for (long x = words[n - 1]; x != 0; x >>>= 8)
 139.300 +//            bb.put((byte) (x & 0xff));
 139.301 +//        return bytes;
 139.302 +//    }
 139.303 +
 139.304 +    /**
 139.305 +     * Returns a new long array containing all the bits in this bit set.
 139.306 +     *
 139.307 +     * <p>More precisely, if
 139.308 +     * <br>{@code long[] longs = s.toLongArray();}
 139.309 +     * <br>then {@code longs.length == (s.length()+63)/64} and
 139.310 +     * <br>{@code s.get(n) == ((longs[n/64] & (1L<<(n%64))) != 0)}
 139.311 +     * <br>for all {@code n < 64 * longs.length}.
 139.312 +     *
 139.313 +     * @return a long array containing a little-endian representation
 139.314 +     *         of all the bits in this bit set
 139.315 +     * @since 1.7
 139.316 +    */
 139.317 +    public long[] toLongArray() {
 139.318 +        return Arrays.copyOf(words, wordsInUse);
 139.319 +    }
 139.320 +
 139.321 +    /**
 139.322 +     * Ensures that the BitSet can hold enough words.
 139.323 +     * @param wordsRequired the minimum acceptable number of words.
 139.324 +     */
 139.325 +    private void ensureCapacity(int wordsRequired) {
 139.326 +        if (words.length < wordsRequired) {
 139.327 +            // Allocate larger of doubled size or required size
 139.328 +            int request = Math.max(2 * words.length, wordsRequired);
 139.329 +            words = Arrays.copyOf(words, request);
 139.330 +            sizeIsSticky = false;
 139.331 +        }
 139.332 +    }
 139.333 +
 139.334 +    /**
 139.335 +     * Ensures that the BitSet can accommodate a given wordIndex,
 139.336 +     * temporarily violating the invariants.  The caller must
 139.337 +     * restore the invariants before returning to the user,
 139.338 +     * possibly using recalculateWordsInUse().
 139.339 +     * @param wordIndex the index to be accommodated.
 139.340 +     */
 139.341 +    private void expandTo(int wordIndex) {
 139.342 +        int wordsRequired = wordIndex+1;
 139.343 +        if (wordsInUse < wordsRequired) {
 139.344 +            ensureCapacity(wordsRequired);
 139.345 +            wordsInUse = wordsRequired;
 139.346 +        }
 139.347 +    }
 139.348 +
 139.349 +    /**
 139.350 +     * Checks that fromIndex ... toIndex is a valid range of bit indices.
 139.351 +     */
 139.352 +    private static void checkRange(int fromIndex, int toIndex) {
 139.353 +        if (fromIndex < 0)
 139.354 +            throw new IndexOutOfBoundsException("fromIndex < 0: " + fromIndex);
 139.355 +        if (toIndex < 0)
 139.356 +            throw new IndexOutOfBoundsException("toIndex < 0: " + toIndex);
 139.357 +        if (fromIndex > toIndex)
 139.358 +            throw new IndexOutOfBoundsException("fromIndex: " + fromIndex +
 139.359 +                                                " > toIndex: " + toIndex);
 139.360 +    }
 139.361 +
 139.362 +    /**
 139.363 +     * Sets the bit at the specified index to the complement of its
 139.364 +     * current value.
 139.365 +     *
 139.366 +     * @param  bitIndex the index of the bit to flip
 139.367 +     * @throws IndexOutOfBoundsException if the specified index is negative
 139.368 +     * @since  1.4
 139.369 +     */
 139.370 +    public void flip(int bitIndex) {
 139.371 +        if (bitIndex < 0)
 139.372 +            throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex);
 139.373 +
 139.374 +        int wordIndex = wordIndex(bitIndex);
 139.375 +        expandTo(wordIndex);
 139.376 +
 139.377 +        words[wordIndex] ^= (1L << bitIndex);
 139.378 +
 139.379 +        recalculateWordsInUse();
 139.380 +        checkInvariants();
 139.381 +    }
 139.382 +
 139.383 +    /**
 139.384 +     * Sets each bit from the specified {@code fromIndex} (inclusive) to the
 139.385 +     * specified {@code toIndex} (exclusive) to the complement of its current
 139.386 +     * value.
 139.387 +     *
 139.388 +     * @param  fromIndex index of the first bit to flip
 139.389 +     * @param  toIndex index after the last bit to flip
 139.390 +     * @throws IndexOutOfBoundsException if {@code fromIndex} is negative,
 139.391 +     *         or {@code toIndex} is negative, or {@code fromIndex} is
 139.392 +     *         larger than {@code toIndex}
 139.393 +     * @since  1.4
 139.394 +     */
 139.395 +    public void flip(int fromIndex, int toIndex) {
 139.396 +        checkRange(fromIndex, toIndex);
 139.397 +
 139.398 +        if (fromIndex == toIndex)
 139.399 +            return;
 139.400 +
 139.401 +        int startWordIndex = wordIndex(fromIndex);
 139.402 +        int endWordIndex   = wordIndex(toIndex - 1);
 139.403 +        expandTo(endWordIndex);
 139.404 +
 139.405 +        long firstWordMask = WORD_MASK << fromIndex;
 139.406 +        long lastWordMask  = WORD_MASK >>> -toIndex;
 139.407 +        if (startWordIndex == endWordIndex) {
 139.408 +            // Case 1: One word
 139.409 +            words[startWordIndex] ^= (firstWordMask & lastWordMask);
 139.410 +        } else {
 139.411 +            // Case 2: Multiple words
 139.412 +            // Handle first word
 139.413 +            words[startWordIndex] ^= firstWordMask;
 139.414 +
 139.415 +            // Handle intermediate words, if any
 139.416 +            for (int i = startWordIndex+1; i < endWordIndex; i++)
 139.417 +                words[i] ^= WORD_MASK;
 139.418 +
 139.419 +            // Handle last word
 139.420 +            words[endWordIndex] ^= lastWordMask;
 139.421 +        }
 139.422 +
 139.423 +        recalculateWordsInUse();
 139.424 +        checkInvariants();
 139.425 +    }
 139.426 +
 139.427 +    /**
 139.428 +     * Sets the bit at the specified index to {@code true}.
 139.429 +     *
 139.430 +     * @param  bitIndex a bit index
 139.431 +     * @throws IndexOutOfBoundsException if the specified index is negative
 139.432 +     * @since  JDK1.0
 139.433 +     */
 139.434 +    public void set(int bitIndex) {
 139.435 +        if (bitIndex < 0)
 139.436 +            throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex);
 139.437 +
 139.438 +        int wordIndex = wordIndex(bitIndex);
 139.439 +        expandTo(wordIndex);
 139.440 +
 139.441 +        words[wordIndex] |= (1L << bitIndex); // Restores invariants
 139.442 +
 139.443 +        checkInvariants();
 139.444 +    }
 139.445 +
 139.446 +    /**
 139.447 +     * Sets the bit at the specified index to the specified value.
 139.448 +     *
 139.449 +     * @param  bitIndex a bit index
 139.450 +     * @param  value a boolean value to set
 139.451 +     * @throws IndexOutOfBoundsException if the specified index is negative
 139.452 +     * @since  1.4
 139.453 +     */
 139.454 +    public void set(int bitIndex, boolean value) {
 139.455 +        if (value)
 139.456 +            set(bitIndex);
 139.457 +        else
 139.458 +            clear(bitIndex);
 139.459 +    }
 139.460 +
 139.461 +    /**
 139.462 +     * Sets the bits from the specified {@code fromIndex} (inclusive) to the
 139.463 +     * specified {@code toIndex} (exclusive) to {@code true}.
 139.464 +     *
 139.465 +     * @param  fromIndex index of the first bit to be set
 139.466 +     * @param  toIndex index after the last bit to be set
 139.467 +     * @throws IndexOutOfBoundsException if {@code fromIndex} is negative,
 139.468 +     *         or {@code toIndex} is negative, or {@code fromIndex} is
 139.469 +     *         larger than {@code toIndex}
 139.470 +     * @since  1.4
 139.471 +     */
 139.472 +    public void set(int fromIndex, int toIndex) {
 139.473 +        checkRange(fromIndex, toIndex);
 139.474 +
 139.475 +        if (fromIndex == toIndex)
 139.476 +            return;
 139.477 +
 139.478 +        // Increase capacity if necessary
 139.479 +        int startWordIndex = wordIndex(fromIndex);
 139.480 +        int endWordIndex   = wordIndex(toIndex - 1);
 139.481 +        expandTo(endWordIndex);
 139.482 +
 139.483 +        long firstWordMask = WORD_MASK << fromIndex;
 139.484 +        long lastWordMask  = WORD_MASK >>> -toIndex;
 139.485 +        if (startWordIndex == endWordIndex) {
 139.486 +            // Case 1: One word
 139.487 +            words[startWordIndex] |= (firstWordMask & lastWordMask);
 139.488 +        } else {
 139.489 +            // Case 2: Multiple words
 139.490 +            // Handle first word
 139.491 +            words[startWordIndex] |= firstWordMask;
 139.492 +
 139.493 +            // Handle intermediate words, if any
 139.494 +            for (int i = startWordIndex+1; i < endWordIndex; i++)
 139.495 +                words[i] = WORD_MASK;
 139.496 +
 139.497 +            // Handle last word (restores invariants)
 139.498 +            words[endWordIndex] |= lastWordMask;
 139.499 +        }
 139.500 +
 139.501 +        checkInvariants();
 139.502 +    }
 139.503 +
 139.504 +    /**
 139.505 +     * Sets the bits from the specified {@code fromIndex} (inclusive) to the
 139.506 +     * specified {@code toIndex} (exclusive) to the specified value.
 139.507 +     *
 139.508 +     * @param  fromIndex index of the first bit to be set
 139.509 +     * @param  toIndex index after the last bit to be set
 139.510 +     * @param  value value to set the selected bits to
 139.511 +     * @throws IndexOutOfBoundsException if {@code fromIndex} is negative,
 139.512 +     *         or {@code toIndex} is negative, or {@code fromIndex} is
 139.513 +     *         larger than {@code toIndex}
 139.514 +     * @since  1.4
 139.515 +     */
 139.516 +    public void set(int fromIndex, int toIndex, boolean value) {
 139.517 +        if (value)
 139.518 +            set(fromIndex, toIndex);
 139.519 +        else
 139.520 +            clear(fromIndex, toIndex);
 139.521 +    }
 139.522 +
 139.523 +    /**
 139.524 +     * Sets the bit specified by the index to {@code false}.
 139.525 +     *
 139.526 +     * @param  bitIndex the index of the bit to be cleared
 139.527 +     * @throws IndexOutOfBoundsException if the specified index is negative
 139.528 +     * @since  JDK1.0
 139.529 +     */
 139.530 +    public void clear(int bitIndex) {
 139.531 +        if (bitIndex < 0)
 139.532 +            throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex);
 139.533 +
 139.534 +        int wordIndex = wordIndex(bitIndex);
 139.535 +        if (wordIndex >= wordsInUse)
 139.536 +            return;
 139.537 +
 139.538 +        words[wordIndex] &= ~(1L << bitIndex);
 139.539 +
 139.540 +        recalculateWordsInUse();
 139.541 +        checkInvariants();
 139.542 +    }
 139.543 +
 139.544 +    /**
 139.545 +     * Sets the bits from the specified {@code fromIndex} (inclusive) to the
 139.546 +     * specified {@code toIndex} (exclusive) to {@code false}.
 139.547 +     *
 139.548 +     * @param  fromIndex index of the first bit to be cleared
 139.549 +     * @param  toIndex index after the last bit to be cleared
 139.550 +     * @throws IndexOutOfBoundsException if {@code fromIndex} is negative,
 139.551 +     *         or {@code toIndex} is negative, or {@code fromIndex} is
 139.552 +     *         larger than {@code toIndex}
 139.553 +     * @since  1.4
 139.554 +     */
 139.555 +    public void clear(int fromIndex, int toIndex) {
 139.556 +        checkRange(fromIndex, toIndex);
 139.557 +
 139.558 +        if (fromIndex == toIndex)
 139.559 +            return;
 139.560 +
 139.561 +        int startWordIndex = wordIndex(fromIndex);
 139.562 +        if (startWordIndex >= wordsInUse)
 139.563 +            return;
 139.564 +
 139.565 +        int endWordIndex = wordIndex(toIndex - 1);
 139.566 +        if (endWordIndex >= wordsInUse) {
 139.567 +            toIndex = length();
 139.568 +            endWordIndex = wordsInUse - 1;
 139.569 +        }
 139.570 +
 139.571 +        long firstWordMask = WORD_MASK << fromIndex;
 139.572 +        long lastWordMask  = WORD_MASK >>> -toIndex;
 139.573 +        if (startWordIndex == endWordIndex) {
 139.574 +            // Case 1: One word
 139.575 +            words[startWordIndex] &= ~(firstWordMask & lastWordMask);
 139.576 +        } else {
 139.577 +            // Case 2: Multiple words
 139.578 +            // Handle first word
 139.579 +            words[startWordIndex] &= ~firstWordMask;
 139.580 +
 139.581 +            // Handle intermediate words, if any
 139.582 +            for (int i = startWordIndex+1; i < endWordIndex; i++)
 139.583 +                words[i] = 0;
 139.584 +
 139.585 +            // Handle last word
 139.586 +            words[endWordIndex] &= ~lastWordMask;
 139.587 +        }
 139.588 +
 139.589 +        recalculateWordsInUse();
 139.590 +        checkInvariants();
 139.591 +    }
 139.592 +
 139.593 +    /**
 139.594 +     * Sets all of the bits in this BitSet to {@code false}.
 139.595 +     *
 139.596 +     * @since 1.4
 139.597 +     */
 139.598 +    public void clear() {
 139.599 +        while (wordsInUse > 0)
 139.600 +            words[--wordsInUse] = 0;
 139.601 +    }
 139.602 +
 139.603 +    /**
 139.604 +     * Returns the value of the bit with the specified index. The value
 139.605 +     * is {@code true} if the bit with the index {@code bitIndex}
 139.606 +     * is currently set in this {@code BitSet}; otherwise, the result
 139.607 +     * is {@code false}.
 139.608 +     *
 139.609 +     * @param  bitIndex   the bit index
 139.610 +     * @return the value of the bit with the specified index
 139.611 +     * @throws IndexOutOfBoundsException if the specified index is negative
 139.612 +     */
 139.613 +    public boolean get(int bitIndex) {
 139.614 +        if (bitIndex < 0)
 139.615 +            throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex);
 139.616 +
 139.617 +        checkInvariants();
 139.618 +
 139.619 +        int wordIndex = wordIndex(bitIndex);
 139.620 +        return (wordIndex < wordsInUse)
 139.621 +            && ((words[wordIndex] & (1L << bitIndex)) != 0);
 139.622 +    }
 139.623 +
 139.624 +    /**
 139.625 +     * Returns a new {@code BitSet} composed of bits from this {@code BitSet}
 139.626 +     * from {@code fromIndex} (inclusive) to {@code toIndex} (exclusive).
 139.627 +     *
 139.628 +     * @param  fromIndex index of the first bit to include
 139.629 +     * @param  toIndex index after the last bit to include
 139.630 +     * @return a new {@code BitSet} from a range of this {@code BitSet}
 139.631 +     * @throws IndexOutOfBoundsException if {@code fromIndex} is negative,
 139.632 +     *         or {@code toIndex} is negative, or {@code fromIndex} is
 139.633 +     *         larger than {@code toIndex}
 139.634 +     * @since  1.4
 139.635 +     */
 139.636 +    public BitSet get(int fromIndex, int toIndex) {
 139.637 +        checkRange(fromIndex, toIndex);
 139.638 +
 139.639 +        checkInvariants();
 139.640 +
 139.641 +        int len = length();
 139.642 +
 139.643 +        // If no set bits in range return empty bitset
 139.644 +        if (len <= fromIndex || fromIndex == toIndex)
 139.645 +            return new BitSet(0);
 139.646 +
 139.647 +        // An optimization
 139.648 +        if (toIndex > len)
 139.649 +            toIndex = len;
 139.650 +
 139.651 +        BitSet result = new BitSet(toIndex - fromIndex);
 139.652 +        int targetWords = wordIndex(toIndex - fromIndex - 1) + 1;
 139.653 +        int sourceIndex = wordIndex(fromIndex);
 139.654 +        boolean wordAligned = ((fromIndex & BIT_INDEX_MASK) == 0);
 139.655 +
 139.656 +        // Process all words but the last word
 139.657 +        for (int i = 0; i < targetWords - 1; i++, sourceIndex++)
 139.658 +            result.words[i] = wordAligned ? words[sourceIndex] :
 139.659 +                (words[sourceIndex] >>> fromIndex) |
 139.660 +                (words[sourceIndex+1] << -fromIndex);
 139.661 +
 139.662 +        // Process the last word
 139.663 +        long lastWordMask = WORD_MASK >>> -toIndex;
 139.664 +        result.words[targetWords - 1] =
 139.665 +            ((toIndex-1) & BIT_INDEX_MASK) < (fromIndex & BIT_INDEX_MASK)
 139.666 +            ? /* straddles source words */
 139.667 +            ((words[sourceIndex] >>> fromIndex) |
 139.668 +             (words[sourceIndex+1] & lastWordMask) << -fromIndex)
 139.669 +            :
 139.670 +            ((words[sourceIndex] & lastWordMask) >>> fromIndex);
 139.671 +
 139.672 +        // Set wordsInUse correctly
 139.673 +        result.wordsInUse = targetWords;
 139.674 +        result.recalculateWordsInUse();
 139.675 +        result.checkInvariants();
 139.676 +
 139.677 +        return result;
 139.678 +    }
 139.679 +
 139.680 +    /**
 139.681 +     * Returns the index of the first bit that is set to {@code true}
 139.682 +     * that occurs on or after the specified starting index. If no such
 139.683 +     * bit exists then {@code -1} is returned.
 139.684 +     *
 139.685 +     * <p>To iterate over the {@code true} bits in a {@code BitSet},
 139.686 +     * use the following loop:
 139.687 +     *
 139.688 +     *  <pre> {@code
 139.689 +     * for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i+1)) {
 139.690 +     *     // operate on index i here
 139.691 +     * }}</pre>
 139.692 +     *
 139.693 +     * @param  fromIndex the index to start checking from (inclusive)
 139.694 +     * @return the index of the next set bit, or {@code -1} if there
 139.695 +     *         is no such bit
 139.696 +     * @throws IndexOutOfBoundsException if the specified index is negative
 139.697 +     * @since  1.4
 139.698 +     */
 139.699 +    public int nextSetBit(int fromIndex) {
 139.700 +        if (fromIndex < 0)
 139.701 +            throw new IndexOutOfBoundsException("fromIndex < 0: " + fromIndex);
 139.702 +
 139.703 +        checkInvariants();
 139.704 +
 139.705 +        int u = wordIndex(fromIndex);
 139.706 +        if (u >= wordsInUse)
 139.707 +            return -1;
 139.708 +
 139.709 +        long word = words[u] & (WORD_MASK << fromIndex);
 139.710 +
 139.711 +        while (true) {
 139.712 +            if (word != 0)
 139.713 +                return (u * BITS_PER_WORD) + Long.numberOfTrailingZeros(word);
 139.714 +            if (++u == wordsInUse)
 139.715 +                return -1;
 139.716 +            word = words[u];
 139.717 +        }
 139.718 +    }
 139.719 +
 139.720 +    /**
 139.721 +     * Returns the index of the first bit that is set to {@code false}
 139.722 +     * that occurs on or after the specified starting index.
 139.723 +     *
 139.724 +     * @param  fromIndex the index to start checking from (inclusive)
 139.725 +     * @return the index of the next clear bit
 139.726 +     * @throws IndexOutOfBoundsException if the specified index is negative
 139.727 +     * @since  1.4
 139.728 +     */
 139.729 +    public int nextClearBit(int fromIndex) {
 139.730 +        // Neither spec nor implementation handle bitsets of maximal length.
 139.731 +        // See 4816253.
 139.732 +        if (fromIndex < 0)
 139.733 +            throw new IndexOutOfBoundsException("fromIndex < 0: " + fromIndex);
 139.734 +
 139.735 +        checkInvariants();
 139.736 +
 139.737 +        int u = wordIndex(fromIndex);
 139.738 +        if (u >= wordsInUse)
 139.739 +            return fromIndex;
 139.740 +
 139.741 +        long word = ~words[u] & (WORD_MASK << fromIndex);
 139.742 +
 139.743 +        while (true) {
 139.744 +            if (word != 0)
 139.745 +                return (u * BITS_PER_WORD) + Long.numberOfTrailingZeros(word);
 139.746 +            if (++u == wordsInUse)
 139.747 +                return wordsInUse * BITS_PER_WORD;
 139.748 +            word = ~words[u];
 139.749 +        }
 139.750 +    }
 139.751 +
 139.752 +    /**
 139.753 +     * Returns the index of the nearest bit that is set to {@code true}
 139.754 +     * that occurs on or before the specified starting index.
 139.755 +     * If no such bit exists, or if {@code -1} is given as the
 139.756 +     * starting index, then {@code -1} is returned.
 139.757 +     *
 139.758 +     * <p>To iterate over the {@code true} bits in a {@code BitSet},
 139.759 +     * use the following loop:
 139.760 +     *
 139.761 +     *  <pre> {@code
 139.762 +     * for (int i = bs.length(); (i = bs.previousSetBit(i-1)) >= 0; ) {
 139.763 +     *     // operate on index i here
 139.764 +     * }}</pre>
 139.765 +     *
 139.766 +     * @param  fromIndex the index to start checking from (inclusive)
 139.767 +     * @return the index of the previous set bit, or {@code -1} if there
 139.768 +     *         is no such bit
 139.769 +     * @throws IndexOutOfBoundsException if the specified index is less
 139.770 +     *         than {@code -1}
 139.771 +     * @since  1.7
 139.772 +     */
 139.773 +    public int previousSetBit(int fromIndex) {
 139.774 +        if (fromIndex < 0) {
 139.775 +            if (fromIndex == -1)
 139.776 +                return -1;
 139.777 +            throw new IndexOutOfBoundsException(
 139.778 +                "fromIndex < -1: " + fromIndex);
 139.779 +        }
 139.780 +
 139.781 +        checkInvariants();
 139.782 +
 139.783 +        int u = wordIndex(fromIndex);
 139.784 +        if (u >= wordsInUse)
 139.785 +            return length() - 1;
 139.786 +
 139.787 +        long word = words[u] & (WORD_MASK >>> -(fromIndex+1));
 139.788 +
 139.789 +        while (true) {
 139.790 +            if (word != 0)
 139.791 +                return (u+1) * BITS_PER_WORD - 1 - Long.numberOfLeadingZeros(word);
 139.792 +            if (u-- == 0)
 139.793 +                return -1;
 139.794 +            word = words[u];
 139.795 +        }
 139.796 +    }
 139.797 +
 139.798 +    /**
 139.799 +     * Returns the index of the nearest bit that is set to {@code false}
 139.800 +     * that occurs on or before the specified starting index.
 139.801 +     * If no such bit exists, or if {@code -1} is given as the
 139.802 +     * starting index, then {@code -1} is returned.
 139.803 +     *
 139.804 +     * @param  fromIndex the index to start checking from (inclusive)
 139.805 +     * @return the index of the previous clear bit, or {@code -1} if there
 139.806 +     *         is no such bit
 139.807 +     * @throws IndexOutOfBoundsException if the specified index is less
 139.808 +     *         than {@code -1}
 139.809 +     * @since  1.7
 139.810 +     */
 139.811 +    public int previousClearBit(int fromIndex) {
 139.812 +        if (fromIndex < 0) {
 139.813 +            if (fromIndex == -1)
 139.814 +                return -1;
 139.815 +            throw new IndexOutOfBoundsException(
 139.816 +                "fromIndex < -1: " + fromIndex);
 139.817 +        }
 139.818 +
 139.819 +        checkInvariants();
 139.820 +
 139.821 +        int u = wordIndex(fromIndex);
 139.822 +        if (u >= wordsInUse)
 139.823 +            return fromIndex;
 139.824 +
 139.825 +        long word = ~words[u] & (WORD_MASK >>> -(fromIndex+1));
 139.826 +
 139.827 +        while (true) {
 139.828 +            if (word != 0)
 139.829 +                return (u+1) * BITS_PER_WORD -1 - Long.numberOfLeadingZeros(word);
 139.830 +            if (u-- == 0)
 139.831 +                return -1;
 139.832 +            word = ~words[u];
 139.833 +        }
 139.834 +    }
 139.835 +
 139.836 +    /**
 139.837 +     * Returns the "logical size" of this {@code BitSet}: the index of
 139.838 +     * the highest set bit in the {@code BitSet} plus one. Returns zero
 139.839 +     * if the {@code BitSet} contains no set bits.
 139.840 +     *
 139.841 +     * @return the logical size of this {@code BitSet}
 139.842 +     * @since  1.2
 139.843 +     */
 139.844 +    public int length() {
 139.845 +        if (wordsInUse == 0)
 139.846 +            return 0;
 139.847 +
 139.848 +        return BITS_PER_WORD * (wordsInUse - 1) +
 139.849 +            (BITS_PER_WORD - Long.numberOfLeadingZeros(words[wordsInUse - 1]));
 139.850 +    }
 139.851 +
 139.852 +    /**
 139.853 +     * Returns true if this {@code BitSet} contains no bits that are set
 139.854 +     * to {@code true}.
 139.855 +     *
 139.856 +     * @return boolean indicating whether this {@code BitSet} is empty
 139.857 +     * @since  1.4
 139.858 +     */
 139.859 +    public boolean isEmpty() {
 139.860 +        return wordsInUse == 0;
 139.861 +    }
 139.862 +
 139.863 +    /**
 139.864 +     * Returns true if the specified {@code BitSet} has any bits set to
 139.865 +     * {@code true} that are also set to {@code true} in this {@code BitSet}.
 139.866 +     *
 139.867 +     * @param  set {@code BitSet} to intersect with
 139.868 +     * @return boolean indicating whether this {@code BitSet} intersects
 139.869 +     *         the specified {@code BitSet}
 139.870 +     * @since  1.4
 139.871 +     */
 139.872 +    public boolean intersects(BitSet set) {
 139.873 +        for (int i = Math.min(wordsInUse, set.wordsInUse) - 1; i >= 0; i--)
 139.874 +            if ((words[i] & set.words[i]) != 0)
 139.875 +                return true;
 139.876 +        return false;
 139.877 +    }
 139.878 +
 139.879 +    /**
 139.880 +     * Returns the number of bits set to {@code true} in this {@code BitSet}.
 139.881 +     *
 139.882 +     * @return the number of bits set to {@code true} in this {@code BitSet}
 139.883 +     * @since  1.4
 139.884 +     */
 139.885 +    public int cardinality() {
 139.886 +        int sum = 0;
 139.887 +        for (int i = 0; i < wordsInUse; i++)
 139.888 +            sum += Long.bitCount(words[i]);
 139.889 +        return sum;
 139.890 +    }
 139.891 +
 139.892 +    /**
 139.893 +     * Performs a logical <b>AND</b> of this target bit set with the
 139.894 +     * argument bit set. This bit set is modified so that each bit in it
 139.895 +     * has the value {@code true} if and only if it both initially
 139.896 +     * had the value {@code true} and the corresponding bit in the
 139.897 +     * bit set argument also had the value {@code true}.
 139.898 +     *
 139.899 +     * @param set a bit set
 139.900 +     */
 139.901 +    public void and(BitSet set) {
 139.902 +        if (this == set)
 139.903 +            return;
 139.904 +
 139.905 +        while (wordsInUse > set.wordsInUse)
 139.906 +            words[--wordsInUse] = 0;
 139.907 +
 139.908 +        // Perform logical AND on words in common
 139.909 +        for (int i = 0; i < wordsInUse; i++)
 139.910 +            words[i] &= set.words[i];
 139.911 +
 139.912 +        recalculateWordsInUse();
 139.913 +        checkInvariants();
 139.914 +    }
 139.915 +
 139.916 +    /**
 139.917 +     * Performs a logical <b>OR</b> of this bit set with the bit set
 139.918 +     * argument. This bit set is modified so that a bit in it has the
 139.919 +     * value {@code true} if and only if it either already had the
 139.920 +     * value {@code true} or the corresponding bit in the bit set
 139.921 +     * argument has the value {@code true}.
 139.922 +     *
 139.923 +     * @param set a bit set
 139.924 +     */
 139.925 +    public void or(BitSet set) {
 139.926 +        if (this == set)
 139.927 +            return;
 139.928 +
 139.929 +        int wordsInCommon = Math.min(wordsInUse, set.wordsInUse);
 139.930 +
 139.931 +        if (wordsInUse < set.wordsInUse) {
 139.932 +            ensureCapacity(set.wordsInUse);
 139.933 +            wordsInUse = set.wordsInUse;
 139.934 +        }
 139.935 +
 139.936 +        // Perform logical OR on words in common
 139.937 +        for (int i = 0; i < wordsInCommon; i++)
 139.938 +            words[i] |= set.words[i];
 139.939 +
 139.940 +        // Copy any remaining words
 139.941 +        if (wordsInCommon < set.wordsInUse)
 139.942 +            System.arraycopy(set.words, wordsInCommon,
 139.943 +                             words, wordsInCommon,
 139.944 +                             wordsInUse - wordsInCommon);
 139.945 +
 139.946 +        // recalculateWordsInUse() is unnecessary
 139.947 +        checkInvariants();
 139.948 +    }
 139.949 +
 139.950 +    /**
 139.951 +     * Performs a logical <b>XOR</b> of this bit set with the bit set
 139.952 +     * argument. This bit set is modified so that a bit in it has the
 139.953 +     * value {@code true} if and only if one of the following
 139.954 +     * statements holds:
 139.955 +     * <ul>
 139.956 +     * <li>The bit initially has the value {@code true}, and the
 139.957 +     *     corresponding bit in the argument has the value {@code false}.
 139.958 +     * <li>The bit initially has the value {@code false}, and the
 139.959 +     *     corresponding bit in the argument has the value {@code true}.
 139.960 +     * </ul>
 139.961 +     *
 139.962 +     * @param  set a bit set
 139.963 +     */
 139.964 +    public void xor(BitSet set) {
 139.965 +        int wordsInCommon = Math.min(wordsInUse, set.wordsInUse);
 139.966 +
 139.967 +        if (wordsInUse < set.wordsInUse) {
 139.968 +            ensureCapacity(set.wordsInUse);
 139.969 +            wordsInUse = set.wordsInUse;
 139.970 +        }
 139.971 +
 139.972 +        // Perform logical XOR on words in common
 139.973 +        for (int i = 0; i < wordsInCommon; i++)
 139.974 +            words[i] ^= set.words[i];
 139.975 +
 139.976 +        // Copy any remaining words
 139.977 +        if (wordsInCommon < set.wordsInUse)
 139.978 +            System.arraycopy(set.words, wordsInCommon,
 139.979 +                             words, wordsInCommon,
 139.980 +                             set.wordsInUse - wordsInCommon);
 139.981 +
 139.982 +        recalculateWordsInUse();
 139.983 +        checkInvariants();
 139.984 +    }
 139.985 +
 139.986 +    /**
 139.987 +     * Clears all of the bits in this {@code BitSet} whose corresponding
 139.988 +     * bit is set in the specified {@code BitSet}.
 139.989 +     *
 139.990 +     * @param  set the {@code BitSet} with which to mask this
 139.991 +     *         {@code BitSet}
 139.992 +     * @since  1.2
 139.993 +     */
 139.994 +    public void andNot(BitSet set) {
 139.995 +        // Perform logical (a & !b) on words in common
 139.996 +        for (int i = Math.min(wordsInUse, set.wordsInUse) - 1; i >= 0; i--)
 139.997 +            words[i] &= ~set.words[i];
 139.998 +
 139.999 +        recalculateWordsInUse();
139.1000 +        checkInvariants();
139.1001 +    }
139.1002 +
139.1003 +    /**
139.1004 +     * Returns the hash code value for this bit set. The hash code depends
139.1005 +     * only on which bits are set within this {@code BitSet}.
139.1006 +     *
139.1007 +     * <p>The hash code is defined to be the result of the following
139.1008 +     * calculation:
139.1009 +     *  <pre> {@code
139.1010 +     * public int hashCode() {
139.1011 +     *     long h = 1234;
139.1012 +     *     long[] words = toLongArray();
139.1013 +     *     for (int i = words.length; --i >= 0; )
139.1014 +     *         h ^= words[i] * (i + 1);
139.1015 +     *     return (int)((h >> 32) ^ h);
139.1016 +     * }}</pre>
139.1017 +     * Note that the hash code changes if the set of bits is altered.
139.1018 +     *
139.1019 +     * @return the hash code value for this bit set
139.1020 +     */
139.1021 +    public int hashCode() {
139.1022 +        long h = 1234;
139.1023 +        for (int i = wordsInUse; --i >= 0; )
139.1024 +            h ^= words[i] * (i + 1);
139.1025 +
139.1026 +        return (int)((h >> 32) ^ h);
139.1027 +    }
139.1028 +
139.1029 +    /**
139.1030 +     * Returns the number of bits of space actually in use by this
139.1031 +     * {@code BitSet} to represent bit values.
139.1032 +     * The maximum element in the set is the size - 1st element.
139.1033 +     *
139.1034 +     * @return the number of bits currently in this bit set
139.1035 +     */
139.1036 +    public int size() {
139.1037 +        return words.length * BITS_PER_WORD;
139.1038 +    }
139.1039 +
139.1040 +    /**
139.1041 +     * Compares this object against the specified object.
139.1042 +     * The result is {@code true} if and only if the argument is
139.1043 +     * not {@code null} and is a {@code Bitset} object that has
139.1044 +     * exactly the same set of bits set to {@code true} as this bit
139.1045 +     * set. That is, for every nonnegative {@code int} index {@code k},
139.1046 +     * <pre>((BitSet)obj).get(k) == this.get(k)</pre>
139.1047 +     * must be true. The current sizes of the two bit sets are not compared.
139.1048 +     *
139.1049 +     * @param  obj the object to compare with
139.1050 +     * @return {@code true} if the objects are the same;
139.1051 +     *         {@code false} otherwise
139.1052 +     * @see    #size()
139.1053 +     */
139.1054 +    public boolean equals(Object obj) {
139.1055 +        if (!(obj instanceof BitSet))
139.1056 +            return false;
139.1057 +        if (this == obj)
139.1058 +            return true;
139.1059 +
139.1060 +        BitSet set = (BitSet) obj;
139.1061 +
139.1062 +        checkInvariants();
139.1063 +        set.checkInvariants();
139.1064 +
139.1065 +        if (wordsInUse != set.wordsInUse)
139.1066 +            return false;
139.1067 +
139.1068 +        // Check words in use by both BitSets
139.1069 +        for (int i = 0; i < wordsInUse; i++)
139.1070 +            if (words[i] != set.words[i])
139.1071 +                return false;
139.1072 +
139.1073 +        return true;
139.1074 +    }
139.1075 +
139.1076 +    /**
139.1077 +     * Cloning this {@code BitSet} produces a new {@code BitSet}
139.1078 +     * that is equal to it.
139.1079 +     * The clone of the bit set is another bit set that has exactly the
139.1080 +     * same bits set to {@code true} as this bit set.
139.1081 +     *
139.1082 +     * @return a clone of this bit set
139.1083 +     * @see    #size()
139.1084 +     */
139.1085 +    public Object clone() {
139.1086 +        if (! sizeIsSticky)
139.1087 +            trimToSize();
139.1088 +
139.1089 +        try {
139.1090 +            BitSet result = (BitSet) super.clone();
139.1091 +            result.words = words.clone();
139.1092 +            result.checkInvariants();
139.1093 +            return result;
139.1094 +        } catch (CloneNotSupportedException e) {
139.1095 +            throw new InternalError();
139.1096 +        }
139.1097 +    }
139.1098 +
139.1099 +    /**
139.1100 +     * Attempts to reduce internal storage used for the bits in this bit set.
139.1101 +     * Calling this method may, but is not required to, affect the value
139.1102 +     * returned by a subsequent call to the {@link #size()} method.
139.1103 +     */
139.1104 +    private void trimToSize() {
139.1105 +        if (wordsInUse != words.length) {
139.1106 +            words = Arrays.copyOf(words, wordsInUse);
139.1107 +            checkInvariants();
139.1108 +        }
139.1109 +    }
139.1110 +
139.1111 +    /**
139.1112 +     * Save the state of the {@code BitSet} instance to a stream (i.e.,
139.1113 +     * serialize it).
139.1114 +     */
139.1115 +    private void writeObject(ObjectOutputStream s)
139.1116 +        throws IOException {
139.1117 +
139.1118 +        checkInvariants();
139.1119 +
139.1120 +        if (! sizeIsSticky)
139.1121 +            trimToSize();
139.1122 +
139.1123 +        ObjectOutputStream.PutField fields = s.putFields();
139.1124 +        fields.put("bits", words);
139.1125 +        s.writeFields();
139.1126 +    }
139.1127 +
139.1128 +    /**
139.1129 +     * Reconstitute the {@code BitSet} instance from a stream (i.e.,
139.1130 +     * deserialize it).
139.1131 +     */
139.1132 +    private void readObject(ObjectInputStream s)
139.1133 +        throws IOException, ClassNotFoundException {
139.1134 +
139.1135 +        ObjectInputStream.GetField fields = s.readFields();
139.1136 +        words = (long[]) fields.get("bits", null);
139.1137 +
139.1138 +        // Assume maximum length then find real length
139.1139 +        // because recalculateWordsInUse assumes maintenance
139.1140 +        // or reduction in logical size
139.1141 +        wordsInUse = words.length;
139.1142 +        recalculateWordsInUse();
139.1143 +        sizeIsSticky = (words.length > 0 && words[words.length-1] == 0L); // heuristic
139.1144 +        checkInvariants();
139.1145 +    }
139.1146 +
139.1147 +    /**
139.1148 +     * Returns a string representation of this bit set. For every index
139.1149 +     * for which this {@code BitSet} contains a bit in the set
139.1150 +     * state, the decimal representation of that index is included in
139.1151 +     * the result. Such indices are listed in order from lowest to
139.1152 +     * highest, separated by ",&nbsp;" (a comma and a space) and
139.1153 +     * surrounded by braces, resulting in the usual mathematical
139.1154 +     * notation for a set of integers.
139.1155 +     *
139.1156 +     * <p>Example:
139.1157 +     * <pre>
139.1158 +     * BitSet drPepper = new BitSet();</pre>
139.1159 +     * Now {@code drPepper.toString()} returns "{@code {}}".<p>
139.1160 +     * <pre>
139.1161 +     * drPepper.set(2);</pre>
139.1162 +     * Now {@code drPepper.toString()} returns "{@code {2}}".<p>
139.1163 +     * <pre>
139.1164 +     * drPepper.set(4);
139.1165 +     * drPepper.set(10);</pre>
139.1166 +     * Now {@code drPepper.toString()} returns "{@code {2, 4, 10}}".
139.1167 +     *
139.1168 +     * @return a string representation of this bit set
139.1169 +     */
139.1170 +    public String toString() {
139.1171 +        checkInvariants();
139.1172 +
139.1173 +        int numBits = (wordsInUse > 128) ?
139.1174 +            cardinality() : wordsInUse * BITS_PER_WORD;
139.1175 +        StringBuilder b = new StringBuilder(6*numBits + 2);
139.1176 +        b.append('{');
139.1177 +
139.1178 +        int i = nextSetBit(0);
139.1179 +        if (i != -1) {
139.1180 +            b.append(i);
139.1181 +            for (i = nextSetBit(i+1); i >= 0; i = nextSetBit(i+1)) {
139.1182 +                int endOfRun = nextClearBit(i);
139.1183 +                do { b.append(", ").append(i); }
139.1184 +                while (++i < endOfRun);
139.1185 +            }
139.1186 +        }
139.1187 +
139.1188 +        b.append('}');
139.1189 +        return b.toString();
139.1190 +    }
139.1191 +}
   140.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   140.2 +++ b/rt/emul/compact/src/main/java/java/util/Calendar.java	Tue Feb 11 13:31:42 2014 +0100
   140.3 @@ -0,0 +1,2806 @@
   140.4 +/*
   140.5 + * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
   140.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   140.7 + *
   140.8 + * This code is free software; you can redistribute it and/or modify it
   140.9 + * under the terms of the GNU General Public License version 2 only, as
  140.10 + * published by the Free Software Foundation.  Oracle designates this
  140.11 + * particular file as subject to the "Classpath" exception as provided
  140.12 + * by Oracle in the LICENSE file that accompanied this code.
  140.13 + *
  140.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  140.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  140.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  140.17 + * version 2 for more details (a copy is included in the LICENSE file that
  140.18 + * accompanied this code).
  140.19 + *
  140.20 + * You should have received a copy of the GNU General Public License version
  140.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  140.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  140.23 + *
  140.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  140.25 + * or visit www.oracle.com if you need additional information or have any
  140.26 + * questions.
  140.27 + */
  140.28 +
  140.29 +/*
  140.30 + * (C) Copyright Taligent, Inc. 1996-1998 - All Rights Reserved
  140.31 + * (C) Copyright IBM Corp. 1996-1998 - All Rights Reserved
  140.32 + *
  140.33 + *   The original version of this source code and documentation is copyrighted
  140.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
  140.35 + * materials are provided under terms of a License Agreement between Taligent
  140.36 + * and Sun. This technology is protected by multiple US and International
  140.37 + * patents. This notice and attribution to Taligent may not be removed.
  140.38 + *   Taligent is a registered trademark of Taligent, Inc.
  140.39 + *
  140.40 + */
  140.41 +
  140.42 +package java.util;
  140.43 +
  140.44 +import java.io.IOException;
  140.45 +import java.io.ObjectInputStream;
  140.46 +import java.io.ObjectOutputStream;
  140.47 +import java.io.OptionalDataException;
  140.48 +import java.io.Serializable;
  140.49 +import java.security.AccessController;
  140.50 +import java.security.PrivilegedActionException;
  140.51 +import java.security.PrivilegedExceptionAction;
  140.52 +import java.text.DateFormat;
  140.53 +import java.text.DateFormatSymbols;
  140.54 +import java.util.concurrent.ConcurrentHashMap;
  140.55 +import java.util.concurrent.ConcurrentMap;
  140.56 +
  140.57 +/**
  140.58 + * The <code>Calendar</code> class is an abstract class that provides methods
  140.59 + * for converting between a specific instant in time and a set of {@link
  140.60 + * #fields calendar fields} such as <code>YEAR</code>, <code>MONTH</code>,
  140.61 + * <code>DAY_OF_MONTH</code>, <code>HOUR</code>, and so on, and for
  140.62 + * manipulating the calendar fields, such as getting the date of the next
  140.63 + * week. An instant in time can be represented by a millisecond value that is
  140.64 + * an offset from the <a name="Epoch"><em>Epoch</em></a>, January 1, 1970
  140.65 + * 00:00:00.000 GMT (Gregorian).
  140.66 + *
  140.67 + * <p>The class also provides additional fields and methods for
  140.68 + * implementing a concrete calendar system outside the package. Those
  140.69 + * fields and methods are defined as <code>protected</code>.
  140.70 + *
  140.71 + * <p>
  140.72 + * Like other locale-sensitive classes, <code>Calendar</code> provides a
  140.73 + * class method, <code>getInstance</code>, for getting a generally useful
  140.74 + * object of this type. <code>Calendar</code>'s <code>getInstance</code> method
  140.75 + * returns a <code>Calendar</code> object whose
  140.76 + * calendar fields have been initialized with the current date and time:
  140.77 + * <blockquote>
  140.78 + * <pre>
  140.79 + *     Calendar rightNow = Calendar.getInstance();
  140.80 + * </pre>
  140.81 + * </blockquote>
  140.82 + *
  140.83 + * <p>A <code>Calendar</code> object can produce all the calendar field values
  140.84 + * needed to implement the date-time formatting for a particular language and
  140.85 + * calendar style (for example, Japanese-Gregorian, Japanese-Traditional).
  140.86 + * <code>Calendar</code> defines the range of values returned by
  140.87 + * certain calendar fields, as well as their meaning.  For example,
  140.88 + * the first month of the calendar system has value <code>MONTH ==
  140.89 + * JANUARY</code> for all calendars.  Other values are defined by the
  140.90 + * concrete subclass, such as <code>ERA</code>.  See individual field
  140.91 + * documentation and subclass documentation for details.
  140.92 + *
  140.93 + * <h4>Getting and Setting Calendar Field Values</h4>
  140.94 + *
  140.95 + * <p>The calendar field values can be set by calling the <code>set</code>
  140.96 + * methods. Any field values set in a <code>Calendar</code> will not be
  140.97 + * interpreted until it needs to calculate its time value (milliseconds from
  140.98 + * the Epoch) or values of the calendar fields. Calling the
  140.99 + * <code>get</code>, <code>getTimeInMillis</code>, <code>getTime</code>,
 140.100 + * <code>add</code> and <code>roll</code> involves such calculation.
 140.101 + *
 140.102 + * <h4>Leniency</h4>
 140.103 + *
 140.104 + * <p><code>Calendar</code> has two modes for interpreting the calendar
 140.105 + * fields, <em>lenient</em> and <em>non-lenient</em>.  When a
 140.106 + * <code>Calendar</code> is in lenient mode, it accepts a wider range of
 140.107 + * calendar field values than it produces.  When a <code>Calendar</code>
 140.108 + * recomputes calendar field values for return by <code>get()</code>, all of
 140.109 + * the calendar fields are normalized. For example, a lenient
 140.110 + * <code>GregorianCalendar</code> interprets <code>MONTH == JANUARY</code>,
 140.111 + * <code>DAY_OF_MONTH == 32</code> as February 1.
 140.112 +
 140.113 + * <p>When a <code>Calendar</code> is in non-lenient mode, it throws an
 140.114 + * exception if there is any inconsistency in its calendar fields. For
 140.115 + * example, a <code>GregorianCalendar</code> always produces
 140.116 + * <code>DAY_OF_MONTH</code> values between 1 and the length of the month. A
 140.117 + * non-lenient <code>GregorianCalendar</code> throws an exception upon
 140.118 + * calculating its time or calendar field values if any out-of-range field
 140.119 + * value has been set.
 140.120 + *
 140.121 + * <h4><a name="first_week">First Week</a></h4>
 140.122 + *
 140.123 + * <code>Calendar</code> defines a locale-specific seven day week using two
 140.124 + * parameters: the first day of the week and the minimal days in first week
 140.125 + * (from 1 to 7).  These numbers are taken from the locale resource data when a
 140.126 + * <code>Calendar</code> is constructed.  They may also be specified explicitly
 140.127 + * through the methods for setting their values.
 140.128 + *
 140.129 + * <p>When setting or getting the <code>WEEK_OF_MONTH</code> or
 140.130 + * <code>WEEK_OF_YEAR</code> fields, <code>Calendar</code> must determine the
 140.131 + * first week of the month or year as a reference point.  The first week of a
 140.132 + * month or year is defined as the earliest seven day period beginning on
 140.133 + * <code>getFirstDayOfWeek()</code> and containing at least
 140.134 + * <code>getMinimalDaysInFirstWeek()</code> days of that month or year.  Weeks
 140.135 + * numbered ..., -1, 0 precede the first week; weeks numbered 2, 3,... follow
 140.136 + * it.  Note that the normalized numbering returned by <code>get()</code> may be
 140.137 + * different.  For example, a specific <code>Calendar</code> subclass may
 140.138 + * designate the week before week 1 of a year as week <code><i>n</i></code> of
 140.139 + * the previous year.
 140.140 + *
 140.141 + * <h4>Calendar Fields Resolution</h4>
 140.142 + *
 140.143 + * When computing a date and time from the calendar fields, there
 140.144 + * may be insufficient information for the computation (such as only
 140.145 + * year and month with no day of month), or there may be inconsistent
 140.146 + * information (such as Tuesday, July 15, 1996 (Gregorian) -- July 15,
 140.147 + * 1996 is actually a Monday). <code>Calendar</code> will resolve
 140.148 + * calendar field values to determine the date and time in the
 140.149 + * following way.
 140.150 + *
 140.151 + * <p>If there is any conflict in calendar field values,
 140.152 + * <code>Calendar</code> gives priorities to calendar fields that have been set
 140.153 + * more recently. The following are the default combinations of the
 140.154 + * calendar fields. The most recent combination, as determined by the
 140.155 + * most recently set single field, will be used.
 140.156 + *
 140.157 + * <p><a name="date_resolution">For the date fields</a>:
 140.158 + * <blockquote>
 140.159 + * <pre>
 140.160 + * YEAR + MONTH + DAY_OF_MONTH
 140.161 + * YEAR + MONTH + WEEK_OF_MONTH + DAY_OF_WEEK
 140.162 + * YEAR + MONTH + DAY_OF_WEEK_IN_MONTH + DAY_OF_WEEK
 140.163 + * YEAR + DAY_OF_YEAR
 140.164 + * YEAR + DAY_OF_WEEK + WEEK_OF_YEAR
 140.165 + * </pre></blockquote>
 140.166 + *
 140.167 + * <a name="time_resolution">For the time of day fields</a>:
 140.168 + * <blockquote>
 140.169 + * <pre>
 140.170 + * HOUR_OF_DAY
 140.171 + * AM_PM + HOUR
 140.172 + * </pre></blockquote>
 140.173 + *
 140.174 + * <p>If there are any calendar fields whose values haven't been set in the selected
 140.175 + * field combination, <code>Calendar</code> uses their default values. The default
 140.176 + * value of each field may vary by concrete calendar systems. For example, in
 140.177 + * <code>GregorianCalendar</code>, the default of a field is the same as that
 140.178 + * of the start of the Epoch: i.e., <code>YEAR = 1970</code>, <code>MONTH =
 140.179 + * JANUARY</code>, <code>DAY_OF_MONTH = 1</code>, etc.
 140.180 + *
 140.181 + * <p>
 140.182 + * <strong>Note:</strong> There are certain possible ambiguities in
 140.183 + * interpretation of certain singular times, which are resolved in the
 140.184 + * following ways:
 140.185 + * <ol>
 140.186 + *     <li> 23:59 is the last minute of the day and 00:00 is the first
 140.187 + *          minute of the next day. Thus, 23:59 on Dec 31, 1999 &lt; 00:00 on
 140.188 + *          Jan 1, 2000 &lt; 00:01 on Jan 1, 2000.
 140.189 + *
 140.190 + *     <li> Although historically not precise, midnight also belongs to "am",
 140.191 + *          and noon belongs to "pm", so on the same day,
 140.192 + *          12:00 am (midnight) &lt; 12:01 am, and 12:00 pm (noon) &lt; 12:01 pm
 140.193 + * </ol>
 140.194 + *
 140.195 + * <p>
 140.196 + * The date or time format strings are not part of the definition of a
 140.197 + * calendar, as those must be modifiable or overridable by the user at
 140.198 + * runtime. Use {@link DateFormat}
 140.199 + * to format dates.
 140.200 + *
 140.201 + * <h4>Field Manipulation</h4>
 140.202 + *
 140.203 + * The calendar fields can be changed using three methods:
 140.204 + * <code>set()</code>, <code>add()</code>, and <code>roll()</code>.</p>
 140.205 + *
 140.206 + * <p><strong><code>set(f, value)</code></strong> changes calendar field
 140.207 + * <code>f</code> to <code>value</code>.  In addition, it sets an
 140.208 + * internal member variable to indicate that calendar field <code>f</code> has
 140.209 + * been changed. Although calendar field <code>f</code> is changed immediately,
 140.210 + * the calendar's time value in milliseconds is not recomputed until the next call to
 140.211 + * <code>get()</code>, <code>getTime()</code>, <code>getTimeInMillis()</code>,
 140.212 + * <code>add()</code>, or <code>roll()</code> is made. Thus, multiple calls to
 140.213 + * <code>set()</code> do not trigger multiple, unnecessary
 140.214 + * computations. As a result of changing a calendar field using
 140.215 + * <code>set()</code>, other calendar fields may also change, depending on the
 140.216 + * calendar field, the calendar field value, and the calendar system. In addition,
 140.217 + * <code>get(f)</code> will not necessarily return <code>value</code> set by
 140.218 + * the call to the <code>set</code> method
 140.219 + * after the calendar fields have been recomputed. The specifics are determined by
 140.220 + * the concrete calendar class.</p>
 140.221 + *
 140.222 + * <p><em>Example</em>: Consider a <code>GregorianCalendar</code>
 140.223 + * originally set to August 31, 1999. Calling <code>set(Calendar.MONTH,
 140.224 + * Calendar.SEPTEMBER)</code> sets the date to September 31,
 140.225 + * 1999. This is a temporary internal representation that resolves to
 140.226 + * October 1, 1999 if <code>getTime()</code>is then called. However, a
 140.227 + * call to <code>set(Calendar.DAY_OF_MONTH, 30)</code> before the call to
 140.228 + * <code>getTime()</code> sets the date to September 30, 1999, since
 140.229 + * no recomputation occurs after <code>set()</code> itself.</p>
 140.230 + *
 140.231 + * <p><strong><code>add(f, delta)</code></strong> adds <code>delta</code>
 140.232 + * to field <code>f</code>.  This is equivalent to calling <code>set(f,
 140.233 + * get(f) + delta)</code> with two adjustments:</p>
 140.234 + *
 140.235 + * <blockquote>
 140.236 + *   <p><strong>Add rule 1</strong>. The value of field <code>f</code>
 140.237 + *   after the call minus the value of field <code>f</code> before the
 140.238 + *   call is <code>delta</code>, modulo any overflow that has occurred in
 140.239 + *   field <code>f</code>. Overflow occurs when a field value exceeds its
 140.240 + *   range and, as a result, the next larger field is incremented or
 140.241 + *   decremented and the field value is adjusted back into its range.</p>
 140.242 + *
 140.243 + *   <p><strong>Add rule 2</strong>. If a smaller field is expected to be
 140.244 + *   invariant, but it is impossible for it to be equal to its
 140.245 + *   prior value because of changes in its minimum or maximum after field
 140.246 + *   <code>f</code> is changed or other constraints, such as time zone
 140.247 + *   offset changes, then its value is adjusted to be as close
 140.248 + *   as possible to its expected value. A smaller field represents a
 140.249 + *   smaller unit of time. <code>HOUR</code> is a smaller field than
 140.250 + *   <code>DAY_OF_MONTH</code>. No adjustment is made to smaller fields
 140.251 + *   that are not expected to be invariant. The calendar system
 140.252 + *   determines what fields are expected to be invariant.</p>
 140.253 + * </blockquote>
 140.254 + *
 140.255 + * <p>In addition, unlike <code>set()</code>, <code>add()</code> forces
 140.256 + * an immediate recomputation of the calendar's milliseconds and all
 140.257 + * fields.</p>
 140.258 + *
 140.259 + * <p><em>Example</em>: Consider a <code>GregorianCalendar</code>
 140.260 + * originally set to August 31, 1999. Calling <code>add(Calendar.MONTH,
 140.261 + * 13)</code> sets the calendar to September 30, 2000. <strong>Add rule
 140.262 + * 1</strong> sets the <code>MONTH</code> field to September, since
 140.263 + * adding 13 months to August gives September of the next year. Since
 140.264 + * <code>DAY_OF_MONTH</code> cannot be 31 in September in a
 140.265 + * <code>GregorianCalendar</code>, <strong>add rule 2</strong> sets the
 140.266 + * <code>DAY_OF_MONTH</code> to 30, the closest possible value. Although
 140.267 + * it is a smaller field, <code>DAY_OF_WEEK</code> is not adjusted by
 140.268 + * rule 2, since it is expected to change when the month changes in a
 140.269 + * <code>GregorianCalendar</code>.</p>
 140.270 + *
 140.271 + * <p><strong><code>roll(f, delta)</code></strong> adds
 140.272 + * <code>delta</code> to field <code>f</code> without changing larger
 140.273 + * fields. This is equivalent to calling <code>add(f, delta)</code> with
 140.274 + * the following adjustment:</p>
 140.275 + *
 140.276 + * <blockquote>
 140.277 + *   <p><strong>Roll rule</strong>. Larger fields are unchanged after the
 140.278 + *   call. A larger field represents a larger unit of
 140.279 + *   time. <code>DAY_OF_MONTH</code> is a larger field than
 140.280 + *   <code>HOUR</code>.</p>
 140.281 + * </blockquote>
 140.282 + *
 140.283 + * <p><em>Example</em>: See {@link java.util.GregorianCalendar#roll(int, int)}.
 140.284 + *
 140.285 + * <p><strong>Usage model</strong>. To motivate the behavior of
 140.286 + * <code>add()</code> and <code>roll()</code>, consider a user interface
 140.287 + * component with increment and decrement buttons for the month, day, and
 140.288 + * year, and an underlying <code>GregorianCalendar</code>. If the
 140.289 + * interface reads January 31, 1999 and the user presses the month
 140.290 + * increment button, what should it read? If the underlying
 140.291 + * implementation uses <code>set()</code>, it might read March 3, 1999. A
 140.292 + * better result would be February 28, 1999. Furthermore, if the user
 140.293 + * presses the month increment button again, it should read March 31,
 140.294 + * 1999, not March 28, 1999. By saving the original date and using either
 140.295 + * <code>add()</code> or <code>roll()</code>, depending on whether larger
 140.296 + * fields should be affected, the user interface can behave as most users
 140.297 + * will intuitively expect.</p>
 140.298 + *
 140.299 + * @see          java.lang.System#currentTimeMillis()
 140.300 + * @see          Date
 140.301 + * @see          GregorianCalendar
 140.302 + * @see          TimeZone
 140.303 + * @see          java.text.DateFormat
 140.304 + * @author Mark Davis, David Goldsmith, Chen-Lieh Huang, Alan Liu
 140.305 + * @since JDK1.1
 140.306 + */
 140.307 +public abstract class Calendar implements Serializable, Cloneable, Comparable<Calendar> {
 140.308 +
 140.309 +    // Data flow in Calendar
 140.310 +    // ---------------------
 140.311 +
 140.312 +    // The current time is represented in two ways by Calendar: as UTC
 140.313 +    // milliseconds from the epoch (1 January 1970 0:00 UTC), and as local
 140.314 +    // fields such as MONTH, HOUR, AM_PM, etc.  It is possible to compute the
 140.315 +    // millis from the fields, and vice versa.  The data needed to do this
 140.316 +    // conversion is encapsulated by a TimeZone object owned by the Calendar.
 140.317 +    // The data provided by the TimeZone object may also be overridden if the
 140.318 +    // user sets the ZONE_OFFSET and/or DST_OFFSET fields directly. The class
 140.319 +    // keeps track of what information was most recently set by the caller, and
 140.320 +    // uses that to compute any other information as needed.
 140.321 +
 140.322 +    // If the user sets the fields using set(), the data flow is as follows.
 140.323 +    // This is implemented by the Calendar subclass's computeTime() method.
 140.324 +    // During this process, certain fields may be ignored.  The disambiguation
 140.325 +    // algorithm for resolving which fields to pay attention to is described
 140.326 +    // in the class documentation.
 140.327 +
 140.328 +    //   local fields (YEAR, MONTH, DATE, HOUR, MINUTE, etc.)
 140.329 +    //           |
 140.330 +    //           | Using Calendar-specific algorithm
 140.331 +    //           V
 140.332 +    //   local standard millis
 140.333 +    //           |
 140.334 +    //           | Using TimeZone or user-set ZONE_OFFSET / DST_OFFSET
 140.335 +    //           V
 140.336 +    //   UTC millis (in time data member)
 140.337 +
 140.338 +    // If the user sets the UTC millis using setTime() or setTimeInMillis(),
 140.339 +    // the data flow is as follows.  This is implemented by the Calendar
 140.340 +    // subclass's computeFields() method.
 140.341 +
 140.342 +    //   UTC millis (in time data member)
 140.343 +    //           |
 140.344 +    //           | Using TimeZone getOffset()
 140.345 +    //           V
 140.346 +    //   local standard millis
 140.347 +    //           |
 140.348 +    //           | Using Calendar-specific algorithm
 140.349 +    //           V
 140.350 +    //   local fields (YEAR, MONTH, DATE, HOUR, MINUTE, etc.)
 140.351 +
 140.352 +    // In general, a round trip from fields, through local and UTC millis, and
 140.353 +    // back out to fields is made when necessary.  This is implemented by the
 140.354 +    // complete() method.  Resolving a partial set of fields into a UTC millis
 140.355 +    // value allows all remaining fields to be generated from that value.  If
 140.356 +    // the Calendar is lenient, the fields are also renormalized to standard
 140.357 +    // ranges when they are regenerated.
 140.358 +
 140.359 +    /**
 140.360 +     * Field number for <code>get</code> and <code>set</code> indicating the
 140.361 +     * era, e.g., AD or BC in the Julian calendar. This is a calendar-specific
 140.362 +     * value; see subclass documentation.
 140.363 +     *
 140.364 +     * @see GregorianCalendar#AD
 140.365 +     * @see GregorianCalendar#BC
 140.366 +     */
 140.367 +    public final static int ERA = 0;
 140.368 +
 140.369 +    /**
 140.370 +     * Field number for <code>get</code> and <code>set</code> indicating the
 140.371 +     * year. This is a calendar-specific value; see subclass documentation.
 140.372 +     */
 140.373 +    public final static int YEAR = 1;
 140.374 +
 140.375 +    /**
 140.376 +     * Field number for <code>get</code> and <code>set</code> indicating the
 140.377 +     * month. This is a calendar-specific value. The first month of
 140.378 +     * the year in the Gregorian and Julian calendars is
 140.379 +     * <code>JANUARY</code> which is 0; the last depends on the number
 140.380 +     * of months in a year.
 140.381 +     *
 140.382 +     * @see #JANUARY
 140.383 +     * @see #FEBRUARY
 140.384 +     * @see #MARCH
 140.385 +     * @see #APRIL
 140.386 +     * @see #MAY
 140.387 +     * @see #JUNE
 140.388 +     * @see #JULY
 140.389 +     * @see #AUGUST
 140.390 +     * @see #SEPTEMBER
 140.391 +     * @see #OCTOBER
 140.392 +     * @see #NOVEMBER
 140.393 +     * @see #DECEMBER
 140.394 +     * @see #UNDECIMBER
 140.395 +     */
 140.396 +    public final static int MONTH = 2;
 140.397 +
 140.398 +    /**
 140.399 +     * Field number for <code>get</code> and <code>set</code> indicating the
 140.400 +     * week number within the current year.  The first week of the year, as
 140.401 +     * defined by <code>getFirstDayOfWeek()</code> and
 140.402 +     * <code>getMinimalDaysInFirstWeek()</code>, has value 1.  Subclasses define
 140.403 +     * the value of <code>WEEK_OF_YEAR</code> for days before the first week of
 140.404 +     * the year.
 140.405 +     *
 140.406 +     * @see #getFirstDayOfWeek
 140.407 +     * @see #getMinimalDaysInFirstWeek
 140.408 +     */
 140.409 +    public final static int WEEK_OF_YEAR = 3;
 140.410 +
 140.411 +    /**
 140.412 +     * Field number for <code>get</code> and <code>set</code> indicating the
 140.413 +     * week number within the current month.  The first week of the month, as
 140.414 +     * defined by <code>getFirstDayOfWeek()</code> and
 140.415 +     * <code>getMinimalDaysInFirstWeek()</code>, has value 1.  Subclasses define
 140.416 +     * the value of <code>WEEK_OF_MONTH</code> for days before the first week of
 140.417 +     * the month.
 140.418 +     *
 140.419 +     * @see #getFirstDayOfWeek
 140.420 +     * @see #getMinimalDaysInFirstWeek
 140.421 +     */
 140.422 +    public final static int WEEK_OF_MONTH = 4;
 140.423 +
 140.424 +    /**
 140.425 +     * Field number for <code>get</code> and <code>set</code> indicating the
 140.426 +     * day of the month. This is a synonym for <code>DAY_OF_MONTH</code>.
 140.427 +     * The first day of the month has value 1.
 140.428 +     *
 140.429 +     * @see #DAY_OF_MONTH
 140.430 +     */
 140.431 +    public final static int DATE = 5;
 140.432 +
 140.433 +    /**
 140.434 +     * Field number for <code>get</code> and <code>set</code> indicating the
 140.435 +     * day of the month. This is a synonym for <code>DATE</code>.
 140.436 +     * The first day of the month has value 1.
 140.437 +     *
 140.438 +     * @see #DATE
 140.439 +     */
 140.440 +    public final static int DAY_OF_MONTH = 5;
 140.441 +
 140.442 +    /**
 140.443 +     * Field number for <code>get</code> and <code>set</code> indicating the day
 140.444 +     * number within the current year.  The first day of the year has value 1.
 140.445 +     */
 140.446 +    public final static int DAY_OF_YEAR = 6;
 140.447 +
 140.448 +    /**
 140.449 +     * Field number for <code>get</code> and <code>set</code> indicating the day
 140.450 +     * of the week.  This field takes values <code>SUNDAY</code>,
 140.451 +     * <code>MONDAY</code>, <code>TUESDAY</code>, <code>WEDNESDAY</code>,
 140.452 +     * <code>THURSDAY</code>, <code>FRIDAY</code>, and <code>SATURDAY</code>.
 140.453 +     *
 140.454 +     * @see #SUNDAY
 140.455 +     * @see #MONDAY
 140.456 +     * @see #TUESDAY
 140.457 +     * @see #WEDNESDAY
 140.458 +     * @see #THURSDAY
 140.459 +     * @see #FRIDAY
 140.460 +     * @see #SATURDAY
 140.461 +     */
 140.462 +    public final static int DAY_OF_WEEK = 7;
 140.463 +
 140.464 +    /**
 140.465 +     * Field number for <code>get</code> and <code>set</code> indicating the
 140.466 +     * ordinal number of the day of the week within the current month. Together
 140.467 +     * with the <code>DAY_OF_WEEK</code> field, this uniquely specifies a day
 140.468 +     * within a month.  Unlike <code>WEEK_OF_MONTH</code> and
 140.469 +     * <code>WEEK_OF_YEAR</code>, this field's value does <em>not</em> depend on
 140.470 +     * <code>getFirstDayOfWeek()</code> or
 140.471 +     * <code>getMinimalDaysInFirstWeek()</code>.  <code>DAY_OF_MONTH 1</code>
 140.472 +     * through <code>7</code> always correspond to <code>DAY_OF_WEEK_IN_MONTH
 140.473 +     * 1</code>; <code>8</code> through <code>14</code> correspond to
 140.474 +     * <code>DAY_OF_WEEK_IN_MONTH 2</code>, and so on.
 140.475 +     * <code>DAY_OF_WEEK_IN_MONTH 0</code> indicates the week before
 140.476 +     * <code>DAY_OF_WEEK_IN_MONTH 1</code>.  Negative values count back from the
 140.477 +     * end of the month, so the last Sunday of a month is specified as
 140.478 +     * <code>DAY_OF_WEEK = SUNDAY, DAY_OF_WEEK_IN_MONTH = -1</code>.  Because
 140.479 +     * negative values count backward they will usually be aligned differently
 140.480 +     * within the month than positive values.  For example, if a month has 31
 140.481 +     * days, <code>DAY_OF_WEEK_IN_MONTH -1</code> will overlap
 140.482 +     * <code>DAY_OF_WEEK_IN_MONTH 5</code> and the end of <code>4</code>.
 140.483 +     *
 140.484 +     * @see #DAY_OF_WEEK
 140.485 +     * @see #WEEK_OF_MONTH
 140.486 +     */
 140.487 +    public final static int DAY_OF_WEEK_IN_MONTH = 8;
 140.488 +
 140.489 +    /**
 140.490 +     * Field number for <code>get</code> and <code>set</code> indicating
 140.491 +     * whether the <code>HOUR</code> is before or after noon.
 140.492 +     * E.g., at 10:04:15.250 PM the <code>AM_PM</code> is <code>PM</code>.
 140.493 +     *
 140.494 +     * @see #AM
 140.495 +     * @see #PM
 140.496 +     * @see #HOUR
 140.497 +     */
 140.498 +    public final static int AM_PM = 9;
 140.499 +
 140.500 +    /**
 140.501 +     * Field number for <code>get</code> and <code>set</code> indicating the
 140.502 +     * hour of the morning or afternoon. <code>HOUR</code> is used for the
 140.503 +     * 12-hour clock (0 - 11). Noon and midnight are represented by 0, not by 12.
 140.504 +     * E.g., at 10:04:15.250 PM the <code>HOUR</code> is 10.
 140.505 +     *
 140.506 +     * @see #AM_PM
 140.507 +     * @see #HOUR_OF_DAY
 140.508 +     */
 140.509 +    public final static int HOUR = 10;
 140.510 +
 140.511 +    /**
 140.512 +     * Field number for <code>get</code> and <code>set</code> indicating the
 140.513 +     * hour of the day. <code>HOUR_OF_DAY</code> is used for the 24-hour clock.
 140.514 +     * E.g., at 10:04:15.250 PM the <code>HOUR_OF_DAY</code> is 22.
 140.515 +     *
 140.516 +     * @see #HOUR
 140.517 +     */
 140.518 +    public final static int HOUR_OF_DAY = 11;
 140.519 +
 140.520 +    /**
 140.521 +     * Field number for <code>get</code> and <code>set</code> indicating the
 140.522 +     * minute within the hour.
 140.523 +     * E.g., at 10:04:15.250 PM the <code>MINUTE</code> is 4.
 140.524 +     */
 140.525 +    public final static int MINUTE = 12;
 140.526 +
 140.527 +    /**
 140.528 +     * Field number for <code>get</code> and <code>set</code> indicating the
 140.529 +     * second within the minute.
 140.530 +     * E.g., at 10:04:15.250 PM the <code>SECOND</code> is 15.
 140.531 +     */
 140.532 +    public final static int SECOND = 13;
 140.533 +
 140.534 +    /**
 140.535 +     * Field number for <code>get</code> and <code>set</code> indicating the
 140.536 +     * millisecond within the second.
 140.537 +     * E.g., at 10:04:15.250 PM the <code>MILLISECOND</code> is 250.
 140.538 +     */
 140.539 +    public final static int MILLISECOND = 14;
 140.540 +
 140.541 +    /**
 140.542 +     * Field number for <code>get</code> and <code>set</code>
 140.543 +     * indicating the raw offset from GMT in milliseconds.
 140.544 +     * <p>
 140.545 +     * This field reflects the correct GMT offset value of the time
 140.546 +     * zone of this <code>Calendar</code> if the
 140.547 +     * <code>TimeZone</code> implementation subclass supports
 140.548 +     * historical GMT offset changes.
 140.549 +     */
 140.550 +    public final static int ZONE_OFFSET = 15;
 140.551 +
 140.552 +    /**
 140.553 +     * Field number for <code>get</code> and <code>set</code> indicating the
 140.554 +     * daylight saving offset in milliseconds.
 140.555 +     * <p>
 140.556 +     * This field reflects the correct daylight saving offset value of
 140.557 +     * the time zone of this <code>Calendar</code> if the
 140.558 +     * <code>TimeZone</code> implementation subclass supports
 140.559 +     * historical Daylight Saving Time schedule changes.
 140.560 +     */
 140.561 +    public final static int DST_OFFSET = 16;
 140.562 +
 140.563 +    /**
 140.564 +     * The number of distinct fields recognized by <code>get</code> and <code>set</code>.
 140.565 +     * Field numbers range from <code>0..FIELD_COUNT-1</code>.
 140.566 +     */
 140.567 +    public final static int FIELD_COUNT = 17;
 140.568 +
 140.569 +    /**
 140.570 +     * Value of the {@link #DAY_OF_WEEK} field indicating
 140.571 +     * Sunday.
 140.572 +     */
 140.573 +    public final static int SUNDAY = 1;
 140.574 +
 140.575 +    /**
 140.576 +     * Value of the {@link #DAY_OF_WEEK} field indicating
 140.577 +     * Monday.
 140.578 +     */
 140.579 +    public final static int MONDAY = 2;
 140.580 +
 140.581 +    /**
 140.582 +     * Value of the {@link #DAY_OF_WEEK} field indicating
 140.583 +     * Tuesday.
 140.584 +     */
 140.585 +    public final static int TUESDAY = 3;
 140.586 +
 140.587 +    /**
 140.588 +     * Value of the {@link #DAY_OF_WEEK} field indicating
 140.589 +     * Wednesday.
 140.590 +     */
 140.591 +    public final static int WEDNESDAY = 4;
 140.592 +
 140.593 +    /**
 140.594 +     * Value of the {@link #DAY_OF_WEEK} field indicating
 140.595 +     * Thursday.
 140.596 +     */
 140.597 +    public final static int THURSDAY = 5;
 140.598 +
 140.599 +    /**
 140.600 +     * Value of the {@link #DAY_OF_WEEK} field indicating
 140.601 +     * Friday.
 140.602 +     */
 140.603 +    public final static int FRIDAY = 6;
 140.604 +
 140.605 +    /**
 140.606 +     * Value of the {@link #DAY_OF_WEEK} field indicating
 140.607 +     * Saturday.
 140.608 +     */
 140.609 +    public final static int SATURDAY = 7;
 140.610 +
 140.611 +    /**
 140.612 +     * Value of the {@link #MONTH} field indicating the
 140.613 +     * first month of the year in the Gregorian and Julian calendars.
 140.614 +     */
 140.615 +    public final static int JANUARY = 0;
 140.616 +
 140.617 +    /**
 140.618 +     * Value of the {@link #MONTH} field indicating the
 140.619 +     * second month of the year in the Gregorian and Julian calendars.
 140.620 +     */
 140.621 +    public final static int FEBRUARY = 1;
 140.622 +
 140.623 +    /**
 140.624 +     * Value of the {@link #MONTH} field indicating the
 140.625 +     * third month of the year in the Gregorian and Julian calendars.
 140.626 +     */
 140.627 +    public final static int MARCH = 2;
 140.628 +
 140.629 +    /**
 140.630 +     * Value of the {@link #MONTH} field indicating the
 140.631 +     * fourth month of the year in the Gregorian and Julian calendars.
 140.632 +     */
 140.633 +    public final static int APRIL = 3;
 140.634 +
 140.635 +    /**
 140.636 +     * Value of the {@link #MONTH} field indicating the
 140.637 +     * fifth month of the year in the Gregorian and Julian calendars.
 140.638 +     */
 140.639 +    public final static int MAY = 4;
 140.640 +
 140.641 +    /**
 140.642 +     * Value of the {@link #MONTH} field indicating the
 140.643 +     * sixth month of the year in the Gregorian and Julian calendars.
 140.644 +     */
 140.645 +    public final static int JUNE = 5;
 140.646 +
 140.647 +    /**
 140.648 +     * Value of the {@link #MONTH} field indicating the
 140.649 +     * seventh month of the year in the Gregorian and Julian calendars.
 140.650 +     */
 140.651 +    public final static int JULY = 6;
 140.652 +
 140.653 +    /**
 140.654 +     * Value of the {@link #MONTH} field indicating the
 140.655 +     * eighth month of the year in the Gregorian and Julian calendars.
 140.656 +     */
 140.657 +    public final static int AUGUST = 7;
 140.658 +
 140.659 +    /**
 140.660 +     * Value of the {@link #MONTH} field indicating the
 140.661 +     * ninth month of the year in the Gregorian and Julian calendars.
 140.662 +     */
 140.663 +    public final static int SEPTEMBER = 8;
 140.664 +
 140.665 +    /**
 140.666 +     * Value of the {@link #MONTH} field indicating the
 140.667 +     * tenth month of the year in the Gregorian and Julian calendars.
 140.668 +     */
 140.669 +    public final static int OCTOBER = 9;
 140.670 +
 140.671 +    /**
 140.672 +     * Value of the {@link #MONTH} field indicating the
 140.673 +     * eleventh month of the year in the Gregorian and Julian calendars.
 140.674 +     */
 140.675 +    public final static int NOVEMBER = 10;
 140.676 +
 140.677 +    /**
 140.678 +     * Value of the {@link #MONTH} field indicating the
 140.679 +     * twelfth month of the year in the Gregorian and Julian calendars.
 140.680 +     */
 140.681 +    public final static int DECEMBER = 11;
 140.682 +
 140.683 +    /**
 140.684 +     * Value of the {@link #MONTH} field indicating the
 140.685 +     * thirteenth month of the year. Although <code>GregorianCalendar</code>
 140.686 +     * does not use this value, lunar calendars do.
 140.687 +     */
 140.688 +    public final static int UNDECIMBER = 12;
 140.689 +
 140.690 +    /**
 140.691 +     * Value of the {@link #AM_PM} field indicating the
 140.692 +     * period of the day from midnight to just before noon.
 140.693 +     */
 140.694 +    public final static int AM = 0;
 140.695 +
 140.696 +    /**
 140.697 +     * Value of the {@link #AM_PM} field indicating the
 140.698 +     * period of the day from noon to just before midnight.
 140.699 +     */
 140.700 +    public final static int PM = 1;
 140.701 +
 140.702 +    /**
 140.703 +     * A style specifier for {@link #getDisplayNames(int, int, Locale)
 140.704 +     * getDisplayNames} indicating names in all styles, such as
 140.705 +     * "January" and "Jan".
 140.706 +     *
 140.707 +     * @see #SHORT
 140.708 +     * @see #LONG
 140.709 +     * @since 1.6
 140.710 +     */
 140.711 +    public static final int ALL_STYLES = 0;
 140.712 +
 140.713 +    /**
 140.714 +     * A style specifier for {@link #getDisplayName(int, int, Locale)
 140.715 +     * getDisplayName} and {@link #getDisplayNames(int, int, Locale)
 140.716 +     * getDisplayNames} indicating a short name, such as "Jan".
 140.717 +     *
 140.718 +     * @see #LONG
 140.719 +     * @since 1.6
 140.720 +     */
 140.721 +    public static final int SHORT = 1;
 140.722 +
 140.723 +    /**
 140.724 +     * A style specifier for {@link #getDisplayName(int, int, Locale)
 140.725 +     * getDisplayName} and {@link #getDisplayNames(int, int, Locale)
 140.726 +     * getDisplayNames} indicating a long name, such as "January".
 140.727 +     *
 140.728 +     * @see #SHORT
 140.729 +     * @since 1.6
 140.730 +     */
 140.731 +    public static final int LONG = 2;
 140.732 +
 140.733 +    // Internal notes:
 140.734 +    // Calendar contains two kinds of time representations: current "time" in
 140.735 +    // milliseconds, and a set of calendar "fields" representing the current time.
 140.736 +    // The two representations are usually in sync, but can get out of sync
 140.737 +    // as follows.
 140.738 +    // 1. Initially, no fields are set, and the time is invalid.
 140.739 +    // 2. If the time is set, all fields are computed and in sync.
 140.740 +    // 3. If a single field is set, the time is invalid.
 140.741 +    // Recomputation of the time and fields happens when the object needs
 140.742 +    // to return a result to the user, or use a result for a computation.
 140.743 +
 140.744 +    /**
 140.745 +     * The calendar field values for the currently set time for this calendar.
 140.746 +     * This is an array of <code>FIELD_COUNT</code> integers, with index values
 140.747 +     * <code>ERA</code> through <code>DST_OFFSET</code>.
 140.748 +     * @serial
 140.749 +     */
 140.750 +    protected int           fields[];
 140.751 +
 140.752 +    /**
 140.753 +     * The flags which tell if a specified calendar field for the calendar is set.
 140.754 +     * A new object has no fields set.  After the first call to a method
 140.755 +     * which generates the fields, they all remain set after that.
 140.756 +     * This is an array of <code>FIELD_COUNT</code> booleans, with index values
 140.757 +     * <code>ERA</code> through <code>DST_OFFSET</code>.
 140.758 +     * @serial
 140.759 +     */
 140.760 +    protected boolean       isSet[];
 140.761 +
 140.762 +    /**
 140.763 +     * Pseudo-time-stamps which specify when each field was set. There
 140.764 +     * are two special values, UNSET and COMPUTED. Values from
 140.765 +     * MINIMUM_USER_SET to Integer.MAX_VALUE are legal user set values.
 140.766 +     */
 140.767 +    transient private int   stamp[];
 140.768 +
 140.769 +    /**
 140.770 +     * The currently set time for this calendar, expressed in milliseconds after
 140.771 +     * January 1, 1970, 0:00:00 GMT.
 140.772 +     * @see #isTimeSet
 140.773 +     * @serial
 140.774 +     */
 140.775 +    protected long          time;
 140.776 +
 140.777 +    /**
 140.778 +     * True if then the value of <code>time</code> is valid.
 140.779 +     * The time is made invalid by a change to an item of <code>field[]</code>.
 140.780 +     * @see #time
 140.781 +     * @serial
 140.782 +     */
 140.783 +    protected boolean       isTimeSet;
 140.784 +
 140.785 +    /**
 140.786 +     * True if <code>fields[]</code> are in sync with the currently set time.
 140.787 +     * If false, then the next attempt to get the value of a field will
 140.788 +     * force a recomputation of all fields from the current value of
 140.789 +     * <code>time</code>.
 140.790 +     * @serial
 140.791 +     */
 140.792 +    protected boolean       areFieldsSet;
 140.793 +
 140.794 +    /**
 140.795 +     * True if all fields have been set.
 140.796 +     * @serial
 140.797 +     */
 140.798 +    transient boolean       areAllFieldsSet;
 140.799 +
 140.800 +    /**
 140.801 +     * <code>True</code> if this calendar allows out-of-range field values during computation
 140.802 +     * of <code>time</code> from <code>fields[]</code>.
 140.803 +     * @see #setLenient
 140.804 +     * @see #isLenient
 140.805 +     * @serial
 140.806 +     */
 140.807 +    private boolean         lenient = true;
 140.808 +
 140.809 +    /**
 140.810 +     * The <code>TimeZone</code> used by this calendar. <code>Calendar</code>
 140.811 +     * uses the time zone data to translate between locale and GMT time.
 140.812 +     * @serial
 140.813 +     */
 140.814 +    private TimeZone        zone;
 140.815 +
 140.816 +    /**
 140.817 +     * <code>True</code> if zone references to a shared TimeZone object.
 140.818 +     */
 140.819 +    transient private boolean sharedZone = false;
 140.820 +
 140.821 +    /**
 140.822 +     * The first day of the week, with possible values <code>SUNDAY</code>,
 140.823 +     * <code>MONDAY</code>, etc.  This is a locale-dependent value.
 140.824 +     * @serial
 140.825 +     */
 140.826 +    private int             firstDayOfWeek;
 140.827 +
 140.828 +    /**
 140.829 +     * The number of days required for the first week in a month or year,
 140.830 +     * with possible values from 1 to 7.  This is a locale-dependent value.
 140.831 +     * @serial
 140.832 +     */
 140.833 +    private int             minimalDaysInFirstWeek;
 140.834 +
 140.835 +    /**
 140.836 +     * Cache to hold the firstDayOfWeek and minimalDaysInFirstWeek
 140.837 +     * of a Locale.
 140.838 +     */
 140.839 +    private static final ConcurrentMap<Locale, int[]> cachedLocaleData
 140.840 +        = new ConcurrentHashMap<Locale, int[]>(3);
 140.841 +
 140.842 +    // Special values of stamp[]
 140.843 +    /**
 140.844 +     * The corresponding fields[] has no value.
 140.845 +     */
 140.846 +    private static final int        UNSET = 0;
 140.847 +
 140.848 +    /**
 140.849 +     * The value of the corresponding fields[] has been calculated internally.
 140.850 +     */
 140.851 +    private static final int        COMPUTED = 1;
 140.852 +
 140.853 +    /**
 140.854 +     * The value of the corresponding fields[] has been set externally. Stamp
 140.855 +     * values which are greater than 1 represents the (pseudo) time when the
 140.856 +     * corresponding fields[] value was set.
 140.857 +     */
 140.858 +    private static final int        MINIMUM_USER_STAMP = 2;
 140.859 +
 140.860 +    /**
 140.861 +     * The mask value that represents all of the fields.
 140.862 +     */
 140.863 +    static final int ALL_FIELDS = (1 << FIELD_COUNT) - 1;
 140.864 +
 140.865 +    /**
 140.866 +     * The next available value for <code>stamp[]</code>, an internal array.
 140.867 +     * This actually should not be written out to the stream, and will probably
 140.868 +     * be removed from the stream in the near future.  In the meantime,
 140.869 +     * a value of <code>MINIMUM_USER_STAMP</code> should be used.
 140.870 +     * @serial
 140.871 +     */
 140.872 +    private int             nextStamp = MINIMUM_USER_STAMP;
 140.873 +
 140.874 +    // the internal serial version which says which version was written
 140.875 +    // - 0 (default) for version up to JDK 1.1.5
 140.876 +    // - 1 for version from JDK 1.1.6, which writes a correct 'time' value
 140.877 +    //     as well as compatible values for other fields.  This is a
 140.878 +    //     transitional format.
 140.879 +    // - 2 (not implemented yet) a future version, in which fields[],
 140.880 +    //     areFieldsSet, and isTimeSet become transient, and isSet[] is
 140.881 +    //     removed. In JDK 1.1.6 we write a format compatible with version 2.
 140.882 +    static final int        currentSerialVersion = 1;
 140.883 +
 140.884 +    /**
 140.885 +     * The version of the serialized data on the stream.  Possible values:
 140.886 +     * <dl>
 140.887 +     * <dt><b>0</b> or not present on stream</dt>
 140.888 +     * <dd>
 140.889 +     * JDK 1.1.5 or earlier.
 140.890 +     * </dd>
 140.891 +     * <dt><b>1</b></dt>
 140.892 +     * <dd>
 140.893 +     * JDK 1.1.6 or later.  Writes a correct 'time' value
 140.894 +     * as well as compatible values for other fields.  This is a
 140.895 +     * transitional format.
 140.896 +     * </dd>
 140.897 +     * </dl>
 140.898 +     * When streaming out this class, the most recent format
 140.899 +     * and the highest allowable <code>serialVersionOnStream</code>
 140.900 +     * is written.
 140.901 +     * @serial
 140.902 +     * @since JDK1.1.6
 140.903 +     */
 140.904 +    private int             serialVersionOnStream = currentSerialVersion;
 140.905 +
 140.906 +    // Proclaim serialization compatibility with JDK 1.1
 140.907 +    static final long       serialVersionUID = -1807547505821590642L;
 140.908 +
 140.909 +    // Mask values for calendar fields
 140.910 +    final static int ERA_MASK           = (1 << ERA);
 140.911 +    final static int YEAR_MASK          = (1 << YEAR);
 140.912 +    final static int MONTH_MASK         = (1 << MONTH);
 140.913 +    final static int WEEK_OF_YEAR_MASK  = (1 << WEEK_OF_YEAR);
 140.914 +    final static int WEEK_OF_MONTH_MASK = (1 << WEEK_OF_MONTH);
 140.915 +    final static int DAY_OF_MONTH_MASK  = (1 << DAY_OF_MONTH);
 140.916 +    final static int DATE_MASK          = DAY_OF_MONTH_MASK;
 140.917 +    final static int DAY_OF_YEAR_MASK   = (1 << DAY_OF_YEAR);
 140.918 +    final static int DAY_OF_WEEK_MASK   = (1 << DAY_OF_WEEK);
 140.919 +    final static int DAY_OF_WEEK_IN_MONTH_MASK  = (1 << DAY_OF_WEEK_IN_MONTH);
 140.920 +    final static int AM_PM_MASK         = (1 << AM_PM);
 140.921 +    final static int HOUR_MASK          = (1 << HOUR);
 140.922 +    final static int HOUR_OF_DAY_MASK   = (1 << HOUR_OF_DAY);
 140.923 +    final static int MINUTE_MASK        = (1 << MINUTE);
 140.924 +    final static int SECOND_MASK        = (1 << SECOND);
 140.925 +    final static int MILLISECOND_MASK   = (1 << MILLISECOND);
 140.926 +    final static int ZONE_OFFSET_MASK   = (1 << ZONE_OFFSET);
 140.927 +    final static int DST_OFFSET_MASK    = (1 << DST_OFFSET);
 140.928 +
 140.929 +    /**
 140.930 +     * Constructs a Calendar with the default time zone
 140.931 +     * and locale.
 140.932 +     * @see     TimeZone#getDefault
 140.933 +     */
 140.934 +    protected Calendar()
 140.935 +    {
 140.936 +        this(TimeZone.getDefaultRef(), Locale.getDefault(Locale.Category.FORMAT));
 140.937 +        sharedZone = true;
 140.938 +    }
 140.939 +
 140.940 +    /**
 140.941 +     * Constructs a calendar with the specified time zone and locale.
 140.942 +     *
 140.943 +     * @param zone the time zone to use
 140.944 +     * @param aLocale the locale for the week data
 140.945 +     */
 140.946 +    protected Calendar(TimeZone zone, Locale aLocale)
 140.947 +    {
 140.948 +        fields = new int[FIELD_COUNT];
 140.949 +        isSet = new boolean[FIELD_COUNT];
 140.950 +        stamp = new int[FIELD_COUNT];
 140.951 +
 140.952 +        this.zone = zone;
 140.953 +        setWeekCountData(aLocale);
 140.954 +    }
 140.955 +
 140.956 +    /**
 140.957 +     * Gets a calendar using the default time zone and locale. The
 140.958 +     * <code>Calendar</code> returned is based on the current time
 140.959 +     * in the default time zone with the default locale.
 140.960 +     *
 140.961 +     * @return a Calendar.
 140.962 +     */
 140.963 +    public static Calendar getInstance()
 140.964 +    {
 140.965 +        Calendar cal = createCalendar(TimeZone.getDefaultRef(), Locale.getDefault(Locale.Category.FORMAT));
 140.966 +        cal.sharedZone = true;
 140.967 +        return cal;
 140.968 +    }
 140.969 +
 140.970 +    /**
 140.971 +     * Gets a calendar using the specified time zone and default locale.
 140.972 +     * The <code>Calendar</code> returned is based on the current time
 140.973 +     * in the given time zone with the default locale.
 140.974 +     *
 140.975 +     * @param zone the time zone to use
 140.976 +     * @return a Calendar.
 140.977 +     */
 140.978 +    public static Calendar getInstance(TimeZone zone)
 140.979 +    {
 140.980 +        return createCalendar(zone, Locale.getDefault(Locale.Category.FORMAT));
 140.981 +    }
 140.982 +
 140.983 +    /**
 140.984 +     * Gets a calendar using the default time zone and specified locale.
 140.985 +     * The <code>Calendar</code> returned is based on the current time
 140.986 +     * in the default time zone with the given locale.
 140.987 +     *
 140.988 +     * @param aLocale the locale for the week data
 140.989 +     * @return a Calendar.
 140.990 +     */
 140.991 +    public static Calendar getInstance(Locale aLocale)
 140.992 +    {
 140.993 +        Calendar cal = createCalendar(TimeZone.getDefaultRef(), aLocale);
 140.994 +        cal.sharedZone = true;
 140.995 +        return cal;
 140.996 +    }
 140.997 +
 140.998 +    /**
 140.999 +     * Gets a calendar with the specified time zone and locale.
140.1000 +     * The <code>Calendar</code> returned is based on the current time
140.1001 +     * in the given time zone with the given locale.
140.1002 +     *
140.1003 +     * @param zone the time zone to use
140.1004 +     * @param aLocale the locale for the week data
140.1005 +     * @return a Calendar.
140.1006 +     */
140.1007 +    public static Calendar getInstance(TimeZone zone,
140.1008 +                                       Locale aLocale)
140.1009 +    {
140.1010 +        return createCalendar(zone, aLocale);
140.1011 +    }
140.1012 +
140.1013 +    private static Calendar createCalendar(TimeZone zone,
140.1014 +                                           Locale aLocale)
140.1015 +    {
140.1016 +        Calendar cal = null;
140.1017 +
140.1018 +        String caltype = aLocale.getUnicodeLocaleType("ca");
140.1019 +        if (caltype == null) {
140.1020 +            // Calendar type is not specified.
140.1021 +            // If the specified locale is a Thai locale,
140.1022 +            // returns a BuddhistCalendar instance.
140.1023 +            if ("th".equals(aLocale.getLanguage())
140.1024 +                    && ("TH".equals(aLocale.getCountry()))) {
140.1025 +//                cal = new BuddhistCalendar(zone, aLocale);
140.1026 +            } else {
140.1027 +//                cal = new GregorianCalendar(zone, aLocale);
140.1028 +            }
140.1029 +        } else if (caltype.equals("japanese")) {
140.1030 +//            cal = new JapaneseImperialCalendar(zone, aLocale);
140.1031 +        } else if (caltype.equals("buddhist")) {
140.1032 +//            cal = new BuddhistCalendar(zone, aLocale);
140.1033 +        } else {
140.1034 +            // Unsupported calendar type.
140.1035 +            // Use Gregorian calendar as a fallback.
140.1036 +//            cal = new GregorianCalendar(zone, aLocale);
140.1037 +        }
140.1038 +
140.1039 +        return cal;
140.1040 +    }
140.1041 +
140.1042 +    /**
140.1043 +     * Returns an array of all locales for which the <code>getInstance</code>
140.1044 +     * methods of this class can return localized instances.
140.1045 +     * The array returned must contain at least a <code>Locale</code>
140.1046 +     * instance equal to {@link java.util.Locale#US Locale.US}.
140.1047 +     *
140.1048 +     * @return An array of locales for which localized
140.1049 +     *         <code>Calendar</code> instances are available.
140.1050 +     */
140.1051 +    public static synchronized Locale[] getAvailableLocales()
140.1052 +    {
140.1053 +        return DateFormat.getAvailableLocales();
140.1054 +    }
140.1055 +
140.1056 +    /**
140.1057 +     * Converts the current calendar field values in {@link #fields fields[]}
140.1058 +     * to the millisecond time value
140.1059 +     * {@link #time}.
140.1060 +     *
140.1061 +     * @see #complete()
140.1062 +     * @see #computeFields()
140.1063 +     */
140.1064 +    protected abstract void computeTime();
140.1065 +
140.1066 +    /**
140.1067 +     * Converts the current millisecond time value {@link #time}
140.1068 +     * to calendar field values in {@link #fields fields[]}.
140.1069 +     * This allows you to sync up the calendar field values with
140.1070 +     * a new time that is set for the calendar.  The time is <em>not</em>
140.1071 +     * recomputed first; to recompute the time, then the fields, call the
140.1072 +     * {@link #complete()} method.
140.1073 +     *
140.1074 +     * @see #computeTime()
140.1075 +     */
140.1076 +    protected abstract void computeFields();
140.1077 +
140.1078 +    /**
140.1079 +     * Returns a <code>Date</code> object representing this
140.1080 +     * <code>Calendar</code>'s time value (millisecond offset from the <a
140.1081 +     * href="#Epoch">Epoch</a>").
140.1082 +     *
140.1083 +     * @return a <code>Date</code> representing the time value.
140.1084 +     * @see #setTime(Date)
140.1085 +     * @see #getTimeInMillis()
140.1086 +     */
140.1087 +    public final Date getTime() {
140.1088 +        return new Date(getTimeInMillis());
140.1089 +    }
140.1090 +
140.1091 +    /**
140.1092 +     * Sets this Calendar's time with the given <code>Date</code>.
140.1093 +     * <p>
140.1094 +     * Note: Calling <code>setTime()</code> with
140.1095 +     * <code>Date(Long.MAX_VALUE)</code> or <code>Date(Long.MIN_VALUE)</code>
140.1096 +     * may yield incorrect field values from <code>get()</code>.
140.1097 +     *
140.1098 +     * @param date the given Date.
140.1099 +     * @see #getTime()
140.1100 +     * @see #setTimeInMillis(long)
140.1101 +     */
140.1102 +    public final void setTime(Date date) {
140.1103 +        setTimeInMillis(date.getTime());
140.1104 +    }
140.1105 +
140.1106 +    /**
140.1107 +     * Returns this Calendar's time value in milliseconds.
140.1108 +     *
140.1109 +     * @return the current time as UTC milliseconds from the epoch.
140.1110 +     * @see #getTime()
140.1111 +     * @see #setTimeInMillis(long)
140.1112 +     */
140.1113 +    public long getTimeInMillis() {
140.1114 +        if (!isTimeSet) {
140.1115 +            updateTime();
140.1116 +        }
140.1117 +        return time;
140.1118 +    }
140.1119 +
140.1120 +    /**
140.1121 +     * Sets this Calendar's current time from the given long value.
140.1122 +     *
140.1123 +     * @param millis the new time in UTC milliseconds from the epoch.
140.1124 +     * @see #setTime(Date)
140.1125 +     * @see #getTimeInMillis()
140.1126 +     */
140.1127 +    public void setTimeInMillis(long millis) {
140.1128 +        // If we don't need to recalculate the calendar field values,
140.1129 +        // do nothing.
140.1130 +//        if (time == millis && isTimeSet && areFieldsSet && areAllFieldsSet
140.1131 +//            && (zone instanceof ZoneInfo) && !((ZoneInfo)zone).isDirty()) {
140.1132 +//            return;
140.1133 +//        }
140.1134 +        time = millis;
140.1135 +        isTimeSet = true;
140.1136 +        areFieldsSet = false;
140.1137 +        computeFields();
140.1138 +        areAllFieldsSet = areFieldsSet = true;
140.1139 +    }
140.1140 +
140.1141 +    /**
140.1142 +     * Returns the value of the given calendar field. In lenient mode,
140.1143 +     * all calendar fields are normalized. In non-lenient mode, all
140.1144 +     * calendar fields are validated and this method throws an
140.1145 +     * exception if any calendar fields have out-of-range values. The
140.1146 +     * normalization and validation are handled by the
140.1147 +     * {@link #complete()} method, which process is calendar
140.1148 +     * system dependent.
140.1149 +     *
140.1150 +     * @param field the given calendar field.
140.1151 +     * @return the value for the given calendar field.
140.1152 +     * @throws ArrayIndexOutOfBoundsException if the specified field is out of range
140.1153 +     *             (<code>field &lt; 0 || field &gt;= FIELD_COUNT</code>).
140.1154 +     * @see #set(int,int)
140.1155 +     * @see #complete()
140.1156 +     */
140.1157 +    public int get(int field)
140.1158 +    {
140.1159 +        complete();
140.1160 +        return internalGet(field);
140.1161 +    }
140.1162 +
140.1163 +    /**
140.1164 +     * Returns the value of the given calendar field. This method does
140.1165 +     * not involve normalization or validation of the field value.
140.1166 +     *
140.1167 +     * @param field the given calendar field.
140.1168 +     * @return the value for the given calendar field.
140.1169 +     * @see #get(int)
140.1170 +     */
140.1171 +    protected final int internalGet(int field)
140.1172 +    {
140.1173 +        return fields[field];
140.1174 +    }
140.1175 +
140.1176 +    /**
140.1177 +     * Sets the value of the given calendar field. This method does
140.1178 +     * not affect any setting state of the field in this
140.1179 +     * <code>Calendar</code> instance.
140.1180 +     *
140.1181 +     * @throws IndexOutOfBoundsException if the specified field is out of range
140.1182 +     *             (<code>field &lt; 0 || field &gt;= FIELD_COUNT</code>).
140.1183 +     * @see #areFieldsSet
140.1184 +     * @see #isTimeSet
140.1185 +     * @see #areAllFieldsSet
140.1186 +     * @see #set(int,int)
140.1187 +     */
140.1188 +    final void internalSet(int field, int value)
140.1189 +    {
140.1190 +        fields[field] = value;
140.1191 +    }
140.1192 +
140.1193 +    /**
140.1194 +     * Sets the given calendar field to the given value. The value is not
140.1195 +     * interpreted by this method regardless of the leniency mode.
140.1196 +     *
140.1197 +     * @param field the given calendar field.
140.1198 +     * @param value the value to be set for the given calendar field.
140.1199 +     * @throws ArrayIndexOutOfBoundsException if the specified field is out of range
140.1200 +     *             (<code>field &lt; 0 || field &gt;= FIELD_COUNT</code>).
140.1201 +     * in non-lenient mode.
140.1202 +     * @see #set(int,int,int)
140.1203 +     * @see #set(int,int,int,int,int)
140.1204 +     * @see #set(int,int,int,int,int,int)
140.1205 +     * @see #get(int)
140.1206 +     */
140.1207 +    public void set(int field, int value)
140.1208 +    {
140.1209 +        // If the fields are partially normalized, calculate all the
140.1210 +        // fields before changing any fields.
140.1211 +        if (areFieldsSet && !areAllFieldsSet) {
140.1212 +            computeFields();
140.1213 +        }
140.1214 +        internalSet(field, value);
140.1215 +        isTimeSet = false;
140.1216 +        areFieldsSet = false;
140.1217 +        isSet[field] = true;
140.1218 +        stamp[field] = nextStamp++;
140.1219 +        if (nextStamp == Integer.MAX_VALUE) {
140.1220 +            adjustStamp();
140.1221 +        }
140.1222 +    }
140.1223 +
140.1224 +    /**
140.1225 +     * Sets the values for the calendar fields <code>YEAR</code>,
140.1226 +     * <code>MONTH</code>, and <code>DAY_OF_MONTH</code>.
140.1227 +     * Previous values of other calendar fields are retained.  If this is not desired,
140.1228 +     * call {@link #clear()} first.
140.1229 +     *
140.1230 +     * @param year the value used to set the <code>YEAR</code> calendar field.
140.1231 +     * @param month the value used to set the <code>MONTH</code> calendar field.
140.1232 +     * Month value is 0-based. e.g., 0 for January.
140.1233 +     * @param date the value used to set the <code>DAY_OF_MONTH</code> calendar field.
140.1234 +     * @see #set(int,int)
140.1235 +     * @see #set(int,int,int,int,int)
140.1236 +     * @see #set(int,int,int,int,int,int)
140.1237 +     */
140.1238 +    public final void set(int year, int month, int date)
140.1239 +    {
140.1240 +        set(YEAR, year);
140.1241 +        set(MONTH, month);
140.1242 +        set(DATE, date);
140.1243 +    }
140.1244 +
140.1245 +    /**
140.1246 +     * Sets the values for the calendar fields <code>YEAR</code>,
140.1247 +     * <code>MONTH</code>, <code>DAY_OF_MONTH</code>,
140.1248 +     * <code>HOUR_OF_DAY</code>, and <code>MINUTE</code>.
140.1249 +     * Previous values of other fields are retained.  If this is not desired,
140.1250 +     * call {@link #clear()} first.
140.1251 +     *
140.1252 +     * @param year the value used to set the <code>YEAR</code> calendar field.
140.1253 +     * @param month the value used to set the <code>MONTH</code> calendar field.
140.1254 +     * Month value is 0-based. e.g., 0 for January.
140.1255 +     * @param date the value used to set the <code>DAY_OF_MONTH</code> calendar field.
140.1256 +     * @param hourOfDay the value used to set the <code>HOUR_OF_DAY</code> calendar field.
140.1257 +     * @param minute the value used to set the <code>MINUTE</code> calendar field.
140.1258 +     * @see #set(int,int)
140.1259 +     * @see #set(int,int,int)
140.1260 +     * @see #set(int,int,int,int,int,int)
140.1261 +     */
140.1262 +    public final void set(int year, int month, int date, int hourOfDay, int minute)
140.1263 +    {
140.1264 +        set(YEAR, year);
140.1265 +        set(MONTH, month);
140.1266 +        set(DATE, date);
140.1267 +        set(HOUR_OF_DAY, hourOfDay);
140.1268 +        set(MINUTE, minute);
140.1269 +    }
140.1270 +
140.1271 +    /**
140.1272 +     * Sets the values for the fields <code>YEAR</code>, <code>MONTH</code>,
140.1273 +     * <code>DAY_OF_MONTH</code>, <code>HOUR</code>, <code>MINUTE</code>, and
140.1274 +     * <code>SECOND</code>.
140.1275 +     * Previous values of other fields are retained.  If this is not desired,
140.1276 +     * call {@link #clear()} first.
140.1277 +     *
140.1278 +     * @param year the value used to set the <code>YEAR</code> calendar field.
140.1279 +     * @param month the value used to set the <code>MONTH</code> calendar field.
140.1280 +     * Month value is 0-based. e.g., 0 for January.
140.1281 +     * @param date the value used to set the <code>DAY_OF_MONTH</code> calendar field.
140.1282 +     * @param hourOfDay the value used to set the <code>HOUR_OF_DAY</code> calendar field.
140.1283 +     * @param minute the value used to set the <code>MINUTE</code> calendar field.
140.1284 +     * @param second the value used to set the <code>SECOND</code> calendar field.
140.1285 +     * @see #set(int,int)
140.1286 +     * @see #set(int,int,int)
140.1287 +     * @see #set(int,int,int,int,int)
140.1288 +     */
140.1289 +    public final void set(int year, int month, int date, int hourOfDay, int minute,
140.1290 +                          int second)
140.1291 +    {
140.1292 +        set(YEAR, year);
140.1293 +        set(MONTH, month);
140.1294 +        set(DATE, date);
140.1295 +        set(HOUR_OF_DAY, hourOfDay);
140.1296 +        set(MINUTE, minute);
140.1297 +        set(SECOND, second);
140.1298 +    }
140.1299 +
140.1300 +    /**
140.1301 +     * Sets all the calendar field values and the time value
140.1302 +     * (millisecond offset from the <a href="#Epoch">Epoch</a>) of
140.1303 +     * this <code>Calendar</code> undefined. This means that {@link
140.1304 +     * #isSet(int) isSet()} will return <code>false</code> for all the
140.1305 +     * calendar fields, and the date and time calculations will treat
140.1306 +     * the fields as if they had never been set. A
140.1307 +     * <code>Calendar</code> implementation class may use its specific
140.1308 +     * default field values for date/time calculations. For example,
140.1309 +     * <code>GregorianCalendar</code> uses 1970 if the
140.1310 +     * <code>YEAR</code> field value is undefined.
140.1311 +     *
140.1312 +     * @see #clear(int)
140.1313 +     */
140.1314 +    public final void clear()
140.1315 +    {
140.1316 +        for (int i = 0; i < fields.length; ) {
140.1317 +            stamp[i] = fields[i] = 0; // UNSET == 0
140.1318 +            isSet[i++] = false;
140.1319 +        }
140.1320 +        areAllFieldsSet = areFieldsSet = false;
140.1321 +        isTimeSet = false;
140.1322 +    }
140.1323 +
140.1324 +    /**
140.1325 +     * Sets the given calendar field value and the time value
140.1326 +     * (millisecond offset from the <a href="#Epoch">Epoch</a>) of
140.1327 +     * this <code>Calendar</code> undefined. This means that {@link
140.1328 +     * #isSet(int) isSet(field)} will return <code>false</code>, and
140.1329 +     * the date and time calculations will treat the field as if it
140.1330 +     * had never been set. A <code>Calendar</code> implementation
140.1331 +     * class may use the field's specific default value for date and
140.1332 +     * time calculations.
140.1333 +     *
140.1334 +     * <p>The {@link #HOUR_OF_DAY}, {@link #HOUR} and {@link #AM_PM}
140.1335 +     * fields are handled independently and the <a
140.1336 +     * href="#time_resolution">the resolution rule for the time of
140.1337 +     * day</a> is applied. Clearing one of the fields doesn't reset
140.1338 +     * the hour of day value of this <code>Calendar</code>. Use {@link
140.1339 +     * #set(int,int) set(Calendar.HOUR_OF_DAY, 0)} to reset the hour
140.1340 +     * value.
140.1341 +     *
140.1342 +     * @param field the calendar field to be cleared.
140.1343 +     * @see #clear()
140.1344 +     */
140.1345 +    public final void clear(int field)
140.1346 +    {
140.1347 +        fields[field] = 0;
140.1348 +        stamp[field] = UNSET;
140.1349 +        isSet[field] = false;
140.1350 +
140.1351 +        areAllFieldsSet = areFieldsSet = false;
140.1352 +        isTimeSet = false;
140.1353 +    }
140.1354 +
140.1355 +    /**
140.1356 +     * Determines if the given calendar field has a value set,
140.1357 +     * including cases that the value has been set by internal fields
140.1358 +     * calculations triggered by a <code>get</code> method call.
140.1359 +     *
140.1360 +     * @return <code>true</code> if the given calendar field has a value set;
140.1361 +     * <code>false</code> otherwise.
140.1362 +     */
140.1363 +    public final boolean isSet(int field)
140.1364 +    {
140.1365 +        return stamp[field] != UNSET;
140.1366 +    }
140.1367 +
140.1368 +    /**
140.1369 +     * Returns the string representation of the calendar
140.1370 +     * <code>field</code> value in the given <code>style</code> and
140.1371 +     * <code>locale</code>.  If no string representation is
140.1372 +     * applicable, <code>null</code> is returned. This method calls
140.1373 +     * {@link Calendar#get(int) get(field)} to get the calendar
140.1374 +     * <code>field</code> value if the string representation is
140.1375 +     * applicable to the given calendar <code>field</code>.
140.1376 +     *
140.1377 +     * <p>For example, if this <code>Calendar</code> is a
140.1378 +     * <code>GregorianCalendar</code> and its date is 2005-01-01, then
140.1379 +     * the string representation of the {@link #MONTH} field would be
140.1380 +     * "January" in the long style in an English locale or "Jan" in
140.1381 +     * the short style. However, no string representation would be
140.1382 +     * available for the {@link #DAY_OF_MONTH} field, and this method
140.1383 +     * would return <code>null</code>.
140.1384 +     *
140.1385 +     * <p>The default implementation supports the calendar fields for
140.1386 +     * which a {@link DateFormatSymbols} has names in the given
140.1387 +     * <code>locale</code>.
140.1388 +     *
140.1389 +     * @param field
140.1390 +     *        the calendar field for which the string representation
140.1391 +     *        is returned
140.1392 +     * @param style
140.1393 +     *        the style applied to the string representation; one of
140.1394 +     *        {@link #SHORT} or {@link #LONG}.
140.1395 +     * @param locale
140.1396 +     *        the locale for the string representation
140.1397 +     * @return the string representation of the given
140.1398 +     *        <code>field</code> in the given <code>style</code>, or
140.1399 +     *        <code>null</code> if no string representation is
140.1400 +     *        applicable.
140.1401 +     * @exception IllegalArgumentException
140.1402 +     *        if <code>field</code> or <code>style</code> is invalid,
140.1403 +     *        or if this <code>Calendar</code> is non-lenient and any
140.1404 +     *        of the calendar fields have invalid values
140.1405 +     * @exception NullPointerException
140.1406 +     *        if <code>locale</code> is null
140.1407 +     * @since 1.6
140.1408 +     */
140.1409 +    public String getDisplayName(int field, int style, Locale locale) {
140.1410 +        if (!checkDisplayNameParams(field, style, ALL_STYLES, LONG, locale,
140.1411 +                                    ERA_MASK|MONTH_MASK|DAY_OF_WEEK_MASK|AM_PM_MASK)) {
140.1412 +            return null;
140.1413 +        }
140.1414 +
140.1415 +        DateFormatSymbols symbols = DateFormatSymbols.getInstance(locale);
140.1416 +        String[] strings = getFieldStrings(field, style, symbols);
140.1417 +        if (strings != null) {
140.1418 +            int fieldValue = get(field);
140.1419 +            if (fieldValue < strings.length) {
140.1420 +                return strings[fieldValue];
140.1421 +            }
140.1422 +        }
140.1423 +        return null;
140.1424 +    }
140.1425 +
140.1426 +    /**
140.1427 +     * Returns a <code>Map</code> containing all names of the calendar
140.1428 +     * <code>field</code> in the given <code>style</code> and
140.1429 +     * <code>locale</code> and their corresponding field values. For
140.1430 +     * example, if this <code>Calendar</code> is a {@link
140.1431 +     * GregorianCalendar}, the returned map would contain "Jan" to
140.1432 +     * {@link #JANUARY}, "Feb" to {@link #FEBRUARY}, and so on, in the
140.1433 +     * {@linkplain #SHORT short} style in an English locale.
140.1434 +     *
140.1435 +     * <p>The values of other calendar fields may be taken into
140.1436 +     * account to determine a set of display names. For example, if
140.1437 +     * this <code>Calendar</code> is a lunisolar calendar system and
140.1438 +     * the year value given by the {@link #YEAR} field has a leap
140.1439 +     * month, this method would return month names containing the leap
140.1440 +     * month name, and month names are mapped to their values specific
140.1441 +     * for the year.
140.1442 +     *
140.1443 +     * <p>The default implementation supports display names contained in
140.1444 +     * a {@link DateFormatSymbols}. For example, if <code>field</code>
140.1445 +     * is {@link #MONTH} and <code>style</code> is {@link
140.1446 +     * #ALL_STYLES}, this method returns a <code>Map</code> containing
140.1447 +     * all strings returned by {@link DateFormatSymbols#getShortMonths()}
140.1448 +     * and {@link DateFormatSymbols#getMonths()}.
140.1449 +     *
140.1450 +     * @param field
140.1451 +     *        the calendar field for which the display names are returned
140.1452 +     * @param style
140.1453 +     *        the style applied to the display names; one of {@link
140.1454 +     *        #SHORT}, {@link #LONG}, or {@link #ALL_STYLES}.
140.1455 +     * @param locale
140.1456 +     *        the locale for the display names
140.1457 +     * @return a <code>Map</code> containing all display names in
140.1458 +     *        <code>style</code> and <code>locale</code> and their
140.1459 +     *        field values, or <code>null</code> if no display names
140.1460 +     *        are defined for <code>field</code>
140.1461 +     * @exception IllegalArgumentException
140.1462 +     *        if <code>field</code> or <code>style</code> is invalid,
140.1463 +     *        or if this <code>Calendar</code> is non-lenient and any
140.1464 +     *        of the calendar fields have invalid values
140.1465 +     * @exception NullPointerException
140.1466 +     *        if <code>locale</code> is null
140.1467 +     * @since 1.6
140.1468 +     */
140.1469 +    public Map<String, Integer> getDisplayNames(int field, int style, Locale locale) {
140.1470 +        if (!checkDisplayNameParams(field, style, ALL_STYLES, LONG, locale,
140.1471 +                                    ERA_MASK|MONTH_MASK|DAY_OF_WEEK_MASK|AM_PM_MASK)) {
140.1472 +            return null;
140.1473 +        }
140.1474 +
140.1475 +        // ALL_STYLES
140.1476 +        if (style == ALL_STYLES) {
140.1477 +            Map<String,Integer> shortNames = getDisplayNamesImpl(field, SHORT, locale);
140.1478 +            if (field == ERA || field == AM_PM) {
140.1479 +                return shortNames;
140.1480 +            }
140.1481 +            Map<String,Integer> longNames = getDisplayNamesImpl(field, LONG, locale);
140.1482 +            if (shortNames == null) {
140.1483 +                return longNames;
140.1484 +            }
140.1485 +            if (longNames != null) {
140.1486 +                shortNames.putAll(longNames);
140.1487 +            }
140.1488 +            return shortNames;
140.1489 +        }
140.1490 +
140.1491 +        // SHORT or LONG
140.1492 +        return getDisplayNamesImpl(field, style, locale);
140.1493 +    }
140.1494 +
140.1495 +    private Map<String,Integer> getDisplayNamesImpl(int field, int style, Locale locale) {
140.1496 +        DateFormatSymbols symbols = DateFormatSymbols.getInstance(locale);
140.1497 +        String[] strings = getFieldStrings(field, style, symbols);
140.1498 +        if (strings != null) {
140.1499 +            Map<String,Integer> names = new HashMap<String,Integer>();
140.1500 +            for (int i = 0; i < strings.length; i++) {
140.1501 +                if (strings[i].length() == 0) {
140.1502 +                    continue;
140.1503 +                }
140.1504 +                names.put(strings[i], i);
140.1505 +            }
140.1506 +            return names;
140.1507 +        }
140.1508 +        return null;
140.1509 +    }
140.1510 +
140.1511 +    boolean checkDisplayNameParams(int field, int style, int minStyle, int maxStyle,
140.1512 +                                   Locale locale, int fieldMask) {
140.1513 +        if (field < 0 || field >= fields.length ||
140.1514 +            style < minStyle || style > maxStyle) {
140.1515 +            throw new IllegalArgumentException();
140.1516 +        }
140.1517 +        if (locale == null) {
140.1518 +            throw new NullPointerException();
140.1519 +        }
140.1520 +        return isFieldSet(fieldMask, field);
140.1521 +    }
140.1522 +
140.1523 +    private String[] getFieldStrings(int field, int style, DateFormatSymbols symbols) {
140.1524 +        String[] strings = null;
140.1525 +        switch (field) {
140.1526 +        case ERA:
140.1527 +            strings = symbols.getEras();
140.1528 +            break;
140.1529 +
140.1530 +        case MONTH:
140.1531 +            strings = (style == LONG) ? symbols.getMonths() : symbols.getShortMonths();
140.1532 +            break;
140.1533 +
140.1534 +        case DAY_OF_WEEK:
140.1535 +            strings = (style == LONG) ? symbols.getWeekdays() : symbols.getShortWeekdays();
140.1536 +            break;
140.1537 +
140.1538 +        case AM_PM:
140.1539 +            strings = symbols.getAmPmStrings();
140.1540 +            break;
140.1541 +        }
140.1542 +        return strings;
140.1543 +    }
140.1544 +
140.1545 +    /**
140.1546 +     * Fills in any unset fields in the calendar fields. First, the {@link
140.1547 +     * #computeTime()} method is called if the time value (millisecond offset
140.1548 +     * from the <a href="#Epoch">Epoch</a>) has not been calculated from
140.1549 +     * calendar field values. Then, the {@link #computeFields()} method is
140.1550 +     * called to calculate all calendar field values.
140.1551 +     */
140.1552 +    protected void complete()
140.1553 +    {
140.1554 +        if (!isTimeSet)
140.1555 +            updateTime();
140.1556 +        if (!areFieldsSet || !areAllFieldsSet) {
140.1557 +            computeFields(); // fills in unset fields
140.1558 +            areAllFieldsSet = areFieldsSet = true;
140.1559 +        }
140.1560 +    }
140.1561 +
140.1562 +    /**
140.1563 +     * Returns whether the value of the specified calendar field has been set
140.1564 +     * externally by calling one of the setter methods rather than by the
140.1565 +     * internal time calculation.
140.1566 +     *
140.1567 +     * @return <code>true</code> if the field has been set externally,
140.1568 +     * <code>false</code> otherwise.
140.1569 +     * @exception IndexOutOfBoundsException if the specified
140.1570 +     *                <code>field</code> is out of range
140.1571 +     *               (<code>field &lt; 0 || field &gt;= FIELD_COUNT</code>).
140.1572 +     * @see #selectFields()
140.1573 +     * @see #setFieldsComputed(int)
140.1574 +     */
140.1575 +    final boolean isExternallySet(int field) {
140.1576 +        return stamp[field] >= MINIMUM_USER_STAMP;
140.1577 +    }
140.1578 +
140.1579 +    /**
140.1580 +     * Returns a field mask (bit mask) indicating all calendar fields that
140.1581 +     * have the state of externally or internally set.
140.1582 +     *
140.1583 +     * @return a bit mask indicating set state fields
140.1584 +     */
140.1585 +    final int getSetStateFields() {
140.1586 +        int mask = 0;
140.1587 +        for (int i = 0; i < fields.length; i++) {
140.1588 +            if (stamp[i] != UNSET) {
140.1589 +                mask |= 1 << i;
140.1590 +            }
140.1591 +        }
140.1592 +        return mask;
140.1593 +    }
140.1594 +
140.1595 +    /**
140.1596 +     * Sets the state of the specified calendar fields to
140.1597 +     * <em>computed</em>. This state means that the specified calendar fields
140.1598 +     * have valid values that have been set by internal time calculation
140.1599 +     * rather than by calling one of the setter methods.
140.1600 +     *
140.1601 +     * @param fieldMask the field to be marked as computed.
140.1602 +     * @exception IndexOutOfBoundsException if the specified
140.1603 +     *                <code>field</code> is out of range
140.1604 +     *               (<code>field &lt; 0 || field &gt;= FIELD_COUNT</code>).
140.1605 +     * @see #isExternallySet(int)
140.1606 +     * @see #selectFields()
140.1607 +     */
140.1608 +    final void setFieldsComputed(int fieldMask) {
140.1609 +        if (fieldMask == ALL_FIELDS) {
140.1610 +            for (int i = 0; i < fields.length; i++) {
140.1611 +                stamp[i] = COMPUTED;
140.1612 +                isSet[i] = true;
140.1613 +            }
140.1614 +            areFieldsSet = areAllFieldsSet = true;
140.1615 +        } else {
140.1616 +            for (int i = 0; i < fields.length; i++) {
140.1617 +                if ((fieldMask & 1) == 1) {
140.1618 +                    stamp[i] = COMPUTED;
140.1619 +                    isSet[i] = true;
140.1620 +                } else {
140.1621 +                    if (areAllFieldsSet && !isSet[i]) {
140.1622 +                        areAllFieldsSet = false;
140.1623 +                    }
140.1624 +                }
140.1625 +                fieldMask >>>= 1;
140.1626 +            }
140.1627 +        }
140.1628 +    }
140.1629 +
140.1630 +    /**
140.1631 +     * Sets the state of the calendar fields that are <em>not</em> specified
140.1632 +     * by <code>fieldMask</code> to <em>unset</em>. If <code>fieldMask</code>
140.1633 +     * specifies all the calendar fields, then the state of this
140.1634 +     * <code>Calendar</code> becomes that all the calendar fields are in sync
140.1635 +     * with the time value (millisecond offset from the Epoch).
140.1636 +     *
140.1637 +     * @param fieldMask the field mask indicating which calendar fields are in
140.1638 +     * sync with the time value.
140.1639 +     * @exception IndexOutOfBoundsException if the specified
140.1640 +     *                <code>field</code> is out of range
140.1641 +     *               (<code>field &lt; 0 || field &gt;= FIELD_COUNT</code>).
140.1642 +     * @see #isExternallySet(int)
140.1643 +     * @see #selectFields()
140.1644 +     */
140.1645 +    final void setFieldsNormalized(int fieldMask) {
140.1646 +        if (fieldMask != ALL_FIELDS) {
140.1647 +            for (int i = 0; i < fields.length; i++) {
140.1648 +                if ((fieldMask & 1) == 0) {
140.1649 +                    stamp[i] = fields[i] = 0; // UNSET == 0
140.1650 +                    isSet[i] = false;
140.1651 +                }
140.1652 +                fieldMask >>= 1;
140.1653 +            }
140.1654 +        }
140.1655 +
140.1656 +        // Some or all of the fields are in sync with the
140.1657 +        // milliseconds, but the stamp values are not normalized yet.
140.1658 +        areFieldsSet = true;
140.1659 +        areAllFieldsSet = false;
140.1660 +    }
140.1661 +
140.1662 +    /**
140.1663 +     * Returns whether the calendar fields are partially in sync with the time
140.1664 +     * value or fully in sync but not stamp values are not normalized yet.
140.1665 +     */
140.1666 +    final boolean isPartiallyNormalized() {
140.1667 +        return areFieldsSet && !areAllFieldsSet;
140.1668 +    }
140.1669 +
140.1670 +    /**
140.1671 +     * Returns whether the calendar fields are fully in sync with the time
140.1672 +     * value.
140.1673 +     */
140.1674 +    final boolean isFullyNormalized() {
140.1675 +        return areFieldsSet && areAllFieldsSet;
140.1676 +    }
140.1677 +
140.1678 +    /**
140.1679 +     * Marks this Calendar as not sync'd.
140.1680 +     */
140.1681 +    final void setUnnormalized() {
140.1682 +        areFieldsSet = areAllFieldsSet = false;
140.1683 +    }
140.1684 +
140.1685 +    /**
140.1686 +     * Returns whether the specified <code>field</code> is on in the
140.1687 +     * <code>fieldMask</code>.
140.1688 +     */
140.1689 +    static final boolean isFieldSet(int fieldMask, int field) {
140.1690 +        return (fieldMask & (1 << field)) != 0;
140.1691 +    }
140.1692 +
140.1693 +    /**
140.1694 +     * Returns a field mask indicating which calendar field values
140.1695 +     * to be used to calculate the time value. The calendar fields are
140.1696 +     * returned as a bit mask, each bit of which corresponds to a field, i.e.,
140.1697 +     * the mask value of <code>field</code> is <code>(1 &lt;&lt;
140.1698 +     * field)</code>. For example, 0x26 represents the <code>YEAR</code>,
140.1699 +     * <code>MONTH</code>, and <code>DAY_OF_MONTH</code> fields (i.e., 0x26 is
140.1700 +     * equal to
140.1701 +     * <code>(1&lt;&lt;YEAR)|(1&lt;&lt;MONTH)|(1&lt;&lt;DAY_OF_MONTH))</code>.
140.1702 +     *
140.1703 +     * <p>This method supports the calendar fields resolution as described in
140.1704 +     * the class description. If the bit mask for a given field is on and its
140.1705 +     * field has not been set (i.e., <code>isSet(field)</code> is
140.1706 +     * <code>false</code>), then the default value of the field has to be
140.1707 +     * used, which case means that the field has been selected because the
140.1708 +     * selected combination involves the field.
140.1709 +     *
140.1710 +     * @return a bit mask of selected fields
140.1711 +     * @see #isExternallySet(int)
140.1712 +     * @see #setInternallySetState(int)
140.1713 +     */
140.1714 +    final int selectFields() {
140.1715 +        // This implementation has been taken from the GregorianCalendar class.
140.1716 +
140.1717 +        // The YEAR field must always be used regardless of its SET
140.1718 +        // state because YEAR is a mandatory field to determine the date
140.1719 +        // and the default value (EPOCH_YEAR) may change through the
140.1720 +        // normalization process.
140.1721 +        int fieldMask = YEAR_MASK;
140.1722 +
140.1723 +        if (stamp[ERA] != UNSET) {
140.1724 +            fieldMask |= ERA_MASK;
140.1725 +        }
140.1726 +        // Find the most recent group of fields specifying the day within
140.1727 +        // the year.  These may be any of the following combinations:
140.1728 +        //   MONTH + DAY_OF_MONTH
140.1729 +        //   MONTH + WEEK_OF_MONTH + DAY_OF_WEEK
140.1730 +        //   MONTH + DAY_OF_WEEK_IN_MONTH + DAY_OF_WEEK
140.1731 +        //   DAY_OF_YEAR
140.1732 +        //   WEEK_OF_YEAR + DAY_OF_WEEK
140.1733 +        // We look for the most recent of the fields in each group to determine
140.1734 +        // the age of the group.  For groups involving a week-related field such
140.1735 +        // as WEEK_OF_MONTH, DAY_OF_WEEK_IN_MONTH, or WEEK_OF_YEAR, both the
140.1736 +        // week-related field and the DAY_OF_WEEK must be set for the group as a
140.1737 +        // whole to be considered.  (See bug 4153860 - liu 7/24/98.)
140.1738 +        int dowStamp = stamp[DAY_OF_WEEK];
140.1739 +        int monthStamp = stamp[MONTH];
140.1740 +        int domStamp = stamp[DAY_OF_MONTH];
140.1741 +        int womStamp = aggregateStamp(stamp[WEEK_OF_MONTH], dowStamp);
140.1742 +        int dowimStamp = aggregateStamp(stamp[DAY_OF_WEEK_IN_MONTH], dowStamp);
140.1743 +        int doyStamp = stamp[DAY_OF_YEAR];
140.1744 +        int woyStamp = aggregateStamp(stamp[WEEK_OF_YEAR], dowStamp);
140.1745 +
140.1746 +        int bestStamp = domStamp;
140.1747 +        if (womStamp > bestStamp) {
140.1748 +            bestStamp = womStamp;
140.1749 +        }
140.1750 +        if (dowimStamp > bestStamp) {
140.1751 +            bestStamp = dowimStamp;
140.1752 +        }
140.1753 +        if (doyStamp > bestStamp) {
140.1754 +            bestStamp = doyStamp;
140.1755 +        }
140.1756 +        if (woyStamp > bestStamp) {
140.1757 +            bestStamp = woyStamp;
140.1758 +        }
140.1759 +
140.1760 +        /* No complete combination exists.  Look for WEEK_OF_MONTH,
140.1761 +         * DAY_OF_WEEK_IN_MONTH, or WEEK_OF_YEAR alone.  Treat DAY_OF_WEEK alone
140.1762 +         * as DAY_OF_WEEK_IN_MONTH.
140.1763 +         */
140.1764 +        if (bestStamp == UNSET) {
140.1765 +            womStamp = stamp[WEEK_OF_MONTH];
140.1766 +            dowimStamp = Math.max(stamp[DAY_OF_WEEK_IN_MONTH], dowStamp);
140.1767 +            woyStamp = stamp[WEEK_OF_YEAR];
140.1768 +            bestStamp = Math.max(Math.max(womStamp, dowimStamp), woyStamp);
140.1769 +
140.1770 +            /* Treat MONTH alone or no fields at all as DAY_OF_MONTH.  This may
140.1771 +             * result in bestStamp = domStamp = UNSET if no fields are set,
140.1772 +             * which indicates DAY_OF_MONTH.
140.1773 +             */
140.1774 +            if (bestStamp == UNSET) {
140.1775 +                bestStamp = domStamp = monthStamp;
140.1776 +            }
140.1777 +        }
140.1778 +
140.1779 +        if (bestStamp == domStamp ||
140.1780 +           (bestStamp == womStamp && stamp[WEEK_OF_MONTH] >= stamp[WEEK_OF_YEAR]) ||
140.1781 +           (bestStamp == dowimStamp && stamp[DAY_OF_WEEK_IN_MONTH] >= stamp[WEEK_OF_YEAR])) {
140.1782 +            fieldMask |= MONTH_MASK;
140.1783 +            if (bestStamp == domStamp) {
140.1784 +                fieldMask |= DAY_OF_MONTH_MASK;
140.1785 +            } else {
140.1786 +                assert (bestStamp == womStamp || bestStamp == dowimStamp);
140.1787 +                if (dowStamp != UNSET) {
140.1788 +                    fieldMask |= DAY_OF_WEEK_MASK;
140.1789 +                }
140.1790 +                if (womStamp == dowimStamp) {
140.1791 +                    // When they are equal, give the priority to
140.1792 +                    // WEEK_OF_MONTH for compatibility.
140.1793 +                    if (stamp[WEEK_OF_MONTH] >= stamp[DAY_OF_WEEK_IN_MONTH]) {
140.1794 +                        fieldMask |= WEEK_OF_MONTH_MASK;
140.1795 +                    } else {
140.1796 +                        fieldMask |= DAY_OF_WEEK_IN_MONTH_MASK;
140.1797 +                    }
140.1798 +                } else {
140.1799 +                    if (bestStamp == womStamp) {
140.1800 +                        fieldMask |= WEEK_OF_MONTH_MASK;
140.1801 +                    } else {
140.1802 +                        assert (bestStamp == dowimStamp);
140.1803 +                        if (stamp[DAY_OF_WEEK_IN_MONTH] != UNSET) {
140.1804 +                            fieldMask |= DAY_OF_WEEK_IN_MONTH_MASK;
140.1805 +                        }
140.1806 +                    }
140.1807 +                }
140.1808 +            }
140.1809 +        } else {
140.1810 +            assert (bestStamp == doyStamp || bestStamp == woyStamp ||
140.1811 +                    bestStamp == UNSET);
140.1812 +            if (bestStamp == doyStamp) {
140.1813 +                fieldMask |= DAY_OF_YEAR_MASK;
140.1814 +            } else {
140.1815 +                assert (bestStamp == woyStamp);
140.1816 +                if (dowStamp != UNSET) {
140.1817 +                    fieldMask |= DAY_OF_WEEK_MASK;
140.1818 +                }
140.1819 +                fieldMask |= WEEK_OF_YEAR_MASK;
140.1820 +            }
140.1821 +        }
140.1822 +
140.1823 +        // Find the best set of fields specifying the time of day.  There
140.1824 +        // are only two possibilities here; the HOUR_OF_DAY or the
140.1825 +        // AM_PM and the HOUR.
140.1826 +        int hourOfDayStamp = stamp[HOUR_OF_DAY];
140.1827 +        int hourStamp = aggregateStamp(stamp[HOUR], stamp[AM_PM]);
140.1828 +        bestStamp = (hourStamp > hourOfDayStamp) ? hourStamp : hourOfDayStamp;
140.1829 +
140.1830 +        // if bestStamp is still UNSET, then take HOUR or AM_PM. (See 4846659)
140.1831 +        if (bestStamp == UNSET) {
140.1832 +            bestStamp = Math.max(stamp[HOUR], stamp[AM_PM]);
140.1833 +        }
140.1834 +
140.1835 +        // Hours
140.1836 +        if (bestStamp != UNSET) {
140.1837 +            if (bestStamp == hourOfDayStamp) {
140.1838 +                fieldMask |= HOUR_OF_DAY_MASK;
140.1839 +            } else {
140.1840 +                fieldMask |= HOUR_MASK;
140.1841 +                if (stamp[AM_PM] != UNSET) {
140.1842 +                    fieldMask |= AM_PM_MASK;
140.1843 +                }
140.1844 +            }
140.1845 +        }
140.1846 +        if (stamp[MINUTE] != UNSET) {
140.1847 +            fieldMask |= MINUTE_MASK;
140.1848 +        }
140.1849 +        if (stamp[SECOND] != UNSET) {
140.1850 +            fieldMask |= SECOND_MASK;
140.1851 +        }
140.1852 +        if (stamp[MILLISECOND] != UNSET) {
140.1853 +            fieldMask |= MILLISECOND_MASK;
140.1854 +        }
140.1855 +        if (stamp[ZONE_OFFSET] >= MINIMUM_USER_STAMP) {
140.1856 +                fieldMask |= ZONE_OFFSET_MASK;
140.1857 +        }
140.1858 +        if (stamp[DST_OFFSET] >= MINIMUM_USER_STAMP) {
140.1859 +            fieldMask |= DST_OFFSET_MASK;
140.1860 +        }
140.1861 +
140.1862 +        return fieldMask;
140.1863 +    }
140.1864 +
140.1865 +    /**
140.1866 +     * Returns the pseudo-time-stamp for two fields, given their
140.1867 +     * individual pseudo-time-stamps.  If either of the fields
140.1868 +     * is unset, then the aggregate is unset.  Otherwise, the
140.1869 +     * aggregate is the later of the two stamps.
140.1870 +     */
140.1871 +    private static final int aggregateStamp(int stamp_a, int stamp_b) {
140.1872 +        if (stamp_a == UNSET || stamp_b == UNSET) {
140.1873 +            return UNSET;
140.1874 +        }
140.1875 +        return (stamp_a > stamp_b) ? stamp_a : stamp_b;
140.1876 +    }
140.1877 +
140.1878 +    /**
140.1879 +     * Compares this <code>Calendar</code> to the specified
140.1880 +     * <code>Object</code>.  The result is <code>true</code> if and only if
140.1881 +     * the argument is a <code>Calendar</code> object of the same calendar
140.1882 +     * system that represents the same time value (millisecond offset from the
140.1883 +     * <a href="#Epoch">Epoch</a>) under the same
140.1884 +     * <code>Calendar</code> parameters as this object.
140.1885 +     *
140.1886 +     * <p>The <code>Calendar</code> parameters are the values represented
140.1887 +     * by the <code>isLenient</code>, <code>getFirstDayOfWeek</code>,
140.1888 +     * <code>getMinimalDaysInFirstWeek</code> and <code>getTimeZone</code>
140.1889 +     * methods. If there is any difference in those parameters
140.1890 +     * between the two <code>Calendar</code>s, this method returns
140.1891 +     * <code>false</code>.
140.1892 +     *
140.1893 +     * <p>Use the {@link #compareTo(Calendar) compareTo} method to
140.1894 +     * compare only the time values.
140.1895 +     *
140.1896 +     * @param obj the object to compare with.
140.1897 +     * @return <code>true</code> if this object is equal to <code>obj</code>;
140.1898 +     * <code>false</code> otherwise.
140.1899 +     */
140.1900 +    public boolean equals(Object obj) {
140.1901 +        if (this == obj)
140.1902 +            return true;
140.1903 +        try {
140.1904 +            Calendar that = (Calendar)obj;
140.1905 +            return compareTo(getMillisOf(that)) == 0 &&
140.1906 +                lenient == that.lenient &&
140.1907 +                firstDayOfWeek == that.firstDayOfWeek &&
140.1908 +                minimalDaysInFirstWeek == that.minimalDaysInFirstWeek &&
140.1909 +                zone.equals(that.zone);
140.1910 +        } catch (Exception e) {
140.1911 +            // Note: GregorianCalendar.computeTime throws
140.1912 +            // IllegalArgumentException if the ERA value is invalid
140.1913 +            // even it's in lenient mode.
140.1914 +        }
140.1915 +        return false;
140.1916 +    }
140.1917 +
140.1918 +    /**
140.1919 +     * Returns a hash code for this calendar.
140.1920 +     *
140.1921 +     * @return a hash code value for this object.
140.1922 +     * @since 1.2
140.1923 +     */
140.1924 +    public int hashCode() {
140.1925 +        // 'otheritems' represents the hash code for the previous versions.
140.1926 +        int otheritems = (lenient ? 1 : 0)
140.1927 +            | (firstDayOfWeek << 1)
140.1928 +            | (minimalDaysInFirstWeek << 4)
140.1929 +            | (zone.hashCode() << 7);
140.1930 +        long t = getMillisOf(this);
140.1931 +        return (int) t ^ (int)(t >> 32) ^ otheritems;
140.1932 +    }
140.1933 +
140.1934 +    /**
140.1935 +     * Returns whether this <code>Calendar</code> represents a time
140.1936 +     * before the time represented by the specified
140.1937 +     * <code>Object</code>. This method is equivalent to:
140.1938 +     * <pre><blockquote>
140.1939 +     *         compareTo(when) < 0
140.1940 +     * </blockquote></pre>
140.1941 +     * if and only if <code>when</code> is a <code>Calendar</code>
140.1942 +     * instance. Otherwise, the method returns <code>false</code>.
140.1943 +     *
140.1944 +     * @param when the <code>Object</code> to be compared
140.1945 +     * @return <code>true</code> if the time of this
140.1946 +     * <code>Calendar</code> is before the time represented by
140.1947 +     * <code>when</code>; <code>false</code> otherwise.
140.1948 +     * @see     #compareTo(Calendar)
140.1949 +     */
140.1950 +    public boolean before(Object when) {
140.1951 +        return when instanceof Calendar
140.1952 +            && compareTo((Calendar)when) < 0;
140.1953 +    }
140.1954 +
140.1955 +    /**
140.1956 +     * Returns whether this <code>Calendar</code> represents a time
140.1957 +     * after the time represented by the specified
140.1958 +     * <code>Object</code>. This method is equivalent to:
140.1959 +     * <pre><blockquote>
140.1960 +     *         compareTo(when) > 0
140.1961 +     * </blockquote></pre>
140.1962 +     * if and only if <code>when</code> is a <code>Calendar</code>
140.1963 +     * instance. Otherwise, the method returns <code>false</code>.
140.1964 +     *
140.1965 +     * @param when the <code>Object</code> to be compared
140.1966 +     * @return <code>true</code> if the time of this <code>Calendar</code> is
140.1967 +     * after the time represented by <code>when</code>; <code>false</code>
140.1968 +     * otherwise.
140.1969 +     * @see     #compareTo(Calendar)
140.1970 +     */
140.1971 +    public boolean after(Object when) {
140.1972 +        return when instanceof Calendar
140.1973 +            && compareTo((Calendar)when) > 0;
140.1974 +    }
140.1975 +
140.1976 +    /**
140.1977 +     * Compares the time values (millisecond offsets from the <a
140.1978 +     * href="#Epoch">Epoch</a>) represented by two
140.1979 +     * <code>Calendar</code> objects.
140.1980 +     *
140.1981 +     * @param anotherCalendar the <code>Calendar</code> to be compared.
140.1982 +     * @return the value <code>0</code> if the time represented by the argument
140.1983 +     * is equal to the time represented by this <code>Calendar</code>; a value
140.1984 +     * less than <code>0</code> if the time of this <code>Calendar</code> is
140.1985 +     * before the time represented by the argument; and a value greater than
140.1986 +     * <code>0</code> if the time of this <code>Calendar</code> is after the
140.1987 +     * time represented by the argument.
140.1988 +     * @exception NullPointerException if the specified <code>Calendar</code> is
140.1989 +     *            <code>null</code>.
140.1990 +     * @exception IllegalArgumentException if the time value of the
140.1991 +     * specified <code>Calendar</code> object can't be obtained due to
140.1992 +     * any invalid calendar values.
140.1993 +     * @since   1.5
140.1994 +     */
140.1995 +    public int compareTo(Calendar anotherCalendar) {
140.1996 +        return compareTo(getMillisOf(anotherCalendar));
140.1997 +    }
140.1998 +
140.1999 +    /**
140.2000 +     * Adds or subtracts the specified amount of time to the given calendar field,
140.2001 +     * based on the calendar's rules. For example, to subtract 5 days from
140.2002 +     * the current time of the calendar, you can achieve it by calling:
140.2003 +     * <p><code>add(Calendar.DAY_OF_MONTH, -5)</code>.
140.2004 +     *
140.2005 +     * @param field the calendar field.
140.2006 +     * @param amount the amount of date or time to be added to the field.
140.2007 +     * @see #roll(int,int)
140.2008 +     * @see #set(int,int)
140.2009 +     */
140.2010 +    abstract public void add(int field, int amount);
140.2011 +
140.2012 +    /**
140.2013 +     * Adds or subtracts (up/down) a single unit of time on the given time
140.2014 +     * field without changing larger fields. For example, to roll the current
140.2015 +     * date up by one day, you can achieve it by calling:
140.2016 +     * <p>roll(Calendar.DATE, true).
140.2017 +     * When rolling on the year or Calendar.YEAR field, it will roll the year
140.2018 +     * value in the range between 1 and the value returned by calling
140.2019 +     * <code>getMaximum(Calendar.YEAR)</code>.
140.2020 +     * When rolling on the month or Calendar.MONTH field, other fields like
140.2021 +     * date might conflict and, need to be changed. For instance,
140.2022 +     * rolling the month on the date 01/31/96 will result in 02/29/96.
140.2023 +     * When rolling on the hour-in-day or Calendar.HOUR_OF_DAY field, it will
140.2024 +     * roll the hour value in the range between 0 and 23, which is zero-based.
140.2025 +     *
140.2026 +     * @param field the time field.
140.2027 +     * @param up indicates if the value of the specified time field is to be
140.2028 +     * rolled up or rolled down. Use true if rolling up, false otherwise.
140.2029 +     * @see Calendar#add(int,int)
140.2030 +     * @see Calendar#set(int,int)
140.2031 +     */
140.2032 +    abstract public void roll(int field, boolean up);
140.2033 +
140.2034 +    /**
140.2035 +     * Adds the specified (signed) amount to the specified calendar field
140.2036 +     * without changing larger fields.  A negative amount means to roll
140.2037 +     * down.
140.2038 +     *
140.2039 +     * <p>NOTE:  This default implementation on <code>Calendar</code> just repeatedly calls the
140.2040 +     * version of {@link #roll(int,boolean) roll()} that rolls by one unit.  This may not
140.2041 +     * always do the right thing.  For example, if the <code>DAY_OF_MONTH</code> field is 31,
140.2042 +     * rolling through February will leave it set to 28.  The <code>GregorianCalendar</code>
140.2043 +     * version of this function takes care of this problem.  Other subclasses
140.2044 +     * should also provide overrides of this function that do the right thing.
140.2045 +     *
140.2046 +     * @param field the calendar field.
140.2047 +     * @param amount the signed amount to add to the calendar <code>field</code>.
140.2048 +     * @since 1.2
140.2049 +     * @see #roll(int,boolean)
140.2050 +     * @see #add(int,int)
140.2051 +     * @see #set(int,int)
140.2052 +     */
140.2053 +    public void roll(int field, int amount)
140.2054 +    {
140.2055 +        while (amount > 0) {
140.2056 +            roll(field, true);
140.2057 +            amount--;
140.2058 +        }
140.2059 +        while (amount < 0) {
140.2060 +            roll(field, false);
140.2061 +            amount++;
140.2062 +        }
140.2063 +    }
140.2064 +
140.2065 +    /**
140.2066 +     * Sets the time zone with the given time zone value.
140.2067 +     *
140.2068 +     * @param value the given time zone.
140.2069 +     */
140.2070 +    public void setTimeZone(TimeZone value)
140.2071 +    {
140.2072 +        zone = value;
140.2073 +        sharedZone = false;
140.2074 +        /* Recompute the fields from the time using the new zone.  This also
140.2075 +         * works if isTimeSet is false (after a call to set()).  In that case
140.2076 +         * the time will be computed from the fields using the new zone, then
140.2077 +         * the fields will get recomputed from that.  Consider the sequence of
140.2078 +         * calls: cal.setTimeZone(EST); cal.set(HOUR, 1); cal.setTimeZone(PST).
140.2079 +         * Is cal set to 1 o'clock EST or 1 o'clock PST?  Answer: PST.  More
140.2080 +         * generally, a call to setTimeZone() affects calls to set() BEFORE AND
140.2081 +         * AFTER it up to the next call to complete().
140.2082 +         */
140.2083 +        areAllFieldsSet = areFieldsSet = false;
140.2084 +    }
140.2085 +
140.2086 +    /**
140.2087 +     * Gets the time zone.
140.2088 +     *
140.2089 +     * @return the time zone object associated with this calendar.
140.2090 +     */
140.2091 +    public TimeZone getTimeZone()
140.2092 +    {
140.2093 +        // If the TimeZone object is shared by other Calendar instances, then
140.2094 +        // create a clone.
140.2095 +        if (sharedZone) {
140.2096 +            zone = (TimeZone) zone.clone();
140.2097 +            sharedZone = false;
140.2098 +        }
140.2099 +        return zone;
140.2100 +    }
140.2101 +
140.2102 +    /**
140.2103 +     * Returns the time zone (without cloning).
140.2104 +     */
140.2105 +    TimeZone getZone() {
140.2106 +        return zone;
140.2107 +    }
140.2108 +
140.2109 +    /**
140.2110 +     * Sets the sharedZone flag to <code>shared</code>.
140.2111 +     */
140.2112 +    void setZoneShared(boolean shared) {
140.2113 +        sharedZone = shared;
140.2114 +    }
140.2115 +
140.2116 +    /**
140.2117 +     * Specifies whether or not date/time interpretation is to be lenient.  With
140.2118 +     * lenient interpretation, a date such as "February 942, 1996" will be
140.2119 +     * treated as being equivalent to the 941st day after February 1, 1996.
140.2120 +     * With strict (non-lenient) interpretation, such dates will cause an exception to be
140.2121 +     * thrown. The default is lenient.
140.2122 +     *
140.2123 +     * @param lenient <code>true</code> if the lenient mode is to be turned
140.2124 +     * on; <code>false</code> if it is to be turned off.
140.2125 +     * @see #isLenient()
140.2126 +     * @see java.text.DateFormat#setLenient
140.2127 +     */
140.2128 +    public void setLenient(boolean lenient)
140.2129 +    {
140.2130 +        this.lenient = lenient;
140.2131 +    }
140.2132 +
140.2133 +    /**
140.2134 +     * Tells whether date/time interpretation is to be lenient.
140.2135 +     *
140.2136 +     * @return <code>true</code> if the interpretation mode of this calendar is lenient;
140.2137 +     * <code>false</code> otherwise.
140.2138 +     * @see #setLenient(boolean)
140.2139 +     */
140.2140 +    public boolean isLenient()
140.2141 +    {
140.2142 +        return lenient;
140.2143 +    }
140.2144 +
140.2145 +    /**
140.2146 +     * Sets what the first day of the week is; e.g., <code>SUNDAY</code> in the U.S.,
140.2147 +     * <code>MONDAY</code> in France.
140.2148 +     *
140.2149 +     * @param value the given first day of the week.
140.2150 +     * @see #getFirstDayOfWeek()
140.2151 +     * @see #getMinimalDaysInFirstWeek()
140.2152 +     */
140.2153 +    public void setFirstDayOfWeek(int value)
140.2154 +    {
140.2155 +        if (firstDayOfWeek == value) {
140.2156 +            return;
140.2157 +        }
140.2158 +        firstDayOfWeek = value;
140.2159 +        invalidateWeekFields();
140.2160 +    }
140.2161 +
140.2162 +    /**
140.2163 +     * Gets what the first day of the week is; e.g., <code>SUNDAY</code> in the U.S.,
140.2164 +     * <code>MONDAY</code> in France.
140.2165 +     *
140.2166 +     * @return the first day of the week.
140.2167 +     * @see #setFirstDayOfWeek(int)
140.2168 +     * @see #getMinimalDaysInFirstWeek()
140.2169 +     */
140.2170 +    public int getFirstDayOfWeek()
140.2171 +    {
140.2172 +        return firstDayOfWeek;
140.2173 +    }
140.2174 +
140.2175 +    /**
140.2176 +     * Sets what the minimal days required in the first week of the year are;
140.2177 +     * For example, if the first week is defined as one that contains the first
140.2178 +     * day of the first month of a year, call this method with value 1. If it
140.2179 +     * must be a full week, use value 7.
140.2180 +     *
140.2181 +     * @param value the given minimal days required in the first week
140.2182 +     * of the year.
140.2183 +     * @see #getMinimalDaysInFirstWeek()
140.2184 +     */
140.2185 +    public void setMinimalDaysInFirstWeek(int value)
140.2186 +    {
140.2187 +        if (minimalDaysInFirstWeek == value) {
140.2188 +            return;
140.2189 +        }
140.2190 +        minimalDaysInFirstWeek = value;
140.2191 +        invalidateWeekFields();
140.2192 +    }
140.2193 +
140.2194 +    /**
140.2195 +     * Gets what the minimal days required in the first week of the year are;
140.2196 +     * e.g., if the first week is defined as one that contains the first day
140.2197 +     * of the first month of a year, this method returns 1. If
140.2198 +     * the minimal days required must be a full week, this method
140.2199 +     * returns 7.
140.2200 +     *
140.2201 +     * @return the minimal days required in the first week of the year.
140.2202 +     * @see #setMinimalDaysInFirstWeek(int)
140.2203 +     */
140.2204 +    public int getMinimalDaysInFirstWeek()
140.2205 +    {
140.2206 +        return minimalDaysInFirstWeek;
140.2207 +    }
140.2208 +
140.2209 +    /**
140.2210 +     * Returns whether this {@code Calendar} supports week dates.
140.2211 +     *
140.2212 +     * <p>The default implementation of this method returns {@code false}.
140.2213 +     *
140.2214 +     * @return {@code true} if this {@code Calendar} supports week dates;
140.2215 +     *         {@code false} otherwise.
140.2216 +     * @see #getWeekYear()
140.2217 +     * @see #setWeekDate(int,int,int)
140.2218 +     * @see #getWeeksInWeekYear()
140.2219 +     * @since 1.7
140.2220 +     */
140.2221 +    public boolean isWeekDateSupported() {
140.2222 +        return false;
140.2223 +    }
140.2224 +
140.2225 +    /**
140.2226 +     * Returns the week year represented by this {@code Calendar}. The
140.2227 +     * week year is in sync with the week cycle. The {@linkplain
140.2228 +     * #getFirstDayOfWeek() first day of the first week} is the first
140.2229 +     * day of the week year.
140.2230 +     *
140.2231 +     * <p>The default implementation of this method throws an
140.2232 +     * {@link UnsupportedOperationException}.
140.2233 +     *
140.2234 +     * @return the week year of this {@code Calendar}
140.2235 +     * @exception UnsupportedOperationException
140.2236 +     *            if any week year numbering isn't supported
140.2237 +     *            in this {@code Calendar}.
140.2238 +     * @see #isWeekDateSupported()
140.2239 +     * @see #getFirstDayOfWeek()
140.2240 +     * @see #getMinimalDaysInFirstWeek()
140.2241 +     * @since 1.7
140.2242 +     */
140.2243 +    public int getWeekYear() {
140.2244 +        throw new UnsupportedOperationException();
140.2245 +    }
140.2246 +
140.2247 +    /**
140.2248 +     * Sets the date of this {@code Calendar} with the the given date
140.2249 +     * specifiers - week year, week of year, and day of week.
140.2250 +     *
140.2251 +     * <p>Unlike the {@code set} method, all of the calendar fields
140.2252 +     * and {@code time} values are calculated upon return.
140.2253 +     *
140.2254 +     * <p>If {@code weekOfYear} is out of the valid week-of-year range
140.2255 +     * in {@code weekYear}, the {@code weekYear} and {@code
140.2256 +     * weekOfYear} values are adjusted in lenient mode, or an {@code
140.2257 +     * IllegalArgumentException} is thrown in non-lenient mode.
140.2258 +     *
140.2259 +     * <p>The default implementation of this method throws an
140.2260 +     * {@code UnsupportedOperationException}.
140.2261 +     *
140.2262 +     * @param weekYear   the week year
140.2263 +     * @param weekOfYear the week number based on {@code weekYear}
140.2264 +     * @param dayOfWeek  the day of week value: one of the constants
140.2265 +     *                   for the {@link #DAY_OF_WEEK} field: {@link
140.2266 +     *                   #SUNDAY}, ..., {@link #SATURDAY}.
140.2267 +     * @exception IllegalArgumentException
140.2268 +     *            if any of the given date specifiers is invalid
140.2269 +     *            or any of the calendar fields are inconsistent
140.2270 +     *            with the given date specifiers in non-lenient mode
140.2271 +     * @exception UnsupportedOperationException
140.2272 +     *            if any week year numbering isn't supported in this
140.2273 +     *            {@code Calendar}.
140.2274 +     * @see #isWeekDateSupported()
140.2275 +     * @see #getFirstDayOfWeek()
140.2276 +     * @see #getMinimalDaysInFirstWeek()
140.2277 +     * @since 1.7
140.2278 +     */
140.2279 +    public void setWeekDate(int weekYear, int weekOfYear, int dayOfWeek) {
140.2280 +        throw new UnsupportedOperationException();
140.2281 +    }
140.2282 +
140.2283 +    /**
140.2284 +     * Returns the number of weeks in the week year represented by this
140.2285 +     * {@code Calendar}.
140.2286 +     *
140.2287 +     * <p>The default implementation of this method throws an
140.2288 +     * {@code UnsupportedOperationException}.
140.2289 +     *
140.2290 +     * @return the number of weeks in the week year.
140.2291 +     * @exception UnsupportedOperationException
140.2292 +     *            if any week year numbering isn't supported in this
140.2293 +     *            {@code Calendar}.
140.2294 +     * @see #WEEK_OF_YEAR
140.2295 +     * @see #isWeekDateSupported()
140.2296 +     * @see #getWeekYear()
140.2297 +     * @see #getActualMaximum(int)
140.2298 +     * @since 1.7
140.2299 +     */
140.2300 +    public int getWeeksInWeekYear() {
140.2301 +        throw new UnsupportedOperationException();
140.2302 +    }
140.2303 +
140.2304 +    /**
140.2305 +     * Returns the minimum value for the given calendar field of this
140.2306 +     * <code>Calendar</code> instance. The minimum value is defined as
140.2307 +     * the smallest value returned by the {@link #get(int) get} method
140.2308 +     * for any possible time value.  The minimum value depends on
140.2309 +     * calendar system specific parameters of the instance.
140.2310 +     *
140.2311 +     * @param field the calendar field.
140.2312 +     * @return the minimum value for the given calendar field.
140.2313 +     * @see #getMaximum(int)
140.2314 +     * @see #getGreatestMinimum(int)
140.2315 +     * @see #getLeastMaximum(int)
140.2316 +     * @see #getActualMinimum(int)
140.2317 +     * @see #getActualMaximum(int)
140.2318 +     */
140.2319 +    abstract public int getMinimum(int field);
140.2320 +
140.2321 +    /**
140.2322 +     * Returns the maximum value for the given calendar field of this
140.2323 +     * <code>Calendar</code> instance. The maximum value is defined as
140.2324 +     * the largest value returned by the {@link #get(int) get} method
140.2325 +     * for any possible time value. The maximum value depends on
140.2326 +     * calendar system specific parameters of the instance.
140.2327 +     *
140.2328 +     * @param field the calendar field.
140.2329 +     * @return the maximum value for the given calendar field.
140.2330 +     * @see #getMinimum(int)
140.2331 +     * @see #getGreatestMinimum(int)
140.2332 +     * @see #getLeastMaximum(int)
140.2333 +     * @see #getActualMinimum(int)
140.2334 +     * @see #getActualMaximum(int)
140.2335 +     */
140.2336 +    abstract public int getMaximum(int field);
140.2337 +
140.2338 +    /**
140.2339 +     * Returns the highest minimum value for the given calendar field
140.2340 +     * of this <code>Calendar</code> instance. The highest minimum
140.2341 +     * value is defined as the largest value returned by {@link
140.2342 +     * #getActualMinimum(int)} for any possible time value. The
140.2343 +     * greatest minimum value depends on calendar system specific
140.2344 +     * parameters of the instance.
140.2345 +     *
140.2346 +     * @param field the calendar field.
140.2347 +     * @return the highest minimum value for the given calendar field.
140.2348 +     * @see #getMinimum(int)
140.2349 +     * @see #getMaximum(int)
140.2350 +     * @see #getLeastMaximum(int)
140.2351 +     * @see #getActualMinimum(int)
140.2352 +     * @see #getActualMaximum(int)
140.2353 +     */
140.2354 +    abstract public int getGreatestMinimum(int field);
140.2355 +
140.2356 +    /**
140.2357 +     * Returns the lowest maximum value for the given calendar field
140.2358 +     * of this <code>Calendar</code> instance. The lowest maximum
140.2359 +     * value is defined as the smallest value returned by {@link
140.2360 +     * #getActualMaximum(int)} for any possible time value. The least
140.2361 +     * maximum value depends on calendar system specific parameters of
140.2362 +     * the instance. For example, a <code>Calendar</code> for the
140.2363 +     * Gregorian calendar system returns 28 for the
140.2364 +     * <code>DAY_OF_MONTH</code> field, because the 28th is the last
140.2365 +     * day of the shortest month of this calendar, February in a
140.2366 +     * common year.
140.2367 +     *
140.2368 +     * @param field the calendar field.
140.2369 +     * @return the lowest maximum value for the given calendar field.
140.2370 +     * @see #getMinimum(int)
140.2371 +     * @see #getMaximum(int)
140.2372 +     * @see #getGreatestMinimum(int)
140.2373 +     * @see #getActualMinimum(int)
140.2374 +     * @see #getActualMaximum(int)
140.2375 +     */
140.2376 +    abstract public int getLeastMaximum(int field);
140.2377 +
140.2378 +    /**
140.2379 +     * Returns the minimum value that the specified calendar field
140.2380 +     * could have, given the time value of this <code>Calendar</code>.
140.2381 +     *
140.2382 +     * <p>The default implementation of this method uses an iterative
140.2383 +     * algorithm to determine the actual minimum value for the
140.2384 +     * calendar field. Subclasses should, if possible, override this
140.2385 +     * with a more efficient implementation - in many cases, they can
140.2386 +     * simply return <code>getMinimum()</code>.
140.2387 +     *
140.2388 +     * @param field the calendar field
140.2389 +     * @return the minimum of the given calendar field for the time
140.2390 +     * value of this <code>Calendar</code>
140.2391 +     * @see #getMinimum(int)
140.2392 +     * @see #getMaximum(int)
140.2393 +     * @see #getGreatestMinimum(int)
140.2394 +     * @see #getLeastMaximum(int)
140.2395 +     * @see #getActualMaximum(int)
140.2396 +     * @since 1.2
140.2397 +     */
140.2398 +    public int getActualMinimum(int field) {
140.2399 +        int fieldValue = getGreatestMinimum(field);
140.2400 +        int endValue = getMinimum(field);
140.2401 +
140.2402 +        // if we know that the minimum value is always the same, just return it
140.2403 +        if (fieldValue == endValue) {
140.2404 +            return fieldValue;
140.2405 +        }
140.2406 +
140.2407 +        // clone the calendar so we don't mess with the real one, and set it to
140.2408 +        // accept anything for the field values
140.2409 +        Calendar work = (Calendar)this.clone();
140.2410 +        work.setLenient(true);
140.2411 +
140.2412 +        // now try each value from getLeastMaximum() to getMaximum() one by one until
140.2413 +        // we get a value that normalizes to another value.  The last value that
140.2414 +        // normalizes to itself is the actual minimum for the current date
140.2415 +        int result = fieldValue;
140.2416 +
140.2417 +        do {
140.2418 +            work.set(field, fieldValue);
140.2419 +            if (work.get(field) != fieldValue) {
140.2420 +                break;
140.2421 +            } else {
140.2422 +                result = fieldValue;
140.2423 +                fieldValue--;
140.2424 +            }
140.2425 +        } while (fieldValue >= endValue);
140.2426 +
140.2427 +        return result;
140.2428 +    }
140.2429 +
140.2430 +    /**
140.2431 +     * Returns the maximum value that the specified calendar field
140.2432 +     * could have, given the time value of this
140.2433 +     * <code>Calendar</code>. For example, the actual maximum value of
140.2434 +     * the <code>MONTH</code> field is 12 in some years, and 13 in
140.2435 +     * other years in the Hebrew calendar system.
140.2436 +     *
140.2437 +     * <p>The default implementation of this method uses an iterative
140.2438 +     * algorithm to determine the actual maximum value for the
140.2439 +     * calendar field. Subclasses should, if possible, override this
140.2440 +     * with a more efficient implementation.
140.2441 +     *
140.2442 +     * @param field the calendar field
140.2443 +     * @return the maximum of the given calendar field for the time
140.2444 +     * value of this <code>Calendar</code>
140.2445 +     * @see #getMinimum(int)
140.2446 +     * @see #getMaximum(int)
140.2447 +     * @see #getGreatestMinimum(int)
140.2448 +     * @see #getLeastMaximum(int)
140.2449 +     * @see #getActualMinimum(int)
140.2450 +     * @since 1.2
140.2451 +     */
140.2452 +    public int getActualMaximum(int field) {
140.2453 +        int fieldValue = getLeastMaximum(field);
140.2454 +        int endValue = getMaximum(field);
140.2455 +
140.2456 +        // if we know that the maximum value is always the same, just return it.
140.2457 +        if (fieldValue == endValue) {
140.2458 +            return fieldValue;
140.2459 +        }
140.2460 +
140.2461 +        // clone the calendar so we don't mess with the real one, and set it to
140.2462 +        // accept anything for the field values.
140.2463 +        Calendar work = (Calendar)this.clone();
140.2464 +        work.setLenient(true);
140.2465 +
140.2466 +        // if we're counting weeks, set the day of the week to Sunday.  We know the
140.2467 +        // last week of a month or year will contain the first day of the week.
140.2468 +        if (field == WEEK_OF_YEAR || field == WEEK_OF_MONTH)
140.2469 +            work.set(DAY_OF_WEEK, firstDayOfWeek);
140.2470 +
140.2471 +        // now try each value from getLeastMaximum() to getMaximum() one by one until
140.2472 +        // we get a value that normalizes to another value.  The last value that
140.2473 +        // normalizes to itself is the actual maximum for the current date
140.2474 +        int result = fieldValue;
140.2475 +
140.2476 +        do {
140.2477 +            work.set(field, fieldValue);
140.2478 +            if (work.get(field) != fieldValue) {
140.2479 +                break;
140.2480 +            } else {
140.2481 +                result = fieldValue;
140.2482 +                fieldValue++;
140.2483 +            }
140.2484 +        } while (fieldValue <= endValue);
140.2485 +
140.2486 +        return result;
140.2487 +    }
140.2488 +
140.2489 +    /**
140.2490 +     * Creates and returns a copy of this object.
140.2491 +     *
140.2492 +     * @return a copy of this object.
140.2493 +     */
140.2494 +    public Object clone()
140.2495 +    {
140.2496 +        try {
140.2497 +            Calendar other = (Calendar) super.clone();
140.2498 +
140.2499 +            other.fields = new int[FIELD_COUNT];
140.2500 +            other.isSet = new boolean[FIELD_COUNT];
140.2501 +            other.stamp = new int[FIELD_COUNT];
140.2502 +            for (int i = 0; i < FIELD_COUNT; i++) {
140.2503 +                other.fields[i] = fields[i];
140.2504 +                other.stamp[i] = stamp[i];
140.2505 +                other.isSet[i] = isSet[i];
140.2506 +            }
140.2507 +            other.zone = (TimeZone) zone.clone();
140.2508 +            return other;
140.2509 +        }
140.2510 +        catch (CloneNotSupportedException e) {
140.2511 +            // this shouldn't happen, since we are Cloneable
140.2512 +            throw new InternalError();
140.2513 +        }
140.2514 +    }
140.2515 +
140.2516 +    private static final String[] FIELD_NAME = {
140.2517 +        "ERA", "YEAR", "MONTH", "WEEK_OF_YEAR", "WEEK_OF_MONTH", "DAY_OF_MONTH",
140.2518 +        "DAY_OF_YEAR", "DAY_OF_WEEK", "DAY_OF_WEEK_IN_MONTH", "AM_PM", "HOUR",
140.2519 +        "HOUR_OF_DAY", "MINUTE", "SECOND", "MILLISECOND", "ZONE_OFFSET",
140.2520 +        "DST_OFFSET"
140.2521 +    };
140.2522 +
140.2523 +    /**
140.2524 +     * Returns the name of the specified calendar field.
140.2525 +     *
140.2526 +     * @param field the calendar field
140.2527 +     * @return the calendar field name
140.2528 +     * @exception IndexOutOfBoundsException if <code>field</code> is negative,
140.2529 +     * equal to or greater then <code>FIELD_COUNT</code>.
140.2530 +     */
140.2531 +    static final String getFieldName(int field) {
140.2532 +        return FIELD_NAME[field];
140.2533 +    }
140.2534 +
140.2535 +    /**
140.2536 +     * Return a string representation of this calendar. This method
140.2537 +     * is intended to be used only for debugging purposes, and the
140.2538 +     * format of the returned string may vary between implementations.
140.2539 +     * The returned string may be empty but may not be <code>null</code>.
140.2540 +     *
140.2541 +     * @return  a string representation of this calendar.
140.2542 +     */
140.2543 +    public String toString() {
140.2544 +        // NOTE: BuddhistCalendar.toString() interprets the string
140.2545 +        // produced by this method so that the Gregorian year number
140.2546 +        // is substituted by its B.E. year value. It relies on
140.2547 +        // "...,YEAR=<year>,..." or "...,YEAR=?,...".
140.2548 +        StringBuilder buffer = new StringBuilder(800);
140.2549 +        buffer.append(getClass().getName()).append('[');
140.2550 +        appendValue(buffer, "time", isTimeSet, time);
140.2551 +        buffer.append(",areFieldsSet=").append(areFieldsSet);
140.2552 +        buffer.append(",areAllFieldsSet=").append(areAllFieldsSet);
140.2553 +        buffer.append(",lenient=").append(lenient);
140.2554 +        buffer.append(",zone=").append(zone);
140.2555 +        appendValue(buffer, ",firstDayOfWeek", true, (long) firstDayOfWeek);
140.2556 +        appendValue(buffer, ",minimalDaysInFirstWeek", true, (long) minimalDaysInFirstWeek);
140.2557 +        for (int i = 0; i < FIELD_COUNT; ++i) {
140.2558 +            buffer.append(',');
140.2559 +            appendValue(buffer, FIELD_NAME[i], isSet(i), (long) fields[i]);
140.2560 +        }
140.2561 +        buffer.append(']');
140.2562 +        return buffer.toString();
140.2563 +    }
140.2564 +
140.2565 +    // =======================privates===============================
140.2566 +
140.2567 +    private static final void appendValue(StringBuilder sb, String item, boolean valid, long value) {
140.2568 +        sb.append(item).append('=');
140.2569 +        if (valid) {
140.2570 +            sb.append(value);
140.2571 +        } else {
140.2572 +            sb.append('?');
140.2573 +        }
140.2574 +    }
140.2575 +
140.2576 +    /**
140.2577 +     * Both firstDayOfWeek and minimalDaysInFirstWeek are locale-dependent.
140.2578 +     * They are used to figure out the week count for a specific date for
140.2579 +     * a given locale. These must be set when a Calendar is constructed.
140.2580 +     * @param desiredLocale the given locale.
140.2581 +     */
140.2582 +    private void setWeekCountData(Locale desiredLocale)
140.2583 +    {
140.2584 +        /* try to get the Locale data from the cache */
140.2585 +        int[] data = cachedLocaleData.get(desiredLocale);
140.2586 +        if (data == null) {  /* cache miss */
140.2587 +//            ResourceBundle bundle = LocaleData.getCalendarData(desiredLocale);
140.2588 +            data = new int[2];
140.2589 +//            data[0] = Integer.parseInt(bundle.getString("firstDayOfWeek"));
140.2590 +//            data[1] = Integer.parseInt(bundle.getString("minimalDaysInFirstWeek"));
140.2591 +            cachedLocaleData.putIfAbsent(desiredLocale, data);
140.2592 +        }
140.2593 +        firstDayOfWeek = data[0];
140.2594 +        minimalDaysInFirstWeek = data[1];
140.2595 +    }
140.2596 +
140.2597 +    /**
140.2598 +     * Recomputes the time and updates the status fields isTimeSet
140.2599 +     * and areFieldsSet.  Callers should check isTimeSet and only
140.2600 +     * call this method if isTimeSet is false.
140.2601 +     */
140.2602 +    private void updateTime() {
140.2603 +        computeTime();
140.2604 +        // The areFieldsSet and areAllFieldsSet values are no longer
140.2605 +        // controlled here (as of 1.5).
140.2606 +        isTimeSet = true;
140.2607 +    }
140.2608 +
140.2609 +    private int compareTo(long t) {
140.2610 +        long thisTime = getMillisOf(this);
140.2611 +        return (thisTime > t) ? 1 : (thisTime == t) ? 0 : -1;
140.2612 +    }
140.2613 +
140.2614 +    private static final long getMillisOf(Calendar calendar) {
140.2615 +        if (calendar.isTimeSet) {
140.2616 +            return calendar.time;
140.2617 +        }
140.2618 +        Calendar cal = (Calendar) calendar.clone();
140.2619 +        cal.setLenient(true);
140.2620 +        return cal.getTimeInMillis();
140.2621 +    }
140.2622 +
140.2623 +    /**
140.2624 +     * Adjusts the stamp[] values before nextStamp overflow. nextStamp
140.2625 +     * is set to the next stamp value upon the return.
140.2626 +     */
140.2627 +    private final void adjustStamp() {
140.2628 +        int max = MINIMUM_USER_STAMP;
140.2629 +        int newStamp = MINIMUM_USER_STAMP;
140.2630 +
140.2631 +        for (;;) {
140.2632 +            int min = Integer.MAX_VALUE;
140.2633 +            for (int i = 0; i < stamp.length; i++) {
140.2634 +                int v = stamp[i];
140.2635 +                if (v >= newStamp && min > v) {
140.2636 +                    min = v;
140.2637 +                }
140.2638 +                if (max < v) {
140.2639 +                    max = v;
140.2640 +                }
140.2641 +            }
140.2642 +            if (max != min && min == Integer.MAX_VALUE) {
140.2643 +                break;
140.2644 +            }
140.2645 +            for (int i = 0; i < stamp.length; i++) {
140.2646 +                if (stamp[i] == min) {
140.2647 +                    stamp[i] = newStamp;
140.2648 +                }
140.2649 +            }
140.2650 +            newStamp++;
140.2651 +            if (min == max) {
140.2652 +                break;
140.2653 +            }
140.2654 +        }
140.2655 +        nextStamp = newStamp;
140.2656 +    }
140.2657 +
140.2658 +    /**
140.2659 +     * Sets the WEEK_OF_MONTH and WEEK_OF_YEAR fields to new values with the
140.2660 +     * new parameter value if they have been calculated internally.
140.2661 +     */
140.2662 +    private void invalidateWeekFields()
140.2663 +    {
140.2664 +        if (stamp[WEEK_OF_MONTH] != COMPUTED &&
140.2665 +            stamp[WEEK_OF_YEAR] != COMPUTED) {
140.2666 +            return;
140.2667 +        }
140.2668 +
140.2669 +        // We have to check the new values of these fields after changing
140.2670 +        // firstDayOfWeek and/or minimalDaysInFirstWeek. If the field values
140.2671 +        // have been changed, then set the new values. (4822110)
140.2672 +        Calendar cal = (Calendar) clone();
140.2673 +        cal.setLenient(true);
140.2674 +        cal.clear(WEEK_OF_MONTH);
140.2675 +        cal.clear(WEEK_OF_YEAR);
140.2676 +
140.2677 +        if (stamp[WEEK_OF_MONTH] == COMPUTED) {
140.2678 +            int weekOfMonth = cal.get(WEEK_OF_MONTH);
140.2679 +            if (fields[WEEK_OF_MONTH] != weekOfMonth) {
140.2680 +                fields[WEEK_OF_MONTH] = weekOfMonth;
140.2681 +            }
140.2682 +        }
140.2683 +
140.2684 +        if (stamp[WEEK_OF_YEAR] == COMPUTED) {
140.2685 +            int weekOfYear = cal.get(WEEK_OF_YEAR);
140.2686 +            if (fields[WEEK_OF_YEAR] != weekOfYear) {
140.2687 +                fields[WEEK_OF_YEAR] = weekOfYear;
140.2688 +            }
140.2689 +        }
140.2690 +    }
140.2691 +
140.2692 +    /**
140.2693 +     * Save the state of this object to a stream (i.e., serialize it).
140.2694 +     *
140.2695 +     * Ideally, <code>Calendar</code> would only write out its state data and
140.2696 +     * the current time, and not write any field data out, such as
140.2697 +     * <code>fields[]</code>, <code>isTimeSet</code>, <code>areFieldsSet</code>,
140.2698 +     * and <code>isSet[]</code>.  <code>nextStamp</code> also should not be part
140.2699 +     * of the persistent state. Unfortunately, this didn't happen before JDK 1.1
140.2700 +     * shipped. To be compatible with JDK 1.1, we will always have to write out
140.2701 +     * the field values and state flags.  However, <code>nextStamp</code> can be
140.2702 +     * removed from the serialization stream; this will probably happen in the
140.2703 +     * near future.
140.2704 +     */
140.2705 +    private void writeObject(ObjectOutputStream stream)
140.2706 +         throws IOException
140.2707 +    {
140.2708 +        // Try to compute the time correctly, for the future (stream
140.2709 +        // version 2) in which we don't write out fields[] or isSet[].
140.2710 +        if (!isTimeSet) {
140.2711 +            try {
140.2712 +                updateTime();
140.2713 +            }
140.2714 +            catch (IllegalArgumentException e) {}
140.2715 +        }
140.2716 +
140.2717 +        // If this Calendar has a ZoneInfo, save it and set a
140.2718 +        // SimpleTimeZone equivalent (as a single DST schedule) for
140.2719 +        // backward compatibility.
140.2720 +        TimeZone savedZone = null;
140.2721 +//        if (zone instanceof ZoneInfo) {
140.2722 +//            SimpleTimeZone stz = ((ZoneInfo)zone).getLastRuleInstance();
140.2723 +//            if (stz == null) {
140.2724 +//                stz = new SimpleTimeZone(zone.getRawOffset(), zone.getID());
140.2725 +//            }
140.2726 +//            savedZone = zone;
140.2727 +//            zone = stz;
140.2728 +//        }
140.2729 +
140.2730 +        // Write out the 1.1 FCS object.
140.2731 +        stream.defaultWriteObject();
140.2732 +
140.2733 +        // Write out the ZoneInfo object
140.2734 +        // 4802409: we write out even if it is null, a temporary workaround
140.2735 +        // the real fix for bug 4844924 in corba-iiop
140.2736 +        stream.writeObject(savedZone);
140.2737 +        if (savedZone != null) {
140.2738 +            zone = savedZone;
140.2739 +        }
140.2740 +    }
140.2741 +
140.2742 +    /**
140.2743 +     * Reconstitutes this object from a stream (i.e., deserialize it).
140.2744 +     */
140.2745 +    private void readObject(ObjectInputStream stream)
140.2746 +         throws IOException, ClassNotFoundException
140.2747 +    {
140.2748 +        final ObjectInputStream input = stream;
140.2749 +        input.defaultReadObject();
140.2750 +
140.2751 +        stamp = new int[FIELD_COUNT];
140.2752 +
140.2753 +        // Starting with version 2 (not implemented yet), we expect that
140.2754 +        // fields[], isSet[], isTimeSet, and areFieldsSet may not be
140.2755 +        // streamed out anymore.  We expect 'time' to be correct.
140.2756 +        if (serialVersionOnStream >= 2)
140.2757 +        {
140.2758 +            isTimeSet = true;
140.2759 +            if (fields == null) fields = new int[FIELD_COUNT];
140.2760 +            if (isSet == null) isSet = new boolean[FIELD_COUNT];
140.2761 +        }
140.2762 +        else if (serialVersionOnStream >= 0)
140.2763 +        {
140.2764 +            for (int i=0; i<FIELD_COUNT; ++i)
140.2765 +                stamp[i] = isSet[i] ? COMPUTED : UNSET;
140.2766 +        }
140.2767 +
140.2768 +        serialVersionOnStream = currentSerialVersion;
140.2769 +
140.2770 +        // If there's a ZoneInfo object, use it for zone.
140.2771 +        TimeZone zi = null;
140.2772 +//        try {
140.2773 +//            zi = AccessController.doPrivileged(
140.2774 +//                    new PrivilegedExceptionAction<ZoneInfo>() {
140.2775 +//                        public ZoneInfo run() throws Exception {
140.2776 +//                            return (ZoneInfo) input.readObject();
140.2777 +//                        }
140.2778 +//                    },
140.2779 +//                    CalendarAccessControlContext.INSTANCE);
140.2780 +//        } catch (PrivilegedActionException pae) {
140.2781 +//            Exception e = pae.getException();
140.2782 +//            if (!(e instanceof OptionalDataException)) {
140.2783 +//                if (e instanceof RuntimeException) {
140.2784 +//                    throw (RuntimeException) e;
140.2785 +//                } else if (e instanceof IOException) {
140.2786 +//                    throw (IOException) e;
140.2787 +//                } else if (e instanceof ClassNotFoundException) {
140.2788 +//                    throw (ClassNotFoundException) e;
140.2789 +//                }
140.2790 +//                throw new RuntimeException(e);
140.2791 +//            }
140.2792 +//        }
140.2793 +        if (zi != null) {
140.2794 +            zone = zi;
140.2795 +        }
140.2796 +
140.2797 +        // If the deserialized object has a SimpleTimeZone, try to
140.2798 +        // replace it with a ZoneInfo equivalent (as of 1.4) in order
140.2799 +        // to be compatible with the SimpleTimeZone-based
140.2800 +        // implementation as much as possible.
140.2801 +        if (zone instanceof SimpleTimeZone) {
140.2802 +            String id = zone.getID();
140.2803 +            TimeZone tz = TimeZone.getTimeZone(id);
140.2804 +            if (tz != null && tz.hasSameRules(zone) && tz.getID().equals(id)) {
140.2805 +                zone = tz;
140.2806 +            }
140.2807 +        }
140.2808 +    }
140.2809 +}
   141.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   141.2 +++ b/rt/emul/compact/src/main/java/java/util/Currency.java	Tue Feb 11 13:31:42 2014 +0100
   141.3 @@ -0,0 +1,735 @@
   141.4 +/*
   141.5 + * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
   141.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   141.7 + *
   141.8 + * This code is free software; you can redistribute it and/or modify it
   141.9 + * under the terms of the GNU General Public License version 2 only, as
  141.10 + * published by the Free Software Foundation.  Oracle designates this
  141.11 + * particular file as subject to the "Classpath" exception as provided
  141.12 + * by Oracle in the LICENSE file that accompanied this code.
  141.13 + *
  141.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  141.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  141.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  141.17 + * version 2 for more details (a copy is included in the LICENSE file that
  141.18 + * accompanied this code).
  141.19 + *
  141.20 + * You should have received a copy of the GNU General Public License version
  141.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  141.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  141.23 + *
  141.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  141.25 + * or visit www.oracle.com if you need additional information or have any
  141.26 + * questions.
  141.27 + */
  141.28 +
  141.29 +package java.util;
  141.30 +
  141.31 +import java.io.BufferedInputStream;
  141.32 +import java.io.DataInputStream;
  141.33 +import java.io.File;
  141.34 +import java.io.FileInputStream;
  141.35 +import java.io.FileReader;
  141.36 +import java.io.IOException;
  141.37 +import java.io.Serializable;
  141.38 +import java.security.AccessController;
  141.39 +import java.security.PrivilegedAction;
  141.40 +import java.util.logging.Level;
  141.41 +import java.util.logging.Logger;
  141.42 +
  141.43 +
  141.44 +/**
  141.45 + * Represents a currency. Currencies are identified by their ISO 4217 currency
  141.46 + * codes. Visit the <a href="http://www.iso.org/iso/en/prods-services/popstds/currencycodes.html">
  141.47 + * ISO web site</a> for more information, including a table of
  141.48 + * currency codes.
  141.49 + * <p>
  141.50 + * The class is designed so that there's never more than one
  141.51 + * <code>Currency</code> instance for any given currency. Therefore, there's
  141.52 + * no public constructor. You obtain a <code>Currency</code> instance using
  141.53 + * the <code>getInstance</code> methods.
  141.54 + * <p>
  141.55 + * Users can supersede the Java runtime currency data by creating a properties
  141.56 + * file named <code>&lt;JAVA_HOME&gt;/lib/currency.properties</code>.  The contents
  141.57 + * of the properties file are key/value pairs of the ISO 3166 country codes
  141.58 + * and the ISO 4217 currency data respectively.  The value part consists of
  141.59 + * three ISO 4217 values of a currency, i.e., an alphabetic code, a numeric
  141.60 + * code, and a minor unit.  Those three ISO 4217 values are separated by commas.
  141.61 + * The lines which start with '#'s are considered comment lines.  For example,
  141.62 + * <p>
  141.63 + * <code>
  141.64 + * #Sample currency properties<br>
  141.65 + * JP=JPZ,999,0
  141.66 + * </code>
  141.67 + * <p>
  141.68 + * will supersede the currency data for Japan.
  141.69 + *
  141.70 + * @since 1.4
  141.71 + */
  141.72 +public final class Currency implements Serializable {
  141.73 +
  141.74 +    private static final long serialVersionUID = -158308464356906721L;
  141.75 +
  141.76 +    /**
  141.77 +     * ISO 4217 currency code for this currency.
  141.78 +     *
  141.79 +     * @serial
  141.80 +     */
  141.81 +    private final String currencyCode;
  141.82 +
  141.83 +    /**
  141.84 +     * Default fraction digits for this currency.
  141.85 +     * Set from currency data tables.
  141.86 +     */
  141.87 +    transient private final int defaultFractionDigits;
  141.88 +
  141.89 +    /**
  141.90 +     * ISO 4217 numeric code for this currency.
  141.91 +     * Set from currency data tables.
  141.92 +     */
  141.93 +    transient private final int numericCode;
  141.94 +
  141.95 +
  141.96 +    // class data: instance map
  141.97 +
  141.98 +    private static HashMap<String, Currency> instances = new HashMap<String, Currency>(7);
  141.99 +    private static HashSet<Currency> available;
 141.100 +
 141.101 +
 141.102 +    // Class data: currency data obtained from currency.data file.
 141.103 +    // Purpose:
 141.104 +    // - determine valid country codes
 141.105 +    // - determine valid currency codes
 141.106 +    // - map country codes to currency codes
 141.107 +    // - obtain default fraction digits for currency codes
 141.108 +    //
 141.109 +    // sc = special case; dfd = default fraction digits
 141.110 +    // Simple countries are those where the country code is a prefix of the
 141.111 +    // currency code, and there are no known plans to change the currency.
 141.112 +    //
 141.113 +    // table formats:
 141.114 +    // - mainTable:
 141.115 +    //   - maps country code to 32-bit int
 141.116 +    //   - 26*26 entries, corresponding to [A-Z]*[A-Z]
 141.117 +    //   - \u007F -> not valid country
 141.118 +    //   - bits 18-31: unused
 141.119 +    //   - bits 8-17: numeric code (0 to 1023)
 141.120 +    //   - bit 7: 1 - special case, bits 0-4 indicate which one
 141.121 +    //            0 - simple country, bits 0-4 indicate final char of currency code
 141.122 +    //   - bits 5-6: fraction digits for simple countries, 0 for special cases
 141.123 +    //   - bits 0-4: final char for currency code for simple country, or ID of special case
 141.124 +    // - special case IDs:
 141.125 +    //   - 0: country has no currency
 141.126 +    //   - other: index into sc* arrays + 1
 141.127 +    // - scCutOverTimes: cut-over time in millis as returned by
 141.128 +    //   System.currentTimeMillis for special case countries that are changing
 141.129 +    //   currencies; Long.MAX_VALUE for countries that are not changing currencies
 141.130 +    // - scOldCurrencies: old currencies for special case countries
 141.131 +    // - scNewCurrencies: new currencies for special case countries that are
 141.132 +    //   changing currencies; null for others
 141.133 +    // - scOldCurrenciesDFD: default fraction digits for old currencies
 141.134 +    // - scNewCurrenciesDFD: default fraction digits for new currencies, 0 for
 141.135 +    //   countries that are not changing currencies
 141.136 +    // - otherCurrencies: concatenation of all currency codes that are not the
 141.137 +    //   main currency of a simple country, separated by "-"
 141.138 +    // - otherCurrenciesDFD: decimal format digits for currencies in otherCurrencies, same order
 141.139 +
 141.140 +    static int formatVersion;
 141.141 +    static int dataVersion;
 141.142 +    static int[] mainTable;
 141.143 +    static long[] scCutOverTimes;
 141.144 +    static String[] scOldCurrencies;
 141.145 +    static String[] scNewCurrencies;
 141.146 +    static int[] scOldCurrenciesDFD;
 141.147 +    static int[] scNewCurrenciesDFD;
 141.148 +    static int[] scOldCurrenciesNumericCode;
 141.149 +    static int[] scNewCurrenciesNumericCode;
 141.150 +    static String otherCurrencies;
 141.151 +    static int[] otherCurrenciesDFD;
 141.152 +    static int[] otherCurrenciesNumericCode;
 141.153 +
 141.154 +    // handy constants - must match definitions in GenerateCurrencyData
 141.155 +    // magic number
 141.156 +    private static final int MAGIC_NUMBER = 0x43757244;
 141.157 +    // number of characters from A to Z
 141.158 +    private static final int A_TO_Z = ('Z' - 'A') + 1;
 141.159 +    // entry for invalid country codes
 141.160 +    private static final int INVALID_COUNTRY_ENTRY = 0x007F;
 141.161 +    // entry for countries without currency
 141.162 +    private static final int COUNTRY_WITHOUT_CURRENCY_ENTRY = 0x0080;
 141.163 +    // mask for simple case country entries
 141.164 +    private static final int SIMPLE_CASE_COUNTRY_MASK = 0x0000;
 141.165 +    // mask for simple case country entry final character
 141.166 +    private static final int SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK = 0x001F;
 141.167 +    // mask for simple case country entry default currency digits
 141.168 +    private static final int SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_MASK = 0x0060;
 141.169 +    // shift count for simple case country entry default currency digits
 141.170 +    private static final int SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT = 5;
 141.171 +    // mask for special case country entries
 141.172 +    private static final int SPECIAL_CASE_COUNTRY_MASK = 0x0080;
 141.173 +    // mask for special case country index
 141.174 +    private static final int SPECIAL_CASE_COUNTRY_INDEX_MASK = 0x001F;
 141.175 +    // delta from entry index component in main table to index into special case tables
 141.176 +    private static final int SPECIAL_CASE_COUNTRY_INDEX_DELTA = 1;
 141.177 +    // mask for distinguishing simple and special case countries
 141.178 +    private static final int COUNTRY_TYPE_MASK = SIMPLE_CASE_COUNTRY_MASK | SPECIAL_CASE_COUNTRY_MASK;
 141.179 +    // mask for the numeric code of the currency
 141.180 +    private static final int NUMERIC_CODE_MASK = 0x0003FF00;
 141.181 +    // shift count for the numeric code of the currency
 141.182 +    private static final int NUMERIC_CODE_SHIFT = 8;
 141.183 +
 141.184 +    // Currency data format version
 141.185 +    private static final int VALID_FORMAT_VERSION = 1;
 141.186 +
 141.187 +    static {
 141.188 +        AccessController.doPrivileged(new PrivilegedAction() {
 141.189 +            public Object run() {
 141.190 +                String homeDir = System.getProperty("java.home");
 141.191 +                try {
 141.192 +                    String dataFile = homeDir + File.separator +
 141.193 +                            "lib" + File.separator + "currency.data";
 141.194 +                    DataInputStream dis = new DataInputStream(
 141.195 +                        new BufferedInputStream(
 141.196 +                        new FileInputStream(dataFile)));
 141.197 +                    if (dis.readInt() != MAGIC_NUMBER) {
 141.198 +                        throw new InternalError("Currency data is possibly corrupted");
 141.199 +                    }
 141.200 +                    formatVersion = dis.readInt();
 141.201 +                    if (formatVersion != VALID_FORMAT_VERSION) {
 141.202 +                        throw new InternalError("Currency data format is incorrect");
 141.203 +                    }
 141.204 +                    dataVersion = dis.readInt();
 141.205 +                    mainTable = readIntArray(dis, A_TO_Z * A_TO_Z);
 141.206 +                    int scCount = dis.readInt();
 141.207 +                    scCutOverTimes = readLongArray(dis, scCount);
 141.208 +                    scOldCurrencies = readStringArray(dis, scCount);
 141.209 +                    scNewCurrencies = readStringArray(dis, scCount);
 141.210 +                    scOldCurrenciesDFD = readIntArray(dis, scCount);
 141.211 +                    scNewCurrenciesDFD = readIntArray(dis, scCount);
 141.212 +                    scOldCurrenciesNumericCode = readIntArray(dis, scCount);
 141.213 +                    scNewCurrenciesNumericCode = readIntArray(dis, scCount);
 141.214 +                    int ocCount = dis.readInt();
 141.215 +                    otherCurrencies = dis.readUTF();
 141.216 +                    otherCurrenciesDFD = readIntArray(dis, ocCount);
 141.217 +                    otherCurrenciesNumericCode = readIntArray(dis, ocCount);
 141.218 +                    dis.close();
 141.219 +                } catch (IOException e) {
 141.220 +                    InternalError ie = new InternalError();
 141.221 +                    ie.initCause(e);
 141.222 +                    throw ie;
 141.223 +                }
 141.224 +
 141.225 +                // look for the properties file for overrides
 141.226 +//                try {
 141.227 +                    File propFile = new File(homeDir + File.separator +
 141.228 +                                             "lib" + File.separator +
 141.229 +                                             "currency.properties");
 141.230 +//                    if (propFile.exists()) {
 141.231 +//                        Properties props = new Properties();
 141.232 +//                        try (FileReader fr = new FileReader(propFile)) {
 141.233 +//                            props.load(fr);
 141.234 +//                        }
 141.235 +//                        Set<String> keys = props.stringPropertyNames();
 141.236 +//                        Pattern propertiesPattern =
 141.237 +//                            Pattern.compile("([A-Z]{3})\\s*,\\s*(\\d{3})\\s*,\\s*([0-3])");
 141.238 +//                        for (String key : keys) {
 141.239 +//                           replaceCurrencyData(propertiesPattern,
 141.240 +//                               key.toUpperCase(Locale.ROOT),
 141.241 +//                               props.getProperty(key).toUpperCase(Locale.ROOT));
 141.242 +//                        }
 141.243 +//                    }
 141.244 +//                } catch (IOException e) {
 141.245 +//                    info("currency.properties is ignored because of an IOException", e);
 141.246 +//                }
 141.247 +                return null;
 141.248 +            }
 141.249 +        });
 141.250 +    }
 141.251 +
 141.252 +    /**
 141.253 +     * Constants for retrieving localized names from the name providers.
 141.254 +     */
 141.255 +    private static final int SYMBOL = 0;
 141.256 +    private static final int DISPLAYNAME = 1;
 141.257 +
 141.258 +
 141.259 +    /**
 141.260 +     * Constructs a <code>Currency</code> instance. The constructor is private
 141.261 +     * so that we can insure that there's never more than one instance for a
 141.262 +     * given currency.
 141.263 +     */
 141.264 +    private Currency(String currencyCode, int defaultFractionDigits, int numericCode) {
 141.265 +        this.currencyCode = currencyCode;
 141.266 +        this.defaultFractionDigits = defaultFractionDigits;
 141.267 +        this.numericCode = numericCode;
 141.268 +    }
 141.269 +
 141.270 +    /**
 141.271 +     * Returns the <code>Currency</code> instance for the given currency code.
 141.272 +     *
 141.273 +     * @param currencyCode the ISO 4217 code of the currency
 141.274 +     * @return the <code>Currency</code> instance for the given currency code
 141.275 +     * @exception NullPointerException if <code>currencyCode</code> is null
 141.276 +     * @exception IllegalArgumentException if <code>currencyCode</code> is not
 141.277 +     * a supported ISO 4217 code.
 141.278 +     */
 141.279 +    public static Currency getInstance(String currencyCode) {
 141.280 +        return getInstance(currencyCode, Integer.MIN_VALUE, 0);
 141.281 +    }
 141.282 +
 141.283 +    private static Currency getInstance(String currencyCode, int defaultFractionDigits,
 141.284 +        int numericCode) {
 141.285 +        synchronized (instances) {
 141.286 +            // Try to look up the currency code in the instances table.
 141.287 +            // This does the null pointer check as a side effect.
 141.288 +            // Also, if there already is an entry, the currencyCode must be valid.
 141.289 +            Currency instance = instances.get(currencyCode);
 141.290 +            if (instance != null) {
 141.291 +                return instance;
 141.292 +            }
 141.293 +
 141.294 +            if (defaultFractionDigits == Integer.MIN_VALUE) {
 141.295 +                // Currency code not internally generated, need to verify first
 141.296 +                // A currency code must have 3 characters and exist in the main table
 141.297 +                // or in the list of other currencies.
 141.298 +                if (currencyCode.length() != 3) {
 141.299 +                    throw new IllegalArgumentException();
 141.300 +                }
 141.301 +                char char1 = currencyCode.charAt(0);
 141.302 +                char char2 = currencyCode.charAt(1);
 141.303 +                int tableEntry = getMainTableEntry(char1, char2);
 141.304 +                if ((tableEntry & COUNTRY_TYPE_MASK) == SIMPLE_CASE_COUNTRY_MASK
 141.305 +                        && tableEntry != INVALID_COUNTRY_ENTRY
 141.306 +                        && currencyCode.charAt(2) - 'A' == (tableEntry & SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK)) {
 141.307 +                    defaultFractionDigits = (tableEntry & SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_MASK) >> SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT;
 141.308 +                    numericCode = (tableEntry & NUMERIC_CODE_MASK) >> NUMERIC_CODE_SHIFT;
 141.309 +                } else {
 141.310 +                    // Check for '-' separately so we don't get false hits in the table.
 141.311 +                    if (currencyCode.charAt(2) == '-') {
 141.312 +                        throw new IllegalArgumentException();
 141.313 +                    }
 141.314 +                    int index = otherCurrencies.indexOf(currencyCode);
 141.315 +                    if (index == -1) {
 141.316 +                        throw new IllegalArgumentException();
 141.317 +                    }
 141.318 +                    defaultFractionDigits = otherCurrenciesDFD[index / 4];
 141.319 +                    numericCode = otherCurrenciesNumericCode[index / 4];
 141.320 +                }
 141.321 +            }
 141.322 +
 141.323 +            instance = new Currency(currencyCode, defaultFractionDigits, numericCode);
 141.324 +            instances.put(currencyCode, instance);
 141.325 +            return instance;
 141.326 +        }
 141.327 +    }
 141.328 +
 141.329 +    /**
 141.330 +     * Returns the <code>Currency</code> instance for the country of the
 141.331 +     * given locale. The language and variant components of the locale
 141.332 +     * are ignored. The result may vary over time, as countries change their
 141.333 +     * currencies. For example, for the original member countries of the
 141.334 +     * European Monetary Union, the method returns the old national currencies
 141.335 +     * until December 31, 2001, and the Euro from January 1, 2002, local time
 141.336 +     * of the respective countries.
 141.337 +     * <p>
 141.338 +     * The method returns <code>null</code> for territories that don't
 141.339 +     * have a currency, such as Antarctica.
 141.340 +     *
 141.341 +     * @param locale the locale for whose country a <code>Currency</code>
 141.342 +     * instance is needed
 141.343 +     * @return the <code>Currency</code> instance for the country of the given
 141.344 +     * locale, or null
 141.345 +     * @exception NullPointerException if <code>locale</code> or its country
 141.346 +     * code is null
 141.347 +     * @exception IllegalArgumentException if the country of the given locale
 141.348 +     * is not a supported ISO 3166 country code.
 141.349 +     */
 141.350 +    public static Currency getInstance(Locale locale) {
 141.351 +        String country = locale.getCountry();
 141.352 +        if (country == null) {
 141.353 +            throw new NullPointerException();
 141.354 +        }
 141.355 +
 141.356 +        if (country.length() != 2) {
 141.357 +            throw new IllegalArgumentException();
 141.358 +        }
 141.359 +
 141.360 +        char char1 = country.charAt(0);
 141.361 +        char char2 = country.charAt(1);
 141.362 +        int tableEntry = getMainTableEntry(char1, char2);
 141.363 +        if ((tableEntry & COUNTRY_TYPE_MASK) == SIMPLE_CASE_COUNTRY_MASK
 141.364 +                    && tableEntry != INVALID_COUNTRY_ENTRY) {
 141.365 +            char finalChar = (char) ((tableEntry & SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK) + 'A');
 141.366 +            int defaultFractionDigits = (tableEntry & SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_MASK) >> SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT;
 141.367 +            int numericCode = (tableEntry & NUMERIC_CODE_MASK) >> NUMERIC_CODE_SHIFT;
 141.368 +            StringBuffer sb = new StringBuffer(country);
 141.369 +            sb.append(finalChar);
 141.370 +            return getInstance(sb.toString(), defaultFractionDigits, numericCode);
 141.371 +        } else {
 141.372 +            // special cases
 141.373 +            if (tableEntry == INVALID_COUNTRY_ENTRY) {
 141.374 +                throw new IllegalArgumentException();
 141.375 +            }
 141.376 +            if (tableEntry == COUNTRY_WITHOUT_CURRENCY_ENTRY) {
 141.377 +                return null;
 141.378 +            } else {
 141.379 +                int index = (tableEntry & SPECIAL_CASE_COUNTRY_INDEX_MASK) - SPECIAL_CASE_COUNTRY_INDEX_DELTA;
 141.380 +                if (scCutOverTimes[index] == Long.MAX_VALUE || System.currentTimeMillis() < scCutOverTimes[index]) {
 141.381 +                    return getInstance(scOldCurrencies[index], scOldCurrenciesDFD[index],
 141.382 +                        scOldCurrenciesNumericCode[index]);
 141.383 +                } else {
 141.384 +                    return getInstance(scNewCurrencies[index], scNewCurrenciesDFD[index],
 141.385 +                        scNewCurrenciesNumericCode[index]);
 141.386 +                }
 141.387 +            }
 141.388 +        }
 141.389 +    }
 141.390 +
 141.391 +    /**
 141.392 +     * Gets the set of available currencies.  The returned set of currencies
 141.393 +     * contains all of the available currencies, which may include currencies
 141.394 +     * that represent obsolete ISO 4217 codes.  The set can be modified
 141.395 +     * without affecting the available currencies in the runtime.
 141.396 +     *
 141.397 +     * @return the set of available currencies.  If there is no currency
 141.398 +     *    available in the runtime, the returned set is empty.
 141.399 +     * @since 1.7
 141.400 +     */
 141.401 +    public static Set<Currency> getAvailableCurrencies() {
 141.402 +        synchronized(Currency.class) {
 141.403 +            if (available == null) {
 141.404 +                available = new HashSet<Currency>(256);
 141.405 +
 141.406 +                // Add simple currencies first
 141.407 +                for (char c1 = 'A'; c1 <= 'Z'; c1 ++) {
 141.408 +                    for (char c2 = 'A'; c2 <= 'Z'; c2 ++) {
 141.409 +                        int tableEntry = getMainTableEntry(c1, c2);
 141.410 +                        if ((tableEntry & COUNTRY_TYPE_MASK) == SIMPLE_CASE_COUNTRY_MASK
 141.411 +                             && tableEntry != INVALID_COUNTRY_ENTRY) {
 141.412 +                            char finalChar = (char) ((tableEntry & SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK) + 'A');
 141.413 +                            int defaultFractionDigits = (tableEntry & SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_MASK) >> SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT;
 141.414 +                            int numericCode = (tableEntry & NUMERIC_CODE_MASK) >> NUMERIC_CODE_SHIFT;
 141.415 +                            StringBuilder sb = new StringBuilder();
 141.416 +                            sb.append(c1);
 141.417 +                            sb.append(c2);
 141.418 +                            sb.append(finalChar);
 141.419 +                            available.add(getInstance(sb.toString(), defaultFractionDigits, numericCode));
 141.420 +                        }
 141.421 +                    }
 141.422 +                }
 141.423 +
 141.424 +                // Now add other currencies
 141.425 +                StringTokenizer st = new StringTokenizer(otherCurrencies, "-");
 141.426 +                while (st.hasMoreElements()) {
 141.427 +                    available.add(getInstance((String)st.nextElement()));
 141.428 +                }
 141.429 +            }
 141.430 +        }
 141.431 +
 141.432 +        return (Set<Currency>) available.clone();
 141.433 +    }
 141.434 +
 141.435 +    /**
 141.436 +     * Gets the ISO 4217 currency code of this currency.
 141.437 +     *
 141.438 +     * @return the ISO 4217 currency code of this currency.
 141.439 +     */
 141.440 +    public String getCurrencyCode() {
 141.441 +        return currencyCode;
 141.442 +    }
 141.443 +
 141.444 +    /**
 141.445 +     * Gets the symbol of this currency for the default locale.
 141.446 +     * For example, for the US Dollar, the symbol is "$" if the default
 141.447 +     * locale is the US, while for other locales it may be "US$". If no
 141.448 +     * symbol can be determined, the ISO 4217 currency code is returned.
 141.449 +     *
 141.450 +     * @return the symbol of this currency for the default locale
 141.451 +     */
 141.452 +    public String getSymbol() {
 141.453 +        return getSymbol(Locale.getDefault(Locale.Category.DISPLAY));
 141.454 +    }
 141.455 +
 141.456 +    /**
 141.457 +     * Gets the symbol of this currency for the specified locale.
 141.458 +     * For example, for the US Dollar, the symbol is "$" if the specified
 141.459 +     * locale is the US, while for other locales it may be "US$". If no
 141.460 +     * symbol can be determined, the ISO 4217 currency code is returned.
 141.461 +     *
 141.462 +     * @param locale the locale for which a display name for this currency is
 141.463 +     * needed
 141.464 +     * @return the symbol of this currency for the specified locale
 141.465 +     * @exception NullPointerException if <code>locale</code> is null
 141.466 +     */
 141.467 +    public String getSymbol(Locale locale) {
 141.468 +        try {
 141.469 +            // Check whether a provider can provide an implementation that's closer
 141.470 +            // to the requested locale than what the Java runtime itself can provide.
 141.471 +            /*
 141.472 +            LocaleServiceProviderPool pool =
 141.473 +                LocaleServiceProviderPool.getPool(CurrencyNameProvider.class);
 141.474 +
 141.475 +            if (pool.hasProviders()) {
 141.476 +                // Assuming that all the country locales include necessary currency
 141.477 +                // symbols in the Java runtime's resources,  so there is no need to
 141.478 +                // examine whether Java runtime's currency resource bundle is missing
 141.479 +                // names.  Therefore, no resource bundle is provided for calling this
 141.480 +                // method.
 141.481 +                String symbol = pool.getLocalizedObject(
 141.482 +                                    CurrencyNameGetter.INSTANCE,
 141.483 +                                    locale, (OpenListResourceBundle)null,
 141.484 +                                    currencyCode, SYMBOL);
 141.485 +                if (symbol != null) {
 141.486 +                    return symbol;
 141.487 +                }
 141.488 +            }
 141.489 +            */
 141.490 +            ResourceBundle bundle = null; //LocaleData.getCurrencyNames(locale);
 141.491 +            return bundle.getString(currencyCode);
 141.492 +        } catch (MissingResourceException e) {
 141.493 +            // use currency code as symbol of last resort
 141.494 +            return currencyCode;
 141.495 +        }
 141.496 +    }
 141.497 +
 141.498 +    /**
 141.499 +     * Gets the default number of fraction digits used with this currency.
 141.500 +     * For example, the default number of fraction digits for the Euro is 2,
 141.501 +     * while for the Japanese Yen it's 0.
 141.502 +     * In the case of pseudo-currencies, such as IMF Special Drawing Rights,
 141.503 +     * -1 is returned.
 141.504 +     *
 141.505 +     * @return the default number of fraction digits used with this currency
 141.506 +     */
 141.507 +    public int getDefaultFractionDigits() {
 141.508 +        return defaultFractionDigits;
 141.509 +    }
 141.510 +
 141.511 +    /**
 141.512 +     * Returns the ISO 4217 numeric code of this currency.
 141.513 +     *
 141.514 +     * @return the ISO 4217 numeric code of this currency
 141.515 +     * @since 1.7
 141.516 +     */
 141.517 +    public int getNumericCode() {
 141.518 +        return numericCode;
 141.519 +    }
 141.520 +
 141.521 +    /**
 141.522 +     * Gets the name that is suitable for displaying this currency for
 141.523 +     * the default locale.  If there is no suitable display name found
 141.524 +     * for the default locale, the ISO 4217 currency code is returned.
 141.525 +     *
 141.526 +     * @return the display name of this currency for the default locale
 141.527 +     * @since 1.7
 141.528 +     */
 141.529 +    public String getDisplayName() {
 141.530 +        return getDisplayName(Locale.getDefault(Locale.Category.DISPLAY));
 141.531 +    }
 141.532 +
 141.533 +    /**
 141.534 +     * Gets the name that is suitable for displaying this currency for
 141.535 +     * the specified locale.  If there is no suitable display name found
 141.536 +     * for the specified locale, the ISO 4217 currency code is returned.
 141.537 +     *
 141.538 +     * @param locale the locale for which a display name for this currency is
 141.539 +     * needed
 141.540 +     * @return the display name of this currency for the specified locale
 141.541 +     * @exception NullPointerException if <code>locale</code> is null
 141.542 +     * @since 1.7
 141.543 +     */
 141.544 +    public String getDisplayName(Locale locale) {
 141.545 +//        try {
 141.546 +//            OpenListResourceBundle bundle = LocaleData.getCurrencyNames(locale);
 141.547 +//            String result = null;
 141.548 +//            String bundleKey = currencyCode.toLowerCase(Locale.ROOT);
 141.549 +//
 141.550 +//            // Check whether a provider can provide an implementation that's closer
 141.551 +//            // to the requested locale than what the Java runtime itself can provide.
 141.552 +//            LocaleServiceProviderPool pool =
 141.553 +//                LocaleServiceProviderPool.getPool(CurrencyNameProvider.class);
 141.554 +//            if (pool.hasProviders()) {
 141.555 +//                result = pool.getLocalizedObject(
 141.556 +//                                    CurrencyNameGetter.INSTANCE,
 141.557 +//                                    locale, bundleKey, bundle, currencyCode, DISPLAYNAME);
 141.558 +//            }
 141.559 +//
 141.560 +//            if (result == null) {
 141.561 +//                result = bundle.getString(bundleKey);
 141.562 +//            }
 141.563 +//
 141.564 +//            if (result != null) {
 141.565 +//                return result;
 141.566 +//            }
 141.567 +//        } catch (MissingResourceException e) {
 141.568 +//            // fall through
 141.569 +//        }
 141.570 +
 141.571 +        // use currency code as symbol of last resort
 141.572 +        return currencyCode;
 141.573 +    }
 141.574 +
 141.575 +    /**
 141.576 +     * Returns the ISO 4217 currency code of this currency.
 141.577 +     *
 141.578 +     * @return the ISO 4217 currency code of this currency
 141.579 +     */
 141.580 +    public String toString() {
 141.581 +        return currencyCode;
 141.582 +    }
 141.583 +
 141.584 +    /**
 141.585 +     * Resolves instances being deserialized to a single instance per currency.
 141.586 +     */
 141.587 +    private Object readResolve() {
 141.588 +        return getInstance(currencyCode);
 141.589 +    }
 141.590 +
 141.591 +    /**
 141.592 +     * Gets the main table entry for the country whose country code consists
 141.593 +     * of char1 and char2.
 141.594 +     */
 141.595 +    private static int getMainTableEntry(char char1, char char2) {
 141.596 +        if (char1 < 'A' || char1 > 'Z' || char2 < 'A' || char2 > 'Z') {
 141.597 +            throw new IllegalArgumentException();
 141.598 +        }
 141.599 +        return mainTable[(char1 - 'A') * A_TO_Z + (char2 - 'A')];
 141.600 +    }
 141.601 +
 141.602 +    /**
 141.603 +     * Sets the main table entry for the country whose country code consists
 141.604 +     * of char1 and char2.
 141.605 +     */
 141.606 +    private static void setMainTableEntry(char char1, char char2, int entry) {
 141.607 +        if (char1 < 'A' || char1 > 'Z' || char2 < 'A' || char2 > 'Z') {
 141.608 +            throw new IllegalArgumentException();
 141.609 +        }
 141.610 +        mainTable[(char1 - 'A') * A_TO_Z + (char2 - 'A')] = entry;
 141.611 +    }
 141.612 +
 141.613 +    /**
 141.614 +     * Obtains a localized currency names from a CurrencyNameProvider
 141.615 +     * implementation.
 141.616 +    private static class CurrencyNameGetter
 141.617 +        implements LocaleServiceProviderPool.LocalizedObjectGetter<CurrencyNameProvider,
 141.618 +                                                                   String> {
 141.619 +        private static final CurrencyNameGetter INSTANCE = new CurrencyNameGetter();
 141.620 +
 141.621 +        public String getObject(CurrencyNameProvider currencyNameProvider,
 141.622 +                                Locale locale,
 141.623 +                                String key,
 141.624 +                                Object... params) {
 141.625 +            assert params.length == 1;
 141.626 +            int type = (Integer)params[0];
 141.627 +
 141.628 +            switch(type) {
 141.629 +            case SYMBOL:
 141.630 +                return currencyNameProvider.getSymbol(key, locale);
 141.631 +            case DISPLAYNAME:
 141.632 +                return currencyNameProvider.getDisplayName(key, locale);
 141.633 +            default:
 141.634 +                assert false; // shouldn't happen
 141.635 +            }
 141.636 +
 141.637 +            return null;
 141.638 +        }
 141.639 +    }
 141.640 +     */
 141.641 +
 141.642 +    private static int[] readIntArray(DataInputStream dis, int count) throws IOException {
 141.643 +        int[] ret = new int[count];
 141.644 +        for (int i = 0; i < count; i++) {
 141.645 +            ret[i] = dis.readInt();
 141.646 +        }
 141.647 +
 141.648 +        return ret;
 141.649 +    }
 141.650 +
 141.651 +    private static long[] readLongArray(DataInputStream dis, int count) throws IOException {
 141.652 +        long[] ret = new long[count];
 141.653 +        for (int i = 0; i < count; i++) {
 141.654 +            ret[i] = dis.readLong();
 141.655 +        }
 141.656 +
 141.657 +        return ret;
 141.658 +    }
 141.659 +
 141.660 +    private static String[] readStringArray(DataInputStream dis, int count) throws IOException {
 141.661 +        String[] ret = new String[count];
 141.662 +        for (int i = 0; i < count; i++) {
 141.663 +            ret[i] = dis.readUTF();
 141.664 +        }
 141.665 +
 141.666 +        return ret;
 141.667 +    }
 141.668 +
 141.669 +    /**
 141.670 +     * Replaces currency data found in the currencydata.properties file
 141.671 +     *
 141.672 +     * @param pattern regex pattern for the properties
 141.673 +     * @param ctry country code
 141.674 +     * @param data currency data.  This is a comma separated string that
 141.675 +     *    consists of "three-letter alphabet code", "three-digit numeric code",
 141.676 +     *    and "one-digit (0,1,2, or 3) default fraction digit".
 141.677 +     *    For example, "JPZ,392,0".
 141.678 +     * @throws
 141.679 +    private static void replaceCurrencyData(Pattern pattern, String ctry, String curdata) {
 141.680 +
 141.681 +        if (ctry.length() != 2) {
 141.682 +            // ignore invalid country code
 141.683 +            String message = new StringBuilder()
 141.684 +                .append("The entry in currency.properties for ")
 141.685 +                .append(ctry).append(" is ignored because of the invalid country code.")
 141.686 +                .toString();
 141.687 +            info(message, null);
 141.688 +            return;
 141.689 +        }
 141.690 +
 141.691 +        Matcher m = pattern.matcher(curdata);
 141.692 +        if (!m.find()) {
 141.693 +            // format is not recognized.  ignore the data
 141.694 +            String message = new StringBuilder()
 141.695 +                .append("The entry in currency.properties for ")
 141.696 +                .append(ctry)
 141.697 +                .append(" is ignored because the value format is not recognized.")
 141.698 +                .toString();
 141.699 +            info(message, null);
 141.700 +            return;
 141.701 +        }
 141.702 +
 141.703 +        String code = m.group(1);
 141.704 +        int numeric = Integer.parseInt(m.group(2));
 141.705 +        int fraction = Integer.parseInt(m.group(3));
 141.706 +        int entry = numeric << NUMERIC_CODE_SHIFT;
 141.707 +
 141.708 +        int index;
 141.709 +        for (index = 0; index < scOldCurrencies.length; index++) {
 141.710 +            if (scOldCurrencies[index].equals(code)) {
 141.711 +                break;
 141.712 +            }
 141.713 +        }
 141.714 +
 141.715 +        if (index == scOldCurrencies.length) {
 141.716 +            // simple case
 141.717 +            entry |= (fraction << SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT) |
 141.718 +                     (code.charAt(2) - 'A');
 141.719 +        } else {
 141.720 +            // special case
 141.721 +            entry |= SPECIAL_CASE_COUNTRY_MASK |
 141.722 +                     (index + SPECIAL_CASE_COUNTRY_INDEX_DELTA);
 141.723 +        }
 141.724 +        setMainTableEntry(ctry.charAt(0), ctry.charAt(1), entry);
 141.725 +    }
 141.726 +     */
 141.727 +
 141.728 +    private static void info(String message, Throwable t) {
 141.729 +        Logger logger = Logger.getLogger("java.util.Currency");
 141.730 +        if (logger.isLoggable(Level.INFO)) {
 141.731 +            if (t != null) {
 141.732 +                logger.log(Level.INFO, message, t);
 141.733 +            } else {
 141.734 +                logger.info(message);
 141.735 +            }
 141.736 +        }
 141.737 +    }
 141.738 +}
   142.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   142.2 +++ b/rt/emul/compact/src/main/java/java/util/CurrencyData.properties	Tue Feb 11 13:31:42 2014 +0100
   142.3 @@ -0,0 +1,586 @@
   142.4 +#
   142.5 +# Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved.
   142.6 +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   142.7 +#
   142.8 +# This code is free software; you can redistribute it and/or modify it
   142.9 +# under the terms of the GNU General Public License version 2 only, as
  142.10 +# published by the Free Software Foundation.  Oracle designates this
  142.11 +# particular file as subject to the "Classpath" exception as provided
  142.12 +# by Oracle in the LICENSE file that accompanied this code.
  142.13 +#
  142.14 +# This code is distributed in the hope that it will be useful, but WITHOUT
  142.15 +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  142.16 +# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  142.17 +# version 2 for more details (a copy is included in the LICENSE file that
  142.18 +# accompanied this code).
  142.19 +#
  142.20 +# You should have received a copy of the GNU General Public License version
  142.21 +# 2 along with this work; if not, write to the Free Software Foundation,
  142.22 +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  142.23 +#
  142.24 +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  142.25 +# or visit www.oracle.com if you need additional information or have any
  142.26 +# questions.
  142.27 +#
  142.28 +
  142.29 +formatVersion=1
  142.30 +
  142.31 +# Version of the currency code information in this class.
  142.32 +# It is a serial number that accompanies with each amendment, such as 
  142.33 +# 'MAxxx.doc'
  142.34 +
  142.35 +dataVersion=140
  142.36 +
  142.37 +# List of all valid ISO 4217 currency codes.
  142.38 +# To ensure compatibility, do not remove codes.
  142.39 +
  142.40 +all=ADP020-AED784-AFA004-AFN971-ALL008-AMD051-ANG532-AOA973-ARS032-ATS040-AUD036-\
  142.41 +    AWG533-AYM945-AZM031-AZN944-BAM977-BBD052-BDT050-BEF056-BGL100-BGN975-BHD048-BIF108-\
  142.42 +    BMD060-BND096-BOB068-BOV984-BRL986-BSD044-BTN064-BWP072-BYB112-BYR974-\
  142.43 +    BZD084-CAD124-CDF976-CHF756-CLF990-CLP152-CNY156-COP170-CRC188-CSD891-CUP192-\
  142.44 +    CVE132-CYP196-CZK203-DEM276-DJF262-DKK208-DOP214-DZD012-EEK233-EGP818-\
  142.45 +    ERN232-ESP724-ETB230-EUR978-FIM246-FJD242-FKP238-FRF250-GBP826-GEL981-\
  142.46 +    GHC288-GHS936-GIP292-GMD270-GNF324-GRD300-GTQ320-GWP624-GYD328-HKD344-HNL340-\
  142.47 +    HRK191-HTG332-HUF348-IDR360-IEP372-ILS376-INR356-IQD368-IRR364-ISK352-\
  142.48 +    ITL380-JMD388-JOD400-JPY392-KES404-KGS417-KHR116-KMF174-KPW408-KRW410-\
  142.49 +    KWD414-KYD136-KZT398-LAK418-LBP422-LKR144-LRD430-LSL426-LTL440-LUF442-\
  142.50 +    LVL428-LYD434-MAD504-MDL498-MGA969-MGF450-MKD807-MMK104-MNT496-MOP446-MRO478-\
  142.51 +    MTL470-MUR480-MVR462-MWK454-MXN484-MXV979-MYR458-MZM508-MZN943-NAD516-NGN566-\
  142.52 +    NIO558-NLG528-NOK578-NPR524-NZD554-OMR512-PAB590-PEN604-PGK598-PHP608-\
  142.53 +    PKR586-PLN985-PTE620-PYG600-QAR634-ROL946-RON946-RSD941-RUB643-RUR810-RWF646-SAR682-\
  142.54 +    SBD090-SCR690-SDD736-SDG938-SEK752-SGD702-SHP654-SIT705-SKK703-SLL694-SOS706-\
  142.55 +    SRD968-SRG740-STD678-SVC222-SYP760-SZL748-THB764-TJS972-TMM795-TND788-TOP776-\
  142.56 +    TPE626-TRL792-TRY949-TTD780-TWD901-TZS834-UAH980-UGX800-USD840-USN997-USS998-\
  142.57 +    UYU858-UZS860-VEB862-VEF937-VND704-VUV548-WST882-XAF950-XAG961-XAU959-XBA955-\
  142.58 +    XBB956-XBC957-XBD958-XCD951-XDR960-XFO000-XFU000-XOF952-XPD964-XPF953-\
  142.59 +    XPT962-XTS963-XXX999-YER886-YUM891-ZAR710-ZMK894-ZWD716-ZWN942
  142.60 +
  142.61 +
  142.62 +# Mappings from ISO 3166 country codes to ISO 4217 currency codes.
  142.63 +#
  142.64 +# Three forms are used:
  142.65 +# Form 1: <country code>=<currency code>
  142.66 +# Form 2: <country code>=<currency code 1>;<time stamp>;<currency code 2>
  142.67 +# Form 3: <country code>=
  142.68 +# Form 1 is used if no future change in currency is known.
  142.69 +# Form 2 indicates that before the specified time currency 1 is used, from
  142.70 +# the specified time currency 2. The time is given in SimpleDateFormat's
  142.71 +# yyyy-MM-dd-HH-mm-ss format in the GMT time zone.
  142.72 +# Form 3 indicates the country doesn't have a currency (the entry is still
  142.73 +# needed to verify that the country code is valid).
  142.74 +#
  142.75 +# The table is based on the following web sites:
  142.76 +# http://www.din.de/gremien/nas/nabd/iso3166ma/codlstp1/db_en.html
  142.77 +# http://www.bsi-global.com/iso4217currency
  142.78 +# http://www.cia.gov/cia/publications/factbook/indexgeo.html
  142.79 +
  142.80 +# AFGHANISTAN
  142.81 +AF=AFN
  142.82 +# \u00c5LAND ISLANDS
  142.83 +AX=EUR
  142.84 +# ALBANIA
  142.85 +AL=ALL
  142.86 +# ALGERIA
  142.87 +DZ=DZD
  142.88 +# AMERICAN SAMOA
  142.89 +AS=USD
  142.90 +# ANDORRA
  142.91 +AD=EUR
  142.92 +# ANGOLA
  142.93 +AO=AOA
  142.94 +# ANGUILLA
  142.95 +AI=XCD
  142.96 +# ANTARCTICA
  142.97 +AQ=
  142.98 +# ANTIGUA AND BARBUDA
  142.99 +AG=XCD
 142.100 +# ARGENTINA
 142.101 +AR=ARS
 142.102 +# ARMENIA
 142.103 +AM=AMD
 142.104 +# ARUBA
 142.105 +AW=AWG
 142.106 +# AUSTRALIA
 142.107 +AU=AUD
 142.108 +# AUSTRIA
 142.109 +AT=EUR
 142.110 +# AZERBAIJAN
 142.111 +AZ=AZM;2005-12-31-20-00-00;AZN
 142.112 +# BAHAMAS
 142.113 +BS=BSD
 142.114 +# BAHRAIN
 142.115 +BH=BHD
 142.116 +# BANGLADESH
 142.117 +BD=BDT
 142.118 +# BARBADOS
 142.119 +BB=BBD
 142.120 +# BELARUS
 142.121 +BY=BYR
 142.122 +# BELGIUM
 142.123 +BE=EUR
 142.124 +# BELIZE
 142.125 +BZ=BZD
 142.126 +# BENIN
 142.127 +BJ=XOF
 142.128 +# BERMUDA
 142.129 +BM=BMD
 142.130 +# BHUTAN
 142.131 +BT=BTN
 142.132 +# BOLIVIA
 142.133 +BO=BOB
 142.134 +# BOSNIA AND HERZEGOVINA
 142.135 +BA=BAM
 142.136 +# BOTSWANA
 142.137 +BW=BWP
 142.138 +# BOUVET ISLAND
 142.139 +BV=NOK
 142.140 +# BRAZIL
 142.141 +BR=BRL
 142.142 +# BRITISH INDIAN OCEAN TERRITORY
 142.143 +IO=USD
 142.144 +# BRUNEI DARUSSALAM
 142.145 +BN=BND
 142.146 +# BULGARIA
 142.147 +BG=BGN
 142.148 +# BURKINA FASO
 142.149 +BF=XOF
 142.150 +# BURUNDI
 142.151 +BI=BIF
 142.152 +# CAMBODIA
 142.153 +KH=KHR
 142.154 +# CAMEROON
 142.155 +CM=XAF
 142.156 +# CANADA
 142.157 +CA=CAD
 142.158 +# CAPE VERDE
 142.159 +CV=CVE
 142.160 +# CAYMAN ISLANDS
 142.161 +KY=KYD
 142.162 +# CENTRAL AFRICAN REPUBLIC
 142.163 +CF=XAF
 142.164 +# CHAD
 142.165 +TD=XAF
 142.166 +# CHILE
 142.167 +CL=CLP
 142.168 +# CHINA
 142.169 +CN=CNY
 142.170 +# CHRISTMAS ISLAND
 142.171 +CX=AUD
 142.172 +# COCOS (KEELING) ISLANDS
 142.173 +CC=AUD
 142.174 +# COLOMBIA
 142.175 +CO=COP
 142.176 +# COMOROS
 142.177 +KM=KMF
 142.178 +# CONGO
 142.179 +CG=XAF
 142.180 +# CONGO, THE DEMOCRATIC REPUBLIC OF THE
 142.181 +CD=CDF
 142.182 +# COOK ISLANDS
 142.183 +CK=NZD
 142.184 +# COSTA RICA
 142.185 +CR=CRC
 142.186 +# COTE D'IVOIRE
 142.187 +CI=XOF
 142.188 +# CROATIA
 142.189 +HR=HRK
 142.190 +# CUBA
 142.191 +CU=CUP
 142.192 +# CYPRUS
 142.193 +CY=EUR
 142.194 +# CZECH REPUBLIC
 142.195 +CZ=CZK
 142.196 +# DENMARK
 142.197 +DK=DKK
 142.198 +# DJIBOUTI
 142.199 +DJ=DJF
 142.200 +# DOMINICA
 142.201 +DM=XCD
 142.202 +# DOMINICAN REPUBLIC
 142.203 +DO=DOP
 142.204 +# ECUADOR
 142.205 +EC=USD
 142.206 +# EGYPT
 142.207 +EG=EGP
 142.208 +# EL SALVADOR
 142.209 +# USD is also legal currency as of 2001/01/01
 142.210 +SV=SVC
 142.211 +# EQUATORIAL GUINEA
 142.212 +GQ=XAF
 142.213 +# ERITREA
 142.214 +ER=ERN
 142.215 +# ESTONIA
 142.216 +EE=EEK
 142.217 +# ETHIOPIA
 142.218 +ET=ETB
 142.219 +# FALKLAND ISLANDS (MALVINAS)
 142.220 +FK=FKP
 142.221 +# FAROE ISLANDS
 142.222 +FO=DKK
 142.223 +# FIJI
 142.224 +FJ=FJD
 142.225 +# FINLAND
 142.226 +FI=EUR
 142.227 +# FRANCE
 142.228 +FR=EUR
 142.229 +# FRENCH GUIANA
 142.230 +GF=EUR
 142.231 +# FRENCH POLYNESIA
 142.232 +PF=XPF
 142.233 +# FRENCH SOUTHERN TERRITORIES
 142.234 +TF=EUR
 142.235 +# GABON
 142.236 +GA=XAF
 142.237 +# GAMBIA
 142.238 +GM=GMD
 142.239 +# GEORGIA
 142.240 +GE=GEL
 142.241 +# GERMANY
 142.242 +DE=EUR
 142.243 +# GHANA
 142.244 +GH=GHS
 142.245 +# GIBRALTAR
 142.246 +GI=GIP
 142.247 +# GREECE
 142.248 +GR=EUR
 142.249 +# GREENLAND
 142.250 +GL=DKK
 142.251 +# GRENADA
 142.252 +GD=XCD
 142.253 +# GUADELOUPE
 142.254 +GP=EUR
 142.255 +# GUAM
 142.256 +GU=USD
 142.257 +# GUATEMALA
 142.258 +GT=GTQ
 142.259 +# GUERNSEY
 142.260 +GG=GBP
 142.261 +# GUINEA
 142.262 +GN=GNF
 142.263 +# GUINEA-BISSAU
 142.264 +GW=XOF
 142.265 +# GUYANA
 142.266 +GY=GYD
 142.267 +# HAITI
 142.268 +HT=HTG
 142.269 +# HEARD ISLAND AND MCDONALD ISLANDS
 142.270 +HM=AUD
 142.271 +# HOLY SEE (VATICAN CITY STATE)
 142.272 +VA=EUR
 142.273 +# HONDURAS
 142.274 +HN=HNL
 142.275 +# HONG KONG
 142.276 +HK=HKD
 142.277 +# HUNGARY
 142.278 +HU=HUF
 142.279 +# ICELAND
 142.280 +IS=ISK
 142.281 +# INDIA
 142.282 +IN=INR
 142.283 +# INDONESIA
 142.284 +ID=IDR
 142.285 +# IRAN, ISLAMIC REPUBLIC OF
 142.286 +IR=IRR
 142.287 +# IRAQ
 142.288 +IQ=IQD
 142.289 +# IRELAND
 142.290 +IE=EUR
 142.291 +# ISLE OF MAN
 142.292 +IM=GBP
 142.293 +# ISRAEL
 142.294 +IL=ILS
 142.295 +# ITALY
 142.296 +IT=EUR
 142.297 +# JAMAICA
 142.298 +JM=JMD
 142.299 +# JAPAN
 142.300 +JP=JPY
 142.301 +# JERSEY
 142.302 +JE=GBP
 142.303 +# JORDAN
 142.304 +JO=JOD
 142.305 +# KAZAKSTAN
 142.306 +KZ=KZT
 142.307 +# KENYA
 142.308 +KE=KES
 142.309 +# KIRIBATI
 142.310 +KI=AUD
 142.311 +# KOREA, DEMOCRATIC PEOPLE'S REPUBLIC OF
 142.312 +KP=KPW
 142.313 +# KOREA, REPUBLIC OF
 142.314 +KR=KRW
 142.315 +# KUWAIT
 142.316 +KW=KWD
 142.317 +# KYRGYZSTAN
 142.318 +KG=KGS
 142.319 +# LAO PEOPLE'S DEMOCRATIC REPUBLIC
 142.320 +LA=LAK
 142.321 +# LATVIA
 142.322 +LV=LVL
 142.323 +# LEBANON
 142.324 +LB=LBP
 142.325 +# LESOTHO
 142.326 +LS=LSL
 142.327 +# LIBERIA
 142.328 +LR=LRD
 142.329 +# LIBYAN ARAB JAMAHIRIYA
 142.330 +LY=LYD
 142.331 +# LIECHTENSTEIN
 142.332 +LI=CHF
 142.333 +# LITHUANIA
 142.334 +LT=LTL
 142.335 +# LUXEMBOURG
 142.336 +LU=EUR
 142.337 +# MACAU
 142.338 +MO=MOP
 142.339 +# MACEDONIA, THE FORMER YUGOSLAV REPUBLIC OF
 142.340 +MK=MKD
 142.341 +# MADAGASCAR
 142.342 +MG=MGA
 142.343 +# MALAWI
 142.344 +MW=MWK
 142.345 +# MALAYSIA
 142.346 +MY=MYR
 142.347 +# MALDIVES
 142.348 +MV=MVR
 142.349 +# MALI
 142.350 +ML=XOF
 142.351 +# MALTA
 142.352 +MT=EUR
 142.353 +# MARSHALL ISLANDS
 142.354 +MH=USD
 142.355 +# MARTINIQUE
 142.356 +MQ=EUR
 142.357 +# MAURITANIA
 142.358 +MR=MRO
 142.359 +# MAURITIUS
 142.360 +MU=MUR
 142.361 +# MAYOTTE
 142.362 +YT=EUR
 142.363 +# MEXICO
 142.364 +MX=MXN
 142.365 +# MICRONESIA, FEDERATED STATES OF
 142.366 +FM=USD
 142.367 +# MOLDOVA, REPUBLIC OF
 142.368 +MD=MDL
 142.369 +# MONACO
 142.370 +MC=EUR
 142.371 +# MONGOLIA
 142.372 +MN=MNT
 142.373 +# MONTENEGRO
 142.374 +ME=EUR
 142.375 +# MONTSERRAT
 142.376 +MS=XCD
 142.377 +# MOROCCO
 142.378 +MA=MAD
 142.379 +# MOZAMBIQUE
 142.380 +MZ=MZM;2006-06-30-22-00-00;MZN
 142.381 +# MYANMAR
 142.382 +MM=MMK
 142.383 +# NAMIBIA
 142.384 +NA=NAD
 142.385 +# NAURU
 142.386 +NR=AUD
 142.387 +# NEPAL
 142.388 +NP=NPR
 142.389 +# NETHERLANDS
 142.390 +NL=EUR
 142.391 +# NETHERLANDS ANTILLES
 142.392 +AN=ANG
 142.393 +# NEW CALEDONIA
 142.394 +NC=XPF
 142.395 +# NEW ZEALAND
 142.396 +NZ=NZD
 142.397 +# NICARAGUA
 142.398 +NI=NIO
 142.399 +# NIGER
 142.400 +NE=XOF
 142.401 +# NIGERIA
 142.402 +NG=NGN
 142.403 +# NIUE
 142.404 +NU=NZD
 142.405 +# NORFOLK ISLAND
 142.406 +NF=AUD
 142.407 +# NORTHERN MARIANA ISLANDS
 142.408 +MP=USD
 142.409 +# NORWAY
 142.410 +NO=NOK
 142.411 +# OMAN
 142.412 +OM=OMR
 142.413 +# PAKISTAN
 142.414 +PK=PKR
 142.415 +# PALAU
 142.416 +PW=USD
 142.417 +# PALESTINIAN TERRITORY, OCCUPIED
 142.418 +PS=ILS
 142.419 +# PANAMA
 142.420 +PA=PAB
 142.421 +# PAPUA NEW GUINEA
 142.422 +PG=PGK
 142.423 +# PARAGUAY
 142.424 +PY=PYG
 142.425 +# PERU
 142.426 +PE=PEN
 142.427 +# PHILIPPINES
 142.428 +PH=PHP
 142.429 +# PITCAIRN
 142.430 +PN=NZD
 142.431 +# POLAND
 142.432 +PL=PLN
 142.433 +# PORTUGAL
 142.434 +PT=EUR
 142.435 +# PUERTO RICO
 142.436 +PR=USD
 142.437 +# QATAR
 142.438 +QA=QAR
 142.439 +# REUNION
 142.440 +RE=EUR
 142.441 +# ROMANIA
 142.442 +RO=ROL;2005-06-30-21-00-00;RON
 142.443 +# RUSSIAN FEDERATION
 142.444 +RU=RUB
 142.445 +# RWANDA
 142.446 +RW=RWF
 142.447 +# SAINT BARTHELEMY
 142.448 +BL=EUR
 142.449 +# SAINT HELENA
 142.450 +SH=SHP
 142.451 +# SAINT KITTS AND NEVIS
 142.452 +KN=XCD
 142.453 +# SAINT LUCIA
 142.454 +LC=XCD
 142.455 +# SAINT MARTIN
 142.456 +MF=EUR
 142.457 +# SAINT PIERRE AND MIQUELON
 142.458 +PM=EUR
 142.459 +# SAINT VINCENT AND THE GRENADINES
 142.460 +VC=XCD
 142.461 +# SAMOA
 142.462 +WS=WST
 142.463 +# SAN MARINO
 142.464 +SM=EUR
 142.465 +# SAO TOME AND PRINCIPE
 142.466 +ST=STD
 142.467 +# SAUDI ARABIA
 142.468 +SA=SAR
 142.469 +# SENEGAL
 142.470 +SN=XOF
 142.471 +# SERBIA
 142.472 +RS=RSD
 142.473 +# SERBIA AND MONTENEGRO
 142.474 +CS=CSD
 142.475 +# SEYCHELLES
 142.476 +SC=SCR
 142.477 +# SIERRA LEONE
 142.478 +SL=SLL
 142.479 +# SINGAPORE
 142.480 +SG=SGD
 142.481 +# SLOVAKIA
 142.482 +SK=SKK
 142.483 +# SLOVENIA
 142.484 +SI=EUR
 142.485 +# SOLOMON ISLANDS
 142.486 +SB=SBD
 142.487 +# SOMALIA
 142.488 +SO=SOS
 142.489 +# SOUTH AFRICA
 142.490 +ZA=ZAR
 142.491 +# SOUTH GEORGIA AND THE SOUTH SANDWICH ISLANDS
 142.492 +GS=GBP
 142.493 +# SPAIN
 142.494 +ES=EUR
 142.495 +# SRI LANKA
 142.496 +LK=LKR
 142.497 +# SUDAN
 142.498 +SD=SDG
 142.499 +# SURINAME
 142.500 +SR=SRD
 142.501 +# SVALBARD AND JAN MAYEN
 142.502 +SJ=NOK
 142.503 +# SWAZILAND
 142.504 +SZ=SZL
 142.505 +# SWEDEN
 142.506 +SE=SEK
 142.507 +# SWITZERLAND
 142.508 +CH=CHF
 142.509 +# SYRIAN ARAB REPUBLIC
 142.510 +SY=SYP
 142.511 +# TAIWAN
 142.512 +TW=TWD
 142.513 +# TAJIKISTAN
 142.514 +TJ=TJS
 142.515 +# TANZANIA, UNITED REPUBLIC OF
 142.516 +TZ=TZS
 142.517 +# THAILAND
 142.518 +TH=THB
 142.519 +# TIMOR-LESTE
 142.520 +TL=USD
 142.521 +# TOGO
 142.522 +TG=XOF
 142.523 +# TOKELAU
 142.524 +TK=NZD
 142.525 +# TONGA
 142.526 +TO=TOP
 142.527 +# TRINIDAD AND TOBAGO
 142.528 +TT=TTD
 142.529 +# TUNISIA
 142.530 +TN=TND
 142.531 +# TURKEY
 142.532 +TR=TRL;2004-12-31-22-00-00;TRY
 142.533 +# TURKMENISTAN
 142.534 +TM=TMM
 142.535 +# TURKS AND CAICOS ISLANDS
 142.536 +TC=USD
 142.537 +# TUVALU
 142.538 +TV=AUD
 142.539 +# UGANDA
 142.540 +UG=UGX
 142.541 +# UKRAINE
 142.542 +UA=UAH
 142.543 +# UNITED ARAB EMIRATES
 142.544 +AE=AED
 142.545 +# UNITED KINGDOM
 142.546 +GB=GBP
 142.547 +# UNITED STATES
 142.548 +US=USD
 142.549 +# UNITED STATES MINOR OUTLYING ISLANDS
 142.550 +UM=USD
 142.551 +# URUGUAY
 142.552 +UY=UYU
 142.553 +# UZBEKISTAN
 142.554 +UZ=UZS
 142.555 +# VANUATU
 142.556 +VU=VUV
 142.557 +# VENEZUELA
 142.558 +VE=VEB;2008-01-01-04-00-00;VEF
 142.559 +# VIET NAM
 142.560 +VN=VND
 142.561 +# VIRGIN ISLANDS, BRITISH
 142.562 +VG=USD
 142.563 +# VIRGIN ISLANDS, U.S.
 142.564 +VI=USD
 142.565 +# WALLIS AND FUTUNA
 142.566 +WF=XPF
 142.567 +# WESTERN SAHARA
 142.568 +EH=MAD
 142.569 +# YEMEN
 142.570 +YE=YER
 142.571 +# ZAMBIA
 142.572 +ZM=ZMK
 142.573 +# ZIMBABWE
 142.574 +ZW=ZWD
 142.575 +
 142.576 +
 142.577 +# List of currencies with 0, 1, OR 3 decimals for minor units, or where there
 142.578 +# are no minor units defined. All others use 2 decimals.
 142.579 +
 142.580 +minor0=\
 142.581 +    ADP-BEF-BIF-BYB-BYR-CLF-CLP-DJF-ESP-GNF-\
 142.582 +    GRD-ISK-ITL-JPY-KMF-KRW-LUF-MGF-PYG-PTE-RWF-\
 142.583 +    TPE-TRL-VUV-XAF-XOF-XPF
 142.584 +minor1=
 142.585 +minor3=\
 142.586 +    BHD-IQD-JOD-KWD-LYD-OMR-TND
 142.587 +minorUndefined=\
 142.588 +    XAG-XAU-XBA-XBB-XBC-XBD-XDR-XFO-XFU-XPD-\
 142.589 +    XPT-XTS-XXX
   143.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   143.2 +++ b/rt/emul/compact/src/main/java/java/util/Date.java	Tue Feb 11 13:31:42 2014 +0100
   143.3 @@ -0,0 +1,1430 @@
   143.4 +/*
   143.5 + * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
   143.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   143.7 + *
   143.8 + * This code is free software; you can redistribute it and/or modify it
   143.9 + * under the terms of the GNU General Public License version 2 only, as
  143.10 + * published by the Free Software Foundation.  Oracle designates this
  143.11 + * particular file as subject to the "Classpath" exception as provided
  143.12 + * by Oracle in the LICENSE file that accompanied this code.
  143.13 + *
  143.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  143.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  143.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  143.17 + * version 2 for more details (a copy is included in the LICENSE file that
  143.18 + * accompanied this code).
  143.19 + *
  143.20 + * You should have received a copy of the GNU General Public License version
  143.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  143.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  143.23 + *
  143.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  143.25 + * or visit www.oracle.com if you need additional information or have any
  143.26 + * questions.
  143.27 + */
  143.28 +
  143.29 +package java.util;
  143.30 +
  143.31 +import java.text.DateFormat;
  143.32 +import java.io.IOException;
  143.33 +import java.io.ObjectOutputStream;
  143.34 +import java.io.ObjectInputStream;
  143.35 +
  143.36 +/**
  143.37 + * The class <code>Date</code> represents a specific instant
  143.38 + * in time, with millisecond precision.
  143.39 + * <p>
  143.40 + * Prior to JDK&nbsp;1.1, the class <code>Date</code> had two additional
  143.41 + * functions.  It allowed the interpretation of dates as year, month, day, hour,
  143.42 + * minute, and second values.  It also allowed the formatting and parsing
  143.43 + * of date strings.  Unfortunately, the API for these functions was not
  143.44 + * amenable to internationalization.  As of JDK&nbsp;1.1, the
  143.45 + * <code>Calendar</code> class should be used to convert between dates and time
  143.46 + * fields and the <code>DateFormat</code> class should be used to format and
  143.47 + * parse date strings.
  143.48 + * The corresponding methods in <code>Date</code> are deprecated.
  143.49 + * <p>
  143.50 + * Although the <code>Date</code> class is intended to reflect
  143.51 + * coordinated universal time (UTC), it may not do so exactly,
  143.52 + * depending on the host environment of the Java Virtual Machine.
  143.53 + * Nearly all modern operating systems assume that 1&nbsp;day&nbsp;=
  143.54 + * 24&nbsp;&times;&nbsp;60&nbsp;&times;&nbsp;60&nbsp;= 86400 seconds
  143.55 + * in all cases. In UTC, however, about once every year or two there
  143.56 + * is an extra second, called a "leap second." The leap
  143.57 + * second is always added as the last second of the day, and always
  143.58 + * on December 31 or June 30. For example, the last minute of the
  143.59 + * year 1995 was 61 seconds long, thanks to an added leap second.
  143.60 + * Most computer clocks are not accurate enough to be able to reflect
  143.61 + * the leap-second distinction.
  143.62 + * <p>
  143.63 + * Some computer standards are defined in terms of Greenwich mean
  143.64 + * time (GMT), which is equivalent to universal time (UT).  GMT is
  143.65 + * the "civil" name for the standard; UT is the
  143.66 + * "scientific" name for the same standard. The
  143.67 + * distinction between UTC and UT is that UTC is based on an atomic
  143.68 + * clock and UT is based on astronomical observations, which for all
  143.69 + * practical purposes is an invisibly fine hair to split. Because the
  143.70 + * earth's rotation is not uniform (it slows down and speeds up
  143.71 + * in complicated ways), UT does not always flow uniformly. Leap
  143.72 + * seconds are introduced as needed into UTC so as to keep UTC within
  143.73 + * 0.9 seconds of UT1, which is a version of UT with certain
  143.74 + * corrections applied. There are other time and date systems as
  143.75 + * well; for example, the time scale used by the satellite-based
  143.76 + * global positioning system (GPS) is synchronized to UTC but is
  143.77 + * <i>not</i> adjusted for leap seconds. An interesting source of
  143.78 + * further information is the U.S. Naval Observatory, particularly
  143.79 + * the Directorate of Time at:
  143.80 + * <blockquote><pre>
  143.81 + *     <a href=http://tycho.usno.navy.mil>http://tycho.usno.navy.mil</a>
  143.82 + * </pre></blockquote>
  143.83 + * <p>
  143.84 + * and their definitions of "Systems of Time" at:
  143.85 + * <blockquote><pre>
  143.86 + *     <a href=http://tycho.usno.navy.mil/systime.html>http://tycho.usno.navy.mil/systime.html</a>
  143.87 + * </pre></blockquote>
  143.88 + * <p>
  143.89 + * In all methods of class <code>Date</code> that accept or return
  143.90 + * year, month, date, hours, minutes, and seconds values, the
  143.91 + * following representations are used:
  143.92 + * <ul>
  143.93 + * <li>A year <i>y</i> is represented by the integer
  143.94 + *     <i>y</i>&nbsp;<code>-&nbsp;1900</code>.
  143.95 + * <li>A month is represented by an integer from 0 to 11; 0 is January,
  143.96 + *     1 is February, and so forth; thus 11 is December.
  143.97 + * <li>A date (day of month) is represented by an integer from 1 to 31
  143.98 + *     in the usual manner.
  143.99 + * <li>An hour is represented by an integer from 0 to 23. Thus, the hour
 143.100 + *     from midnight to 1 a.m. is hour 0, and the hour from noon to 1
 143.101 + *     p.m. is hour 12.
 143.102 + * <li>A minute is represented by an integer from 0 to 59 in the usual manner.
 143.103 + * <li>A second is represented by an integer from 0 to 61; the values 60 and
 143.104 + *     61 occur only for leap seconds and even then only in Java
 143.105 + *     implementations that actually track leap seconds correctly. Because
 143.106 + *     of the manner in which leap seconds are currently introduced, it is
 143.107 + *     extremely unlikely that two leap seconds will occur in the same
 143.108 + *     minute, but this specification follows the date and time conventions
 143.109 + *     for ISO C.
 143.110 + * </ul>
 143.111 + * <p>
 143.112 + * In all cases, arguments given to methods for these purposes need
 143.113 + * not fall within the indicated ranges; for example, a date may be
 143.114 + * specified as January 32 and is interpreted as meaning February 1.
 143.115 + *
 143.116 + * @author  James Gosling
 143.117 + * @author  Arthur van Hoff
 143.118 + * @author  Alan Liu
 143.119 + * @see     java.text.DateFormat
 143.120 + * @see     java.util.Calendar
 143.121 + * @see     java.util.TimeZone
 143.122 + * @since   JDK1.0
 143.123 + */
 143.124 +public class Date
 143.125 +    implements java.io.Serializable, Cloneable, Comparable<Date>
 143.126 +{
 143.127 +    private static final BaseCalendar gcal = new BaseCalendar();
 143.128 +                                
 143.129 +    private static BaseCalendar jcal;
 143.130 +
 143.131 +    private transient long fastTime;
 143.132 +
 143.133 +    /*
 143.134 +     * If cdate is null, then fastTime indicates the time in millis.
 143.135 +     * If cdate.isNormalized() is true, then fastTime and cdate are in
 143.136 +     * synch. Otherwise, fastTime is ignored, and cdate indicates the
 143.137 +     * time.
 143.138 +     */
 143.139 +    private transient BaseCalendar.Datum cdate;
 143.140 +
 143.141 +    // Initialized just before the value is used. See parse().
 143.142 +    private static int defaultCenturyStart;
 143.143 +
 143.144 +    /* use serialVersionUID from modified java.util.Date for
 143.145 +     * interoperability with JDK1.1. The Date was modified to write
 143.146 +     * and read only the UTC time.
 143.147 +     */
 143.148 +    private static final long serialVersionUID = 7523967970034938905L;
 143.149 +
 143.150 +    /**
 143.151 +     * Allocates a <code>Date</code> object and initializes it so that
 143.152 +     * it represents the time at which it was allocated, measured to the
 143.153 +     * nearest millisecond.
 143.154 +     *
 143.155 +     * @see     java.lang.System#currentTimeMillis()
 143.156 +     */
 143.157 +    public Date() {
 143.158 +        this(System.currentTimeMillis());
 143.159 +    }
 143.160 +
 143.161 +    /**
 143.162 +     * Allocates a <code>Date</code> object and initializes it to
 143.163 +     * represent the specified number of milliseconds since the
 143.164 +     * standard base time known as "the epoch", namely January 1,
 143.165 +     * 1970, 00:00:00 GMT.
 143.166 +     *
 143.167 +     * @param   date   the milliseconds since January 1, 1970, 00:00:00 GMT.
 143.168 +     * @see     java.lang.System#currentTimeMillis()
 143.169 +     */
 143.170 +    public Date(long date) {
 143.171 +        fastTime = date;
 143.172 +    }
 143.173 +
 143.174 +    /**
 143.175 +     * Allocates a <code>Date</code> object and initializes it so that
 143.176 +     * it represents midnight, local time, at the beginning of the day
 143.177 +     * specified by the <code>year</code>, <code>month</code>, and
 143.178 +     * <code>date</code> arguments.
 143.179 +     *
 143.180 +     * @param   year    the year minus 1900.
 143.181 +     * @param   month   the month between 0-11.
 143.182 +     * @param   date    the day of the month between 1-31.
 143.183 +     * @see     java.util.Calendar
 143.184 +     * @deprecated As of JDK version 1.1,
 143.185 +     * replaced by <code>Calendar.set(year + 1900, month, date)</code>
 143.186 +     * or <code>GregorianCalendar(year + 1900, month, date)</code>.
 143.187 +     */
 143.188 +    @Deprecated
 143.189 +    public Date(int year, int month, int date) {
 143.190 +        this(year, month, date, 0, 0, 0);
 143.191 +    }
 143.192 +
 143.193 +    /**
 143.194 +     * Allocates a <code>Date</code> object and initializes it so that
 143.195 +     * it represents the instant at the start of the minute specified by
 143.196 +     * the <code>year</code>, <code>month</code>, <code>date</code>,
 143.197 +     * <code>hrs</code>, and <code>min</code> arguments, in the local
 143.198 +     * time zone.
 143.199 +     *
 143.200 +     * @param   year    the year minus 1900.
 143.201 +     * @param   month   the month between 0-11.
 143.202 +     * @param   date    the day of the month between 1-31.
 143.203 +     * @param   hrs     the hours between 0-23.
 143.204 +     * @param   min     the minutes between 0-59.
 143.205 +     * @see     java.util.Calendar
 143.206 +     * @deprecated As of JDK version 1.1,
 143.207 +     * replaced by <code>Calendar.set(year + 1900, month, date,
 143.208 +     * hrs, min)</code> or <code>GregorianCalendar(year + 1900,
 143.209 +     * month, date, hrs, min)</code>.
 143.210 +     */
 143.211 +    @Deprecated
 143.212 +    public Date(int year, int month, int date, int hrs, int min) {
 143.213 +        this(year, month, date, hrs, min, 0);
 143.214 +    }
 143.215 +
 143.216 +    /**
 143.217 +     * Allocates a <code>Date</code> object and initializes it so that
 143.218 +     * it represents the instant at the start of the second specified
 143.219 +     * by the <code>year</code>, <code>month</code>, <code>date</code>,
 143.220 +     * <code>hrs</code>, <code>min</code>, and <code>sec</code> arguments,
 143.221 +     * in the local time zone.
 143.222 +     *
 143.223 +     * @param   year    the year minus 1900.
 143.224 +     * @param   month   the month between 0-11.
 143.225 +     * @param   date    the day of the month between 1-31.
 143.226 +     * @param   hrs     the hours between 0-23.
 143.227 +     * @param   min     the minutes between 0-59.
 143.228 +     * @param   sec     the seconds between 0-59.
 143.229 +     * @see     java.util.Calendar
 143.230 +     * @deprecated As of JDK version 1.1,
 143.231 +     * replaced by <code>Calendar.set(year + 1900, month, date,
 143.232 +     * hrs, min, sec)</code> or <code>GregorianCalendar(year + 1900,
 143.233 +     * month, date, hrs, min, sec)</code>.
 143.234 +     */
 143.235 +    @Deprecated
 143.236 +    public Date(int year, int month, int date, int hrs, int min, int sec) {
 143.237 +        int y = year + 1900;
 143.238 +        // month is 0-based. So we have to normalize month to support Long.MAX_VALUE.
 143.239 +        if (month >= 12) {
 143.240 +            y += month / 12;
 143.241 +            month %= 12;
 143.242 +        } else if (month < 0) {
 143.243 +            y += month / 12;
 143.244 +            month = month % 12;
 143.245 +        }
 143.246 +        BaseCalendar cal = getCalendarSystem(y);
 143.247 +        cdate = (BaseCalendar.Datum) cal.newCalendarDate(TimeZone.getDefaultRef());
 143.248 +        cdate.setNormalizedDate(y, month + 1, date).setTimeOfDay(hrs, min, sec, 0);
 143.249 +        getTimeImpl();
 143.250 +        cdate = null;
 143.251 +    }
 143.252 +
 143.253 +    /**
 143.254 +     * Allocates a <code>Date</code> object and initializes it so that
 143.255 +     * it represents the date and time indicated by the string
 143.256 +     * <code>s</code>, which is interpreted as if by the
 143.257 +     * {@link Date#parse} method.
 143.258 +     *
 143.259 +     * @param   s   a string representation of the date.
 143.260 +     * @see     java.text.DateFormat
 143.261 +     * @see     java.util.Date#parse(java.lang.String)
 143.262 +     * @deprecated As of JDK version 1.1,
 143.263 +     * replaced by <code>DateFormat.parse(String s)</code>.
 143.264 +     */
 143.265 +    @Deprecated
 143.266 +    public Date(String s) {
 143.267 +        this(parse(s));
 143.268 +    }
 143.269 +
 143.270 +    /**
 143.271 +     * Return a copy of this object.
 143.272 +     */
 143.273 +    public Object clone() {
 143.274 +        Date d = null;
 143.275 +        try {
 143.276 +            d = (Date)super.clone();
 143.277 +            if (cdate != null) {
 143.278 +                d.cdate = (BaseCalendar.Datum) cdate.clone();
 143.279 +            }
 143.280 +        } catch (CloneNotSupportedException e) {} // Won't happen
 143.281 +        return d;
 143.282 +    }
 143.283 +
 143.284 +    /**
 143.285 +     * Determines the date and time based on the arguments. The
 143.286 +     * arguments are interpreted as a year, month, day of the month,
 143.287 +     * hour of the day, minute within the hour, and second within the
 143.288 +     * minute, exactly as for the <tt>Date</tt> constructor with six
 143.289 +     * arguments, except that the arguments are interpreted relative
 143.290 +     * to UTC rather than to the local time zone. The time indicated is
 143.291 +     * returned represented as the distance, measured in milliseconds,
 143.292 +     * of that time from the epoch (00:00:00 GMT on January 1, 1970).
 143.293 +     *
 143.294 +     * @param   year    the year minus 1900.
 143.295 +     * @param   month   the month between 0-11.
 143.296 +     * @param   date    the day of the month between 1-31.
 143.297 +     * @param   hrs     the hours between 0-23.
 143.298 +     * @param   min     the minutes between 0-59.
 143.299 +     * @param   sec     the seconds between 0-59.
 143.300 +     * @return  the number of milliseconds since January 1, 1970, 00:00:00 GMT for
 143.301 +     *          the date and time specified by the arguments.
 143.302 +     * @see     java.util.Calendar
 143.303 +     * @deprecated As of JDK version 1.1,
 143.304 +     * replaced by <code>Calendar.set(year + 1900, month, date,
 143.305 +     * hrs, min, sec)</code> or <code>GregorianCalendar(year + 1900,
 143.306 +     * month, date, hrs, min, sec)</code>, using a UTC
 143.307 +     * <code>TimeZone</code>, followed by <code>Calendar.getTime().getTime()</code>.
 143.308 +     */
 143.309 +    @Deprecated
 143.310 +    public static long UTC(int year, int month, int date,
 143.311 +                           int hrs, int min, int sec) {
 143.312 +        int y = year + 1900;
 143.313 +        // month is 0-based. So we have to normalize month to support Long.MAX_VALUE.
 143.314 +        if (month >= 12) {
 143.315 +            y += month / 12;
 143.316 +            month %= 12;
 143.317 +        } else if (month < 0) {
 143.318 +            y += month / 12;
 143.319 +            month = month % 12;
 143.320 +        }
 143.321 +        int m = month + 1;
 143.322 +        BaseCalendar cal = getCalendarSystem(y);
 143.323 +        BaseCalendar.Datum udate = (BaseCalendar.Datum) cal.newCalendarDate(null);
 143.324 +        udate.setNormalizedDate(y, m, date).setTimeOfDay(hrs, min, sec, 0);
 143.325 +
 143.326 +        // Use a Date instance to perform normalization. Its fastTime
 143.327 +        // is the UTC value after the normalization.
 143.328 +        Date d = new Date(0);
 143.329 +        d.normalize(udate);
 143.330 +        return d.fastTime;
 143.331 +    }
 143.332 +
 143.333 +    /**
 143.334 +     * Attempts to interpret the string <tt>s</tt> as a representation
 143.335 +     * of a date and time. If the attempt is successful, the time
 143.336 +     * indicated is returned represented as the distance, measured in
 143.337 +     * milliseconds, of that time from the epoch (00:00:00 GMT on
 143.338 +     * January 1, 1970). If the attempt fails, an
 143.339 +     * <tt>IllegalArgumentException</tt> is thrown.
 143.340 +     * <p>
 143.341 +     * It accepts many syntaxes; in particular, it recognizes the IETF
 143.342 +     * standard date syntax: "Sat, 12 Aug 1995 13:30:00 GMT". It also
 143.343 +     * understands the continental U.S. time-zone abbreviations, but for
 143.344 +     * general use, a time-zone offset should be used: "Sat, 12 Aug 1995
 143.345 +     * 13:30:00 GMT+0430" (4 hours, 30 minutes west of the Greenwich
 143.346 +     * meridian). If no time zone is specified, the local time zone is
 143.347 +     * assumed. GMT and UTC are considered equivalent.
 143.348 +     * <p>
 143.349 +     * The string <tt>s</tt> is processed from left to right, looking for
 143.350 +     * data of interest. Any material in <tt>s</tt> that is within the
 143.351 +     * ASCII parenthesis characters <tt>(</tt> and <tt>)</tt> is ignored.
 143.352 +     * Parentheses may be nested. Otherwise, the only characters permitted
 143.353 +     * within <tt>s</tt> are these ASCII characters:
 143.354 +     * <blockquote><pre>
 143.355 +     * abcdefghijklmnopqrstuvwxyz
 143.356 +     * ABCDEFGHIJKLMNOPQRSTUVWXYZ
 143.357 +     * 0123456789,+-:/</pre></blockquote>
 143.358 +     * and whitespace characters.<p>
 143.359 +     * A consecutive sequence of decimal digits is treated as a decimal
 143.360 +     * number:<ul>
 143.361 +     * <li>If a number is preceded by <tt>+</tt> or <tt>-</tt> and a year
 143.362 +     *     has already been recognized, then the number is a time-zone
 143.363 +     *     offset. If the number is less than 24, it is an offset measured
 143.364 +     *     in hours. Otherwise, it is regarded as an offset in minutes,
 143.365 +     *     expressed in 24-hour time format without punctuation. A
 143.366 +     *     preceding <tt>-</tt> means a westward offset. Time zone offsets
 143.367 +     *     are always relative to UTC (Greenwich). Thus, for example,
 143.368 +     *     <tt>-5</tt> occurring in the string would mean "five hours west
 143.369 +     *     of Greenwich" and <tt>+0430</tt> would mean "four hours and
 143.370 +     *     thirty minutes east of Greenwich." It is permitted for the
 143.371 +     *     string to specify <tt>GMT</tt>, <tt>UT</tt>, or <tt>UTC</tt>
 143.372 +     *     redundantly-for example, <tt>GMT-5</tt> or <tt>utc+0430</tt>.
 143.373 +     * <li>The number is regarded as a year number if one of the
 143.374 +     *     following conditions is true:
 143.375 +     * <ul>
 143.376 +     *     <li>The number is equal to or greater than 70 and followed by a
 143.377 +     *         space, comma, slash, or end of string
 143.378 +     *     <li>The number is less than 70, and both a month and a day of
 143.379 +     *         the month have already been recognized</li>
 143.380 +     * </ul>
 143.381 +     *     If the recognized year number is less than 100, it is
 143.382 +     *     interpreted as an abbreviated year relative to a century of
 143.383 +     *     which dates are within 80 years before and 19 years after
 143.384 +     *     the time when the Date class is initialized.
 143.385 +     *     After adjusting the year number, 1900 is subtracted from
 143.386 +     *     it. For example, if the current year is 1999 then years in
 143.387 +     *     the range 19 to 99 are assumed to mean 1919 to 1999, while
 143.388 +     *     years from 0 to 18 are assumed to mean 2000 to 2018.  Note
 143.389 +     *     that this is slightly different from the interpretation of
 143.390 +     *     years less than 100 that is used in {@link java.text.SimpleDateFormat}.
 143.391 +     * <li>If the number is followed by a colon, it is regarded as an hour,
 143.392 +     *     unless an hour has already been recognized, in which case it is
 143.393 +     *     regarded as a minute.
 143.394 +     * <li>If the number is followed by a slash, it is regarded as a month
 143.395 +     *     (it is decreased by 1 to produce a number in the range <tt>0</tt>
 143.396 +     *     to <tt>11</tt>), unless a month has already been recognized, in
 143.397 +     *     which case it is regarded as a day of the month.
 143.398 +     * <li>If the number is followed by whitespace, a comma, a hyphen, or
 143.399 +     *     end of string, then if an hour has been recognized but not a
 143.400 +     *     minute, it is regarded as a minute; otherwise, if a minute has
 143.401 +     *     been recognized but not a second, it is regarded as a second;
 143.402 +     *     otherwise, it is regarded as a day of the month. </ul><p>
 143.403 +     * A consecutive sequence of letters is regarded as a word and treated
 143.404 +     * as follows:<ul>
 143.405 +     * <li>A word that matches <tt>AM</tt>, ignoring case, is ignored (but
 143.406 +     *     the parse fails if an hour has not been recognized or is less
 143.407 +     *     than <tt>1</tt> or greater than <tt>12</tt>).
 143.408 +     * <li>A word that matches <tt>PM</tt>, ignoring case, adds <tt>12</tt>
 143.409 +     *     to the hour (but the parse fails if an hour has not been
 143.410 +     *     recognized or is less than <tt>1</tt> or greater than <tt>12</tt>).
 143.411 +     * <li>Any word that matches any prefix of <tt>SUNDAY, MONDAY, TUESDAY,
 143.412 +     *     WEDNESDAY, THURSDAY, FRIDAY</tt>, or <tt>SATURDAY</tt>, ignoring
 143.413 +     *     case, is ignored. For example, <tt>sat, Friday, TUE</tt>, and
 143.414 +     *     <tt>Thurs</tt> are ignored.
 143.415 +     * <li>Otherwise, any word that matches any prefix of <tt>JANUARY,
 143.416 +     *     FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY, AUGUST, SEPTEMBER,
 143.417 +     *     OCTOBER, NOVEMBER</tt>, or <tt>DECEMBER</tt>, ignoring case, and
 143.418 +     *     considering them in the order given here, is recognized as
 143.419 +     *     specifying a month and is converted to a number (<tt>0</tt> to
 143.420 +     *     <tt>11</tt>). For example, <tt>aug, Sept, april</tt>, and
 143.421 +     *     <tt>NOV</tt> are recognized as months. So is <tt>Ma</tt>, which
 143.422 +     *     is recognized as <tt>MARCH</tt>, not <tt>MAY</tt>.
 143.423 +     * <li>Any word that matches <tt>GMT, UT</tt>, or <tt>UTC</tt>, ignoring
 143.424 +     *     case, is treated as referring to UTC.
 143.425 +     * <li>Any word that matches <tt>EST, CST, MST</tt>, or <tt>PST</tt>,
 143.426 +     *     ignoring case, is recognized as referring to the time zone in
 143.427 +     *     North America that is five, six, seven, or eight hours west of
 143.428 +     *     Greenwich, respectively. Any word that matches <tt>EDT, CDT,
 143.429 +     *     MDT</tt>, or <tt>PDT</tt>, ignoring case, is recognized as
 143.430 +     *     referring to the same time zone, respectively, during daylight
 143.431 +     *     saving time.</ul><p>
 143.432 +     * Once the entire string s has been scanned, it is converted to a time
 143.433 +     * result in one of two ways. If a time zone or time-zone offset has been
 143.434 +     * recognized, then the year, month, day of month, hour, minute, and
 143.435 +     * second are interpreted in UTC and then the time-zone offset is
 143.436 +     * applied. Otherwise, the year, month, day of month, hour, minute, and
 143.437 +     * second are interpreted in the local time zone.
 143.438 +     *
 143.439 +     * @param   s   a string to be parsed as a date.
 143.440 +     * @return  the number of milliseconds since January 1, 1970, 00:00:00 GMT
 143.441 +     *          represented by the string argument.
 143.442 +     * @see     java.text.DateFormat
 143.443 +     * @deprecated As of JDK version 1.1,
 143.444 +     * replaced by <code>DateFormat.parse(String s)</code>.
 143.445 +     */
 143.446 +    @Deprecated
 143.447 +    public static long parse(String s) {
 143.448 +        int year = Integer.MIN_VALUE;
 143.449 +        int mon = -1;
 143.450 +        int mday = -1;
 143.451 +        int hour = -1;
 143.452 +        int min = -1;
 143.453 +        int sec = -1;
 143.454 +        int millis = -1;
 143.455 +        int c = -1;
 143.456 +        int i = 0;
 143.457 +        int n = -1;
 143.458 +        int wst = -1;
 143.459 +        int tzoffset = -1;
 143.460 +        int prevc = 0;
 143.461 +    syntax:
 143.462 +        {
 143.463 +            if (s == null)
 143.464 +                break syntax;
 143.465 +            int limit = s.length();
 143.466 +            while (i < limit) {
 143.467 +                c = s.charAt(i);
 143.468 +                i++;
 143.469 +                if (c <= ' ' || c == ',')
 143.470 +                    continue;
 143.471 +                if (c == '(') { // skip comments
 143.472 +                    int depth = 1;
 143.473 +                    while (i < limit) {
 143.474 +                        c = s.charAt(i);
 143.475 +                        i++;
 143.476 +                        if (c == '(') depth++;
 143.477 +                        else if (c == ')')
 143.478 +                            if (--depth <= 0)
 143.479 +                                break;
 143.480 +                    }
 143.481 +                    continue;
 143.482 +                }
 143.483 +                if ('0' <= c && c <= '9') {
 143.484 +                    n = c - '0';
 143.485 +                    while (i < limit && '0' <= (c = s.charAt(i)) && c <= '9') {
 143.486 +                        n = n * 10 + c - '0';
 143.487 +                        i++;
 143.488 +                    }
 143.489 +                    if (prevc == '+' || prevc == '-' && year != Integer.MIN_VALUE) {
 143.490 +                        // timezone offset
 143.491 +                        if (n < 24)
 143.492 +                            n = n * 60; // EG. "GMT-3"
 143.493 +                        else
 143.494 +                            n = n % 100 + n / 100 * 60; // eg "GMT-0430"
 143.495 +                        if (prevc == '+')   // plus means east of GMT
 143.496 +                            n = -n;
 143.497 +                        if (tzoffset != 0 && tzoffset != -1)
 143.498 +                            break syntax;
 143.499 +                        tzoffset = n;
 143.500 +                    } else if (n >= 70)
 143.501 +                        if (year != Integer.MIN_VALUE)
 143.502 +                            break syntax;
 143.503 +                        else if (c <= ' ' || c == ',' || c == '/' || i >= limit)
 143.504 +                            // year = n < 1900 ? n : n - 1900;
 143.505 +                            year = n;
 143.506 +                        else
 143.507 +                            break syntax;
 143.508 +                    else if (c == ':')
 143.509 +                        if (hour < 0)
 143.510 +                            hour = (byte) n;
 143.511 +                        else if (min < 0)
 143.512 +                            min = (byte) n;
 143.513 +                        else
 143.514 +                            break syntax;
 143.515 +                    else if (c == '/')
 143.516 +                        if (mon < 0)
 143.517 +                            mon = (byte) (n - 1);
 143.518 +                        else if (mday < 0)
 143.519 +                            mday = (byte) n;
 143.520 +                        else
 143.521 +                            break syntax;
 143.522 +                    else if (i < limit && c != ',' && c > ' ' && c != '-')
 143.523 +                        break syntax;
 143.524 +                    else if (hour >= 0 && min < 0)
 143.525 +                        min = (byte) n;
 143.526 +                    else if (min >= 0 && sec < 0)
 143.527 +                        sec = (byte) n;
 143.528 +                    else if (mday < 0)
 143.529 +                        mday = (byte) n;
 143.530 +                    // Handle two-digit years < 70 (70-99 handled above).
 143.531 +                    else if (year == Integer.MIN_VALUE && mon >= 0 && mday >= 0)
 143.532 +                        year = n;
 143.533 +                    else
 143.534 +                        break syntax;
 143.535 +                    prevc = 0;
 143.536 +                } else if (c == '/' || c == ':' || c == '+' || c == '-')
 143.537 +                    prevc = c;
 143.538 +                else {
 143.539 +                    int st = i - 1;
 143.540 +                    while (i < limit) {
 143.541 +                        c = s.charAt(i);
 143.542 +                        if (!('A' <= c && c <= 'Z' || 'a' <= c && c <= 'z'))
 143.543 +                            break;
 143.544 +                        i++;
 143.545 +                    }
 143.546 +                    if (i <= st + 1)
 143.547 +                        break syntax;
 143.548 +                    int k;
 143.549 +                    for (k = wtb.length; --k >= 0;)
 143.550 +                        if (wtb[k].regionMatches(true, 0, s, st, i - st)) {
 143.551 +                            int action = ttb[k];
 143.552 +                            if (action != 0) {
 143.553 +                                if (action == 1) {  // pm
 143.554 +                                    if (hour > 12 || hour < 1)
 143.555 +                                        break syntax;
 143.556 +                                    else if (hour < 12)
 143.557 +                                        hour += 12;
 143.558 +                                } else if (action == 14) {  // am
 143.559 +                                    if (hour > 12 || hour < 1)
 143.560 +                                        break syntax;
 143.561 +                                    else if (hour == 12)
 143.562 +                                        hour = 0;
 143.563 +                                } else if (action <= 13) {  // month!
 143.564 +                                    if (mon < 0)
 143.565 +                                        mon = (byte) (action - 2);
 143.566 +                                    else
 143.567 +                                        break syntax;
 143.568 +                                } else {
 143.569 +                                    tzoffset = action - 10000;
 143.570 +                                }
 143.571 +                            }
 143.572 +                            break;
 143.573 +                        }
 143.574 +                    if (k < 0)
 143.575 +                        break syntax;
 143.576 +                    prevc = 0;
 143.577 +                }
 143.578 +            }
 143.579 +            if (year == Integer.MIN_VALUE || mon < 0 || mday < 0)
 143.580 +                break syntax;
 143.581 +            // Parse 2-digit years within the correct default century.
 143.582 +            if (year < 100) {
 143.583 +                synchronized (Date.class) {
 143.584 +                    if (defaultCenturyStart == 0) {
 143.585 +                        defaultCenturyStart = gcal.getCalendarDate().getYear() - 80;
 143.586 +                    }
 143.587 +                }
 143.588 +                year += (defaultCenturyStart / 100) * 100;
 143.589 +                if (year < defaultCenturyStart) year += 100;
 143.590 +            }
 143.591 +            if (sec < 0)
 143.592 +                sec = 0;
 143.593 +            if (min < 0)
 143.594 +                min = 0;
 143.595 +            if (hour < 0)
 143.596 +                hour = 0;
 143.597 +            BaseCalendar cal = getCalendarSystem(year);
 143.598 +            if (tzoffset == -1)  { // no time zone specified, have to use local
 143.599 +                BaseCalendar.Datum ldate = (BaseCalendar.Datum) cal.newCalendarDate(TimeZone.getDefaultRef());
 143.600 +                ldate.setDate(year, mon + 1, mday);
 143.601 +                ldate.setTimeOfDay(hour, min, sec, 0);
 143.602 +                return cal.getTime(ldate);
 143.603 +            }
 143.604 +            BaseCalendar.Datum udate = (BaseCalendar.Datum) cal.newCalendarDate(null); // no time zone
 143.605 +            udate.setDate(year, mon + 1, mday);
 143.606 +            udate.setTimeOfDay(hour, min, sec, 0);
 143.607 +            return cal.getTime(udate) + tzoffset * (60 * 1000);
 143.608 +        }
 143.609 +        // syntax error
 143.610 +        throw new IllegalArgumentException();
 143.611 +    }
 143.612 +    private final static String wtb[] = {
 143.613 +        "am", "pm",
 143.614 +        "monday", "tuesday", "wednesday", "thursday", "friday",
 143.615 +        "saturday", "sunday",
 143.616 +        "january", "february", "march", "april", "may", "june",
 143.617 +        "july", "august", "september", "october", "november", "december",
 143.618 +        "gmt", "ut", "utc", "est", "edt", "cst", "cdt",
 143.619 +        "mst", "mdt", "pst", "pdt"
 143.620 +    };
 143.621 +    private final static int ttb[] = {
 143.622 +        14, 1, 0, 0, 0, 0, 0, 0, 0,
 143.623 +        2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
 143.624 +        10000 + 0, 10000 + 0, 10000 + 0,    // GMT/UT/UTC
 143.625 +        10000 + 5 * 60, 10000 + 4 * 60,     // EST/EDT
 143.626 +        10000 + 6 * 60, 10000 + 5 * 60,     // CST/CDT
 143.627 +        10000 + 7 * 60, 10000 + 6 * 60,     // MST/MDT
 143.628 +        10000 + 8 * 60, 10000 + 7 * 60      // PST/PDT
 143.629 +    };
 143.630 +
 143.631 +    /**
 143.632 +     * Returns a value that is the result of subtracting 1900 from the
 143.633 +     * year that contains or begins with the instant in time represented
 143.634 +     * by this <code>Date</code> object, as interpreted in the local
 143.635 +     * time zone.
 143.636 +     *
 143.637 +     * @return  the year represented by this date, minus 1900.
 143.638 +     * @see     java.util.Calendar
 143.639 +     * @deprecated As of JDK version 1.1,
 143.640 +     * replaced by <code>Calendar.get(Calendar.YEAR) - 1900</code>.
 143.641 +     */
 143.642 +    @Deprecated
 143.643 +    public int getYear() {
 143.644 +        return normalize().getYear() - 1900;
 143.645 +    }
 143.646 +
 143.647 +    /**
 143.648 +     * Sets the year of this <tt>Date</tt> object to be the specified
 143.649 +     * value plus 1900. This <code>Date</code> object is modified so
 143.650 +     * that it represents a point in time within the specified year,
 143.651 +     * with the month, date, hour, minute, and second the same as
 143.652 +     * before, as interpreted in the local time zone. (Of course, if
 143.653 +     * the date was February 29, for example, and the year is set to a
 143.654 +     * non-leap year, then the new date will be treated as if it were
 143.655 +     * on March 1.)
 143.656 +     *
 143.657 +     * @param   year    the year value.
 143.658 +     * @see     java.util.Calendar
 143.659 +     * @deprecated As of JDK version 1.1,
 143.660 +     * replaced by <code>Calendar.set(Calendar.YEAR, year + 1900)</code>.
 143.661 +     */
 143.662 +    @Deprecated
 143.663 +    public void setYear(int year) {
 143.664 +        getCalendarDate().setNormalizedYear(year + 1900);
 143.665 +    }
 143.666 +
 143.667 +    /**
 143.668 +     * Returns a number representing the month that contains or begins
 143.669 +     * with the instant in time represented by this <tt>Date</tt> object.
 143.670 +     * The value returned is between <code>0</code> and <code>11</code>,
 143.671 +     * with the value <code>0</code> representing January.
 143.672 +     *
 143.673 +     * @return  the month represented by this date.
 143.674 +     * @see     java.util.Calendar
 143.675 +     * @deprecated As of JDK version 1.1,
 143.676 +     * replaced by <code>Calendar.get(Calendar.MONTH)</code>.
 143.677 +     */
 143.678 +    @Deprecated
 143.679 +    public int getMonth() {
 143.680 +        return normalize().getMonth() - 1; // adjust 1-based to 0-based
 143.681 +    }
 143.682 +
 143.683 +    /**
 143.684 +     * Sets the month of this date to the specified value. This
 143.685 +     * <tt>Date</tt> object is modified so that it represents a point
 143.686 +     * in time within the specified month, with the year, date, hour,
 143.687 +     * minute, and second the same as before, as interpreted in the
 143.688 +     * local time zone. If the date was October 31, for example, and
 143.689 +     * the month is set to June, then the new date will be treated as
 143.690 +     * if it were on July 1, because June has only 30 days.
 143.691 +     *
 143.692 +     * @param   month   the month value between 0-11.
 143.693 +     * @see     java.util.Calendar
 143.694 +     * @deprecated As of JDK version 1.1,
 143.695 +     * replaced by <code>Calendar.set(Calendar.MONTH, int month)</code>.
 143.696 +     */
 143.697 +    @Deprecated
 143.698 +    public void setMonth(int month) {
 143.699 +        int y = 0;
 143.700 +        if (month >= 12) {
 143.701 +            y = month / 12;
 143.702 +            month %= 12;
 143.703 +        } else if (month < 0) {
 143.704 +            y = month / 12;
 143.705 +            month = month % 12;
 143.706 +        }
 143.707 +        BaseCalendar.Datum d = getCalendarDate();
 143.708 +        if (y != 0) {
 143.709 +            d.setNormalizedYear(d.getNormalizedYear() + y);
 143.710 +        }
 143.711 +        d.setMonth(month + 1); // adjust 0-based to 1-based month numbering
 143.712 +    }
 143.713 +
 143.714 +    /**
 143.715 +     * Returns the day of the month represented by this <tt>Date</tt> object.
 143.716 +     * The value returned is between <code>1</code> and <code>31</code>
 143.717 +     * representing the day of the month that contains or begins with the
 143.718 +     * instant in time represented by this <tt>Date</tt> object, as
 143.719 +     * interpreted in the local time zone.
 143.720 +     *
 143.721 +     * @return  the day of the month represented by this date.
 143.722 +     * @see     java.util.Calendar
 143.723 +     * @deprecated As of JDK version 1.1,
 143.724 +     * replaced by <code>Calendar.get(Calendar.DAY_OF_MONTH)</code>.
 143.725 +     * @deprecated
 143.726 +     */
 143.727 +    @Deprecated
 143.728 +    public int getDate() {
 143.729 +        return normalize().getDayOfMonth();
 143.730 +    }
 143.731 +
 143.732 +    /**
 143.733 +     * Sets the day of the month of this <tt>Date</tt> object to the
 143.734 +     * specified value. This <tt>Date</tt> object is modified so that
 143.735 +     * it represents a point in time within the specified day of the
 143.736 +     * month, with the year, month, hour, minute, and second the same
 143.737 +     * as before, as interpreted in the local time zone. If the date
 143.738 +     * was April 30, for example, and the date is set to 31, then it
 143.739 +     * will be treated as if it were on May 1, because April has only
 143.740 +     * 30 days.
 143.741 +     *
 143.742 +     * @param   date   the day of the month value between 1-31.
 143.743 +     * @see     java.util.Calendar
 143.744 +     * @deprecated As of JDK version 1.1,
 143.745 +     * replaced by <code>Calendar.set(Calendar.DAY_OF_MONTH, int date)</code>.
 143.746 +     */
 143.747 +    @Deprecated
 143.748 +    public void setDate(int date) {
 143.749 +        getCalendarDate().setDayOfMonth(date);
 143.750 +    }
 143.751 +
 143.752 +    /**
 143.753 +     * Returns the day of the week represented by this date. The
 143.754 +     * returned value (<tt>0</tt> = Sunday, <tt>1</tt> = Monday,
 143.755 +     * <tt>2</tt> = Tuesday, <tt>3</tt> = Wednesday, <tt>4</tt> =
 143.756 +     * Thursday, <tt>5</tt> = Friday, <tt>6</tt> = Saturday)
 143.757 +     * represents the day of the week that contains or begins with
 143.758 +     * the instant in time represented by this <tt>Date</tt> object,
 143.759 +     * as interpreted in the local time zone.
 143.760 +     *
 143.761 +     * @return  the day of the week represented by this date.
 143.762 +     * @see     java.util.Calendar
 143.763 +     * @deprecated As of JDK version 1.1,
 143.764 +     * replaced by <code>Calendar.get(Calendar.DAY_OF_WEEK)</code>.
 143.765 +     */
 143.766 +    @Deprecated
 143.767 +    public int getDay() {
 143.768 +        return normalize().getDayOfWeek() - 7;//gcal.SUNDAY;
 143.769 +    }
 143.770 +
 143.771 +    /**
 143.772 +     * Returns the hour represented by this <tt>Date</tt> object. The
 143.773 +     * returned value is a number (<tt>0</tt> through <tt>23</tt>)
 143.774 +     * representing the hour within the day that contains or begins
 143.775 +     * with the instant in time represented by this <tt>Date</tt>
 143.776 +     * object, as interpreted in the local time zone.
 143.777 +     *
 143.778 +     * @return  the hour represented by this date.
 143.779 +     * @see     java.util.Calendar
 143.780 +     * @deprecated As of JDK version 1.1,
 143.781 +     * replaced by <code>Calendar.get(Calendar.HOUR_OF_DAY)</code>.
 143.782 +     */
 143.783 +    @Deprecated
 143.784 +    public int getHours() {
 143.785 +        return normalize().getHours();
 143.786 +    }
 143.787 +
 143.788 +    /**
 143.789 +     * Sets the hour of this <tt>Date</tt> object to the specified value.
 143.790 +     * This <tt>Date</tt> object is modified so that it represents a point
 143.791 +     * in time within the specified hour of the day, with the year, month,
 143.792 +     * date, minute, and second the same as before, as interpreted in the
 143.793 +     * local time zone.
 143.794 +     *
 143.795 +     * @param   hours   the hour value.
 143.796 +     * @see     java.util.Calendar
 143.797 +     * @deprecated As of JDK version 1.1,
 143.798 +     * replaced by <code>Calendar.set(Calendar.HOUR_OF_DAY, int hours)</code>.
 143.799 +     */
 143.800 +    @Deprecated
 143.801 +    public void setHours(int hours) {
 143.802 +        getCalendarDate().setHours(hours);
 143.803 +    }
 143.804 +
 143.805 +    /**
 143.806 +     * Returns the number of minutes past the hour represented by this date,
 143.807 +     * as interpreted in the local time zone.
 143.808 +     * The value returned is between <code>0</code> and <code>59</code>.
 143.809 +     *
 143.810 +     * @return  the number of minutes past the hour represented by this date.
 143.811 +     * @see     java.util.Calendar
 143.812 +     * @deprecated As of JDK version 1.1,
 143.813 +     * replaced by <code>Calendar.get(Calendar.MINUTE)</code>.
 143.814 +     */
 143.815 +    @Deprecated
 143.816 +    public int getMinutes() {
 143.817 +        return normalize().getMinutes();
 143.818 +    }
 143.819 +
 143.820 +    /**
 143.821 +     * Sets the minutes of this <tt>Date</tt> object to the specified value.
 143.822 +     * This <tt>Date</tt> object is modified so that it represents a point
 143.823 +     * in time within the specified minute of the hour, with the year, month,
 143.824 +     * date, hour, and second the same as before, as interpreted in the
 143.825 +     * local time zone.
 143.826 +     *
 143.827 +     * @param   minutes   the value of the minutes.
 143.828 +     * @see     java.util.Calendar
 143.829 +     * @deprecated As of JDK version 1.1,
 143.830 +     * replaced by <code>Calendar.set(Calendar.MINUTE, int minutes)</code>.
 143.831 +     */
 143.832 +    @Deprecated
 143.833 +    public void setMinutes(int minutes) {
 143.834 +        getCalendarDate().setMinutes(minutes);
 143.835 +    }
 143.836 +
 143.837 +    /**
 143.838 +     * Returns the number of seconds past the minute represented by this date.
 143.839 +     * The value returned is between <code>0</code> and <code>61</code>. The
 143.840 +     * values <code>60</code> and <code>61</code> can only occur on those
 143.841 +     * Java Virtual Machines that take leap seconds into account.
 143.842 +     *
 143.843 +     * @return  the number of seconds past the minute represented by this date.
 143.844 +     * @see     java.util.Calendar
 143.845 +     * @deprecated As of JDK version 1.1,
 143.846 +     * replaced by <code>Calendar.get(Calendar.SECOND)</code>.
 143.847 +     */
 143.848 +    @Deprecated
 143.849 +    public int getSeconds() {
 143.850 +        return normalize().getSeconds();
 143.851 +    }
 143.852 +
 143.853 +    /**
 143.854 +     * Sets the seconds of this <tt>Date</tt> to the specified value.
 143.855 +     * This <tt>Date</tt> object is modified so that it represents a
 143.856 +     * point in time within the specified second of the minute, with
 143.857 +     * the year, month, date, hour, and minute the same as before, as
 143.858 +     * interpreted in the local time zone.
 143.859 +     *
 143.860 +     * @param   seconds   the seconds value.
 143.861 +     * @see     java.util.Calendar
 143.862 +     * @deprecated As of JDK version 1.1,
 143.863 +     * replaced by <code>Calendar.set(Calendar.SECOND, int seconds)</code>.
 143.864 +     */
 143.865 +    @Deprecated
 143.866 +    public void setSeconds(int seconds) {
 143.867 +        getCalendarDate().setSeconds(seconds);
 143.868 +    }
 143.869 +
 143.870 +    /**
 143.871 +     * Returns the number of milliseconds since January 1, 1970, 00:00:00 GMT
 143.872 +     * represented by this <tt>Date</tt> object.
 143.873 +     *
 143.874 +     * @return  the number of milliseconds since January 1, 1970, 00:00:00 GMT
 143.875 +     *          represented by this date.
 143.876 +     */
 143.877 +    public long getTime() {
 143.878 +        return getTimeImpl();
 143.879 +    }
 143.880 +
 143.881 +    private final long getTimeImpl() {
 143.882 +        if (cdate != null && !cdate.isNormalized()) {
 143.883 +            normalize();
 143.884 +        }
 143.885 +        return fastTime;
 143.886 +    }
 143.887 +
 143.888 +    /**
 143.889 +     * Sets this <code>Date</code> object to represent a point in time that is
 143.890 +     * <code>time</code> milliseconds after January 1, 1970 00:00:00 GMT.
 143.891 +     *
 143.892 +     * @param   time   the number of milliseconds.
 143.893 +     */
 143.894 +    public void setTime(long time) {
 143.895 +        fastTime = time;
 143.896 +        cdate = null;
 143.897 +    }
 143.898 +
 143.899 +    /**
 143.900 +     * Tests if this date is before the specified date.
 143.901 +     *
 143.902 +     * @param   when   a date.
 143.903 +     * @return  <code>true</code> if and only if the instant of time
 143.904 +     *            represented by this <tt>Date</tt> object is strictly
 143.905 +     *            earlier than the instant represented by <tt>when</tt>;
 143.906 +     *          <code>false</code> otherwise.
 143.907 +     * @exception NullPointerException if <code>when</code> is null.
 143.908 +     */
 143.909 +    public boolean before(Date when) {
 143.910 +        return getMillisOf(this) < getMillisOf(when);
 143.911 +    }
 143.912 +
 143.913 +    /**
 143.914 +     * Tests if this date is after the specified date.
 143.915 +     *
 143.916 +     * @param   when   a date.
 143.917 +     * @return  <code>true</code> if and only if the instant represented
 143.918 +     *          by this <tt>Date</tt> object is strictly later than the
 143.919 +     *          instant represented by <tt>when</tt>;
 143.920 +     *          <code>false</code> otherwise.
 143.921 +     * @exception NullPointerException if <code>when</code> is null.
 143.922 +     */
 143.923 +    public boolean after(Date when) {
 143.924 +        return getMillisOf(this) > getMillisOf(when);
 143.925 +    }
 143.926 +
 143.927 +    /**
 143.928 +     * Compares two dates for equality.
 143.929 +     * The result is <code>true</code> if and only if the argument is
 143.930 +     * not <code>null</code> and is a <code>Date</code> object that
 143.931 +     * represents the same point in time, to the millisecond, as this object.
 143.932 +     * <p>
 143.933 +     * Thus, two <code>Date</code> objects are equal if and only if the
 143.934 +     * <code>getTime</code> method returns the same <code>long</code>
 143.935 +     * value for both.
 143.936 +     *
 143.937 +     * @param   obj   the object to compare with.
 143.938 +     * @return  <code>true</code> if the objects are the same;
 143.939 +     *          <code>false</code> otherwise.
 143.940 +     * @see     java.util.Date#getTime()
 143.941 +     */
 143.942 +    public boolean equals(Object obj) {
 143.943 +        return obj instanceof Date && getTime() == ((Date) obj).getTime();
 143.944 +    }
 143.945 +
 143.946 +    /**
 143.947 +     * Returns the millisecond value of this <code>Date</code> object
 143.948 +     * without affecting its internal state.
 143.949 +     */
 143.950 +    static final long getMillisOf(Date date) {
 143.951 +        if (date.cdate == null || date.cdate.isNormalized()) {
 143.952 +            return date.fastTime;
 143.953 +        }
 143.954 +        BaseCalendar.Datum d = (BaseCalendar.Datum) date.cdate.clone();
 143.955 +        return gcal.getTime(d);
 143.956 +    }
 143.957 +
 143.958 +    /**
 143.959 +     * Compares two Dates for ordering.
 143.960 +     *
 143.961 +     * @param   anotherDate   the <code>Date</code> to be compared.
 143.962 +     * @return  the value <code>0</code> if the argument Date is equal to
 143.963 +     *          this Date; a value less than <code>0</code> if this Date
 143.964 +     *          is before the Date argument; and a value greater than
 143.965 +     *      <code>0</code> if this Date is after the Date argument.
 143.966 +     * @since   1.2
 143.967 +     * @exception NullPointerException if <code>anotherDate</code> is null.
 143.968 +     */
 143.969 +    public int compareTo(Date anotherDate) {
 143.970 +        long thisTime = getMillisOf(this);
 143.971 +        long anotherTime = getMillisOf(anotherDate);
 143.972 +        return (thisTime<anotherTime ? -1 : (thisTime==anotherTime ? 0 : 1));
 143.973 +    }
 143.974 +
 143.975 +    /**
 143.976 +     * Returns a hash code value for this object. The result is the
 143.977 +     * exclusive OR of the two halves of the primitive <tt>long</tt>
 143.978 +     * value returned by the {@link Date#getTime}
 143.979 +     * method. That is, the hash code is the value of the expression:
 143.980 +     * <blockquote><pre>
 143.981 +     * (int)(this.getTime()^(this.getTime() >>> 32))</pre></blockquote>
 143.982 +     *
 143.983 +     * @return  a hash code value for this object.
 143.984 +     */
 143.985 +    public int hashCode() {
 143.986 +        long ht = this.getTime();
 143.987 +        return (int) ht ^ (int) (ht >> 32);
 143.988 +    }
 143.989 +
 143.990 +    /**
 143.991 +     * Converts this <code>Date</code> object to a <code>String</code>
 143.992 +     * of the form:
 143.993 +     * <blockquote><pre>
 143.994 +     * dow mon dd hh:mm:ss zzz yyyy</pre></blockquote>
 143.995 +     * where:<ul>
 143.996 +     * <li><tt>dow</tt> is the day of the week (<tt>Sun, Mon, Tue, Wed,
 143.997 +     *     Thu, Fri, Sat</tt>).
 143.998 +     * <li><tt>mon</tt> is the month (<tt>Jan, Feb, Mar, Apr, May, Jun,
 143.999 +     *     Jul, Aug, Sep, Oct, Nov, Dec</tt>).
143.1000 +     * <li><tt>dd</tt> is the day of the month (<tt>01</tt> through
143.1001 +     *     <tt>31</tt>), as two decimal digits.
143.1002 +     * <li><tt>hh</tt> is the hour of the day (<tt>00</tt> through
143.1003 +     *     <tt>23</tt>), as two decimal digits.
143.1004 +     * <li><tt>mm</tt> is the minute within the hour (<tt>00</tt> through
143.1005 +     *     <tt>59</tt>), as two decimal digits.
143.1006 +     * <li><tt>ss</tt> is the second within the minute (<tt>00</tt> through
143.1007 +     *     <tt>61</tt>, as two decimal digits.
143.1008 +     * <li><tt>zzz</tt> is the time zone (and may reflect daylight saving
143.1009 +     *     time). Standard time zone abbreviations include those
143.1010 +     *     recognized by the method <tt>parse</tt>. If time zone
143.1011 +     *     information is not available, then <tt>zzz</tt> is empty -
143.1012 +     *     that is, it consists of no characters at all.
143.1013 +     * <li><tt>yyyy</tt> is the year, as four decimal digits.
143.1014 +     * </ul>
143.1015 +     *
143.1016 +     * @return  a string representation of this date.
143.1017 +     * @see     java.util.Date#toLocaleString()
143.1018 +     * @see     java.util.Date#toGMTString()
143.1019 +     */
143.1020 +    public String toString() {
143.1021 +        // "EEE MMM dd HH:mm:ss zzz yyyy";
143.1022 +        BaseCalendar.Datum date = normalize();
143.1023 +        StringBuilder sb = new StringBuilder(28);
143.1024 +        int index = date.getDayOfWeek();
143.1025 +        if (index == 7) {
143.1026 +            index = 8;
143.1027 +        }
143.1028 +        convertToAbbr(sb, wtb[index]).append(' ');                        // EEE
143.1029 +        convertToAbbr(sb, wtb[date.getMonth() - 1 + 2 + 7]).append(' ');  // MMM
143.1030 +//        CalendarUtils.sprintf0d(sb, date.getDayOfMonth(), 2).append(' '); // dd
143.1031 +//
143.1032 +//        CalendarUtils.sprintf0d(sb, date.getHours(), 2).append(':');   // HH
143.1033 +//        CalendarUtils.sprintf0d(sb, date.getMinutes(), 2).append(':'); // mm
143.1034 +//        CalendarUtils.sprintf0d(sb, date.getSeconds(), 2).append(' '); // ss
143.1035 +//        TimeZone zi = date.getZone();
143.1036 +//        if (zi != null) {
143.1037 +//            sb.append(zi.getDisplayName(date.isDaylightTime(), zi.SHORT, Locale.US)); // zzz
143.1038 +//        } else {
143.1039 +//            sb.append("GMT");
143.1040 +//        }
143.1041 +        sb.append(' ').append(date.getYear());  // yyyy
143.1042 +        return sb.toString();
143.1043 +    }
143.1044 +
143.1045 +    /**
143.1046 +     * Converts the given name to its 3-letter abbreviation (e.g.,
143.1047 +     * "monday" -> "Mon") and stored the abbreviation in the given
143.1048 +     * <code>StringBuilder</code>.
143.1049 +     */
143.1050 +    private static final StringBuilder convertToAbbr(StringBuilder sb, String name) {
143.1051 +        sb.append(Character.toUpperCase(name.charAt(0)));
143.1052 +        sb.append(name.charAt(1)).append(name.charAt(2));
143.1053 +        return sb;
143.1054 +    }
143.1055 +
143.1056 +    /**
143.1057 +     * Creates a string representation of this <tt>Date</tt> object in an
143.1058 +     * implementation-dependent form. The intent is that the form should
143.1059 +     * be familiar to the user of the Java application, wherever it may
143.1060 +     * happen to be running. The intent is comparable to that of the
143.1061 +     * "<code>%c</code>" format supported by the <code>strftime()</code>
143.1062 +     * function of ISO&nbsp;C.
143.1063 +     *
143.1064 +     * @return  a string representation of this date, using the locale
143.1065 +     *          conventions.
143.1066 +     * @see     java.text.DateFormat
143.1067 +     * @see     java.util.Date#toString()
143.1068 +     * @see     java.util.Date#toGMTString()
143.1069 +     * @deprecated As of JDK version 1.1,
143.1070 +     * replaced by <code>DateFormat.format(Date date)</code>.
143.1071 +     */
143.1072 +    @Deprecated
143.1073 +    public String toLocaleString() {
143.1074 +        DateFormat formatter = DateFormat.getDateTimeInstance();
143.1075 +        return formatter.format(this);
143.1076 +    }
143.1077 +
143.1078 +    /**
143.1079 +     * Creates a string representation of this <tt>Date</tt> object of
143.1080 +     * the form:
143.1081 +     * <blockquote<pre>
143.1082 +     * d mon yyyy hh:mm:ss GMT</pre></blockquote>
143.1083 +     * where:<ul>
143.1084 +     * <li><i>d</i> is the day of the month (<tt>1</tt> through <tt>31</tt>),
143.1085 +     *     as one or two decimal digits.
143.1086 +     * <li><i>mon</i> is the month (<tt>Jan, Feb, Mar, Apr, May, Jun, Jul,
143.1087 +     *     Aug, Sep, Oct, Nov, Dec</tt>).
143.1088 +     * <li><i>yyyy</i> is the year, as four decimal digits.
143.1089 +     * <li><i>hh</i> is the hour of the day (<tt>00</tt> through <tt>23</tt>),
143.1090 +     *     as two decimal digits.
143.1091 +     * <li><i>mm</i> is the minute within the hour (<tt>00</tt> through
143.1092 +     *     <tt>59</tt>), as two decimal digits.
143.1093 +     * <li><i>ss</i> is the second within the minute (<tt>00</tt> through
143.1094 +     *     <tt>61</tt>), as two decimal digits.
143.1095 +     * <li><i>GMT</i> is exactly the ASCII letters "<tt>GMT</tt>" to indicate
143.1096 +     *     Greenwich Mean Time.
143.1097 +     * </ul><p>
143.1098 +     * The result does not depend on the local time zone.
143.1099 +     *
143.1100 +     * @return  a string representation of this date, using the Internet GMT
143.1101 +     *          conventions.
143.1102 +     * @see     java.text.DateFormat
143.1103 +     * @see     java.util.Date#toString()
143.1104 +     * @see     java.util.Date#toLocaleString()
143.1105 +     * @deprecated As of JDK version 1.1,
143.1106 +     * replaced by <code>DateFormat.format(Date date)</code>, using a
143.1107 +     * GMT <code>TimeZone</code>.
143.1108 +     */
143.1109 +    @Deprecated
143.1110 +    public String toGMTString() {
143.1111 +        // d MMM yyyy HH:mm:ss 'GMT'
143.1112 +        long t = getTime();
143.1113 +        BaseCalendar cal = getCalendarSystem(t);
143.1114 +        StringBuilder sb = new StringBuilder(32);
143.1115 +//        BaseCalendar.Datum date =
143.1116 +//            (BaseCalendar.Datum) cal.getCalendarDate(getTime(), (TimeZone)null);
143.1117 +//        CalendarUtils.sprintf0d(sb, date.getDayOfMonth(), 1).append(' '); // d
143.1118 +//        convertToAbbr(sb, wtb[date.getMonth() - 1 + 2 + 7]).append(' ');  // MMM
143.1119 +//        sb.append(date.getYear()).append(' ');                            // yyyy
143.1120 +//        CalendarUtils.sprintf0d(sb, date.getHours(), 2).append(':');      // HH
143.1121 +//        CalendarUtils.sprintf0d(sb, date.getMinutes(), 2).append(':');    // mm
143.1122 +//        CalendarUtils.sprintf0d(sb, date.getSeconds(), 2);                // ss
143.1123 +        sb.append(" GMT");                                                // ' GMT'
143.1124 +        return sb.toString();
143.1125 +    }
143.1126 +
143.1127 +    /**
143.1128 +     * Returns the offset, measured in minutes, for the local time zone
143.1129 +     * relative to UTC that is appropriate for the time represented by
143.1130 +     * this <code>Date</code> object.
143.1131 +     * <p>
143.1132 +     * For example, in Massachusetts, five time zones west of Greenwich:
143.1133 +     * <blockquote><pre>
143.1134 +     * new Date(96, 1, 14).getTimezoneOffset() returns 300</pre></blockquote>
143.1135 +     * because on February 14, 1996, standard time (Eastern Standard Time)
143.1136 +     * is in use, which is offset five hours from UTC; but:
143.1137 +     * <blockquote><pre>
143.1138 +     * new Date(96, 5, 1).getTimezoneOffset() returns 240</pre></blockquote>
143.1139 +     * because on June 1, 1996, daylight saving time (Eastern Daylight Time)
143.1140 +     * is in use, which is offset only four hours from UTC.<p>
143.1141 +     * This method produces the same result as if it computed:
143.1142 +     * <blockquote><pre>
143.1143 +     * (this.getTime() - UTC(this.getYear(),
143.1144 +     *                       this.getMonth(),
143.1145 +     *                       this.getDate(),
143.1146 +     *                       this.getHours(),
143.1147 +     *                       this.getMinutes(),
143.1148 +     *                       this.getSeconds())) / (60 * 1000)
143.1149 +     * </pre></blockquote>
143.1150 +     *
143.1151 +     * @return  the time-zone offset, in minutes, for the current time zone.
143.1152 +     * @see     java.util.Calendar#ZONE_OFFSET
143.1153 +     * @see     java.util.Calendar#DST_OFFSET
143.1154 +     * @see     java.util.TimeZone#getDefault
143.1155 +     * @deprecated As of JDK version 1.1,
143.1156 +     * replaced by <code>-(Calendar.get(Calendar.ZONE_OFFSET) +
143.1157 +     * Calendar.get(Calendar.DST_OFFSET)) / (60 * 1000)</code>.
143.1158 +     */
143.1159 +    @Deprecated
143.1160 +    public int getTimezoneOffset() {
143.1161 +        int zoneOffset;
143.1162 +        if (cdate == null) {
143.1163 +            TimeZone tz = TimeZone.getDefaultRef();
143.1164 +            zoneOffset = tz.getOffset(fastTime);
143.1165 +        } else {
143.1166 +            normalize();
143.1167 +            zoneOffset = cdate.getZoneOffset();
143.1168 +        }
143.1169 +        return -zoneOffset/60000;  // convert to minutes
143.1170 +    }
143.1171 +
143.1172 +    private final BaseCalendar.Datum getCalendarDate() {
143.1173 +        if (cdate == null) {
143.1174 +//            BaseCalendar cal = getCalendarSystem(fastTime);
143.1175 +//            cdate = (BaseCalendar.Datum) cal.getCalendarDate(fastTime,
143.1176 +//                                                            TimeZone.getDefaultRef());
143.1177 +        }
143.1178 +        return cdate;
143.1179 +    }
143.1180 +
143.1181 +    private final BaseCalendar.Datum normalize() {
143.1182 +        if (cdate == null) {
143.1183 +//            BaseCalendar cal = getCalendarSystem(fastTime);
143.1184 +//            cdate = (BaseCalendar.Datum) cal.getCalendarDate(fastTime,
143.1185 +//                                                            TimeZone.getDefaultRef());
143.1186 +//            return cdate;
143.1187 +        }
143.1188 +
143.1189 +        // Normalize cdate with the TimeZone in cdate first. This is
143.1190 +        // required for the compatible behavior.
143.1191 +        if (!cdate.isNormalized()) {
143.1192 +            cdate = normalize(cdate);
143.1193 +        }
143.1194 +
143.1195 +        // If the default TimeZone has changed, then recalculate the
143.1196 +        // fields with the new TimeZone.
143.1197 +        TimeZone tz = TimeZone.getDefaultRef();
143.1198 +        if (tz != cdate.getZone()) {
143.1199 +//            cdate.setZone(tz);
143.1200 +//            CalendarSystem cal = getCalendarSystem(cdate);
143.1201 +//            cal.getCalendarDate(fastTime, cdate);
143.1202 +        }
143.1203 +        return cdate;
143.1204 +    }
143.1205 +
143.1206 +    // fastTime and the returned data are in sync upon return.
143.1207 +    private final BaseCalendar.Datum normalize(BaseCalendar.Datum date) {
143.1208 +        int y = date.getNormalizedYear();
143.1209 +        int m = date.getMonth();
143.1210 +        int d = date.getDayOfMonth();
143.1211 +        int hh = date.getHours();
143.1212 +        int mm = date.getMinutes();
143.1213 +        int ss = date.getSeconds();
143.1214 +        int ms = date.getMillis();
143.1215 +        TimeZone tz = date.getZone();
143.1216 +
143.1217 +        // If the specified year can't be handled using a long value
143.1218 +        // in milliseconds, GregorianCalendar is used for full
143.1219 +        // compatibility with underflow and overflow. This is required
143.1220 +        // by some JCK tests. The limits are based max year values -
143.1221 +        // years that can be represented by max values of d, hh, mm,
143.1222 +        // ss and ms. Also, let GregorianCalendar handle the default
143.1223 +        // cutover year so that we don't need to worry about the
143.1224 +        // transition here.
143.1225 +//        if (y == 1582 || y > 280000000 || y < -280000000) {
143.1226 +//            if (tz == null) {
143.1227 +//                tz = TimeZone.getTimeZone("GMT");
143.1228 +//            }
143.1229 +//            GregorianCalendar gc = new GregorianCalendar(tz);
143.1230 +//            gc.clear();
143.1231 +//            gc.set(gc.MILLISECOND, ms);
143.1232 +//            gc.set(y, m-1, d, hh, mm, ss);
143.1233 +//            fastTime = gc.getTimeInMillis();
143.1234 +//            BaseCalendar cal = getCalendarSystem(fastTime);
143.1235 +//            date = (BaseCalendar.Datum) cal.getCalendarDate(fastTime, tz);
143.1236 +//            return date;
143.1237 +//        }
143.1238 +
143.1239 +        BaseCalendar cal = getCalendarSystem(y);
143.1240 +        if (cal != getCalendarSystem(date)) {
143.1241 +            date = (BaseCalendar.Datum) cal.newCalendarDate(tz);
143.1242 +            date.setNormalizedDate(y, m, d).setTimeOfDay(hh, mm, ss, ms);
143.1243 +        }
143.1244 +        // Perform the GregorianCalendar-style normalization.
143.1245 +        fastTime = cal.getTime(date);
143.1246 +
143.1247 +        // In case the normalized date requires the other calendar
143.1248 +        // system, we need to recalculate it using the other one.
143.1249 +        BaseCalendar ncal = getCalendarSystem(fastTime);
143.1250 +        if (ncal != cal) {
143.1251 +            date = (BaseCalendar.Datum) ncal.newCalendarDate(tz);
143.1252 +            date.setNormalizedDate(y, m, d).setTimeOfDay(hh, mm, ss, ms);
143.1253 +            fastTime = ncal.getTime(date);
143.1254 +        }
143.1255 +        return date;
143.1256 +    }
143.1257 +
143.1258 +    /**
143.1259 +     * Returns the Gregorian or Julian calendar system to use with the
143.1260 +     * given date. Use Gregorian from October 15, 1582.
143.1261 +     *
143.1262 +     * @param year normalized calendar year (not -1900)
143.1263 +     * @return the CalendarSystem to use for the specified date
143.1264 +     */
143.1265 +    private static final BaseCalendar getCalendarSystem(int year) {
143.1266 +        if (year >= 1582) {
143.1267 +            return gcal;
143.1268 +        }
143.1269 +        return getJulianCalendar();
143.1270 +    }
143.1271 +
143.1272 +    private static final BaseCalendar getCalendarSystem(long utc) {
143.1273 +        // Quickly check if the time stamp given by `utc' is the Epoch
143.1274 +        // or later. If it's before 1970, we convert the cutover to
143.1275 +        // local time to compare.
143.1276 +//        if (utc >= 0
143.1277 +//            || utc >= GregorianCalendar.DEFAULT_GREGORIAN_CUTOVER
143.1278 +//                        - TimeZone.getDefaultRef().getOffset(utc)) {
143.1279 +            return gcal;
143.1280 +//        }
143.1281 +//        return getJulianCalendar();
143.1282 +    }
143.1283 +
143.1284 +    private static final BaseCalendar getCalendarSystem(BaseCalendar.Datum cdate) {
143.1285 +        if (jcal == null) {
143.1286 +            return gcal;
143.1287 +        }
143.1288 +        if (cdate.getEra() != null) {
143.1289 +            return jcal;
143.1290 +        }
143.1291 +        return gcal;
143.1292 +    }
143.1293 +
143.1294 +    synchronized private static final BaseCalendar getJulianCalendar() {
143.1295 +        if (jcal == null) {
143.1296 +//            jcal = (BaseCalendar) CalendarSystem.forName("julian");
143.1297 +        }
143.1298 +        return jcal;
143.1299 +    }
143.1300 +
143.1301 +    /**
143.1302 +     * Save the state of this object to a stream (i.e., serialize it).
143.1303 +     *
143.1304 +     * @serialData The value returned by <code>getTime()</code>
143.1305 +     *             is emitted (long).  This represents the offset from
143.1306 +     *             January 1, 1970, 00:00:00 GMT in milliseconds.
143.1307 +     */
143.1308 +    private void writeObject(ObjectOutputStream s)
143.1309 +         throws IOException
143.1310 +    {
143.1311 +        s.writeLong(getTimeImpl());
143.1312 +    }
143.1313 +
143.1314 +    /**
143.1315 +     * Reconstitute this object from a stream (i.e., deserialize it).
143.1316 +     */
143.1317 +    private void readObject(ObjectInputStream s)
143.1318 +         throws IOException, ClassNotFoundException
143.1319 +    {
143.1320 +        fastTime = s.readLong();
143.1321 +    }
143.1322 +    
143.1323 +    static final class BaseCalendar {
143.1324 +        Datum newCalendarDate(TimeZone t) {
143.1325 +            return new Datum();
143.1326 +        }
143.1327 +        
143.1328 +        Datum getNthDayOfWeek(int a, int b, Datum c) {
143.1329 +            return new Datum();
143.1330 +        }
143.1331 +
143.1332 +        Datum getCalendarDate() {
143.1333 +            return new Datum();
143.1334 +        }
143.1335 +
143.1336 +        int getTime(Datum udate) {
143.1337 +            return 0;
143.1338 +        }
143.1339 +
143.1340 +        int getMonthLength(Datum cdate) {
143.1341 +            return 0;
143.1342 +        }
143.1343 +
143.1344 +        void getCalendarDate(long l, Datum cdate) {
143.1345 +        }
143.1346 +        
143.1347 +        static class Datum implements Cloneable {
143.1348 +            public Datum clone() {
143.1349 +                return new Datum();
143.1350 +            }
143.1351 +            
143.1352 +            Datum setNormalizedDate(int y, int i, int date) {
143.1353 +                return this;
143.1354 +            }
143.1355 +
143.1356 +            void setTimeOfDay(int hrs, int min, int sec, int i) {
143.1357 +            }
143.1358 +
143.1359 +            int getYear() {
143.1360 +                return 0;
143.1361 +            }
143.1362 +
143.1363 +            void setDate(int year, int i, int mday) {
143.1364 +            }
143.1365 +
143.1366 +            void setNormalizedYear(int i) {
143.1367 +            }
143.1368 +
143.1369 +            int getMonth() {
143.1370 +                return 0;
143.1371 +            }
143.1372 +
143.1373 +            int getNormalizedYear() {
143.1374 +                return 0;
143.1375 +            }
143.1376 +
143.1377 +            void setMonth(int i) {
143.1378 +            }
143.1379 +
143.1380 +            int getDayOfMonth() {
143.1381 +                return 0;
143.1382 +            }
143.1383 +
143.1384 +            void setDayOfMonth(int date) {
143.1385 +            }
143.1386 +
143.1387 +            int getDayOfWeek() {
143.1388 +                return 0;
143.1389 +            }
143.1390 +
143.1391 +            int getHours() {
143.1392 +                return 0;
143.1393 +            }
143.1394 +
143.1395 +            void setHours(int hours) {
143.1396 +            }
143.1397 +
143.1398 +            int getMinutes() {
143.1399 +                return 0;
143.1400 +            }
143.1401 +
143.1402 +            void setMinutes(int minutes) {
143.1403 +            }
143.1404 +
143.1405 +            int getSeconds() {
143.1406 +                return 0;
143.1407 +            }
143.1408 +
143.1409 +            void setSeconds(int seconds) {
143.1410 +            }
143.1411 +
143.1412 +            boolean isNormalized() {
143.1413 +                return false;
143.1414 +            }
143.1415 +
143.1416 +            Object getEra() {
143.1417 +                return this;
143.1418 +            }
143.1419 +
143.1420 +            int getMillis() {
143.1421 +                return 0;
143.1422 +            }
143.1423 +
143.1424 +            TimeZone getZone() {
143.1425 +                return TimeZone.NO_TIMEZONE;
143.1426 +            }
143.1427 +
143.1428 +            int getZoneOffset() {
143.1429 +                return 0;
143.1430 +            }
143.1431 +        }
143.1432 +    }
143.1433 +}
   144.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   144.2 +++ b/rt/emul/compact/src/main/java/java/util/EnumMap.java	Tue Feb 11 13:31:42 2014 +0100
   144.3 @@ -0,0 +1,797 @@
   144.4 +/*
   144.5 + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
   144.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   144.7 + *
   144.8 + * This code is free software; you can redistribute it and/or modify it
   144.9 + * under the terms of the GNU General Public License version 2 only, as
  144.10 + * published by the Free Software Foundation.  Oracle designates this
  144.11 + * particular file as subject to the "Classpath" exception as provided
  144.12 + * by Oracle in the LICENSE file that accompanied this code.
  144.13 + *
  144.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  144.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  144.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  144.17 + * version 2 for more details (a copy is included in the LICENSE file that
  144.18 + * accompanied this code).
  144.19 + *
  144.20 + * You should have received a copy of the GNU General Public License version
  144.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  144.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  144.23 + *
  144.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  144.25 + * or visit www.oracle.com if you need additional information or have any
  144.26 + * questions.
  144.27 + */
  144.28 +
  144.29 +package java.util;
  144.30 +
  144.31 +import java.util.Map.Entry;
  144.32 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
  144.33 +
  144.34 +/**
  144.35 + * A specialized {@link Map} implementation for use with enum type keys.  All
  144.36 + * of the keys in an enum map must come from a single enum type that is
  144.37 + * specified, explicitly or implicitly, when the map is created.  Enum maps
  144.38 + * are represented internally as arrays.  This representation is extremely
  144.39 + * compact and efficient.
  144.40 + *
  144.41 + * <p>Enum maps are maintained in the <i>natural order</i> of their keys
  144.42 + * (the order in which the enum constants are declared).  This is reflected
  144.43 + * in the iterators returned by the collections views ({@link #keySet()},
  144.44 + * {@link #entrySet()}, and {@link #values()}).
  144.45 + *
  144.46 + * <p>Iterators returned by the collection views are <i>weakly consistent</i>:
  144.47 + * they will never throw {@link ConcurrentModificationException} and they may
  144.48 + * or may not show the effects of any modifications to the map that occur while
  144.49 + * the iteration is in progress.
  144.50 + *
  144.51 + * <p>Null keys are not permitted.  Attempts to insert a null key will
  144.52 + * throw {@link NullPointerException}.  Attempts to test for the
  144.53 + * presence of a null key or to remove one will, however, function properly.
  144.54 + * Null values are permitted.
  144.55 +
  144.56 + * <P>Like most collection implementations <tt>EnumMap</tt> is not
  144.57 + * synchronized. If multiple threads access an enum map concurrently, and at
  144.58 + * least one of the threads modifies the map, it should be synchronized
  144.59 + * externally.  This is typically accomplished by synchronizing on some
  144.60 + * object that naturally encapsulates the enum map.  If no such object exists,
  144.61 + * the map should be "wrapped" using the {@link Collections#synchronizedMap}
  144.62 + * method.  This is best done at creation time, to prevent accidental
  144.63 + * unsynchronized access:
  144.64 + *
  144.65 + * <pre>
  144.66 + *     Map&lt;EnumKey, V&gt; m
  144.67 + *         = Collections.synchronizedMap(new EnumMap&lt;EnumKey, V&gt;(...));
  144.68 + * </pre>
  144.69 + *
  144.70 + * <p>Implementation note: All basic operations execute in constant time.
  144.71 + * They are likely (though not guaranteed) to be faster than their
  144.72 + * {@link HashMap} counterparts.
  144.73 + *
  144.74 + * <p>This class is a member of the
  144.75 + * <a href="{@docRoot}/../technotes/guides/collections/index.html">
  144.76 + * Java Collections Framework</a>.
  144.77 + *
  144.78 + * @author Josh Bloch
  144.79 + * @see EnumSet
  144.80 + * @since 1.5
  144.81 + */
  144.82 +public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V>
  144.83 +    implements java.io.Serializable, Cloneable
  144.84 +{
  144.85 +    /**
  144.86 +     * The <tt>Class</tt> object for the enum type of all the keys of this map.
  144.87 +     *
  144.88 +     * @serial
  144.89 +     */
  144.90 +    private final Class<K> keyType;
  144.91 +
  144.92 +    /**
  144.93 +     * All of the values comprising K.  (Cached for performance.)
  144.94 +     */
  144.95 +    private transient K[] keyUniverse;
  144.96 +
  144.97 +    /**
  144.98 +     * Array representation of this map.  The ith element is the value
  144.99 +     * to which universe[i] is currently mapped, or null if it isn't
 144.100 +     * mapped to anything, or NULL if it's mapped to null.
 144.101 +     */
 144.102 +    private transient Object[] vals;
 144.103 +
 144.104 +    /**
 144.105 +     * The number of mappings in this map.
 144.106 +     */
 144.107 +    private transient int size = 0;
 144.108 +
 144.109 +    /**
 144.110 +     * Distinguished non-null value for representing null values.
 144.111 +     */
 144.112 +    private static final Object NULL = new Integer(0);
 144.113 +
 144.114 +    private Object maskNull(Object value) {
 144.115 +        return (value == null ? NULL : value);
 144.116 +    }
 144.117 +
 144.118 +    private V unmaskNull(Object value) {
 144.119 +        return (V) (value == NULL ? null : value);
 144.120 +    }
 144.121 +
 144.122 +    private static final Enum[] ZERO_LENGTH_ENUM_ARRAY = new Enum[0];
 144.123 +
 144.124 +    /**
 144.125 +     * Creates an empty enum map with the specified key type.
 144.126 +     *
 144.127 +     * @param keyType the class object of the key type for this enum map
 144.128 +     * @throws NullPointerException if <tt>keyType</tt> is null
 144.129 +     */
 144.130 +    public EnumMap(Class<K> keyType) {
 144.131 +        this.keyType = keyType;
 144.132 +        keyUniverse = getKeyUniverse(keyType);
 144.133 +        vals = new Object[keyUniverse.length];
 144.134 +    }
 144.135 +
 144.136 +    /**
 144.137 +     * Creates an enum map with the same key type as the specified enum
 144.138 +     * map, initially containing the same mappings (if any).
 144.139 +     *
 144.140 +     * @param m the enum map from which to initialize this enum map
 144.141 +     * @throws NullPointerException if <tt>m</tt> is null
 144.142 +     */
 144.143 +    public EnumMap(EnumMap<K, ? extends V> m) {
 144.144 +        keyType = m.keyType;
 144.145 +        keyUniverse = m.keyUniverse;
 144.146 +        vals = m.vals.clone();
 144.147 +        size = m.size;
 144.148 +    }
 144.149 +
 144.150 +    /**
 144.151 +     * Creates an enum map initialized from the specified map.  If the
 144.152 +     * specified map is an <tt>EnumMap</tt> instance, this constructor behaves
 144.153 +     * identically to {@link #EnumMap(EnumMap)}.  Otherwise, the specified map
 144.154 +     * must contain at least one mapping (in order to determine the new
 144.155 +     * enum map's key type).
 144.156 +     *
 144.157 +     * @param m the map from which to initialize this enum map
 144.158 +     * @throws IllegalArgumentException if <tt>m</tt> is not an
 144.159 +     *     <tt>EnumMap</tt> instance and contains no mappings
 144.160 +     * @throws NullPointerException if <tt>m</tt> is null
 144.161 +     */
 144.162 +    public EnumMap(Map<K, ? extends V> m) {
 144.163 +        if (m instanceof EnumMap) {
 144.164 +            EnumMap<K, ? extends V> em = (EnumMap<K, ? extends V>) m;
 144.165 +            keyType = em.keyType;
 144.166 +            keyUniverse = em.keyUniverse;
 144.167 +            vals = em.vals.clone();
 144.168 +            size = em.size;
 144.169 +        } else {
 144.170 +            if (m.isEmpty())
 144.171 +                throw new IllegalArgumentException("Specified map is empty");
 144.172 +            keyType = m.keySet().iterator().next().getDeclaringClass();
 144.173 +            keyUniverse = getKeyUniverse(keyType);
 144.174 +            vals = new Object[keyUniverse.length];
 144.175 +            putAll(m);
 144.176 +        }
 144.177 +    }
 144.178 +
 144.179 +    // Query Operations
 144.180 +
 144.181 +    /**
 144.182 +     * Returns the number of key-value mappings in this map.
 144.183 +     *
 144.184 +     * @return the number of key-value mappings in this map
 144.185 +     */
 144.186 +    public int size() {
 144.187 +        return size;
 144.188 +    }
 144.189 +
 144.190 +    /**
 144.191 +     * Returns <tt>true</tt> if this map maps one or more keys to the
 144.192 +     * specified value.
 144.193 +     *
 144.194 +     * @param value the value whose presence in this map is to be tested
 144.195 +     * @return <tt>true</tt> if this map maps one or more keys to this value
 144.196 +     */
 144.197 +    public boolean containsValue(Object value) {
 144.198 +        value = maskNull(value);
 144.199 +
 144.200 +        for (Object val : vals)
 144.201 +            if (value.equals(val))
 144.202 +                return true;
 144.203 +
 144.204 +        return false;
 144.205 +    }
 144.206 +
 144.207 +    /**
 144.208 +     * Returns <tt>true</tt> if this map contains a mapping for the specified
 144.209 +     * key.
 144.210 +     *
 144.211 +     * @param key the key whose presence in this map is to be tested
 144.212 +     * @return <tt>true</tt> if this map contains a mapping for the specified
 144.213 +     *            key
 144.214 +     */
 144.215 +    public boolean containsKey(Object key) {
 144.216 +        return isValidKey(key) && vals[((Enum)key).ordinal()] != null;
 144.217 +    }
 144.218 +
 144.219 +    private boolean containsMapping(Object key, Object value) {
 144.220 +        return isValidKey(key) &&
 144.221 +            maskNull(value).equals(vals[((Enum)key).ordinal()]);
 144.222 +    }
 144.223 +
 144.224 +    /**
 144.225 +     * Returns the value to which the specified key is mapped,
 144.226 +     * or {@code null} if this map contains no mapping for the key.
 144.227 +     *
 144.228 +     * <p>More formally, if this map contains a mapping from a key
 144.229 +     * {@code k} to a value {@code v} such that {@code (key == k)},
 144.230 +     * then this method returns {@code v}; otherwise it returns
 144.231 +     * {@code null}.  (There can be at most one such mapping.)
 144.232 +     *
 144.233 +     * <p>A return value of {@code null} does not <i>necessarily</i>
 144.234 +     * indicate that the map contains no mapping for the key; it's also
 144.235 +     * possible that the map explicitly maps the key to {@code null}.
 144.236 +     * The {@link #containsKey containsKey} operation may be used to
 144.237 +     * distinguish these two cases.
 144.238 +     */
 144.239 +    public V get(Object key) {
 144.240 +        return (isValidKey(key) ?
 144.241 +                unmaskNull(vals[((Enum)key).ordinal()]) : null);
 144.242 +    }
 144.243 +
 144.244 +    // Modification Operations
 144.245 +
 144.246 +    /**
 144.247 +     * Associates the specified value with the specified key in this map.
 144.248 +     * If the map previously contained a mapping for this key, the old
 144.249 +     * value is replaced.
 144.250 +     *
 144.251 +     * @param key the key with which the specified value is to be associated
 144.252 +     * @param value the value to be associated with the specified key
 144.253 +     *
 144.254 +     * @return the previous value associated with specified key, or
 144.255 +     *     <tt>null</tt> if there was no mapping for key.  (A <tt>null</tt>
 144.256 +     *     return can also indicate that the map previously associated
 144.257 +     *     <tt>null</tt> with the specified key.)
 144.258 +     * @throws NullPointerException if the specified key is null
 144.259 +     */
 144.260 +    public V put(K key, V value) {
 144.261 +        typeCheck(key);
 144.262 +
 144.263 +        int index = key.ordinal();
 144.264 +        Object oldValue = vals[index];
 144.265 +        vals[index] = maskNull(value);
 144.266 +        if (oldValue == null)
 144.267 +            size++;
 144.268 +        return unmaskNull(oldValue);
 144.269 +    }
 144.270 +
 144.271 +    /**
 144.272 +     * Removes the mapping for this key from this map if present.
 144.273 +     *
 144.274 +     * @param key the key whose mapping is to be removed from the map
 144.275 +     * @return the previous value associated with specified key, or
 144.276 +     *     <tt>null</tt> if there was no entry for key.  (A <tt>null</tt>
 144.277 +     *     return can also indicate that the map previously associated
 144.278 +     *     <tt>null</tt> with the specified key.)
 144.279 +     */
 144.280 +    public V remove(Object key) {
 144.281 +        if (!isValidKey(key))
 144.282 +            return null;
 144.283 +        int index = ((Enum)key).ordinal();
 144.284 +        Object oldValue = vals[index];
 144.285 +        vals[index] = null;
 144.286 +        if (oldValue != null)
 144.287 +            size--;
 144.288 +        return unmaskNull(oldValue);
 144.289 +    }
 144.290 +
 144.291 +    private boolean removeMapping(Object key, Object value) {
 144.292 +        if (!isValidKey(key))
 144.293 +            return false;
 144.294 +        int index = ((Enum)key).ordinal();
 144.295 +        if (maskNull(value).equals(vals[index])) {
 144.296 +            vals[index] = null;
 144.297 +            size--;
 144.298 +            return true;
 144.299 +        }
 144.300 +        return false;
 144.301 +    }
 144.302 +
 144.303 +    /**
 144.304 +     * Returns true if key is of the proper type to be a key in this
 144.305 +     * enum map.
 144.306 +     */
 144.307 +    private boolean isValidKey(Object key) {
 144.308 +        if (key == null)
 144.309 +            return false;
 144.310 +
 144.311 +        // Cheaper than instanceof Enum followed by getDeclaringClass
 144.312 +        Class keyClass = key.getClass();
 144.313 +        return keyClass == keyType || keyClass.getSuperclass() == keyType;
 144.314 +    }
 144.315 +
 144.316 +    // Bulk Operations
 144.317 +
 144.318 +    /**
 144.319 +     * Copies all of the mappings from the specified map to this map.
 144.320 +     * These mappings will replace any mappings that this map had for
 144.321 +     * any of the keys currently in the specified map.
 144.322 +     *
 144.323 +     * @param m the mappings to be stored in this map
 144.324 +     * @throws NullPointerException the specified map is null, or if
 144.325 +     *     one or more keys in the specified map are null
 144.326 +     */
 144.327 +    public void putAll(Map<? extends K, ? extends V> m) {
 144.328 +        if (m instanceof EnumMap) {
 144.329 +            EnumMap<? extends K, ? extends V> em =
 144.330 +                (EnumMap<? extends K, ? extends V>)m;
 144.331 +            if (em.keyType != keyType) {
 144.332 +                if (em.isEmpty())
 144.333 +                    return;
 144.334 +                throw new ClassCastException(em.keyType + " != " + keyType);
 144.335 +            }
 144.336 +
 144.337 +            for (int i = 0; i < keyUniverse.length; i++) {
 144.338 +                Object emValue = em.vals[i];
 144.339 +                if (emValue != null) {
 144.340 +                    if (vals[i] == null)
 144.341 +                        size++;
 144.342 +                    vals[i] = emValue;
 144.343 +                }
 144.344 +            }
 144.345 +        } else {
 144.346 +            super.putAll(m);
 144.347 +        }
 144.348 +    }
 144.349 +
 144.350 +    /**
 144.351 +     * Removes all mappings from this map.
 144.352 +     */
 144.353 +    public void clear() {
 144.354 +        Arrays.fill(vals, null);
 144.355 +        size = 0;
 144.356 +    }
 144.357 +
 144.358 +    // Views
 144.359 +
 144.360 +    /**
 144.361 +     * This field is initialized to contain an instance of the entry set
 144.362 +     * view the first time this view is requested.  The view is stateless,
 144.363 +     * so there's no reason to create more than one.
 144.364 +     */
 144.365 +    private transient Set<Map.Entry<K,V>> entrySet = null;
 144.366 +
 144.367 +    /**
 144.368 +     * Returns a {@link Set} view of the keys contained in this map.
 144.369 +     * The returned set obeys the general contract outlined in
 144.370 +     * {@link Map#keySet()}.  The set's iterator will return the keys
 144.371 +     * in their natural order (the order in which the enum constants
 144.372 +     * are declared).
 144.373 +     *
 144.374 +     * @return a set view of the keys contained in this enum map
 144.375 +     */
 144.376 +    public Set<K> keySet() {
 144.377 +        Set<K> ks = keySet;
 144.378 +        if (ks != null)
 144.379 +            return ks;
 144.380 +        else
 144.381 +            return keySet = new KeySet();
 144.382 +    }
 144.383 +
 144.384 +    private class KeySet extends AbstractSet<K> {
 144.385 +        public Iterator<K> iterator() {
 144.386 +            return new KeyIterator();
 144.387 +        }
 144.388 +        public int size() {
 144.389 +            return size;
 144.390 +        }
 144.391 +        public boolean contains(Object o) {
 144.392 +            return containsKey(o);
 144.393 +        }
 144.394 +        public boolean remove(Object o) {
 144.395 +            int oldSize = size;
 144.396 +            EnumMap.this.remove(o);
 144.397 +            return size != oldSize;
 144.398 +        }
 144.399 +        public void clear() {
 144.400 +            EnumMap.this.clear();
 144.401 +        }
 144.402 +    }
 144.403 +
 144.404 +    /**
 144.405 +     * Returns a {@link Collection} view of the values contained in this map.
 144.406 +     * The returned collection obeys the general contract outlined in
 144.407 +     * {@link Map#values()}.  The collection's iterator will return the
 144.408 +     * values in the order their corresponding keys appear in map,
 144.409 +     * which is their natural order (the order in which the enum constants
 144.410 +     * are declared).
 144.411 +     *
 144.412 +     * @return a collection view of the values contained in this map
 144.413 +     */
 144.414 +    public Collection<V> values() {
 144.415 +        Collection<V> vs = values;
 144.416 +        if (vs != null)
 144.417 +            return vs;
 144.418 +        else
 144.419 +            return values = new Values();
 144.420 +    }
 144.421 +
 144.422 +    private class Values extends AbstractCollection<V> {
 144.423 +        public Iterator<V> iterator() {
 144.424 +            return new ValueIterator();
 144.425 +        }
 144.426 +        public int size() {
 144.427 +            return size;
 144.428 +        }
 144.429 +        public boolean contains(Object o) {
 144.430 +            return containsValue(o);
 144.431 +        }
 144.432 +        public boolean remove(Object o) {
 144.433 +            o = maskNull(o);
 144.434 +
 144.435 +            for (int i = 0; i < vals.length; i++) {
 144.436 +                if (o.equals(vals[i])) {
 144.437 +                    vals[i] = null;
 144.438 +                    size--;
 144.439 +                    return true;
 144.440 +                }
 144.441 +            }
 144.442 +            return false;
 144.443 +        }
 144.444 +        public void clear() {
 144.445 +            EnumMap.this.clear();
 144.446 +        }
 144.447 +    }
 144.448 +
 144.449 +    /**
 144.450 +     * Returns a {@link Set} view of the mappings contained in this map.
 144.451 +     * The returned set obeys the general contract outlined in
 144.452 +     * {@link Map#keySet()}.  The set's iterator will return the
 144.453 +     * mappings in the order their keys appear in map, which is their
 144.454 +     * natural order (the order in which the enum constants are declared).
 144.455 +     *
 144.456 +     * @return a set view of the mappings contained in this enum map
 144.457 +     */
 144.458 +    public Set<Map.Entry<K,V>> entrySet() {
 144.459 +        Set<Map.Entry<K,V>> es = entrySet;
 144.460 +        if (es != null)
 144.461 +            return es;
 144.462 +        else
 144.463 +            return entrySet = new EntrySet();
 144.464 +    }
 144.465 +
 144.466 +    private class EntrySet extends AbstractSet<Map.Entry<K,V>> {
 144.467 +        public Iterator<Map.Entry<K,V>> iterator() {
 144.468 +            return new EntryIterator();
 144.469 +        }
 144.470 +
 144.471 +        public boolean contains(Object o) {
 144.472 +            if (!(o instanceof Map.Entry))
 144.473 +                return false;
 144.474 +            Map.Entry entry = (Map.Entry)o;
 144.475 +            return containsMapping(entry.getKey(), entry.getValue());
 144.476 +        }
 144.477 +        public boolean remove(Object o) {
 144.478 +            if (!(o instanceof Map.Entry))
 144.479 +                return false;
 144.480 +            Map.Entry entry = (Map.Entry)o;
 144.481 +            return removeMapping(entry.getKey(), entry.getValue());
 144.482 +        }
 144.483 +        public int size() {
 144.484 +            return size;
 144.485 +        }
 144.486 +        public void clear() {
 144.487 +            EnumMap.this.clear();
 144.488 +        }
 144.489 +        public Object[] toArray() {
 144.490 +            return fillEntryArray(new Object[size]);
 144.491 +        }
 144.492 +        @SuppressWarnings("unchecked")
 144.493 +        public <T> T[] toArray(T[] a) {
 144.494 +            int size = size();
 144.495 +            if (a.length < size)
 144.496 +                a = (T[])java.lang.reflect.Array
 144.497 +                    .newInstance(a.getClass().getComponentType(), size);
 144.498 +            if (a.length > size)
 144.499 +                a[size] = null;
 144.500 +            return (T[]) fillEntryArray(a);
 144.501 +        }
 144.502 +        private Object[] fillEntryArray(Object[] a) {
 144.503 +            int j = 0;
 144.504 +            for (int i = 0; i < vals.length; i++)
 144.505 +                if (vals[i] != null)
 144.506 +                    a[j++] = new AbstractMap.SimpleEntry<>(
 144.507 +                        keyUniverse[i], unmaskNull(vals[i]));
 144.508 +            return a;
 144.509 +        }
 144.510 +    }
 144.511 +
 144.512 +    private abstract class EnumMapIterator<T> implements Iterator<T> {
 144.513 +        // Lower bound on index of next element to return
 144.514 +        int index = 0;
 144.515 +
 144.516 +        // Index of last returned element, or -1 if none
 144.517 +        int lastReturnedIndex = -1;
 144.518 +
 144.519 +        public boolean hasNext() {
 144.520 +            while (index < vals.length && vals[index] == null)
 144.521 +                index++;
 144.522 +            return index != vals.length;
 144.523 +        }
 144.524 +
 144.525 +        public void remove() {
 144.526 +            checkLastReturnedIndex();
 144.527 +
 144.528 +            if (vals[lastReturnedIndex] != null) {
 144.529 +                vals[lastReturnedIndex] = null;
 144.530 +                size--;
 144.531 +            }
 144.532 +            lastReturnedIndex = -1;
 144.533 +        }
 144.534 +
 144.535 +        private void checkLastReturnedIndex() {
 144.536 +            if (lastReturnedIndex < 0)
 144.537 +                throw new IllegalStateException();
 144.538 +        }
 144.539 +    }
 144.540 +
 144.541 +    private class KeyIterator extends EnumMapIterator<K> {
 144.542 +        public K next() {
 144.543 +            if (!hasNext())
 144.544 +                throw new NoSuchElementException();
 144.545 +            lastReturnedIndex = index++;
 144.546 +            return keyUniverse[lastReturnedIndex];
 144.547 +        }
 144.548 +    }
 144.549 +
 144.550 +    private class ValueIterator extends EnumMapIterator<V> {
 144.551 +        public V next() {
 144.552 +            if (!hasNext())
 144.553 +                throw new NoSuchElementException();
 144.554 +            lastReturnedIndex = index++;
 144.555 +            return unmaskNull(vals[lastReturnedIndex]);
 144.556 +        }
 144.557 +    }
 144.558 +
 144.559 +    private class EntryIterator extends EnumMapIterator<Map.Entry<K,V>> {
 144.560 +        private Entry lastReturnedEntry = null;
 144.561 +
 144.562 +        public Map.Entry<K,V> next() {
 144.563 +            if (!hasNext())
 144.564 +                throw new NoSuchElementException();
 144.565 +            lastReturnedEntry = new Entry(index++);
 144.566 +            return lastReturnedEntry;
 144.567 +        }
 144.568 +
 144.569 +        public void remove() {
 144.570 +            lastReturnedIndex =
 144.571 +                ((null == lastReturnedEntry) ? -1 : lastReturnedEntry.index);
 144.572 +            super.remove();
 144.573 +            lastReturnedEntry.index = lastReturnedIndex;
 144.574 +            lastReturnedEntry = null;
 144.575 +        }
 144.576 +
 144.577 +        private class Entry implements Map.Entry<K,V> {
 144.578 +            private int index;
 144.579 +
 144.580 +            private Entry(int index) {
 144.581 +                this.index = index;
 144.582 +            }
 144.583 +
 144.584 +            public K getKey() {
 144.585 +                checkIndexForEntryUse();
 144.586 +                return keyUniverse[index];
 144.587 +            }
 144.588 +
 144.589 +            public V getValue() {
 144.590 +                checkIndexForEntryUse();
 144.591 +                return unmaskNull(vals[index]);
 144.592 +            }
 144.593 +
 144.594 +            public V setValue(V value) {
 144.595 +                checkIndexForEntryUse();
 144.596 +                V oldValue = unmaskNull(vals[index]);
 144.597 +                vals[index] = maskNull(value);
 144.598 +                return oldValue;
 144.599 +            }
 144.600 +
 144.601 +            public boolean equals(Object o) {
 144.602 +                if (index < 0)
 144.603 +                    return o == this;
 144.604 +
 144.605 +                if (!(o instanceof Map.Entry))
 144.606 +                    return false;
 144.607 +
 144.608 +                Map.Entry e = (Map.Entry)o;
 144.609 +                V ourValue = unmaskNull(vals[index]);
 144.610 +                Object hisValue = e.getValue();
 144.611 +                return (e.getKey() == keyUniverse[index] &&
 144.612 +                        (ourValue == hisValue ||
 144.613 +                         (ourValue != null && ourValue.equals(hisValue))));
 144.614 +            }
 144.615 +
 144.616 +            public int hashCode() {
 144.617 +                if (index < 0)
 144.618 +                    return super.hashCode();
 144.619 +
 144.620 +                return entryHashCode(index);
 144.621 +            }
 144.622 +
 144.623 +            public String toString() {
 144.624 +                if (index < 0)
 144.625 +                    return super.toString();
 144.626 +
 144.627 +                return keyUniverse[index] + "="
 144.628 +                    + unmaskNull(vals[index]);
 144.629 +            }
 144.630 +
 144.631 +            private void checkIndexForEntryUse() {
 144.632 +                if (index < 0)
 144.633 +                    throw new IllegalStateException("Entry was removed");
 144.634 +            }
 144.635 +        }
 144.636 +    }
 144.637 +
 144.638 +    // Comparison and hashing
 144.639 +
 144.640 +    /**
 144.641 +     * Compares the specified object with this map for equality.  Returns
 144.642 +     * <tt>true</tt> if the given object is also a map and the two maps
 144.643 +     * represent the same mappings, as specified in the {@link
 144.644 +     * Map#equals(Object)} contract.
 144.645 +     *
 144.646 +     * @param o the object to be compared for equality with this map
 144.647 +     * @return <tt>true</tt> if the specified object is equal to this map
 144.648 +     */
 144.649 +    public boolean equals(Object o) {
 144.650 +        if (this == o)
 144.651 +            return true;
 144.652 +        if (o instanceof EnumMap)
 144.653 +            return equals((EnumMap)o);
 144.654 +        if (!(o instanceof Map))
 144.655 +            return false;
 144.656 +
 144.657 +        Map<K,V> m = (Map<K,V>)o;
 144.658 +        if (size != m.size())
 144.659 +            return false;
 144.660 +
 144.661 +        for (int i = 0; i < keyUniverse.length; i++) {
 144.662 +            if (null != vals[i]) {
 144.663 +                K key = keyUniverse[i];
 144.664 +                V value = unmaskNull(vals[i]);
 144.665 +                if (null == value) {
 144.666 +                    if (!((null == m.get(key)) && m.containsKey(key)))
 144.667 +                       return false;
 144.668 +                } else {
 144.669 +                   if (!value.equals(m.get(key)))
 144.670 +                      return false;
 144.671 +                }
 144.672 +            }
 144.673 +        }
 144.674 +
 144.675 +        return true;
 144.676 +    }
 144.677 +
 144.678 +    private boolean equals(EnumMap em) {
 144.679 +        if (em.keyType != keyType)
 144.680 +            return size == 0 && em.size == 0;
 144.681 +
 144.682 +        // Key types match, compare each value
 144.683 +        for (int i = 0; i < keyUniverse.length; i++) {
 144.684 +            Object ourValue =    vals[i];
 144.685 +            Object hisValue = em.vals[i];
 144.686 +            if (hisValue != ourValue &&
 144.687 +                (hisValue == null || !hisValue.equals(ourValue)))
 144.688 +                return false;
 144.689 +        }
 144.690 +        return true;
 144.691 +    }
 144.692 +
 144.693 +    /**
 144.694 +     * Returns the hash code value for this map.  The hash code of a map is
 144.695 +     * defined to be the sum of the hash codes of each entry in the map.
 144.696 +     */
 144.697 +    public int hashCode() {
 144.698 +        int h = 0;
 144.699 +
 144.700 +        for (int i = 0; i < keyUniverse.length; i++) {
 144.701 +            if (null != vals[i]) {
 144.702 +                h += entryHashCode(i);
 144.703 +            }
 144.704 +        }
 144.705 +
 144.706 +        return h;
 144.707 +    }
 144.708 +
 144.709 +    private int entryHashCode(int index) {
 144.710 +        return (keyUniverse[index].hashCode() ^ vals[index].hashCode());
 144.711 +    }
 144.712 +
 144.713 +    /**
 144.714 +     * Returns a shallow copy of this enum map.  (The values themselves
 144.715 +     * are not cloned.
 144.716 +     *
 144.717 +     * @return a shallow copy of this enum map
 144.718 +     */
 144.719 +    public EnumMap<K, V> clone() {
 144.720 +        EnumMap<K, V> result = null;
 144.721 +        try {
 144.722 +            result = (EnumMap<K, V>) super.clone();
 144.723 +        } catch(CloneNotSupportedException e) {
 144.724 +            throw new AssertionError();
 144.725 +        }
 144.726 +        result.vals = result.vals.clone();
 144.727 +        return result;
 144.728 +    }
 144.729 +
 144.730 +    /**
 144.731 +     * Throws an exception if e is not of the correct type for this enum set.
 144.732 +     */
 144.733 +    private void typeCheck(K key) {
 144.734 +        Class keyClass = key.getClass();
 144.735 +        if (keyClass != keyType && keyClass.getSuperclass() != keyType)
 144.736 +            throw new ClassCastException(keyClass + " != " + keyType);
 144.737 +    }
 144.738 +
 144.739 +    /**
 144.740 +     * Returns all of the values comprising K.
 144.741 +     * The result is uncloned, cached, and shared by all callers.
 144.742 +     */
 144.743 +    @JavaScriptBody(args = { "enumType" }, body = "return enumType.cnstr.fld_$VALUES;")
 144.744 +    private static native <K extends Enum<K>> K[] getKeyUniverse(Class<K> keyType);
 144.745 +
 144.746 +    private static final long serialVersionUID = 458661240069192865L;
 144.747 +
 144.748 +    /**
 144.749 +     * Save the state of the <tt>EnumMap</tt> instance to a stream (i.e.,
 144.750 +     * serialize it).
 144.751 +     *
 144.752 +     * @serialData The <i>size</i> of the enum map (the number of key-value
 144.753 +     *             mappings) is emitted (int), followed by the key (Object)
 144.754 +     *             and value (Object) for each key-value mapping represented
 144.755 +     *             by the enum map.
 144.756 +     */
 144.757 +    private void writeObject(java.io.ObjectOutputStream s)
 144.758 +        throws java.io.IOException
 144.759 +    {
 144.760 +        // Write out the key type and any hidden stuff
 144.761 +        s.defaultWriteObject();
 144.762 +
 144.763 +        // Write out size (number of Mappings)
 144.764 +        s.writeInt(size);
 144.765 +
 144.766 +        // Write out keys and values (alternating)
 144.767 +        int entriesToBeWritten = size;
 144.768 +        for (int i = 0; entriesToBeWritten > 0; i++) {
 144.769 +            if (null != vals[i]) {
 144.770 +                s.writeObject(keyUniverse[i]);
 144.771 +                s.writeObject(unmaskNull(vals[i]));
 144.772 +                entriesToBeWritten--;
 144.773 +            }
 144.774 +        }
 144.775 +    }
 144.776 +
 144.777 +    /**
 144.778 +     * Reconstitute the <tt>EnumMap</tt> instance from a stream (i.e.,
 144.779 +     * deserialize it).
 144.780 +     */
 144.781 +    private void readObject(java.io.ObjectInputStream s)
 144.782 +        throws java.io.IOException, ClassNotFoundException
 144.783 +    {
 144.784 +        // Read in the key type and any hidden stuff
 144.785 +        s.defaultReadObject();
 144.786 +
 144.787 +        keyUniverse = getKeyUniverse(keyType);
 144.788 +        vals = new Object[keyUniverse.length];
 144.789 +
 144.790 +        // Read in size (number of Mappings)
 144.791 +        int size = s.readInt();
 144.792 +
 144.793 +        // Read the keys and values, and put the mappings in the HashMap
 144.794 +        for (int i = 0; i < size; i++) {
 144.795 +            K key = (K) s.readObject();
 144.796 +            V value = (V) s.readObject();
 144.797 +            put(key, value);
 144.798 +        }
 144.799 +    }
 144.800 +}
   145.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   145.2 +++ b/rt/emul/compact/src/main/java/java/util/EnumSet.java	Tue Feb 11 13:31:42 2014 +0100
   145.3 @@ -0,0 +1,441 @@
   145.4 +/*
   145.5 + * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
   145.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   145.7 + *
   145.8 + * This code is free software; you can redistribute it and/or modify it
   145.9 + * under the terms of the GNU General Public License version 2 only, as
  145.10 + * published by the Free Software Foundation.  Oracle designates this
  145.11 + * particular file as subject to the "Classpath" exception as provided
  145.12 + * by Oracle in the LICENSE file that accompanied this code.
  145.13 + *
  145.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  145.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  145.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  145.17 + * version 2 for more details (a copy is included in the LICENSE file that
  145.18 + * accompanied this code).
  145.19 + *
  145.20 + * You should have received a copy of the GNU General Public License version
  145.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  145.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  145.23 + *
  145.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  145.25 + * or visit www.oracle.com if you need additional information or have any
  145.26 + * questions.
  145.27 + */
  145.28 +
  145.29 +package java.util;
  145.30 +
  145.31 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
  145.32 +
  145.33 +/**
  145.34 + * A specialized {@link Set} implementation for use with enum types.  All of
  145.35 + * the elements in an enum set must come from a single enum type that is
  145.36 + * specified, explicitly or implicitly, when the set is created.  Enum sets
  145.37 + * are represented internally as bit vectors.  This representation is
  145.38 + * extremely compact and efficient. The space and time performance of this
  145.39 + * class should be good enough to allow its use as a high-quality, typesafe
  145.40 + * alternative to traditional <tt>int</tt>-based "bit flags."  Even bulk
  145.41 + * operations (such as <tt>containsAll</tt> and <tt>retainAll</tt>) should
  145.42 + * run very quickly if their argument is also an enum set.
  145.43 + *
  145.44 + * <p>The iterator returned by the <tt>iterator</tt> method traverses the
  145.45 + * elements in their <i>natural order</i> (the order in which the enum
  145.46 + * constants are declared).  The returned iterator is <i>weakly
  145.47 + * consistent</i>: it will never throw {@link ConcurrentModificationException}
  145.48 + * and it may or may not show the effects of any modifications to the set that
  145.49 + * occur while the iteration is in progress.
  145.50 + *
  145.51 + * <p>Null elements are not permitted.  Attempts to insert a null element
  145.52 + * will throw {@link NullPointerException}.  Attempts to test for the
  145.53 + * presence of a null element or to remove one will, however, function
  145.54 + * properly.
  145.55 + *
  145.56 + * <P>Like most collection implementations, <tt>EnumSet</tt> is not
  145.57 + * synchronized.  If multiple threads access an enum set concurrently, and at
  145.58 + * least one of the threads modifies the set, it should be synchronized
  145.59 + * externally.  This is typically accomplished by synchronizing on some
  145.60 + * object that naturally encapsulates the enum set.  If no such object exists,
  145.61 + * the set should be "wrapped" using the {@link Collections#synchronizedSet}
  145.62 + * method.  This is best done at creation time, to prevent accidental
  145.63 + * unsynchronized access:
  145.64 + *
  145.65 + * <pre>
  145.66 + * Set&lt;MyEnum&gt; s = Collections.synchronizedSet(EnumSet.noneOf(MyEnum.class));
  145.67 + * </pre>
  145.68 + *
  145.69 + * <p>Implementation note: All basic operations execute in constant time.
  145.70 + * They are likely (though not guaranteed) to be much faster than their
  145.71 + * {@link HashSet} counterparts.  Even bulk operations execute in
  145.72 + * constant time if their argument is also an enum set.
  145.73 + *
  145.74 + * <p>This class is a member of the
  145.75 + * <a href="{@docRoot}/../technotes/guides/collections/index.html">
  145.76 + * Java Collections Framework</a>.
  145.77 + *
  145.78 + * @author Josh Bloch
  145.79 + * @since 1.5
  145.80 + * @see EnumMap
  145.81 + * @serial exclude
  145.82 + */
  145.83 +public abstract class EnumSet<E extends Enum<E>> extends AbstractSet<E>
  145.84 +    implements Cloneable, java.io.Serializable
  145.85 +{
  145.86 +    /**
  145.87 +     * The class of all the elements of this set.
  145.88 +     */
  145.89 +    final Class<E> elementType;
  145.90 +
  145.91 +    /**
  145.92 +     * All of the values comprising T.  (Cached for performance.)
  145.93 +     */
  145.94 +    final Enum[] universe;
  145.95 +
  145.96 +    private static Enum[] ZERO_LENGTH_ENUM_ARRAY = new Enum[0];
  145.97 +
  145.98 +    EnumSet(Class<E>elementType, Enum[] universe) {
  145.99 +        this.elementType = elementType;
 145.100 +        this.universe    = universe;
 145.101 +    }
 145.102 +
 145.103 +    /**
 145.104 +     * Creates an empty enum set with the specified element type.
 145.105 +     *
 145.106 +     * @param elementType the class object of the element type for this enum
 145.107 +     *     set
 145.108 +     * @throws NullPointerException if <tt>elementType</tt> is null
 145.109 +     */
 145.110 +    public static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> elementType) {
 145.111 +        Enum[] universe = getUniverse(elementType);
 145.112 +        if (universe == null)
 145.113 +            throw new ClassCastException(elementType + " not an enum");
 145.114 +
 145.115 +        if (universe.length <= 64)
 145.116 +            return new RegularEnumSet<>(elementType, universe);
 145.117 +        else
 145.118 +            return new JumboEnumSet<>(elementType, universe);
 145.119 +    }
 145.120 +
 145.121 +    /**
 145.122 +     * Creates an enum set containing all of the elements in the specified
 145.123 +     * element type.
 145.124 +     *
 145.125 +     * @param elementType the class object of the element type for this enum
 145.126 +     *     set
 145.127 +     * @throws NullPointerException if <tt>elementType</tt> is null
 145.128 +     */
 145.129 +    public static <E extends Enum<E>> EnumSet<E> allOf(Class<E> elementType) {
 145.130 +        EnumSet<E> result = noneOf(elementType);
 145.131 +        result.addAll();
 145.132 +        return result;
 145.133 +    }
 145.134 +
 145.135 +    /**
 145.136 +     * Adds all of the elements from the appropriate enum type to this enum
 145.137 +     * set, which is empty prior to the call.
 145.138 +     */
 145.139 +    abstract void addAll();
 145.140 +
 145.141 +    /**
 145.142 +     * Creates an enum set with the same element type as the specified enum
 145.143 +     * set, initially containing the same elements (if any).
 145.144 +     *
 145.145 +     * @param s the enum set from which to initialize this enum set
 145.146 +     * @throws NullPointerException if <tt>s</tt> is null
 145.147 +     */
 145.148 +    public static <E extends Enum<E>> EnumSet<E> copyOf(EnumSet<E> s) {
 145.149 +        return s.clone();
 145.150 +    }
 145.151 +
 145.152 +    /**
 145.153 +     * Creates an enum set initialized from the specified collection.  If
 145.154 +     * the specified collection is an <tt>EnumSet</tt> instance, this static
 145.155 +     * factory method behaves identically to {@link #copyOf(EnumSet)}.
 145.156 +     * Otherwise, the specified collection must contain at least one element
 145.157 +     * (in order to determine the new enum set's element type).
 145.158 +     *
 145.159 +     * @param c the collection from which to initialize this enum set
 145.160 +     * @throws IllegalArgumentException if <tt>c</tt> is not an
 145.161 +     *     <tt>EnumSet</tt> instance and contains no elements
 145.162 +     * @throws NullPointerException if <tt>c</tt> is null
 145.163 +     */
 145.164 +    public static <E extends Enum<E>> EnumSet<E> copyOf(Collection<E> c) {
 145.165 +        if (c instanceof EnumSet) {
 145.166 +            return ((EnumSet<E>)c).clone();
 145.167 +        } else {
 145.168 +            if (c.isEmpty())
 145.169 +                throw new IllegalArgumentException("Collection is empty");
 145.170 +            Iterator<E> i = c.iterator();
 145.171 +            E first = i.next();
 145.172 +            EnumSet<E> result = EnumSet.of(first);
 145.173 +            while (i.hasNext())
 145.174 +                result.add(i.next());
 145.175 +            return result;
 145.176 +        }
 145.177 +    }
 145.178 +
 145.179 +    /**
 145.180 +     * Creates an enum set with the same element type as the specified enum
 145.181 +     * set, initially containing all the elements of this type that are
 145.182 +     * <i>not</i> contained in the specified set.
 145.183 +     *
 145.184 +     * @param s the enum set from whose complement to initialize this enum set
 145.185 +     * @throws NullPointerException if <tt>s</tt> is null
 145.186 +     */
 145.187 +    public static <E extends Enum<E>> EnumSet<E> complementOf(EnumSet<E> s) {
 145.188 +        EnumSet<E> result = copyOf(s);
 145.189 +        result.complement();
 145.190 +        return result;
 145.191 +    }
 145.192 +
 145.193 +    /**
 145.194 +     * Creates an enum set initially containing the specified element.
 145.195 +     *
 145.196 +     * Overloadings of this method exist to initialize an enum set with
 145.197 +     * one through five elements.  A sixth overloading is provided that
 145.198 +     * uses the varargs feature.  This overloading may be used to create
 145.199 +     * an enum set initially containing an arbitrary number of elements, but
 145.200 +     * is likely to run slower than the overloadings that do not use varargs.
 145.201 +     *
 145.202 +     * @param e the element that this set is to contain initially
 145.203 +     * @throws NullPointerException if <tt>e</tt> is null
 145.204 +     * @return an enum set initially containing the specified element
 145.205 +     */
 145.206 +    public static <E extends Enum<E>> EnumSet<E> of(E e) {
 145.207 +        EnumSet<E> result = noneOf(e.getDeclaringClass());
 145.208 +        result.add(e);
 145.209 +        return result;
 145.210 +    }
 145.211 +
 145.212 +    /**
 145.213 +     * Creates an enum set initially containing the specified elements.
 145.214 +     *
 145.215 +     * Overloadings of this method exist to initialize an enum set with
 145.216 +     * one through five elements.  A sixth overloading is provided that
 145.217 +     * uses the varargs feature.  This overloading may be used to create
 145.218 +     * an enum set initially containing an arbitrary number of elements, but
 145.219 +     * is likely to run slower than the overloadings that do not use varargs.
 145.220 +     *
 145.221 +     * @param e1 an element that this set is to contain initially
 145.222 +     * @param e2 another element that this set is to contain initially
 145.223 +     * @throws NullPointerException if any parameters are null
 145.224 +     * @return an enum set initially containing the specified elements
 145.225 +     */
 145.226 +    public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2) {
 145.227 +        EnumSet<E> result = noneOf(e1.getDeclaringClass());
 145.228 +        result.add(e1);
 145.229 +        result.add(e2);
 145.230 +        return result;
 145.231 +    }
 145.232 +
 145.233 +    /**
 145.234 +     * Creates an enum set initially containing the specified elements.
 145.235 +     *
 145.236 +     * Overloadings of this method exist to initialize an enum set with
 145.237 +     * one through five elements.  A sixth overloading is provided that
 145.238 +     * uses the varargs feature.  This overloading may be used to create
 145.239 +     * an enum set initially containing an arbitrary number of elements, but
 145.240 +     * is likely to run slower than the overloadings that do not use varargs.
 145.241 +     *
 145.242 +     * @param e1 an element that this set is to contain initially
 145.243 +     * @param e2 another element that this set is to contain initially
 145.244 +     * @param e3 another element that this set is to contain initially
 145.245 +     * @throws NullPointerException if any parameters are null
 145.246 +     * @return an enum set initially containing the specified elements
 145.247 +     */
 145.248 +    public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3) {
 145.249 +        EnumSet<E> result = noneOf(e1.getDeclaringClass());
 145.250 +        result.add(e1);
 145.251 +        result.add(e2);
 145.252 +        result.add(e3);
 145.253 +        return result;
 145.254 +    }
 145.255 +
 145.256 +    /**
 145.257 +     * Creates an enum set initially containing the specified elements.
 145.258 +     *
 145.259 +     * Overloadings of this method exist to initialize an enum set with
 145.260 +     * one through five elements.  A sixth overloading is provided that
 145.261 +     * uses the varargs feature.  This overloading may be used to create
 145.262 +     * an enum set initially containing an arbitrary number of elements, but
 145.263 +     * is likely to run slower than the overloadings that do not use varargs.
 145.264 +     *
 145.265 +     * @param e1 an element that this set is to contain initially
 145.266 +     * @param e2 another element that this set is to contain initially
 145.267 +     * @param e3 another element that this set is to contain initially
 145.268 +     * @param e4 another element that this set is to contain initially
 145.269 +     * @throws NullPointerException if any parameters are null
 145.270 +     * @return an enum set initially containing the specified elements
 145.271 +     */
 145.272 +    public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3, E e4) {
 145.273 +        EnumSet<E> result = noneOf(e1.getDeclaringClass());
 145.274 +        result.add(e1);
 145.275 +        result.add(e2);
 145.276 +        result.add(e3);
 145.277 +        result.add(e4);
 145.278 +        return result;
 145.279 +    }
 145.280 +
 145.281 +    /**
 145.282 +     * Creates an enum set initially containing the specified elements.
 145.283 +     *
 145.284 +     * Overloadings of this method exist to initialize an enum set with
 145.285 +     * one through five elements.  A sixth overloading is provided that
 145.286 +     * uses the varargs feature.  This overloading may be used to create
 145.287 +     * an enum set initially containing an arbitrary number of elements, but
 145.288 +     * is likely to run slower than the overloadings that do not use varargs.
 145.289 +     *
 145.290 +     * @param e1 an element that this set is to contain initially
 145.291 +     * @param e2 another element that this set is to contain initially
 145.292 +     * @param e3 another element that this set is to contain initially
 145.293 +     * @param e4 another element that this set is to contain initially
 145.294 +     * @param e5 another element that this set is to contain initially
 145.295 +     * @throws NullPointerException if any parameters are null
 145.296 +     * @return an enum set initially containing the specified elements
 145.297 +     */
 145.298 +    public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3, E e4,
 145.299 +                                                    E e5)
 145.300 +    {
 145.301 +        EnumSet<E> result = noneOf(e1.getDeclaringClass());
 145.302 +        result.add(e1);
 145.303 +        result.add(e2);
 145.304 +        result.add(e3);
 145.305 +        result.add(e4);
 145.306 +        result.add(e5);
 145.307 +        return result;
 145.308 +    }
 145.309 +
 145.310 +    /**
 145.311 +     * Creates an enum set initially containing the specified elements.
 145.312 +     * This factory, whose parameter list uses the varargs feature, may
 145.313 +     * be used to create an enum set initially containing an arbitrary
 145.314 +     * number of elements, but it is likely to run slower than the overloadings
 145.315 +     * that do not use varargs.
 145.316 +     *
 145.317 +     * @param first an element that the set is to contain initially
 145.318 +     * @param rest the remaining elements the set is to contain initially
 145.319 +     * @throws NullPointerException if any of the specified elements are null,
 145.320 +     *     or if <tt>rest</tt> is null
 145.321 +     * @return an enum set initially containing the specified elements
 145.322 +     */
 145.323 +    @SafeVarargs
 145.324 +    public static <E extends Enum<E>> EnumSet<E> of(E first, E... rest) {
 145.325 +        EnumSet<E> result = noneOf(first.getDeclaringClass());
 145.326 +        result.add(first);
 145.327 +        for (E e : rest)
 145.328 +            result.add(e);
 145.329 +        return result;
 145.330 +    }
 145.331 +
 145.332 +    /**
 145.333 +     * Creates an enum set initially containing all of the elements in the
 145.334 +     * range defined by the two specified endpoints.  The returned set will
 145.335 +     * contain the endpoints themselves, which may be identical but must not
 145.336 +     * be out of order.
 145.337 +     *
 145.338 +     * @param from the first element in the range
 145.339 +     * @param to the last element in the range
 145.340 +     * @throws NullPointerException if {@code from} or {@code to} are null
 145.341 +     * @throws IllegalArgumentException if {@code from.compareTo(to) > 0}
 145.342 +     * @return an enum set initially containing all of the elements in the
 145.343 +     *         range defined by the two specified endpoints
 145.344 +     */
 145.345 +    public static <E extends Enum<E>> EnumSet<E> range(E from, E to) {
 145.346 +        if (from.compareTo(to) > 0)
 145.347 +            throw new IllegalArgumentException(from + " > " + to);
 145.348 +        EnumSet<E> result = noneOf(from.getDeclaringClass());
 145.349 +        result.addRange(from, to);
 145.350 +        return result;
 145.351 +    }
 145.352 +
 145.353 +    /**
 145.354 +     * Adds the specified range to this enum set, which is empty prior
 145.355 +     * to the call.
 145.356 +     */
 145.357 +    abstract void addRange(E from, E to);
 145.358 +
 145.359 +    /**
 145.360 +     * Returns a copy of this set.
 145.361 +     *
 145.362 +     * @return a copy of this set
 145.363 +     */
 145.364 +    public EnumSet<E> clone() {
 145.365 +        try {
 145.366 +            return (EnumSet<E>) super.clone();
 145.367 +        } catch(CloneNotSupportedException e) {
 145.368 +            throw new AssertionError(e);
 145.369 +        }
 145.370 +    }
 145.371 +
 145.372 +    /**
 145.373 +     * Complements the contents of this enum set.
 145.374 +     */
 145.375 +    abstract void complement();
 145.376 +
 145.377 +    /**
 145.378 +     * Throws an exception if e is not of the correct type for this enum set.
 145.379 +     */
 145.380 +    final void typeCheck(E e) {
 145.381 +        Class eClass = e.getClass();
 145.382 +        if (eClass != elementType && eClass.getSuperclass() != elementType)
 145.383 +            throw new ClassCastException(eClass + " != " + elementType);
 145.384 +    }
 145.385 +
 145.386 +    /**
 145.387 +     * Returns all of the values comprising E.
 145.388 +     * The result is uncloned, cached, and shared by all callers.
 145.389 +     */
 145.390 +    @JavaScriptBody(args = { "enumType" }, body = "return enumType.cnstr.fld_$VALUES;")
 145.391 +    private static native <E extends Enum<E>> E[] getUniverse(Class<E> elementType);
 145.392 +
 145.393 +    /**
 145.394 +     * This class is used to serialize all EnumSet instances, regardless of
 145.395 +     * implementation type.  It captures their "logical contents" and they
 145.396 +     * are reconstructed using public static factories.  This is necessary
 145.397 +     * to ensure that the existence of a particular implementation type is
 145.398 +     * an implementation detail.
 145.399 +     *
 145.400 +     * @serial include
 145.401 +     */
 145.402 +    private static class SerializationProxy <E extends Enum<E>>
 145.403 +        implements java.io.Serializable
 145.404 +    {
 145.405 +        /**
 145.406 +         * The element type of this enum set.
 145.407 +         *
 145.408 +         * @serial
 145.409 +         */
 145.410 +        private final Class<E> elementType;
 145.411 +
 145.412 +        /**
 145.413 +         * The elements contained in this enum set.
 145.414 +         *
 145.415 +         * @serial
 145.416 +         */
 145.417 +        private final Enum[] elements;
 145.418 +
 145.419 +        SerializationProxy(EnumSet<E> set) {
 145.420 +            elementType = set.elementType;
 145.421 +            elements = set.toArray(ZERO_LENGTH_ENUM_ARRAY);
 145.422 +        }
 145.423 +
 145.424 +        private Object readResolve() {
 145.425 +            EnumSet<E> result = EnumSet.noneOf(elementType);
 145.426 +            for (Enum e : elements)
 145.427 +                result.add((E)e);
 145.428 +            return result;
 145.429 +        }
 145.430 +
 145.431 +        private static final long serialVersionUID = 362491234563181265L;
 145.432 +    }
 145.433 +
 145.434 +    Object writeReplace() {
 145.435 +        return new SerializationProxy<>(this);
 145.436 +    }
 145.437 +
 145.438 +    // readObject method for the serialization proxy pattern
 145.439 +    // See Effective Java, Second Ed., Item 78.
 145.440 +    private void readObject(java.io.ObjectInputStream stream)
 145.441 +        throws java.io.InvalidObjectException {
 145.442 +        throw new java.io.InvalidObjectException("Proxy required");
 145.443 +    }
 145.444 +}
   146.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   146.2 +++ b/rt/emul/compact/src/main/java/java/util/JumboEnumSet.java	Tue Feb 11 13:31:42 2014 +0100
   146.3 @@ -0,0 +1,375 @@
   146.4 +/*
   146.5 + * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
   146.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   146.7 + *
   146.8 + * This code is free software; you can redistribute it and/or modify it
   146.9 + * under the terms of the GNU General Public License version 2 only, as
  146.10 + * published by the Free Software Foundation.  Oracle designates this
  146.11 + * particular file as subject to the "Classpath" exception as provided
  146.12 + * by Oracle in the LICENSE file that accompanied this code.
  146.13 + *
  146.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  146.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  146.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  146.17 + * version 2 for more details (a copy is included in the LICENSE file that
  146.18 + * accompanied this code).
  146.19 + *
  146.20 + * You should have received a copy of the GNU General Public License version
  146.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  146.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  146.23 + *
  146.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  146.25 + * or visit www.oracle.com if you need additional information or have any
  146.26 + * questions.
  146.27 + */
  146.28 +
  146.29 +package java.util;
  146.30 +
  146.31 +/**
  146.32 + * Private implementation class for EnumSet, for "jumbo" enum types
  146.33 + * (i.e., those with more than 64 elements).
  146.34 + *
  146.35 + * @author Josh Bloch
  146.36 + * @since 1.5
  146.37 + * @serial exclude
  146.38 + */
  146.39 +class JumboEnumSet<E extends Enum<E>> extends EnumSet<E> {
  146.40 +    private static final long serialVersionUID = 334349849919042784L;
  146.41 +
  146.42 +    /**
  146.43 +     * Bit vector representation of this set.  The ith bit of the jth
  146.44 +     * element of this array represents the  presence of universe[64*j +i]
  146.45 +     * in this set.
  146.46 +     */
  146.47 +    private long elements[];
  146.48 +
  146.49 +    // Redundant - maintained for performance
  146.50 +    private int size = 0;
  146.51 +
  146.52 +    JumboEnumSet(Class<E>elementType, Enum[] universe) {
  146.53 +        super(elementType, universe);
  146.54 +        elements = new long[(universe.length + 63) >>> 6];
  146.55 +    }
  146.56 +
  146.57 +    void addRange(E from, E to) {
  146.58 +        int fromIndex = from.ordinal() >>> 6;
  146.59 +        int toIndex = to.ordinal() >>> 6;
  146.60 +
  146.61 +        if (fromIndex == toIndex) {
  146.62 +            elements[fromIndex] = (-1L >>>  (from.ordinal() - to.ordinal() - 1))
  146.63 +                            << from.ordinal();
  146.64 +        } else {
  146.65 +            elements[fromIndex] = (-1L << from.ordinal());
  146.66 +            for (int i = fromIndex + 1; i < toIndex; i++)
  146.67 +                elements[i] = -1;
  146.68 +            elements[toIndex] = -1L >>> (63 - to.ordinal());
  146.69 +        }
  146.70 +        size = to.ordinal() - from.ordinal() + 1;
  146.71 +    }
  146.72 +
  146.73 +    void addAll() {
  146.74 +        for (int i = 0; i < elements.length; i++)
  146.75 +            elements[i] = -1;
  146.76 +        elements[elements.length - 1] >>>= -universe.length;
  146.77 +        size = universe.length;
  146.78 +    }
  146.79 +
  146.80 +    void complement() {
  146.81 +        for (int i = 0; i < elements.length; i++)
  146.82 +            elements[i] = ~elements[i];
  146.83 +        elements[elements.length - 1] &= (-1L >>> -universe.length);
  146.84 +        size = universe.length - size;
  146.85 +    }
  146.86 +
  146.87 +    /**
  146.88 +     * Returns an iterator over the elements contained in this set.  The
  146.89 +     * iterator traverses the elements in their <i>natural order</i> (which is
  146.90 +     * the order in which the enum constants are declared). The returned
  146.91 +     * Iterator is a "weakly consistent" iterator that will never throw {@link
  146.92 +     * ConcurrentModificationException}.
  146.93 +     *
  146.94 +     * @return an iterator over the elements contained in this set
  146.95 +     */
  146.96 +    public Iterator<E> iterator() {
  146.97 +        return new EnumSetIterator<>();
  146.98 +    }
  146.99 +
 146.100 +    private class EnumSetIterator<E extends Enum<E>> implements Iterator<E> {
 146.101 +        /**
 146.102 +         * A bit vector representing the elements in the current "word"
 146.103 +         * of the set not yet returned by this iterator.
 146.104 +         */
 146.105 +        long unseen;
 146.106 +
 146.107 +        /**
 146.108 +         * The index corresponding to unseen in the elements array.
 146.109 +         */
 146.110 +        int unseenIndex = 0;
 146.111 +
 146.112 +        /**
 146.113 +         * The bit representing the last element returned by this iterator
 146.114 +         * but not removed, or zero if no such element exists.
 146.115 +         */
 146.116 +        long lastReturned = 0;
 146.117 +
 146.118 +        /**
 146.119 +         * The index corresponding to lastReturned in the elements array.
 146.120 +         */
 146.121 +        int lastReturnedIndex = 0;
 146.122 +
 146.123 +        EnumSetIterator() {
 146.124 +            unseen = elements[0];
 146.125 +        }
 146.126 +
 146.127 +        public boolean hasNext() {
 146.128 +            while (unseen == 0 && unseenIndex < elements.length - 1)
 146.129 +                unseen = elements[++unseenIndex];
 146.130 +            return unseen != 0;
 146.131 +        }
 146.132 +
 146.133 +        public E next() {
 146.134 +            if (!hasNext())
 146.135 +                throw new NoSuchElementException();
 146.136 +            lastReturned = unseen & -unseen;
 146.137 +            lastReturnedIndex = unseenIndex;
 146.138 +            unseen -= lastReturned;
 146.139 +            return (E) universe[(lastReturnedIndex << 6)
 146.140 +                                + Long.numberOfTrailingZeros(lastReturned)];
 146.141 +        }
 146.142 +
 146.143 +        public void remove() {
 146.144 +            if (lastReturned == 0)
 146.145 +                throw new IllegalStateException();
 146.146 +            final long oldElements = elements[lastReturnedIndex];
 146.147 +            elements[lastReturnedIndex] &= ~lastReturned;
 146.148 +            if (oldElements != elements[lastReturnedIndex]) {
 146.149 +                size--;
 146.150 +            }
 146.151 +            lastReturned = 0;
 146.152 +        }
 146.153 +    }
 146.154 +
 146.155 +    /**
 146.156 +     * Returns the number of elements in this set.
 146.157 +     *
 146.158 +     * @return the number of elements in this set
 146.159 +     */
 146.160 +    public int size() {
 146.161 +        return size;
 146.162 +    }
 146.163 +
 146.164 +    /**
 146.165 +     * Returns <tt>true</tt> if this set contains no elements.
 146.166 +     *
 146.167 +     * @return <tt>true</tt> if this set contains no elements
 146.168 +     */
 146.169 +    public boolean isEmpty() {
 146.170 +        return size == 0;
 146.171 +    }
 146.172 +
 146.173 +    /**
 146.174 +     * Returns <tt>true</tt> if this set contains the specified element.
 146.175 +     *
 146.176 +     * @param e element to be checked for containment in this collection
 146.177 +     * @return <tt>true</tt> if this set contains the specified element
 146.178 +     */
 146.179 +    public boolean contains(Object e) {
 146.180 +        if (e == null)
 146.181 +            return false;
 146.182 +        Class eClass = e.getClass();
 146.183 +        if (eClass != elementType && eClass.getSuperclass() != elementType)
 146.184 +            return false;
 146.185 +
 146.186 +        int eOrdinal = ((Enum)e).ordinal();
 146.187 +        return (elements[eOrdinal >>> 6] & (1L << eOrdinal)) != 0;
 146.188 +    }
 146.189 +
 146.190 +    // Modification Operations
 146.191 +
 146.192 +    /**
 146.193 +     * Adds the specified element to this set if it is not already present.
 146.194 +     *
 146.195 +     * @param e element to be added to this set
 146.196 +     * @return <tt>true</tt> if the set changed as a result of the call
 146.197 +     *
 146.198 +     * @throws NullPointerException if <tt>e</tt> is null
 146.199 +     */
 146.200 +    public boolean add(E e) {
 146.201 +        typeCheck(e);
 146.202 +
 146.203 +        int eOrdinal = e.ordinal();
 146.204 +        int eWordNum = eOrdinal >>> 6;
 146.205 +
 146.206 +        long oldElements = elements[eWordNum];
 146.207 +        elements[eWordNum] |= (1L << eOrdinal);
 146.208 +        boolean result = (elements[eWordNum] != oldElements);
 146.209 +        if (result)
 146.210 +            size++;
 146.211 +        return result;
 146.212 +    }
 146.213 +
 146.214 +    /**
 146.215 +     * Removes the specified element from this set if it is present.
 146.216 +     *
 146.217 +     * @param e element to be removed from this set, if present
 146.218 +     * @return <tt>true</tt> if the set contained the specified element
 146.219 +     */
 146.220 +    public boolean remove(Object e) {
 146.221 +        if (e == null)
 146.222 +            return false;
 146.223 +        Class eClass = e.getClass();
 146.224 +        if (eClass != elementType && eClass.getSuperclass() != elementType)
 146.225 +            return false;
 146.226 +        int eOrdinal = ((Enum)e).ordinal();
 146.227 +        int eWordNum = eOrdinal >>> 6;
 146.228 +
 146.229 +        long oldElements = elements[eWordNum];
 146.230 +        elements[eWordNum] &= ~(1L << eOrdinal);
 146.231 +        boolean result = (elements[eWordNum] != oldElements);
 146.232 +        if (result)
 146.233 +            size--;
 146.234 +        return result;
 146.235 +    }
 146.236 +
 146.237 +    // Bulk Operations
 146.238 +
 146.239 +    /**
 146.240 +     * Returns <tt>true</tt> if this set contains all of the elements
 146.241 +     * in the specified collection.
 146.242 +     *
 146.243 +     * @param c collection to be checked for containment in this set
 146.244 +     * @return <tt>true</tt> if this set contains all of the elements
 146.245 +     *        in the specified collection
 146.246 +     * @throws NullPointerException if the specified collection is null
 146.247 +     */
 146.248 +    public boolean containsAll(Collection<?> c) {
 146.249 +        if (!(c instanceof JumboEnumSet))
 146.250 +            return super.containsAll(c);
 146.251 +
 146.252 +        JumboEnumSet es = (JumboEnumSet)c;
 146.253 +        if (es.elementType != elementType)
 146.254 +            return es.isEmpty();
 146.255 +
 146.256 +        for (int i = 0; i < elements.length; i++)
 146.257 +            if ((es.elements[i] & ~elements[i]) != 0)
 146.258 +                return false;
 146.259 +        return true;
 146.260 +    }
 146.261 +
 146.262 +    /**
 146.263 +     * Adds all of the elements in the specified collection to this set.
 146.264 +     *
 146.265 +     * @param c collection whose elements are to be added to this set
 146.266 +     * @return <tt>true</tt> if this set changed as a result of the call
 146.267 +     * @throws NullPointerException if the specified collection or any of
 146.268 +     *     its elements are null
 146.269 +     */
 146.270 +    public boolean addAll(Collection<? extends E> c) {
 146.271 +        if (!(c instanceof JumboEnumSet))
 146.272 +            return super.addAll(c);
 146.273 +
 146.274 +        JumboEnumSet es = (JumboEnumSet)c;
 146.275 +        if (es.elementType != elementType) {
 146.276 +            if (es.isEmpty())
 146.277 +                return false;
 146.278 +            else
 146.279 +                throw new ClassCastException(
 146.280 +                    es.elementType + " != " + elementType);
 146.281 +        }
 146.282 +
 146.283 +        for (int i = 0; i < elements.length; i++)
 146.284 +            elements[i] |= es.elements[i];
 146.285 +        return recalculateSize();
 146.286 +    }
 146.287 +
 146.288 +    /**
 146.289 +     * Removes from this set all of its elements that are contained in
 146.290 +     * the specified collection.
 146.291 +     *
 146.292 +     * @param c elements to be removed from this set
 146.293 +     * @return <tt>true</tt> if this set changed as a result of the call
 146.294 +     * @throws NullPointerException if the specified collection is null
 146.295 +     */
 146.296 +    public boolean removeAll(Collection<?> c) {
 146.297 +        if (!(c instanceof JumboEnumSet))
 146.298 +            return super.removeAll(c);
 146.299 +
 146.300 +        JumboEnumSet es = (JumboEnumSet)c;
 146.301 +        if (es.elementType != elementType)
 146.302 +            return false;
 146.303 +
 146.304 +        for (int i = 0; i < elements.length; i++)
 146.305 +            elements[i] &= ~es.elements[i];
 146.306 +        return recalculateSize();
 146.307 +    }
 146.308 +
 146.309 +    /**
 146.310 +     * Retains only the elements in this set that are contained in the
 146.311 +     * specified collection.
 146.312 +     *
 146.313 +     * @param c elements to be retained in this set
 146.314 +     * @return <tt>true</tt> if this set changed as a result of the call
 146.315 +     * @throws NullPointerException if the specified collection is null
 146.316 +     */
 146.317 +    public boolean retainAll(Collection<?> c) {
 146.318 +        if (!(c instanceof JumboEnumSet))
 146.319 +            return super.retainAll(c);
 146.320 +
 146.321 +        JumboEnumSet<?> es = (JumboEnumSet<?>)c;
 146.322 +        if (es.elementType != elementType) {
 146.323 +            boolean changed = (size != 0);
 146.324 +            clear();
 146.325 +            return changed;
 146.326 +        }
 146.327 +
 146.328 +        for (int i = 0; i < elements.length; i++)
 146.329 +            elements[i] &= es.elements[i];
 146.330 +        return recalculateSize();
 146.331 +    }
 146.332 +
 146.333 +    /**
 146.334 +     * Removes all of the elements from this set.
 146.335 +     */
 146.336 +    public void clear() {
 146.337 +        Arrays.fill(elements, 0);
 146.338 +        size = 0;
 146.339 +    }
 146.340 +
 146.341 +    /**
 146.342 +     * Compares the specified object with this set for equality.  Returns
 146.343 +     * <tt>true</tt> if the given object is also a set, the two sets have
 146.344 +     * the same size, and every member of the given set is contained in
 146.345 +     * this set.
 146.346 +     *
 146.347 +     * @param e object to be compared for equality with this set
 146.348 +     * @return <tt>true</tt> if the specified object is equal to this set
 146.349 +     */
 146.350 +    public boolean equals(Object o) {
 146.351 +        if (!(o instanceof JumboEnumSet))
 146.352 +            return super.equals(o);
 146.353 +
 146.354 +        JumboEnumSet es = (JumboEnumSet)o;
 146.355 +        if (es.elementType != elementType)
 146.356 +            return size == 0 && es.size == 0;
 146.357 +
 146.358 +        return Arrays.equals(es.elements, elements);
 146.359 +    }
 146.360 +
 146.361 +    /**
 146.362 +     * Recalculates the size of the set.  Returns true if it's changed.
 146.363 +     */
 146.364 +    private boolean recalculateSize() {
 146.365 +        int oldSize = size;
 146.366 +        size = 0;
 146.367 +        for (long elt : elements)
 146.368 +            size += Long.bitCount(elt);
 146.369 +
 146.370 +        return size != oldSize;
 146.371 +    }
 146.372 +
 146.373 +    public EnumSet<E> clone() {
 146.374 +        JumboEnumSet<E> result = (JumboEnumSet<E>) super.clone();
 146.375 +        result.elements = result.elements.clone();
 146.376 +        return result;
 146.377 +    }
 146.378 +}
   147.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   147.2 +++ b/rt/emul/compact/src/main/java/java/util/Locale.java	Tue Feb 11 13:31:42 2014 +0100
   147.3 @@ -0,0 +1,1012 @@
   147.4 +/*
   147.5 + * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
   147.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   147.7 + *
   147.8 + * This code is free software; you can redistribute it and/or modify it
   147.9 + * under the terms of the GNU General Public License version 2 only, as
  147.10 + * published by the Free Software Foundation.  Oracle designates this
  147.11 + * particular file as subject to the "Classpath" exception as provided
  147.12 + * by Oracle in the LICENSE file that accompanied this code.
  147.13 + *
  147.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  147.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  147.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  147.17 + * version 2 for more details (a copy is included in the LICENSE file that
  147.18 + * accompanied this code).
  147.19 + *
  147.20 + * You should have received a copy of the GNU General Public License version
  147.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  147.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  147.23 + *
  147.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  147.25 + * or visit www.oracle.com if you need additional information or have any
  147.26 + * questions.
  147.27 + */
  147.28 +
  147.29 +/*
  147.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
  147.31 + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
  147.32 + *
  147.33 + * The original version of this source code and documentation
  147.34 + * is copyrighted and owned by Taligent, Inc., a wholly-owned
  147.35 + * subsidiary of IBM. These materials are provided under terms
  147.36 + * of a License Agreement between Taligent and Sun. This technology
  147.37 + * is protected by multiple US and International patents.
  147.38 + *
  147.39 + * This notice and attribution to Taligent may not be removed.
  147.40 + * Taligent is a registered trademark of Taligent, Inc.
  147.41 + *
  147.42 + */
  147.43 +
  147.44 +package java.util;
  147.45 +
  147.46 +import java.io.IOException;
  147.47 +import java.io.ObjectInputStream;
  147.48 +import java.io.ObjectOutputStream;
  147.49 +import java.io.ObjectStreamField;
  147.50 +import java.io.Serializable;
  147.51 +
  147.52 +/**
  147.53 + * A <code>Locale</code> object represents a specific geographical, political,
  147.54 + * or cultural region. An operation that requires a <code>Locale</code> to perform
  147.55 + * its task is called <em>locale-sensitive</em> and uses the <code>Locale</code>
  147.56 + * to tailor information for the user. For example, displaying a number
  147.57 + * is a locale-sensitive operation&mdash; the number should be formatted
  147.58 + * according to the customs and conventions of the user's native country,
  147.59 + * region, or culture.
  147.60 + *
  147.61 + * <p> The <code>Locale</code> class implements identifiers
  147.62 + * interchangeable with BCP 47 (IETF BCP 47, "Tags for Identifying
  147.63 + * Languages"), with support for the LDML (UTS#35, "Unicode Locale
  147.64 + * Data Markup Language") BCP 47-compatible extensions for locale data
  147.65 + * exchange.
  147.66 + *
  147.67 + * <p> A <code>Locale</code> object logically consists of the fields
  147.68 + * described below.
  147.69 + *
  147.70 + * <dl>
  147.71 + *   <dt><a name="def_language"/><b>language</b></dt>
  147.72 + *
  147.73 + *   <dd>ISO 639 alpha-2 or alpha-3 language code, or registered
  147.74 + *   language subtags up to 8 alpha letters (for future enhancements).
  147.75 + *   When a language has both an alpha-2 code and an alpha-3 code, the
  147.76 + *   alpha-2 code must be used.  You can find a full list of valid
  147.77 + *   language codes in the IANA Language Subtag Registry (search for
  147.78 + *   "Type: language").  The language field is case insensitive, but
  147.79 + *   <code>Locale</code> always canonicalizes to lower case.</dd><br>
  147.80 + *
  147.81 + *   <dd>Well-formed language values have the form
  147.82 + *   <code>[a-zA-Z]{2,8}</code>.  Note that this is not the the full
  147.83 + *   BCP47 language production, since it excludes extlang.  They are
  147.84 + *   not needed since modern three-letter language codes replace
  147.85 + *   them.</dd><br>
  147.86 + *
  147.87 + *   <dd>Example: "en" (English), "ja" (Japanese), "kok" (Konkani)</dd><br>
  147.88 + *
  147.89 + *   <dt><a name="def_script"/><b>script</b></dt>
  147.90 + *
  147.91 + *   <dd>ISO 15924 alpha-4 script code.  You can find a full list of
  147.92 + *   valid script codes in the IANA Language Subtag Registry (search
  147.93 + *   for "Type: script").  The script field is case insensitive, but
  147.94 + *   <code>Locale</code> always canonicalizes to title case (the first
  147.95 + *   letter is upper case and the rest of the letters are lower
  147.96 + *   case).</dd><br>
  147.97 + *
  147.98 + *   <dd>Well-formed script values have the form
  147.99 + *   <code>[a-zA-Z]{4}</code></dd><br>
 147.100 + *
 147.101 + *   <dd>Example: "Latn" (Latin), "Cyrl" (Cyrillic)</dd><br>
 147.102 + *
 147.103 + *   <dt><a name="def_region"/><b>country (region)</b></dt>
 147.104 + *
 147.105 + *   <dd>ISO 3166 alpha-2 country code or UN M.49 numeric-3 area code.
 147.106 + *   You can find a full list of valid country and region codes in the
 147.107 + *   IANA Language Subtag Registry (search for "Type: region").  The
 147.108 + *   country (region) field is case insensitive, but
 147.109 + *   <code>Locale</code> always canonicalizes to upper case.</dd><br>
 147.110 + *
 147.111 + *   <dd>Well-formed country/region values have
 147.112 + *   the form <code>[a-zA-Z]{2} | [0-9]{3}</code></dd><br>
 147.113 + *
 147.114 + *   <dd>Example: "US" (United States), "FR" (France), "029"
 147.115 + *   (Caribbean)</dd><br>
 147.116 + *
 147.117 + *   <dt><a name="def_variant"/><b>variant</b></dt>
 147.118 + *
 147.119 + *   <dd>Any arbitrary value used to indicate a variation of a
 147.120 + *   <code>Locale</code>.  Where there are two or more variant values
 147.121 + *   each indicating its own semantics, these values should be ordered
 147.122 + *   by importance, with most important first, separated by
 147.123 + *   underscore('_').  The variant field is case sensitive.</dd><br>
 147.124 + *
 147.125 + *   <dd>Note: IETF BCP 47 places syntactic restrictions on variant
 147.126 + *   subtags.  Also BCP 47 subtags are strictly used to indicate
 147.127 + *   additional variations that define a language or its dialects that
 147.128 + *   are not covered by any combinations of language, script and
 147.129 + *   region subtags.  You can find a full list of valid variant codes
 147.130 + *   in the IANA Language Subtag Registry (search for "Type: variant").
 147.131 + *
 147.132 + *   <p>However, the variant field in <code>Locale</code> has
 147.133 + *   historically been used for any kind of variation, not just
 147.134 + *   language variations.  For example, some supported variants
 147.135 + *   available in Java SE Runtime Environments indicate alternative
 147.136 + *   cultural behaviors such as calendar type or number script.  In
 147.137 + *   BCP 47 this kind of information, which does not identify the
 147.138 + *   language, is supported by extension subtags or private use
 147.139 + *   subtags.</dd><br>
 147.140 + *
 147.141 + *   <dd>Well-formed variant values have the form <code>SUBTAG
 147.142 + *   (('_'|'-') SUBTAG)*</code> where <code>SUBTAG =
 147.143 + *   [0-9][0-9a-zA-Z]{3} | [0-9a-zA-Z]{5,8}</code>. (Note: BCP 47 only
 147.144 + *   uses hyphen ('-') as a delimiter, this is more lenient).</dd><br>
 147.145 + *
 147.146 + *   <dd>Example: "polyton" (Polytonic Greek), "POSIX"</dd><br>
 147.147 + *
 147.148 + *   <dt><a name="def_extensions"/><b>extensions</b></dt>
 147.149 + *
 147.150 + *   <dd>A map from single character keys to string values, indicating
 147.151 + *   extensions apart from language identification.  The extensions in
 147.152 + *   <code>Locale</code> implement the semantics and syntax of BCP 47
 147.153 + *   extension subtags and private use subtags. The extensions are
 147.154 + *   case insensitive, but <code>Locale</code> canonicalizes all
 147.155 + *   extension keys and values to lower case. Note that extensions
 147.156 + *   cannot have empty values.</dd><br>
 147.157 + *
 147.158 + *   <dd>Well-formed keys are single characters from the set
 147.159 + *   <code>[0-9a-zA-Z]</code>.  Well-formed values have the form
 147.160 + *   <code>SUBTAG ('-' SUBTAG)*</code> where for the key 'x'
 147.161 + *   <code>SUBTAG = [0-9a-zA-Z]{1,8}</code> and for other keys
 147.162 + *   <code>SUBTAG = [0-9a-zA-Z]{2,8}</code> (that is, 'x' allows
 147.163 + *   single-character subtags).</dd><br>
 147.164 + *
 147.165 + *   <dd>Example: key="u"/value="ca-japanese" (Japanese Calendar),
 147.166 + *   key="x"/value="java-1-7"</dd>
 147.167 + * </dl>
 147.168 + *
 147.169 + * <b>Note:</b> Although BCP 47 requires field values to be registered
 147.170 + * in the IANA Language Subtag Registry, the <code>Locale</code> class
 147.171 + * does not provide any validation features.  The <code>Builder</code>
 147.172 + * only checks if an individual field satisfies the syntactic
 147.173 + * requirement (is well-formed), but does not validate the value
 147.174 + * itself.  See {@link Builder} for details.
 147.175 + *
 147.176 + * <h4><a name="def_locale_extension">Unicode locale/language extension</h4>
 147.177 + *
 147.178 + * <p>UTS#35, "Unicode Locale Data Markup Language" defines optional
 147.179 + * attributes and keywords to override or refine the default behavior
 147.180 + * associated with a locale.  A keyword is represented by a pair of
 147.181 + * key and type.  For example, "nu-thai" indicates that Thai local
 147.182 + * digits (value:"thai") should be used for formatting numbers
 147.183 + * (key:"nu").
 147.184 + *
 147.185 + * <p>The keywords are mapped to a BCP 47 extension value using the
 147.186 + * extension key 'u' ({@link #UNICODE_LOCALE_EXTENSION}).  The above
 147.187 + * example, "nu-thai", becomes the extension "u-nu-thai".code
 147.188 + *
 147.189 + * <p>Thus, when a <code>Locale</code> object contains Unicode locale
 147.190 + * attributes and keywords,
 147.191 + * <code>getExtension(UNICODE_LOCALE_EXTENSION)</code> will return a
 147.192 + * String representing this information, for example, "nu-thai".  The
 147.193 + * <code>Locale</code> class also provides {@link
 147.194 + * #getUnicodeLocaleAttributes}, {@link #getUnicodeLocaleKeys}, and
 147.195 + * {@link #getUnicodeLocaleType} which allow you to access Unicode
 147.196 + * locale attributes and key/type pairs directly.  When represented as
 147.197 + * a string, the Unicode Locale Extension lists attributes
 147.198 + * alphabetically, followed by key/type sequences with keys listed
 147.199 + * alphabetically (the order of subtags comprising a key's type is
 147.200 + * fixed when the type is defined)
 147.201 + *
 147.202 + * <p>A well-formed locale key has the form
 147.203 + * <code>[0-9a-zA-Z]{2}</code>.  A well-formed locale type has the
 147.204 + * form <code>"" | [0-9a-zA-Z]{3,8} ('-' [0-9a-zA-Z]{3,8})*</code> (it
 147.205 + * can be empty, or a series of subtags 3-8 alphanums in length).  A
 147.206 + * well-formed locale attribute has the form
 147.207 + * <code>[0-9a-zA-Z]{3,8}</code> (it is a single subtag with the same
 147.208 + * form as a locale type subtag).
 147.209 + *
 147.210 + * <p>The Unicode locale extension specifies optional behavior in
 147.211 + * locale-sensitive services.  Although the LDML specification defines
 147.212 + * various keys and values, actual locale-sensitive service
 147.213 + * implementations in a Java Runtime Environment might not support any
 147.214 + * particular Unicode locale attributes or key/type pairs.
 147.215 + *
 147.216 + * <h4>Creating a Locale</h4>
 147.217 + *
 147.218 + * <p>There are several different ways to create a <code>Locale</code>
 147.219 + * object.
 147.220 + *
 147.221 + * <h5>Builder</h5>
 147.222 + *
 147.223 + * <p>Using {@link Builder} you can construct a <code>Locale</code> object
 147.224 + * that conforms to BCP 47 syntax.
 147.225 + *
 147.226 + * <h5>Constructors</h5>
 147.227 + *
 147.228 + * <p>The <code>Locale</code> class provides three constructors:
 147.229 + * <blockquote>
 147.230 + * <pre>
 147.231 + *     {@link #Locale(String language)}
 147.232 + *     {@link #Locale(String language, String country)}
 147.233 + *     {@link #Locale(String language, String country, String variant)}
 147.234 + * </pre>
 147.235 + * </blockquote>
 147.236 + * These constructors allow you to create a <code>Locale</code> object
 147.237 + * with language, country and variant, but you cannot specify
 147.238 + * script or extensions.
 147.239 + *
 147.240 + * <h5>Factory Methods</h5>
 147.241 + *
 147.242 + * <p>The method {@link #forLanguageTag} creates a <code>Locale</code>
 147.243 + * object for a well-formed BCP 47 language tag.
 147.244 + *
 147.245 + * <h5>Locale Constants</h5>
 147.246 + *
 147.247 + * <p>The <code>Locale</code> class provides a number of convenient constants
 147.248 + * that you can use to create <code>Locale</code> objects for commonly used
 147.249 + * locales. For example, the following creates a <code>Locale</code> object
 147.250 + * for the United States:
 147.251 + * <blockquote>
 147.252 + * <pre>
 147.253 + *     Locale.US
 147.254 + * </pre>
 147.255 + * </blockquote>
 147.256 + *
 147.257 + * <h4>Use of Locale</h4>
 147.258 + *
 147.259 + * <p>Once you've created a <code>Locale</code> you can query it for information
 147.260 + * about itself. Use <code>getCountry</code> to get the country (or region)
 147.261 + * code and <code>getLanguage</code> to get the language code.
 147.262 + * You can use <code>getDisplayCountry</code> to get the
 147.263 + * name of the country suitable for displaying to the user. Similarly,
 147.264 + * you can use <code>getDisplayLanguage</code> to get the name of
 147.265 + * the language suitable for displaying to the user. Interestingly,
 147.266 + * the <code>getDisplayXXX</code> methods are themselves locale-sensitive
 147.267 + * and have two versions: one that uses the default locale and one
 147.268 + * that uses the locale specified as an argument.
 147.269 + *
 147.270 + * <p>The Java Platform provides a number of classes that perform locale-sensitive
 147.271 + * operations. For example, the <code>NumberFormat</code> class formats
 147.272 + * numbers, currency, and percentages in a locale-sensitive manner. Classes
 147.273 + * such as <code>NumberFormat</code> have several convenience methods
 147.274 + * for creating a default object of that type. For example, the
 147.275 + * <code>NumberFormat</code> class provides these three convenience methods
 147.276 + * for creating a default <code>NumberFormat</code> object:
 147.277 + * <blockquote>
 147.278 + * <pre>
 147.279 + *     NumberFormat.getInstance()
 147.280 + *     NumberFormat.getCurrencyInstance()
 147.281 + *     NumberFormat.getPercentInstance()
 147.282 + * </pre>
 147.283 + * </blockquote>
 147.284 + * Each of these methods has two variants; one with an explicit locale
 147.285 + * and one without; the latter uses the default locale:
 147.286 + * <blockquote>
 147.287 + * <pre>
 147.288 + *     NumberFormat.getInstance(myLocale)
 147.289 + *     NumberFormat.getCurrencyInstance(myLocale)
 147.290 + *     NumberFormat.getPercentInstance(myLocale)
 147.291 + * </pre>
 147.292 + * </blockquote>
 147.293 + * A <code>Locale</code> is the mechanism for identifying the kind of object
 147.294 + * (<code>NumberFormat</code>) that you would like to get. The locale is
 147.295 + * <STRONG>just</STRONG> a mechanism for identifying objects,
 147.296 + * <STRONG>not</STRONG> a container for the objects themselves.
 147.297 + *
 147.298 + * <h4>Compatibility</h4>
 147.299 + *
 147.300 + * <p>In order to maintain compatibility with existing usage, Locale's
 147.301 + * constructors retain their behavior prior to the Java Runtime
 147.302 + * Environment version 1.7.  The same is largely true for the
 147.303 + * <code>toString</code> method. Thus Locale objects can continue to
 147.304 + * be used as they were. In particular, clients who parse the output
 147.305 + * of toString into language, country, and variant fields can continue
 147.306 + * to do so (although this is strongly discouraged), although the
 147.307 + * variant field will have additional information in it if script or
 147.308 + * extensions are present.
 147.309 + *
 147.310 + * <p>In addition, BCP 47 imposes syntax restrictions that are not
 147.311 + * imposed by Locale's constructors. This means that conversions
 147.312 + * between some Locales and BCP 47 language tags cannot be made without
 147.313 + * losing information. Thus <code>toLanguageTag</code> cannot
 147.314 + * represent the state of locales whose language, country, or variant
 147.315 + * do not conform to BCP 47.
 147.316 + *
 147.317 + * <p>Because of these issues, it is recommended that clients migrate
 147.318 + * away from constructing non-conforming locales and use the
 147.319 + * <code>forLanguageTag</code> and <code>Locale.Builder</code> APIs instead.
 147.320 + * Clients desiring a string representation of the complete locale can
 147.321 + * then always rely on <code>toLanguageTag</code> for this purpose.
 147.322 + *
 147.323 + * <h5><a name="special_cases_constructor"/>Special cases</h5>
 147.324 + *
 147.325 + * <p>For compatibility reasons, two
 147.326 + * non-conforming locales are treated as special cases.  These are
 147.327 + * <b><tt>ja_JP_JP</tt></b> and <b><tt>th_TH_TH</tt></b>. These are ill-formed
 147.328 + * in BCP 47 since the variants are too short. To ease migration to BCP 47,
 147.329 + * these are treated specially during construction.  These two cases (and only
 147.330 + * these) cause a constructor to generate an extension, all other values behave
 147.331 + * exactly as they did prior to Java 7.
 147.332 + *
 147.333 + * <p>Java has used <tt>ja_JP_JP</tt> to represent Japanese as used in
 147.334 + * Japan together with the Japanese Imperial calendar. This is now
 147.335 + * representable using a Unicode locale extension, by specifying the
 147.336 + * Unicode locale key <tt>ca</tt> (for "calendar") and type
 147.337 + * <tt>japanese</tt>. When the Locale constructor is called with the
 147.338 + * arguments "ja", "JP", "JP", the extension "u-ca-japanese" is
 147.339 + * automatically added.
 147.340 + *
 147.341 + * <p>Java has used <tt>th_TH_TH</tt> to represent Thai as used in
 147.342 + * Thailand together with Thai digits. This is also now representable using
 147.343 + * a Unicode locale extension, by specifying the Unicode locale key
 147.344 + * <tt>nu</tt> (for "number") and value <tt>thai</tt>. When the Locale
 147.345 + * constructor is called with the arguments "th", "TH", "TH", the
 147.346 + * extension "u-nu-thai" is automatically added.
 147.347 + *
 147.348 + * <h5>Serialization</h5>
 147.349 + *
 147.350 + * <p>During serialization, writeObject writes all fields to the output
 147.351 + * stream, including extensions.
 147.352 + *
 147.353 + * <p>During deserialization, readResolve adds extensions as described
 147.354 + * in <a href="#special_cases_constructor">Special Cases</a>, only
 147.355 + * for the two cases th_TH_TH and ja_JP_JP.
 147.356 + *
 147.357 + * <h5>Legacy language codes</h5>
 147.358 + *
 147.359 + * <p>Locale's constructor has always converted three language codes to
 147.360 + * their earlier, obsoleted forms: <tt>he</tt> maps to <tt>iw</tt>,
 147.361 + * <tt>yi</tt> maps to <tt>ji</tt>, and <tt>id</tt> maps to
 147.362 + * <tt>in</tt>.  This continues to be the case, in order to not break
 147.363 + * backwards compatibility.
 147.364 + *
 147.365 + * <p>The APIs added in 1.7 map between the old and new language codes,
 147.366 + * maintaining the old codes internal to Locale (so that
 147.367 + * <code>getLanguage</code> and <code>toString</code> reflect the old
 147.368 + * code), but using the new codes in the BCP 47 language tag APIs (so
 147.369 + * that <code>toLanguageTag</code> reflects the new one). This
 147.370 + * preserves the equivalence between Locales no matter which code or
 147.371 + * API is used to construct them. Java's default resource bundle
 147.372 + * lookup mechanism also implements this mapping, so that resources
 147.373 + * can be named using either convention, see {@link ResourceBundle.Control}.
 147.374 + *
 147.375 + * <h5>Three-letter language/country(region) codes</h5>
 147.376 + *
 147.377 + * <p>The Locale constructors have always specified that the language
 147.378 + * and the country param be two characters in length, although in
 147.379 + * practice they have accepted any length.  The specification has now
 147.380 + * been relaxed to allow language codes of two to eight characters and
 147.381 + * country (region) codes of two to three characters, and in
 147.382 + * particular, three-letter language codes and three-digit region
 147.383 + * codes as specified in the IANA Language Subtag Registry.  For
 147.384 + * compatibility, the implementation still does not impose a length
 147.385 + * constraint.
 147.386 + *
 147.387 + * @see Builder
 147.388 + * @see ResourceBundle
 147.389 + * @see java.text.Format
 147.390 + * @see java.text.NumberFormat
 147.391 + * @see java.text.Collator
 147.392 + * @author Mark Davis
 147.393 + * @since 1.1
 147.394 + */
 147.395 +public final class Locale implements Cloneable, Serializable {
 147.396 +
 147.397 +    /** Useful constant for language.
 147.398 +     */
 147.399 +    static public final Locale ENGLISH = createConstant("en", "");
 147.400 +
 147.401 +    /** Useful constant for language.
 147.402 +     */
 147.403 +    static public final Locale FRENCH = createConstant("fr", "");
 147.404 +
 147.405 +    /** Useful constant for language.
 147.406 +     */
 147.407 +    static public final Locale GERMAN = createConstant("de", "");
 147.408 +
 147.409 +    /** Useful constant for language.
 147.410 +     */
 147.411 +    static public final Locale ITALIAN = createConstant("it", "");
 147.412 +
 147.413 +    /** Useful constant for language.
 147.414 +     */
 147.415 +    static public final Locale JAPANESE = createConstant("ja", "");
 147.416 +
 147.417 +    /** Useful constant for language.
 147.418 +     */
 147.419 +    static public final Locale KOREAN = createConstant("ko", "");
 147.420 +
 147.421 +    /** Useful constant for language.
 147.422 +     */
 147.423 +    static public final Locale CHINESE = createConstant("zh", "");
 147.424 +
 147.425 +    /** Useful constant for language.
 147.426 +     */
 147.427 +    static public final Locale SIMPLIFIED_CHINESE = createConstant("zh", "CN");
 147.428 +
 147.429 +    /** Useful constant for language.
 147.430 +     */
 147.431 +    static public final Locale TRADITIONAL_CHINESE = createConstant("zh", "TW");
 147.432 +
 147.433 +    /** Useful constant for country.
 147.434 +     */
 147.435 +    static public final Locale FRANCE = createConstant("fr", "FR");
 147.436 +
 147.437 +    /** Useful constant for country.
 147.438 +     */
 147.439 +    static public final Locale GERMANY = createConstant("de", "DE");
 147.440 +
 147.441 +    /** Useful constant for country.
 147.442 +     */
 147.443 +    static public final Locale ITALY = createConstant("it", "IT");
 147.444 +
 147.445 +    /** Useful constant for country.
 147.446 +     */
 147.447 +    static public final Locale JAPAN = createConstant("ja", "JP");
 147.448 +
 147.449 +    /** Useful constant for country.
 147.450 +     */
 147.451 +    static public final Locale KOREA = createConstant("ko", "KR");
 147.452 +
 147.453 +    /** Useful constant for country.
 147.454 +     */
 147.455 +    static public final Locale CHINA = SIMPLIFIED_CHINESE;
 147.456 +
 147.457 +    /** Useful constant for country.
 147.458 +     */
 147.459 +    static public final Locale PRC = SIMPLIFIED_CHINESE;
 147.460 +
 147.461 +    /** Useful constant for country.
 147.462 +     */
 147.463 +    static public final Locale TAIWAN = TRADITIONAL_CHINESE;
 147.464 +
 147.465 +    /** Useful constant for country.
 147.466 +     */
 147.467 +    static public final Locale UK = createConstant("en", "GB");
 147.468 +
 147.469 +    /** Useful constant for country.
 147.470 +     */
 147.471 +    static public final Locale US = createConstant("en", "US");
 147.472 +
 147.473 +    /** Useful constant for country.
 147.474 +     */
 147.475 +    static public final Locale CANADA = createConstant("en", "CA");
 147.476 +
 147.477 +    /** Useful constant for country.
 147.478 +     */
 147.479 +    static public final Locale CANADA_FRENCH = createConstant("fr", "CA");
 147.480 +
 147.481 +    /**
 147.482 +     * Useful constant for the root locale.  The root locale is the locale whose
 147.483 +     * language, country, and variant are empty ("") strings.  This is regarded
 147.484 +     * as the base locale of all locales, and is used as the language/country
 147.485 +     * neutral locale for the locale sensitive operations.
 147.486 +     *
 147.487 +     * @since 1.6
 147.488 +     */
 147.489 +    static public final Locale ROOT = createConstant("", "");
 147.490 +
 147.491 +    /**
 147.492 +     * The key for the private use extension ('x').
 147.493 +     *
 147.494 +     * @see #getExtension(char)
 147.495 +     * @see Builder#setExtension(char, String)
 147.496 +     * @since 1.7
 147.497 +     */
 147.498 +    static public final char PRIVATE_USE_EXTENSION = 'x';
 147.499 +
 147.500 +    /**
 147.501 +     * The key for Unicode locale extension ('u').
 147.502 +     *
 147.503 +     * @see #getExtension(char)
 147.504 +     * @see Builder#setExtension(char, String)
 147.505 +     * @since 1.7
 147.506 +     */
 147.507 +    static public final char UNICODE_LOCALE_EXTENSION = 'u';
 147.508 +
 147.509 +    /** serialization ID
 147.510 +     */
 147.511 +    static final long serialVersionUID = 9149081749638150636L;
 147.512 +
 147.513 +    /**
 147.514 +     * Display types for retrieving localized names from the name providers.
 147.515 +     */
 147.516 +    private static final int DISPLAY_LANGUAGE = 0;
 147.517 +    private static final int DISPLAY_COUNTRY  = 1;
 147.518 +    private static final int DISPLAY_VARIANT  = 2;
 147.519 +    private static final int DISPLAY_SCRIPT   = 3;
 147.520 +
 147.521 +    static Locale getInstance(String language, String script, String region, String v, Object object) {
 147.522 +        return new Locale(language, script, region);
 147.523 +    }
 147.524 +
 147.525 +    static Locale getInstance(String no, String no0, String ny) {
 147.526 +        return new Locale(no, no0, ny);
 147.527 +    }
 147.528 +    
 147.529 +    private String language;
 147.530 +    private String country;
 147.531 +    private String variant;
 147.532 +
 147.533 +
 147.534 +    /**
 147.535 +     * Construct a locale from language, country and variant.
 147.536 +     * This constructor normalizes the language value to lowercase and
 147.537 +     * the country value to uppercase.
 147.538 +     * <p>
 147.539 +     * <b>Note:</b>
 147.540 +     * <ul>
 147.541 +     * <li>ISO 639 is not a stable standard; some of the language codes it defines
 147.542 +     * (specifically "iw", "ji", and "in") have changed.  This constructor accepts both the
 147.543 +     * old codes ("iw", "ji", and "in") and the new codes ("he", "yi", and "id"), but all other
 147.544 +     * API on Locale will return only the OLD codes.
 147.545 +     * <li>For backward compatibility reasons, this constructor does not make
 147.546 +     * any syntactic checks on the input.
 147.547 +     * <li>The two cases ("ja", "JP", "JP") and ("th", "TH", "TH") are handled specially,
 147.548 +     * see <a href="#special_cases_constructor">Special Cases</a> for more information.
 147.549 +     * </ul>
 147.550 +     *
 147.551 +     * @param language An ISO 639 alpha-2 or alpha-3 language code, or a language subtag
 147.552 +     * up to 8 characters in length.  See the <code>Locale</code> class description about
 147.553 +     * valid language values.
 147.554 +     * @param country An ISO 3166 alpha-2 country code or a UN M.49 numeric-3 area code.
 147.555 +     * See the <code>Locale</code> class description about valid country values.
 147.556 +     * @param variant Any arbitrary value used to indicate a variation of a <code>Locale</code>.
 147.557 +     * See the <code>Locale</code> class description for the details.
 147.558 +     * @exception NullPointerException thrown if any argument is null.
 147.559 +     */
 147.560 +    public Locale(String language, String country, String variant) {
 147.561 +        if (language== null || country == null || variant == null) {
 147.562 +            throw new NullPointerException();
 147.563 +        }
 147.564 +        this.language = language;
 147.565 +        this.country = country;
 147.566 +        this.variant = variant;
 147.567 +    }
 147.568 +
 147.569 +    /**
 147.570 +     * Construct a locale from language and country.
 147.571 +     * This constructor normalizes the language value to lowercase and
 147.572 +     * the country value to uppercase.
 147.573 +     * <p>
 147.574 +     * <b>Note:</b>
 147.575 +     * <ul>
 147.576 +     * <li>ISO 639 is not a stable standard; some of the language codes it defines
 147.577 +     * (specifically "iw", "ji", and "in") have changed.  This constructor accepts both the
 147.578 +     * old codes ("iw", "ji", and "in") and the new codes ("he", "yi", and "id"), but all other
 147.579 +     * API on Locale will return only the OLD codes.
 147.580 +     * <li>For backward compatibility reasons, this constructor does not make
 147.581 +     * any syntactic checks on the input.
 147.582 +     * </ul>
 147.583 +     *
 147.584 +     * @param language An ISO 639 alpha-2 or alpha-3 language code, or a language subtag
 147.585 +     * up to 8 characters in length.  See the <code>Locale</code> class description about
 147.586 +     * valid language values.
 147.587 +     * @param country An ISO 3166 alpha-2 country code or a UN M.49 numeric-3 area code.
 147.588 +     * See the <code>Locale</code> class description about valid country values.
 147.589 +     * @exception NullPointerException thrown if either argument is null.
 147.590 +     */
 147.591 +    public Locale(String language, String country) {
 147.592 +        this(language, country, "");
 147.593 +    }
 147.594 +
 147.595 +    /**
 147.596 +     * Construct a locale from a language code.
 147.597 +     * This constructor normalizes the language value to lowercase.
 147.598 +     * <p>
 147.599 +     * <b>Note:</b>
 147.600 +     * <ul>
 147.601 +     * <li>ISO 639 is not a stable standard; some of the language codes it defines
 147.602 +     * (specifically "iw", "ji", and "in") have changed.  This constructor accepts both the
 147.603 +     * old codes ("iw", "ji", and "in") and the new codes ("he", "yi", and "id"), but all other
 147.604 +     * API on Locale will return only the OLD codes.
 147.605 +     * <li>For backward compatibility reasons, this constructor does not make
 147.606 +     * any syntactic checks on the input.
 147.607 +     * </ul>
 147.608 +     *
 147.609 +     * @param language An ISO 639 alpha-2 or alpha-3 language code, or a language subtag
 147.610 +     * up to 8 characters in length.  See the <code>Locale</code> class description about
 147.611 +     * valid language values.
 147.612 +     * @exception NullPointerException thrown if argument is null.
 147.613 +     * @since 1.4
 147.614 +     */
 147.615 +    public Locale(String language) {
 147.616 +        this(language, "", "");
 147.617 +    }
 147.618 +
 147.619 +    /**
 147.620 +     * This method must be called only for creating the Locale.*
 147.621 +     * constants due to making shortcuts.
 147.622 +     */
 147.623 +    private static Locale createConstant(String lang, String country) {
 147.624 +        return new Locale(lang, country);
 147.625 +    }
 147.626 +
 147.627 +    /**
 147.628 +     * Gets the current value of the default locale for this instance
 147.629 +     * of the Java Virtual Machine.
 147.630 +     * <p>
 147.631 +     * The Java Virtual Machine sets the default locale during startup
 147.632 +     * based on the host environment. It is used by many locale-sensitive
 147.633 +     * methods if no locale is explicitly specified.
 147.634 +     * It can be changed using the
 147.635 +     * {@link #setDefault(java.util.Locale) setDefault} method.
 147.636 +     *
 147.637 +     * @return the default locale for this instance of the Java Virtual Machine
 147.638 +     */
 147.639 +    public static Locale getDefault() {
 147.640 +        return Locale.US;
 147.641 +    }
 147.642 +
 147.643 +    /**
 147.644 +     * Gets the current value of the default locale for the specified Category
 147.645 +     * for this instance of the Java Virtual Machine.
 147.646 +     * <p>
 147.647 +     * The Java Virtual Machine sets the default locale during startup based
 147.648 +     * on the host environment. It is used by many locale-sensitive methods
 147.649 +     * if no locale is explicitly specified. It can be changed using the
 147.650 +     * setDefault(Locale.Category, Locale) method.
 147.651 +     *
 147.652 +     * @param category - the specified category to get the default locale
 147.653 +     * @throws NullPointerException - if category is null
 147.654 +     * @return the default locale for the specified Category for this instance
 147.655 +     *     of the Java Virtual Machine
 147.656 +     * @see #setDefault(Locale.Category, Locale)
 147.657 +     * @since 1.7
 147.658 +     */
 147.659 +    public static Locale getDefault(Locale.Category category) {
 147.660 +        return Locale.US;
 147.661 +    }
 147.662 +    
 147.663 +    /**
 147.664 +     * Sets the default locale for this instance of the Java Virtual Machine.
 147.665 +     * This does not affect the host locale.
 147.666 +     * <p>
 147.667 +     * If there is a security manager, its <code>checkPermission</code>
 147.668 +     * method is called with a <code>PropertyPermission("user.language", "write")</code>
 147.669 +     * permission before the default locale is changed.
 147.670 +     * <p>
 147.671 +     * The Java Virtual Machine sets the default locale during startup
 147.672 +     * based on the host environment. It is used by many locale-sensitive
 147.673 +     * methods if no locale is explicitly specified.
 147.674 +     * <p>
 147.675 +     * Since changing the default locale may affect many different areas
 147.676 +     * of functionality, this method should only be used if the caller
 147.677 +     * is prepared to reinitialize locale-sensitive code running
 147.678 +     * within the same Java Virtual Machine.
 147.679 +     * <p>
 147.680 +     * By setting the default locale with this method, all of the default
 147.681 +     * locales for each Category are also set to the specified default locale.
 147.682 +     *
 147.683 +     * @throws SecurityException
 147.684 +     *        if a security manager exists and its
 147.685 +     *        <code>checkPermission</code> method doesn't allow the operation.
 147.686 +     * @throws NullPointerException if <code>newLocale</code> is null
 147.687 +     * @param newLocale the new default locale
 147.688 +     * @see SecurityManager#checkPermission
 147.689 +     * @see java.util.PropertyPermission
 147.690 +     */
 147.691 +    public static void setDefault(Locale newLocale) {
 147.692 +        throw new SecurityException();
 147.693 +    }
 147.694 +
 147.695 +    /**
 147.696 +     * Returns an array of all installed locales.
 147.697 +     * The returned array represents the union of locales supported
 147.698 +     * by the Java runtime environment and by installed
 147.699 +     * {@link java.util.spi.LocaleServiceProvider LocaleServiceProvider}
 147.700 +     * implementations.  It must contain at least a <code>Locale</code>
 147.701 +     * instance equal to {@link java.util.Locale#US Locale.US}.
 147.702 +     *
 147.703 +     * @return An array of installed locales.
 147.704 +     */
 147.705 +    public static Locale[] getAvailableLocales() {
 147.706 +        return new Locale[] { Locale.US };
 147.707 +    }
 147.708 +
 147.709 +    /**
 147.710 +     * Returns the language code of this Locale.
 147.711 +     *
 147.712 +     * <p><b>Note:</b> ISO 639 is not a stable standard&mdash; some languages' codes have changed.
 147.713 +     * Locale's constructor recognizes both the new and the old codes for the languages
 147.714 +     * whose codes have changed, but this function always returns the old code.  If you
 147.715 +     * want to check for a specific language whose code has changed, don't do
 147.716 +     * <pre>
 147.717 +     * if (locale.getLanguage().equals("he")) // BAD!
 147.718 +     *    ...
 147.719 +     * </pre>
 147.720 +     * Instead, do
 147.721 +     * <pre>
 147.722 +     * if (locale.getLanguage().equals(new Locale("he").getLanguage()))
 147.723 +     *    ...
 147.724 +     * </pre>
 147.725 +     * @return The language code, or the empty string if none is defined.
 147.726 +     * @see #getDisplayLanguage
 147.727 +     */
 147.728 +    public String getLanguage() {
 147.729 +        return language;
 147.730 +    }
 147.731 +
 147.732 +    /**
 147.733 +     * Returns the script for this locale, which should
 147.734 +     * either be the empty string or an ISO 15924 4-letter script
 147.735 +     * code. The first letter is uppercase and the rest are
 147.736 +     * lowercase, for example, 'Latn', 'Cyrl'.
 147.737 +     *
 147.738 +     * @return The script code, or the empty string if none is defined.
 147.739 +     * @see #getDisplayScript
 147.740 +     * @since 1.7
 147.741 +     */
 147.742 +    public String getScript() {
 147.743 +        return "";
 147.744 +    }
 147.745 +
 147.746 +    /**
 147.747 +     * Returns the country/region code for this locale, which should
 147.748 +     * either be the empty string, an uppercase ISO 3166 2-letter code,
 147.749 +     * or a UN M.49 3-digit code.
 147.750 +     *
 147.751 +     * @return The country/region code, or the empty string if none is defined.
 147.752 +     * @see #getDisplayCountry
 147.753 +     */
 147.754 +    public String getCountry() {
 147.755 +        return country;
 147.756 +    }
 147.757 +
 147.758 +    /**
 147.759 +     * Returns the variant code for this locale.
 147.760 +     *
 147.761 +     * @return The variant code, or the empty string if none is defined.
 147.762 +     * @see #getDisplayVariant
 147.763 +     */
 147.764 +    public String getVariant() {
 147.765 +        return variant;
 147.766 +    }
 147.767 +    
 147.768 +    String getRegion() {
 147.769 +        return getCountry();
 147.770 +    }
 147.771 +
 147.772 +    /**
 147.773 +     * Returns the extension (or private use) value associated with
 147.774 +     * the specified key, or null if there is no extension
 147.775 +     * associated with the key. To be well-formed, the key must be one
 147.776 +     * of <code>[0-9A-Za-z]</code>. Keys are case-insensitive, so
 147.777 +     * for example 'z' and 'Z' represent the same extension.
 147.778 +     *
 147.779 +     * @param key the extension key
 147.780 +     * @return The extension, or null if this locale defines no
 147.781 +     * extension for the specified key.
 147.782 +     * @throws IllegalArgumentException if key is not well-formed
 147.783 +     * @see #PRIVATE_USE_EXTENSION
 147.784 +     * @see #UNICODE_LOCALE_EXTENSION
 147.785 +     * @since 1.7
 147.786 +     */
 147.787 +    public String getExtension(char key) {
 147.788 +        return null;
 147.789 +    }
 147.790 +
 147.791 +    /**
 147.792 +     * Returns the set of extension keys associated with this locale, or the
 147.793 +     * empty set if it has no extensions. The returned set is unmodifiable.
 147.794 +     * The keys will all be lower-case.
 147.795 +     *
 147.796 +     * @return The set of extension keys, or the empty set if this locale has
 147.797 +     * no extensions.
 147.798 +     * @since 1.7
 147.799 +     */
 147.800 +    public Set<Character> getExtensionKeys() {
 147.801 +        return Collections.emptySet();
 147.802 +    }
 147.803 +
 147.804 +    /**
 147.805 +     * Returns the set of unicode locale attributes associated with
 147.806 +     * this locale, or the empty set if it has no attributes. The
 147.807 +     * returned set is unmodifiable.
 147.808 +     *
 147.809 +     * @return The set of attributes.
 147.810 +     * @since 1.7
 147.811 +     */
 147.812 +    public Set<String> getUnicodeLocaleAttributes() {
 147.813 +        return Collections.emptySet();
 147.814 +    }
 147.815 +
 147.816 +    /**
 147.817 +     * Returns the Unicode locale type associated with the specified Unicode locale key
 147.818 +     * for this locale. Returns the empty string for keys that are defined with no type.
 147.819 +     * Returns null if the key is not defined. Keys are case-insensitive. The key must
 147.820 +     * be two alphanumeric characters ([0-9a-zA-Z]), or an IllegalArgumentException is
 147.821 +     * thrown.
 147.822 +     *
 147.823 +     * @param key the Unicode locale key
 147.824 +     * @return The Unicode locale type associated with the key, or null if the
 147.825 +     * locale does not define the key.
 147.826 +     * @throws IllegalArgumentException if the key is not well-formed
 147.827 +     * @throws NullPointerException if <code>key</code> is null
 147.828 +     * @since 1.7
 147.829 +     */
 147.830 +    public String getUnicodeLocaleType(String key) {
 147.831 +        return null;
 147.832 +    }
 147.833 +
 147.834 +    /**
 147.835 +     * Returns the set of Unicode locale keys defined by this locale, or the empty set if
 147.836 +     * this locale has none.  The returned set is immutable.  Keys are all lower case.
 147.837 +     *
 147.838 +     * @return The set of Unicode locale keys, or the empty set if this locale has
 147.839 +     * no Unicode locale keywords.
 147.840 +     * @since 1.7
 147.841 +     */
 147.842 +    public Set<String> getUnicodeLocaleKeys() {
 147.843 +        return Collections.emptySet();
 147.844 +    }
 147.845 +
 147.846 +    /**
 147.847 +     * Returns a string representation of this <code>Locale</code>
 147.848 +     * object, consisting of language, country, variant, script,
 147.849 +     * and extensions as below:
 147.850 +     * <p><blockquote>
 147.851 +     * language + "_" + country + "_" + (variant + "_#" | "#") + script + "-" + extensions
 147.852 +     * </blockquote>
 147.853 +     *
 147.854 +     * Language is always lower case, country is always upper case, script is always title
 147.855 +     * case, and extensions are always lower case.  Extensions and private use subtags
 147.856 +     * will be in canonical order as explained in {@link #toLanguageTag}.
 147.857 +     *
 147.858 +     * <p>When the locale has neither script nor extensions, the result is the same as in
 147.859 +     * Java 6 and prior.
 147.860 +     *
 147.861 +     * <p>If both the language and country fields are missing, this function will return
 147.862 +     * the empty string, even if the variant, script, or extensions field is present (you
 147.863 +     * can't have a locale with just a variant, the variant must accompany a well-formed
 147.864 +     * language or country code).
 147.865 +     *
 147.866 +     * <p>If script or extensions are present and variant is missing, no underscore is
 147.867 +     * added before the "#".
 147.868 +     *
 147.869 +     * <p>This behavior is designed to support debugging and to be compatible with
 147.870 +     * previous uses of <code>toString</code> that expected language, country, and variant
 147.871 +     * fields only.  To represent a Locale as a String for interchange purposes, use
 147.872 +     * {@link #toLanguageTag}.
 147.873 +     *
 147.874 +     * <p>Examples: <ul><tt>
 147.875 +     * <li>en
 147.876 +     * <li>de_DE
 147.877 +     * <li>_GB
 147.878 +     * <li>en_US_WIN
 147.879 +     * <li>de__POSIX
 147.880 +     * <li>zh_CN_#Hans
 147.881 +     * <li>zh_TW_#Hant-x-java
 147.882 +     * <li>th_TH_TH_#u-nu-thai</tt></ul>
 147.883 +     *
 147.884 +     * @return A string representation of the Locale, for debugging.
 147.885 +     * @see #getDisplayName
 147.886 +     * @see #toLanguageTag
 147.887 +     */
 147.888 +    @Override
 147.889 +    public final String toString() {
 147.890 +        Locale baseLocale = this;
 147.891 +        boolean l = (baseLocale.getLanguage().length() != 0);
 147.892 +        boolean s = (baseLocale.getScript().length() != 0);
 147.893 +        boolean r = (baseLocale.getRegion().length() != 0);
 147.894 +        boolean v = (baseLocale.getVariant().length() != 0);
 147.895 +        boolean e = false; //(localeExtensions != null && localeExtensions.getID().length() != 0);
 147.896 +
 147.897 +        StringBuilder result = new StringBuilder(baseLocale.getLanguage());
 147.898 +        if (r || (l && (v || s || e))) {
 147.899 +            result.append('_')
 147.900 +                .append(baseLocale.getRegion()); // This may just append '_'
 147.901 +        }
 147.902 +        if (v && (l || r)) {
 147.903 +            result.append('_')
 147.904 +                .append(baseLocale.getVariant());
 147.905 +        }
 147.906 +
 147.907 +        if (s && (l || r)) {
 147.908 +            result.append("_#")
 147.909 +                .append(baseLocale.getScript());
 147.910 +        }
 147.911 +
 147.912 +        if (e && (l || r)) {
 147.913 +            result.append('_');
 147.914 +            if (!s) {
 147.915 +                result.append('#');
 147.916 +            }
 147.917 +//            result.append(localeExtensions.getID());
 147.918 +        }
 147.919 +
 147.920 +        return result.toString();
 147.921 +    }
 147.922 +
 147.923 +    
 147.924 +    /**
 147.925 +     * Overrides Cloneable.
 147.926 +     */
 147.927 +    public Object clone()
 147.928 +    {
 147.929 +        try {
 147.930 +            Locale that = (Locale)super.clone();
 147.931 +            return that;
 147.932 +        } catch (CloneNotSupportedException e) {
 147.933 +            throw new InternalError();
 147.934 +        }
 147.935 +    }
 147.936 +
 147.937 +    /**
 147.938 +     * Override hashCode.
 147.939 +     * Since Locales are often used in hashtables, caches the value
 147.940 +     * for speed.
 147.941 +     */
 147.942 +    @Override
 147.943 +    public int hashCode() {
 147.944 +        int hash = 3;
 147.945 +        hash = 43 * hash + Objects.hashCode(this.language);
 147.946 +        hash = 43 * hash + Objects.hashCode(this.country);
 147.947 +        hash = 43 * hash + Objects.hashCode(this.variant);
 147.948 +        return hash;
 147.949 +    }
 147.950 +
 147.951 +    // Overrides
 147.952 +    @Override
 147.953 +    public boolean equals(Object obj) {
 147.954 +        if (obj == null) {
 147.955 +            return false;
 147.956 +        }
 147.957 +        if (getClass() != obj.getClass()) {
 147.958 +            return false;
 147.959 +        }
 147.960 +        final Locale other = (Locale) obj;
 147.961 +        if (!Objects.equals(this.language, other.language)) {
 147.962 +            return false;
 147.963 +        }
 147.964 +        if (!Objects.equals(this.country, other.country)) {
 147.965 +            return false;
 147.966 +        }
 147.967 +        if (!Objects.equals(this.variant, other.variant)) {
 147.968 +            return false;
 147.969 +        }
 147.970 +        return true;
 147.971 +    }
 147.972 +
 147.973 +    /**
 147.974 +     * Enum for locale categories.  These locale categories are used to get/set
 147.975 +     * the default locale for the specific functionality represented by the
 147.976 +     * category.
 147.977 +     *
 147.978 +     * @see #getDefault(Locale.Category)
 147.979 +     * @see #setDefault(Locale.Category, Locale)
 147.980 +     * @since 1.7
 147.981 +     */
 147.982 +    public enum Category {
 147.983 +
 147.984 +        /**
 147.985 +         * Category used to represent the default locale for
 147.986 +         * displaying user interfaces.
 147.987 +         */
 147.988 +        DISPLAY("user.language.display",
 147.989 +                "user.script.display",
 147.990 +                "user.country.display",
 147.991 +                "user.variant.display"),
 147.992 +
 147.993 +        /**
 147.994 +         * Category used to represent the default locale for
 147.995 +         * formatting dates, numbers, and/or currencies.
 147.996 +         */
 147.997 +        FORMAT("user.language.format",
 147.998 +               "user.script.format",
 147.999 +               "user.country.format",
147.1000 +               "user.variant.format");
147.1001 +
147.1002 +        Category(String languageKey, String scriptKey, String countryKey, String variantKey) {
147.1003 +            this.languageKey = languageKey;
147.1004 +            this.scriptKey = scriptKey;
147.1005 +            this.countryKey = countryKey;
147.1006 +            this.variantKey = variantKey;
147.1007 +        }
147.1008 +
147.1009 +        final String languageKey;
147.1010 +        final String scriptKey;
147.1011 +        final String countryKey;
147.1012 +        final String variantKey;
147.1013 +    }
147.1014 +
147.1015 +}
   148.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   148.2 +++ b/rt/emul/compact/src/main/java/java/util/MissingResourceException.java	Tue Feb 11 13:31:42 2014 +0100
   148.3 @@ -0,0 +1,124 @@
   148.4 +/*
   148.5 + * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
   148.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   148.7 + *
   148.8 + * This code is free software; you can redistribute it and/or modify it
   148.9 + * under the terms of the GNU General Public License version 2 only, as
  148.10 + * published by the Free Software Foundation.  Oracle designates this
  148.11 + * particular file as subject to the "Classpath" exception as provided
  148.12 + * by Oracle in the LICENSE file that accompanied this code.
  148.13 + *
  148.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  148.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  148.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  148.17 + * version 2 for more details (a copy is included in the LICENSE file that
  148.18 + * accompanied this code).
  148.19 + *
  148.20 + * You should have received a copy of the GNU General Public License version
  148.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  148.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  148.23 + *
  148.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  148.25 + * or visit www.oracle.com if you need additional information or have any
  148.26 + * questions.
  148.27 + */
  148.28 +
  148.29 +/*
  148.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
  148.31 + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
  148.32 + *
  148.33 + * The original version of this source code and documentation
  148.34 + * is copyrighted and owned by Taligent, Inc., a wholly-owned
  148.35 + * subsidiary of IBM. These materials are provided under terms
  148.36 + * of a License Agreement between Taligent and Sun. This technology
  148.37 + * is protected by multiple US and International patents.
  148.38 + *
  148.39 + * This notice and attribution to Taligent may not be removed.
  148.40 + * Taligent is a registered trademark of Taligent, Inc.
  148.41 + *
  148.42 + */
  148.43 +
  148.44 +package java.util;
  148.45 +
  148.46 +/**
  148.47 + * Signals that a resource is missing.
  148.48 + * @see java.lang.Exception
  148.49 + * @see ResourceBundle
  148.50 + * @author      Mark Davis
  148.51 + * @since       JDK1.1
  148.52 + */
  148.53 +public
  148.54 +class MissingResourceException extends RuntimeException {
  148.55 +
  148.56 +    /**
  148.57 +     * Constructs a MissingResourceException with the specified information.
  148.58 +     * A detail message is a String that describes this particular exception.
  148.59 +     * @param s the detail message
  148.60 +     * @param className the name of the resource class
  148.61 +     * @param key the key for the missing resource.
  148.62 +     */
  148.63 +    public MissingResourceException(String s, String className, String key) {
  148.64 +        super(s);
  148.65 +        this.className = className;
  148.66 +        this.key = key;
  148.67 +    }
  148.68 +
  148.69 +    /**
  148.70 +     * Constructs a <code>MissingResourceException</code> with
  148.71 +     * <code>message</code>, <code>className</code>, <code>key</code>,
  148.72 +     * and <code>cause</code>. This constructor is package private for
  148.73 +     * use by <code>ResourceBundle.getBundle</code>.
  148.74 +     *
  148.75 +     * @param message
  148.76 +     *        the detail message
  148.77 +     * @param className
  148.78 +     *        the name of the resource class
  148.79 +     * @param key
  148.80 +     *        the key for the missing resource.
  148.81 +     * @param cause
  148.82 +     *        the cause (which is saved for later retrieval by the
  148.83 +     *        {@link Throwable.getCause()} method). (A null value is
  148.84 +     *        permitted, and indicates that the cause is nonexistent
  148.85 +     *        or unknown.)
  148.86 +     */
  148.87 +    MissingResourceException(String message, String className, String key, Throwable cause) {
  148.88 +        super(message, cause);
  148.89 +        this.className = className;
  148.90 +        this.key = key;
  148.91 +    }
  148.92 +
  148.93 +    /**
  148.94 +     * Gets parameter passed by constructor.
  148.95 +     *
  148.96 +     * @return the name of the resource class
  148.97 +     */
  148.98 +    public String getClassName() {
  148.99 +        return className;
 148.100 +    }
 148.101 +
 148.102 +    /**
 148.103 +     * Gets parameter passed by constructor.
 148.104 +     *
 148.105 +     * @return the key for the missing resource
 148.106 +     */
 148.107 +    public String getKey() {
 148.108 +        return key;
 148.109 +    }
 148.110 +
 148.111 +    //============ privates ============
 148.112 +
 148.113 +    // serialization compatibility with JDK1.1
 148.114 +    private static final long serialVersionUID = -4876345176062000401L;
 148.115 +
 148.116 +    /**
 148.117 +     * The class name of the resource bundle requested by the user.
 148.118 +     * @serial
 148.119 +     */
 148.120 +    private String className;
 148.121 +
 148.122 +    /**
 148.123 +     * The name of the specific resource requested by the user.
 148.124 +     * @serial
 148.125 +     */
 148.126 +    private String key;
 148.127 +}
   149.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   149.2 +++ b/rt/emul/compact/src/main/java/java/util/Properties.java	Tue Feb 11 13:31:42 2014 +0100
   149.3 @@ -0,0 +1,1113 @@
   149.4 +/*
   149.5 + * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
   149.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   149.7 + *
   149.8 + * This code is free software; you can redistribute it and/or modify it
   149.9 + * under the terms of the GNU General Public License version 2 only, as
  149.10 + * published by the Free Software Foundation.  Oracle designates this
  149.11 + * particular file as subject to the "Classpath" exception as provided
  149.12 + * by Oracle in the LICENSE file that accompanied this code.
  149.13 + *
  149.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  149.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  149.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  149.17 + * version 2 for more details (a copy is included in the LICENSE file that
  149.18 + * accompanied this code).
  149.19 + *
  149.20 + * You should have received a copy of the GNU General Public License version
  149.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  149.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  149.23 + *
  149.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  149.25 + * or visit www.oracle.com if you need additional information or have any
  149.26 + * questions.
  149.27 + */
  149.28 +
  149.29 +package java.util;
  149.30 +
  149.31 +import java.io.IOException;
  149.32 +import java.io.PrintStream;
  149.33 +import java.io.PrintWriter;
  149.34 +import java.io.InputStream;
  149.35 +import java.io.OutputStream;
  149.36 +import java.io.Reader;
  149.37 +import java.io.Writer;
  149.38 +import java.io.OutputStreamWriter;
  149.39 +import java.io.BufferedWriter;
  149.40 +
  149.41 +/**
  149.42 + * The <code>Properties</code> class represents a persistent set of
  149.43 + * properties. The <code>Properties</code> can be saved to a stream
  149.44 + * or loaded from a stream. Each key and its corresponding value in
  149.45 + * the property list is a string.
  149.46 + * <p>
  149.47 + * A property list can contain another property list as its
  149.48 + * "defaults"; this second property list is searched if
  149.49 + * the property key is not found in the original property list.
  149.50 + * <p>
  149.51 + * Because <code>Properties</code> inherits from <code>Hashtable</code>, the
  149.52 + * <code>put</code> and <code>putAll</code> methods can be applied to a
  149.53 + * <code>Properties</code> object.  Their use is strongly discouraged as they
  149.54 + * allow the caller to insert entries whose keys or values are not
  149.55 + * <code>Strings</code>.  The <code>setProperty</code> method should be used
  149.56 + * instead.  If the <code>store</code> or <code>save</code> method is called
  149.57 + * on a "compromised" <code>Properties</code> object that contains a
  149.58 + * non-<code>String</code> key or value, the call will fail. Similarly,
  149.59 + * the call to the <code>propertyNames</code> or <code>list</code> method
  149.60 + * will fail if it is called on a "compromised" <code>Properties</code>
  149.61 + * object that contains a non-<code>String</code> key.
  149.62 + *
  149.63 + * <p>
  149.64 + * The {@link #load(java.io.Reader) load(Reader)} <tt>/</tt>
  149.65 + * {@link #store(java.io.Writer, java.lang.String) store(Writer, String)}
  149.66 + * methods load and store properties from and to a character based stream
  149.67 + * in a simple line-oriented format specified below.
  149.68 + *
  149.69 + * The {@link #load(java.io.InputStream) load(InputStream)} <tt>/</tt>
  149.70 + * {@link #store(java.io.OutputStream, java.lang.String) store(OutputStream, String)}
  149.71 + * methods work the same way as the load(Reader)/store(Writer, String) pair, except
  149.72 + * the input/output stream is encoded in ISO 8859-1 character encoding.
  149.73 + * Characters that cannot be directly represented in this encoding can be written using
  149.74 + * Unicode escapes as defined in section 3.3 of
  149.75 + * <cite>The Java&trade; Language Specification</cite>;
  149.76 + * only a single 'u' character is allowed in an escape
  149.77 + * sequence. The native2ascii tool can be used to convert property files to and
  149.78 + * from other character encodings.
  149.79 + *
  149.80 + * <p> The {@link #loadFromXML(InputStream)} and {@link
  149.81 + * #storeToXML(OutputStream, String, String)} methods load and store properties
  149.82 + * in a simple XML format.  By default the UTF-8 character encoding is used,
  149.83 + * however a specific encoding may be specified if required.  An XML properties
  149.84 + * document has the following DOCTYPE declaration:
  149.85 + *
  149.86 + * <pre>
  149.87 + * &lt;!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"&gt;
  149.88 + * </pre>
  149.89 + * Note that the system URI (http://java.sun.com/dtd/properties.dtd) is
  149.90 + * <i>not</i> accessed when exporting or importing properties; it merely
  149.91 + * serves as a string to uniquely identify the DTD, which is:
  149.92 + * <pre>
  149.93 + *    &lt;?xml version="1.0" encoding="UTF-8"?&gt;
  149.94 + *
  149.95 + *    &lt;!-- DTD for properties --&gt;
  149.96 + *
  149.97 + *    &lt;!ELEMENT properties ( comment?, entry* ) &gt;
  149.98 + *
  149.99 + *    &lt;!ATTLIST properties version CDATA #FIXED "1.0"&gt;
 149.100 + *
 149.101 + *    &lt;!ELEMENT comment (#PCDATA) &gt;
 149.102 + *
 149.103 + *    &lt;!ELEMENT entry (#PCDATA) &gt;
 149.104 + *
 149.105 + *    &lt;!ATTLIST entry key CDATA #REQUIRED&gt;
 149.106 + * </pre>
 149.107 + *
 149.108 + * <p>This class is thread-safe: multiple threads can share a single
 149.109 + * <tt>Properties</tt> object without the need for external synchronization.
 149.110 + *
 149.111 + * @see <a href="../../../technotes/tools/solaris/native2ascii.html">native2ascii tool for Solaris</a>
 149.112 + * @see <a href="../../../technotes/tools/windows/native2ascii.html">native2ascii tool for Windows</a>
 149.113 + *
 149.114 + * @author  Arthur van Hoff
 149.115 + * @author  Michael McCloskey
 149.116 + * @author  Xueming Shen
 149.117 + * @since   JDK1.0
 149.118 + */
 149.119 +public
 149.120 +class Properties extends Hashtable<Object,Object> {
 149.121 +    /**
 149.122 +     * use serialVersionUID from JDK 1.1.X for interoperability
 149.123 +     */
 149.124 +     private static final long serialVersionUID = 4112578634029874840L;
 149.125 +
 149.126 +    /**
 149.127 +     * A property list that contains default values for any keys not
 149.128 +     * found in this property list.
 149.129 +     *
 149.130 +     * @serial
 149.131 +     */
 149.132 +    protected Properties defaults;
 149.133 +
 149.134 +    /**
 149.135 +     * Creates an empty property list with no default values.
 149.136 +     */
 149.137 +    public Properties() {
 149.138 +        this(null);
 149.139 +    }
 149.140 +
 149.141 +    /**
 149.142 +     * Creates an empty property list with the specified defaults.
 149.143 +     *
 149.144 +     * @param   defaults   the defaults.
 149.145 +     */
 149.146 +    public Properties(Properties defaults) {
 149.147 +        this.defaults = defaults;
 149.148 +    }
 149.149 +
 149.150 +    /**
 149.151 +     * Calls the <tt>Hashtable</tt> method <code>put</code>. Provided for
 149.152 +     * parallelism with the <tt>getProperty</tt> method. Enforces use of
 149.153 +     * strings for property keys and values. The value returned is the
 149.154 +     * result of the <tt>Hashtable</tt> call to <code>put</code>.
 149.155 +     *
 149.156 +     * @param key the key to be placed into this property list.
 149.157 +     * @param value the value corresponding to <tt>key</tt>.
 149.158 +     * @return     the previous value of the specified key in this property
 149.159 +     *             list, or <code>null</code> if it did not have one.
 149.160 +     * @see #getProperty
 149.161 +     * @since    1.2
 149.162 +     */
 149.163 +    public synchronized Object setProperty(String key, String value) {
 149.164 +        return put(key, value);
 149.165 +    }
 149.166 +
 149.167 +
 149.168 +    /**
 149.169 +     * Reads a property list (key and element pairs) from the input
 149.170 +     * character stream in a simple line-oriented format.
 149.171 +     * <p>
 149.172 +     * Properties are processed in terms of lines. There are two
 149.173 +     * kinds of line, <i>natural lines</i> and <i>logical lines</i>.
 149.174 +     * A natural line is defined as a line of
 149.175 +     * characters that is terminated either by a set of line terminator
 149.176 +     * characters (<code>\n</code> or <code>\r</code> or <code>\r\n</code>)
 149.177 +     * or by the end of the stream. A natural line may be either a blank line,
 149.178 +     * a comment line, or hold all or some of a key-element pair. A logical
 149.179 +     * line holds all the data of a key-element pair, which may be spread
 149.180 +     * out across several adjacent natural lines by escaping
 149.181 +     * the line terminator sequence with a backslash character
 149.182 +     * <code>\</code>.  Note that a comment line cannot be extended
 149.183 +     * in this manner; every natural line that is a comment must have
 149.184 +     * its own comment indicator, as described below. Lines are read from
 149.185 +     * input until the end of the stream is reached.
 149.186 +     *
 149.187 +     * <p>
 149.188 +     * A natural line that contains only white space characters is
 149.189 +     * considered blank and is ignored.  A comment line has an ASCII
 149.190 +     * <code>'#'</code> or <code>'!'</code> as its first non-white
 149.191 +     * space character; comment lines are also ignored and do not
 149.192 +     * encode key-element information.  In addition to line
 149.193 +     * terminators, this format considers the characters space
 149.194 +     * (<code>' '</code>, <code>'&#92;u0020'</code>), tab
 149.195 +     * (<code>'\t'</code>, <code>'&#92;u0009'</code>), and form feed
 149.196 +     * (<code>'\f'</code>, <code>'&#92;u000C'</code>) to be white
 149.197 +     * space.
 149.198 +     *
 149.199 +     * <p>
 149.200 +     * If a logical line is spread across several natural lines, the
 149.201 +     * backslash escaping the line terminator sequence, the line
 149.202 +     * terminator sequence, and any white space at the start of the
 149.203 +     * following line have no affect on the key or element values.
 149.204 +     * The remainder of the discussion of key and element parsing
 149.205 +     * (when loading) will assume all the characters constituting
 149.206 +     * the key and element appear on a single natural line after
 149.207 +     * line continuation characters have been removed.  Note that
 149.208 +     * it is <i>not</i> sufficient to only examine the character
 149.209 +     * preceding a line terminator sequence to decide if the line
 149.210 +     * terminator is escaped; there must be an odd number of
 149.211 +     * contiguous backslashes for the line terminator to be escaped.
 149.212 +     * Since the input is processed from left to right, a
 149.213 +     * non-zero even number of 2<i>n</i> contiguous backslashes
 149.214 +     * before a line terminator (or elsewhere) encodes <i>n</i>
 149.215 +     * backslashes after escape processing.
 149.216 +     *
 149.217 +     * <p>
 149.218 +     * The key contains all of the characters in the line starting
 149.219 +     * with the first non-white space character and up to, but not
 149.220 +     * including, the first unescaped <code>'='</code>,
 149.221 +     * <code>':'</code>, or white space character other than a line
 149.222 +     * terminator. All of these key termination characters may be
 149.223 +     * included in the key by escaping them with a preceding backslash
 149.224 +     * character; for example,<p>
 149.225 +     *
 149.226 +     * <code>\:\=</code><p>
 149.227 +     *
 149.228 +     * would be the two-character key <code>":="</code>.  Line
 149.229 +     * terminator characters can be included using <code>\r</code> and
 149.230 +     * <code>\n</code> escape sequences.  Any white space after the
 149.231 +     * key is skipped; if the first non-white space character after
 149.232 +     * the key is <code>'='</code> or <code>':'</code>, then it is
 149.233 +     * ignored and any white space characters after it are also
 149.234 +     * skipped.  All remaining characters on the line become part of
 149.235 +     * the associated element string; if there are no remaining
 149.236 +     * characters, the element is the empty string
 149.237 +     * <code>&quot;&quot;</code>.  Once the raw character sequences
 149.238 +     * constituting the key and element are identified, escape
 149.239 +     * processing is performed as described above.
 149.240 +     *
 149.241 +     * <p>
 149.242 +     * As an example, each of the following three lines specifies the key
 149.243 +     * <code>"Truth"</code> and the associated element value
 149.244 +     * <code>"Beauty"</code>:
 149.245 +     * <p>
 149.246 +     * <pre>
 149.247 +     * Truth = Beauty
 149.248 +     *  Truth:Beauty
 149.249 +     * Truth                    :Beauty
 149.250 +     * </pre>
 149.251 +     * As another example, the following three lines specify a single
 149.252 +     * property:
 149.253 +     * <p>
 149.254 +     * <pre>
 149.255 +     * fruits                           apple, banana, pear, \
 149.256 +     *                                  cantaloupe, watermelon, \
 149.257 +     *                                  kiwi, mango
 149.258 +     * </pre>
 149.259 +     * The key is <code>"fruits"</code> and the associated element is:
 149.260 +     * <p>
 149.261 +     * <pre>"apple, banana, pear, cantaloupe, watermelon, kiwi, mango"</pre>
 149.262 +     * Note that a space appears before each <code>\</code> so that a space
 149.263 +     * will appear after each comma in the final result; the <code>\</code>,
 149.264 +     * line terminator, and leading white space on the continuation line are
 149.265 +     * merely discarded and are <i>not</i> replaced by one or more other
 149.266 +     * characters.
 149.267 +     * <p>
 149.268 +     * As a third example, the line:
 149.269 +     * <p>
 149.270 +     * <pre>cheeses
 149.271 +     * </pre>
 149.272 +     * specifies that the key is <code>"cheeses"</code> and the associated
 149.273 +     * element is the empty string <code>""</code>.<p>
 149.274 +     * <p>
 149.275 +     *
 149.276 +     * <a name="unicodeescapes"></a>
 149.277 +     * Characters in keys and elements can be represented in escape
 149.278 +     * sequences similar to those used for character and string literals
 149.279 +     * (see sections 3.3 and 3.10.6 of
 149.280 +     * <cite>The Java&trade; Language Specification</cite>).
 149.281 +     *
 149.282 +     * The differences from the character escape sequences and Unicode
 149.283 +     * escapes used for characters and strings are:
 149.284 +     *
 149.285 +     * <ul>
 149.286 +     * <li> Octal escapes are not recognized.
 149.287 +     *
 149.288 +     * <li> The character sequence <code>\b</code> does <i>not</i>
 149.289 +     * represent a backspace character.
 149.290 +     *
 149.291 +     * <li> The method does not treat a backslash character,
 149.292 +     * <code>\</code>, before a non-valid escape character as an
 149.293 +     * error; the backslash is silently dropped.  For example, in a
 149.294 +     * Java string the sequence <code>"\z"</code> would cause a
 149.295 +     * compile time error.  In contrast, this method silently drops
 149.296 +     * the backslash.  Therefore, this method treats the two character
 149.297 +     * sequence <code>"\b"</code> as equivalent to the single
 149.298 +     * character <code>'b'</code>.
 149.299 +     *
 149.300 +     * <li> Escapes are not necessary for single and double quotes;
 149.301 +     * however, by the rule above, single and double quote characters
 149.302 +     * preceded by a backslash still yield single and double quote
 149.303 +     * characters, respectively.
 149.304 +     *
 149.305 +     * <li> Only a single 'u' character is allowed in a Uniocde escape
 149.306 +     * sequence.
 149.307 +     *
 149.308 +     * </ul>
 149.309 +     * <p>
 149.310 +     * The specified stream remains open after this method returns.
 149.311 +     *
 149.312 +     * @param   reader   the input character stream.
 149.313 +     * @throws  IOException  if an error occurred when reading from the
 149.314 +     *          input stream.
 149.315 +     * @throws  IllegalArgumentException if a malformed Unicode escape
 149.316 +     *          appears in the input.
 149.317 +     * @since   1.6
 149.318 +     */
 149.319 +    public synchronized void load(Reader reader) throws IOException {
 149.320 +        load0(new LineReader(reader));
 149.321 +    }
 149.322 +
 149.323 +    /**
 149.324 +     * Reads a property list (key and element pairs) from the input
 149.325 +     * byte stream. The input stream is in a simple line-oriented
 149.326 +     * format as specified in
 149.327 +     * {@link #load(java.io.Reader) load(Reader)} and is assumed to use
 149.328 +     * the ISO 8859-1 character encoding; that is each byte is one Latin1
 149.329 +     * character. Characters not in Latin1, and certain special characters,
 149.330 +     * are represented in keys and elements using Unicode escapes as defined in
 149.331 +     * section 3.3 of
 149.332 +     * <cite>The Java&trade; Language Specification</cite>.
 149.333 +     * <p>
 149.334 +     * The specified stream remains open after this method returns.
 149.335 +     *
 149.336 +     * @param      inStream   the input stream.
 149.337 +     * @exception  IOException  if an error occurred when reading from the
 149.338 +     *             input stream.
 149.339 +     * @throws     IllegalArgumentException if the input stream contains a
 149.340 +     *             malformed Unicode escape sequence.
 149.341 +     * @since 1.2
 149.342 +     */
 149.343 +    public synchronized void load(InputStream inStream) throws IOException {
 149.344 +        load0(new LineReader(inStream));
 149.345 +    }
 149.346 +
 149.347 +    private void load0 (LineReader lr) throws IOException {
 149.348 +        char[] convtBuf = new char[1024];
 149.349 +        int limit;
 149.350 +        int keyLen;
 149.351 +        int valueStart;
 149.352 +        char c;
 149.353 +        boolean hasSep;
 149.354 +        boolean precedingBackslash;
 149.355 +
 149.356 +        while ((limit = lr.readLine()) >= 0) {
 149.357 +            c = 0;
 149.358 +            keyLen = 0;
 149.359 +            valueStart = limit;
 149.360 +            hasSep = false;
 149.361 +
 149.362 +            //System.out.println("line=<" + new String(lineBuf, 0, limit) + ">");
 149.363 +            precedingBackslash = false;
 149.364 +            while (keyLen < limit) {
 149.365 +                c = lr.lineBuf[keyLen];
 149.366 +                //need check if escaped.
 149.367 +                if ((c == '=' ||  c == ':') && !precedingBackslash) {
 149.368 +                    valueStart = keyLen + 1;
 149.369 +                    hasSep = true;
 149.370 +                    break;
 149.371 +                } else if ((c == ' ' || c == '\t' ||  c == '\f') && !precedingBackslash) {
 149.372 +                    valueStart = keyLen + 1;
 149.373 +                    break;
 149.374 +                }
 149.375 +                if (c == '\\') {
 149.376 +                    precedingBackslash = !precedingBackslash;
 149.377 +                } else {
 149.378 +                    precedingBackslash = false;
 149.379 +                }
 149.380 +                keyLen++;
 149.381 +            }
 149.382 +            while (valueStart < limit) {
 149.383 +                c = lr.lineBuf[valueStart];
 149.384 +                if (c != ' ' && c != '\t' &&  c != '\f') {
 149.385 +                    if (!hasSep && (c == '=' ||  c == ':')) {
 149.386 +                        hasSep = true;
 149.387 +                    } else {
 149.388 +                        break;
 149.389 +                    }
 149.390 +                }
 149.391 +                valueStart++;
 149.392 +            }
 149.393 +            String key = loadConvert(lr.lineBuf, 0, keyLen, convtBuf);
 149.394 +            String value = loadConvert(lr.lineBuf, valueStart, limit - valueStart, convtBuf);
 149.395 +            put(key, value);
 149.396 +        }
 149.397 +    }
 149.398 +
 149.399 +    /* Read in a "logical line" from an InputStream/Reader, skip all comment
 149.400 +     * and blank lines and filter out those leading whitespace characters
 149.401 +     * (\u0020, \u0009 and \u000c) from the beginning of a "natural line".
 149.402 +     * Method returns the char length of the "logical line" and stores
 149.403 +     * the line in "lineBuf".
 149.404 +     */
 149.405 +    class LineReader {
 149.406 +        public LineReader(InputStream inStream) {
 149.407 +            this.inStream = inStream;
 149.408 +            inByteBuf = new byte[8192];
 149.409 +        }
 149.410 +
 149.411 +        public LineReader(Reader reader) {
 149.412 +            this.reader = reader;
 149.413 +            inCharBuf = new char[8192];
 149.414 +        }
 149.415 +
 149.416 +        byte[] inByteBuf;
 149.417 +        char[] inCharBuf;
 149.418 +        char[] lineBuf = new char[1024];
 149.419 +        int inLimit = 0;
 149.420 +        int inOff = 0;
 149.421 +        InputStream inStream;
 149.422 +        Reader reader;
 149.423 +
 149.424 +        int readLine() throws IOException {
 149.425 +            int len = 0;
 149.426 +            char c = 0;
 149.427 +
 149.428 +            boolean skipWhiteSpace = true;
 149.429 +            boolean isCommentLine = false;
 149.430 +            boolean isNewLine = true;
 149.431 +            boolean appendedLineBegin = false;
 149.432 +            boolean precedingBackslash = false;
 149.433 +            boolean skipLF = false;
 149.434 +
 149.435 +            while (true) {
 149.436 +                if (inOff >= inLimit) {
 149.437 +                    inLimit = (inStream==null)?reader.read(inCharBuf)
 149.438 +                                              :inStream.read(inByteBuf);
 149.439 +                    inOff = 0;
 149.440 +                    if (inLimit <= 0) {
 149.441 +                        if (len == 0 || isCommentLine) {
 149.442 +                            return -1;
 149.443 +                        }
 149.444 +                        return len;
 149.445 +                    }
 149.446 +                }
 149.447 +                if (inStream != null) {
 149.448 +                    //The line below is equivalent to calling a
 149.449 +                    //ISO8859-1 decoder.
 149.450 +                    c = (char) (0xff & inByteBuf[inOff++]);
 149.451 +                } else {
 149.452 +                    c = inCharBuf[inOff++];
 149.453 +                }
 149.454 +                if (skipLF) {
 149.455 +                    skipLF = false;
 149.456 +                    if (c == '\n') {
 149.457 +                        continue;
 149.458 +                    }
 149.459 +                }
 149.460 +                if (skipWhiteSpace) {
 149.461 +                    if (c == ' ' || c == '\t' || c == '\f') {
 149.462 +                        continue;
 149.463 +                    }
 149.464 +                    if (!appendedLineBegin && (c == '\r' || c == '\n')) {
 149.465 +                        continue;
 149.466 +                    }
 149.467 +                    skipWhiteSpace = false;
 149.468 +                    appendedLineBegin = false;
 149.469 +                }
 149.470 +                if (isNewLine) {
 149.471 +                    isNewLine = false;
 149.472 +                    if (c == '#' || c == '!') {
 149.473 +                        isCommentLine = true;
 149.474 +                        continue;
 149.475 +                    }
 149.476 +                }
 149.477 +
 149.478 +                if (c != '\n' && c != '\r') {
 149.479 +                    lineBuf[len++] = c;
 149.480 +                    if (len == lineBuf.length) {
 149.481 +                        int newLength = lineBuf.length * 2;
 149.482 +                        if (newLength < 0) {
 149.483 +                            newLength = Integer.MAX_VALUE;
 149.484 +                        }
 149.485 +                        char[] buf = new char[newLength];
 149.486 +                        System.arraycopy(lineBuf, 0, buf, 0, lineBuf.length);
 149.487 +                        lineBuf = buf;
 149.488 +                    }
 149.489 +                    //flip the preceding backslash flag
 149.490 +                    if (c == '\\') {
 149.491 +                        precedingBackslash = !precedingBackslash;
 149.492 +                    } else {
 149.493 +                        precedingBackslash = false;
 149.494 +                    }
 149.495 +                }
 149.496 +                else {
 149.497 +                    // reached EOL
 149.498 +                    if (isCommentLine || len == 0) {
 149.499 +                        isCommentLine = false;
 149.500 +                        isNewLine = true;
 149.501 +                        skipWhiteSpace = true;
 149.502 +                        len = 0;
 149.503 +                        continue;
 149.504 +                    }
 149.505 +                    if (inOff >= inLimit) {
 149.506 +                        inLimit = (inStream==null)
 149.507 +                                  ?reader.read(inCharBuf)
 149.508 +                                  :inStream.read(inByteBuf);
 149.509 +                        inOff = 0;
 149.510 +                        if (inLimit <= 0) {
 149.511 +                            return len;
 149.512 +                        }
 149.513 +                    }
 149.514 +                    if (precedingBackslash) {
 149.515 +                        len -= 1;
 149.516 +                        //skip the leading whitespace characters in following line
 149.517 +                        skipWhiteSpace = true;
 149.518 +                        appendedLineBegin = true;
 149.519 +                        precedingBackslash = false;
 149.520 +                        if (c == '\r') {
 149.521 +                            skipLF = true;
 149.522 +                        }
 149.523 +                    } else {
 149.524 +                        return len;
 149.525 +                    }
 149.526 +                }
 149.527 +            }
 149.528 +        }
 149.529 +    }
 149.530 +
 149.531 +    /*
 149.532 +     * Converts encoded &#92;uxxxx to unicode chars
 149.533 +     * and changes special saved chars to their original forms
 149.534 +     */
 149.535 +    private String loadConvert (char[] in, int off, int len, char[] convtBuf) {
 149.536 +        if (convtBuf.length < len) {
 149.537 +            int newLen = len * 2;
 149.538 +            if (newLen < 0) {
 149.539 +                newLen = Integer.MAX_VALUE;
 149.540 +            }
 149.541 +            convtBuf = new char[newLen];
 149.542 +        }
 149.543 +        char aChar;
 149.544 +        char[] out = convtBuf;
 149.545 +        int outLen = 0;
 149.546 +        int end = off + len;
 149.547 +
 149.548 +        while (off < end) {
 149.549 +            aChar = in[off++];
 149.550 +            if (aChar == '\\') {
 149.551 +                aChar = in[off++];
 149.552 +                if(aChar == 'u') {
 149.553 +                    // Read the xxxx
 149.554 +                    int value=0;
 149.555 +                    for (int i=0; i<4; i++) {
 149.556 +                        aChar = in[off++];
 149.557 +                        switch (aChar) {
 149.558 +                          case '0': case '1': case '2': case '3': case '4':
 149.559 +                          case '5': case '6': case '7': case '8': case '9':
 149.560 +                             value = (value << 4) + aChar - '0';
 149.561 +                             break;
 149.562 +                          case 'a': case 'b': case 'c':
 149.563 +                          case 'd': case 'e': case 'f':
 149.564 +                             value = (value << 4) + 10 + aChar - 'a';
 149.565 +                             break;
 149.566 +                          case 'A': case 'B': case 'C':
 149.567 +                          case 'D': case 'E': case 'F':
 149.568 +                             value = (value << 4) + 10 + aChar - 'A';
 149.569 +                             break;
 149.570 +                          default:
 149.571 +                              throw new IllegalArgumentException(
 149.572 +                                           "Malformed \\uxxxx encoding.");
 149.573 +                        }
 149.574 +                     }
 149.575 +                    out[outLen++] = (char)value;
 149.576 +                } else {
 149.577 +                    if (aChar == 't') aChar = '\t';
 149.578 +                    else if (aChar == 'r') aChar = '\r';
 149.579 +                    else if (aChar == 'n') aChar = '\n';
 149.580 +                    else if (aChar == 'f') aChar = '\f';
 149.581 +                    out[outLen++] = aChar;
 149.582 +                }
 149.583 +            } else {
 149.584 +                out[outLen++] = aChar;
 149.585 +            }
 149.586 +        }
 149.587 +        return new String (out, 0, outLen);
 149.588 +    }
 149.589 +
 149.590 +    /*
 149.591 +     * Converts unicodes to encoded &#92;uxxxx and escapes
 149.592 +     * special characters with a preceding slash
 149.593 +     */
 149.594 +    private String saveConvert(String theString,
 149.595 +                               boolean escapeSpace,
 149.596 +                               boolean escapeUnicode) {
 149.597 +        int len = theString.length();
 149.598 +        int bufLen = len * 2;
 149.599 +        if (bufLen < 0) {
 149.600 +            bufLen = Integer.MAX_VALUE;
 149.601 +        }
 149.602 +        StringBuffer outBuffer = new StringBuffer(bufLen);
 149.603 +
 149.604 +        for(int x=0; x<len; x++) {
 149.605 +            char aChar = theString.charAt(x);
 149.606 +            // Handle common case first, selecting largest block that
 149.607 +            // avoids the specials below
 149.608 +            if ((aChar > 61) && (aChar < 127)) {
 149.609 +                if (aChar == '\\') {
 149.610 +                    outBuffer.append('\\'); outBuffer.append('\\');
 149.611 +                    continue;
 149.612 +                }
 149.613 +                outBuffer.append(aChar);
 149.614 +                continue;
 149.615 +            }
 149.616 +            switch(aChar) {
 149.617 +                case ' ':
 149.618 +                    if (x == 0 || escapeSpace)
 149.619 +                        outBuffer.append('\\');
 149.620 +                    outBuffer.append(' ');
 149.621 +                    break;
 149.622 +                case '\t':outBuffer.append('\\'); outBuffer.append('t');
 149.623 +                          break;
 149.624 +                case '\n':outBuffer.append('\\'); outBuffer.append('n');
 149.625 +                          break;
 149.626 +                case '\r':outBuffer.append('\\'); outBuffer.append('r');
 149.627 +                          break;
 149.628 +                case '\f':outBuffer.append('\\'); outBuffer.append('f');
 149.629 +                          break;
 149.630 +                case '=': // Fall through
 149.631 +                case ':': // Fall through
 149.632 +                case '#': // Fall through
 149.633 +                case '!':
 149.634 +                    outBuffer.append('\\'); outBuffer.append(aChar);
 149.635 +                    break;
 149.636 +                default:
 149.637 +                    if (((aChar < 0x0020) || (aChar > 0x007e)) & escapeUnicode ) {
 149.638 +                        outBuffer.append('\\');
 149.639 +                        outBuffer.append('u');
 149.640 +                        outBuffer.append(toHex((aChar >> 12) & 0xF));
 149.641 +                        outBuffer.append(toHex((aChar >>  8) & 0xF));
 149.642 +                        outBuffer.append(toHex((aChar >>  4) & 0xF));
 149.643 +                        outBuffer.append(toHex( aChar        & 0xF));
 149.644 +                    } else {
 149.645 +                        outBuffer.append(aChar);
 149.646 +                    }
 149.647 +            }
 149.648 +        }
 149.649 +        return outBuffer.toString();
 149.650 +    }
 149.651 +
 149.652 +    private static void writeComments(BufferedWriter bw, String comments)
 149.653 +        throws IOException {
 149.654 +        bw.write("#");
 149.655 +        int len = comments.length();
 149.656 +        int current = 0;
 149.657 +        int last = 0;
 149.658 +        char[] uu = new char[6];
 149.659 +        uu[0] = '\\';
 149.660 +        uu[1] = 'u';
 149.661 +        while (current < len) {
 149.662 +            char c = comments.charAt(current);
 149.663 +            if (c > '\u00ff' || c == '\n' || c == '\r') {
 149.664 +                if (last != current)
 149.665 +                    bw.write(comments.substring(last, current));
 149.666 +                if (c > '\u00ff') {
 149.667 +                    uu[2] = toHex((c >> 12) & 0xf);
 149.668 +                    uu[3] = toHex((c >>  8) & 0xf);
 149.669 +                    uu[4] = toHex((c >>  4) & 0xf);
 149.670 +                    uu[5] = toHex( c        & 0xf);
 149.671 +                    bw.write(new String(uu));
 149.672 +                } else {
 149.673 +                    bw.newLine();
 149.674 +                    if (c == '\r' &&
 149.675 +                        current != len - 1 &&
 149.676 +                        comments.charAt(current + 1) == '\n') {
 149.677 +                        current++;
 149.678 +                    }
 149.679 +                    if (current == len - 1 ||
 149.680 +                        (comments.charAt(current + 1) != '#' &&
 149.681 +                        comments.charAt(current + 1) != '!'))
 149.682 +                        bw.write("#");
 149.683 +                }
 149.684 +                last = current + 1;
 149.685 +            }
 149.686 +            current++;
 149.687 +        }
 149.688 +        if (last != current)
 149.689 +            bw.write(comments.substring(last, current));
 149.690 +        bw.newLine();
 149.691 +    }
 149.692 +
 149.693 +    /**
 149.694 +     * Calls the <code>store(OutputStream out, String comments)</code> method
 149.695 +     * and suppresses IOExceptions that were thrown.
 149.696 +     *
 149.697 +     * @deprecated This method does not throw an IOException if an I/O error
 149.698 +     * occurs while saving the property list.  The preferred way to save a
 149.699 +     * properties list is via the <code>store(OutputStream out,
 149.700 +     * String comments)</code> method or the
 149.701 +     * <code>storeToXML(OutputStream os, String comment)</code> method.
 149.702 +     *
 149.703 +     * @param   out      an output stream.
 149.704 +     * @param   comments   a description of the property list.
 149.705 +     * @exception  ClassCastException  if this <code>Properties</code> object
 149.706 +     *             contains any keys or values that are not
 149.707 +     *             <code>Strings</code>.
 149.708 +     */
 149.709 +    @Deprecated
 149.710 +    public void save(OutputStream out, String comments)  {
 149.711 +        try {
 149.712 +            store(out, comments);
 149.713 +        } catch (IOException e) {
 149.714 +        }
 149.715 +    }
 149.716 +
 149.717 +    /**
 149.718 +     * Writes this property list (key and element pairs) in this
 149.719 +     * <code>Properties</code> table to the output character stream in a
 149.720 +     * format suitable for using the {@link #load(java.io.Reader) load(Reader)}
 149.721 +     * method.
 149.722 +     * <p>
 149.723 +     * Properties from the defaults table of this <code>Properties</code>
 149.724 +     * table (if any) are <i>not</i> written out by this method.
 149.725 +     * <p>
 149.726 +     * If the comments argument is not null, then an ASCII <code>#</code>
 149.727 +     * character, the comments string, and a line separator are first written
 149.728 +     * to the output stream. Thus, the <code>comments</code> can serve as an
 149.729 +     * identifying comment. Any one of a line feed ('\n'), a carriage
 149.730 +     * return ('\r'), or a carriage return followed immediately by a line feed
 149.731 +     * in comments is replaced by a line separator generated by the <code>Writer</code>
 149.732 +     * and if the next character in comments is not character <code>#</code> or
 149.733 +     * character <code>!</code> then an ASCII <code>#</code> is written out
 149.734 +     * after that line separator.
 149.735 +     * <p>
 149.736 +     * Next, a comment line is always written, consisting of an ASCII
 149.737 +     * <code>#</code> character, the current date and time (as if produced
 149.738 +     * by the <code>toString</code> method of <code>Date</code> for the
 149.739 +     * current time), and a line separator as generated by the <code>Writer</code>.
 149.740 +     * <p>
 149.741 +     * Then every entry in this <code>Properties</code> table is
 149.742 +     * written out, one per line. For each entry the key string is
 149.743 +     * written, then an ASCII <code>=</code>, then the associated
 149.744 +     * element string. For the key, all space characters are
 149.745 +     * written with a preceding <code>\</code> character.  For the
 149.746 +     * element, leading space characters, but not embedded or trailing
 149.747 +     * space characters, are written with a preceding <code>\</code>
 149.748 +     * character. The key and element characters <code>#</code>,
 149.749 +     * <code>!</code>, <code>=</code>, and <code>:</code> are written
 149.750 +     * with a preceding backslash to ensure that they are properly loaded.
 149.751 +     * <p>
 149.752 +     * After the entries have been written, the output stream is flushed.
 149.753 +     * The output stream remains open after this method returns.
 149.754 +     * <p>
 149.755 +     *
 149.756 +     * @param   writer      an output character stream writer.
 149.757 +     * @param   comments   a description of the property list.
 149.758 +     * @exception  IOException if writing this property list to the specified
 149.759 +     *             output stream throws an <tt>IOException</tt>.
 149.760 +     * @exception  ClassCastException  if this <code>Properties</code> object
 149.761 +     *             contains any keys or values that are not <code>Strings</code>.
 149.762 +     * @exception  NullPointerException  if <code>writer</code> is null.
 149.763 +     * @since 1.6
 149.764 +     */
 149.765 +    public void store(Writer writer, String comments)
 149.766 +        throws IOException
 149.767 +    {
 149.768 +        store0((writer instanceof BufferedWriter)?(BufferedWriter)writer
 149.769 +                                                 : new BufferedWriter(writer),
 149.770 +               comments,
 149.771 +               false);
 149.772 +    }
 149.773 +
 149.774 +    /**
 149.775 +     * Writes this property list (key and element pairs) in this
 149.776 +     * <code>Properties</code> table to the output stream in a format suitable
 149.777 +     * for loading into a <code>Properties</code> table using the
 149.778 +     * {@link #load(InputStream) load(InputStream)} method.
 149.779 +     * <p>
 149.780 +     * Properties from the defaults table of this <code>Properties</code>
 149.781 +     * table (if any) are <i>not</i> written out by this method.
 149.782 +     * <p>
 149.783 +     * This method outputs the comments, properties keys and values in
 149.784 +     * the same format as specified in
 149.785 +     * {@link #store(java.io.Writer, java.lang.String) store(Writer)},
 149.786 +     * with the following differences:
 149.787 +     * <ul>
 149.788 +     * <li>The stream is written using the ISO 8859-1 character encoding.
 149.789 +     *
 149.790 +     * <li>Characters not in Latin-1 in the comments are written as
 149.791 +     * <code>&#92;u</code><i>xxxx</i> for their appropriate unicode
 149.792 +     * hexadecimal value <i>xxxx</i>.
 149.793 +     *
 149.794 +     * <li>Characters less than <code>&#92;u0020</code> and characters greater
 149.795 +     * than <code>&#92;u007E</code> in property keys or values are written
 149.796 +     * as <code>&#92;u</code><i>xxxx</i> for the appropriate hexadecimal
 149.797 +     * value <i>xxxx</i>.
 149.798 +     * </ul>
 149.799 +     * <p>
 149.800 +     * After the entries have been written, the output stream is flushed.
 149.801 +     * The output stream remains open after this method returns.
 149.802 +     * <p>
 149.803 +     * @param   out      an output stream.
 149.804 +     * @param   comments   a description of the property list.
 149.805 +     * @exception  IOException if writing this property list to the specified
 149.806 +     *             output stream throws an <tt>IOException</tt>.
 149.807 +     * @exception  ClassCastException  if this <code>Properties</code> object
 149.808 +     *             contains any keys or values that are not <code>Strings</code>.
 149.809 +     * @exception  NullPointerException  if <code>out</code> is null.
 149.810 +     * @since 1.2
 149.811 +     */
 149.812 +    public void store(OutputStream out, String comments)
 149.813 +        throws IOException
 149.814 +    {
 149.815 +        store0(new BufferedWriter(new OutputStreamWriter(out, "8859_1")),
 149.816 +               comments,
 149.817 +               true);
 149.818 +    }
 149.819 +
 149.820 +    private void store0(BufferedWriter bw, String comments, boolean escUnicode)
 149.821 +        throws IOException
 149.822 +    {
 149.823 +        if (comments != null) {
 149.824 +            writeComments(bw, comments);
 149.825 +        }
 149.826 +        bw.write("#" + new Date().toString());
 149.827 +        bw.newLine();
 149.828 +        synchronized (this) {
 149.829 +            for (Enumeration e = keys(); e.hasMoreElements();) {
 149.830 +                String key = (String)e.nextElement();
 149.831 +                String val = (String)get(key);
 149.832 +                key = saveConvert(key, true, escUnicode);
 149.833 +                /* No need to escape embedded and trailing spaces for value, hence
 149.834 +                 * pass false to flag.
 149.835 +                 */
 149.836 +                val = saveConvert(val, false, escUnicode);
 149.837 +                bw.write(key + "=" + val);
 149.838 +                bw.newLine();
 149.839 +            }
 149.840 +        }
 149.841 +        bw.flush();
 149.842 +    }
 149.843 +
 149.844 +    /**
 149.845 +     * Loads all of the properties represented by the XML document on the
 149.846 +     * specified input stream into this properties table.
 149.847 +     *
 149.848 +     * <p>The XML document must have the following DOCTYPE declaration:
 149.849 +     * <pre>
 149.850 +     * &lt;!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"&gt;
 149.851 +     * </pre>
 149.852 +     * Furthermore, the document must satisfy the properties DTD described
 149.853 +     * above.
 149.854 +     *
 149.855 +     * <p>The specified stream is closed after this method returns.
 149.856 +     *
 149.857 +     * @param in the input stream from which to read the XML document.
 149.858 +     * @throws IOException if reading from the specified input stream
 149.859 +     *         results in an <tt>IOException</tt>.
 149.860 +     * @throws InvalidPropertiesFormatException Data on input stream does not
 149.861 +     *         constitute a valid XML document with the mandated document type.
 149.862 +     * @throws NullPointerException if <code>in</code> is null.
 149.863 +     * @see    #storeToXML(OutputStream, String, String)
 149.864 +     * @since 1.5
 149.865 +     */
 149.866 +    public synchronized void loadFromXML(InputStream in)
 149.867 +        throws IOException
 149.868 +    {
 149.869 +        if (in == null)
 149.870 +            throw new NullPointerException();
 149.871 +        throw new IOException();
 149.872 +    }
 149.873 +
 149.874 +    /**
 149.875 +     * Emits an XML document representing all of the properties contained
 149.876 +     * in this table.
 149.877 +     *
 149.878 +     * <p> An invocation of this method of the form <tt>props.storeToXML(os,
 149.879 +     * comment)</tt> behaves in exactly the same way as the invocation
 149.880 +     * <tt>props.storeToXML(os, comment, "UTF-8");</tt>.
 149.881 +     *
 149.882 +     * @param os the output stream on which to emit the XML document.
 149.883 +     * @param comment a description of the property list, or <code>null</code>
 149.884 +     *        if no comment is desired.
 149.885 +     * @throws IOException if writing to the specified output stream
 149.886 +     *         results in an <tt>IOException</tt>.
 149.887 +     * @throws NullPointerException if <code>os</code> is null.
 149.888 +     * @throws ClassCastException  if this <code>Properties</code> object
 149.889 +     *         contains any keys or values that are not
 149.890 +     *         <code>Strings</code>.
 149.891 +     * @see    #loadFromXML(InputStream)
 149.892 +     * @since 1.5
 149.893 +     */
 149.894 +    public void storeToXML(OutputStream os, String comment)
 149.895 +        throws IOException
 149.896 +    {
 149.897 +        if (os == null)
 149.898 +            throw new NullPointerException();
 149.899 +        storeToXML(os, comment, "UTF-8");
 149.900 +    }
 149.901 +
 149.902 +    /**
 149.903 +     * Emits an XML document representing all of the properties contained
 149.904 +     * in this table, using the specified encoding.
 149.905 +     *
 149.906 +     * <p>The XML document will have the following DOCTYPE declaration:
 149.907 +     * <pre>
 149.908 +     * &lt;!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"&gt;
 149.909 +     * </pre>
 149.910 +     *
 149.911 +     *<p>If the specified comment is <code>null</code> then no comment
 149.912 +     * will be stored in the document.
 149.913 +     *
 149.914 +     * <p>The specified stream remains open after this method returns.
 149.915 +     *
 149.916 +     * @param os        the output stream on which to emit the XML document.
 149.917 +     * @param comment   a description of the property list, or <code>null</code>
 149.918 +     *                  if no comment is desired.
 149.919 +     * @param  encoding the name of a supported
 149.920 +     *                  <a href="../lang/package-summary.html#charenc">
 149.921 +     *                  character encoding</a>
 149.922 +     *
 149.923 +     * @throws IOException if writing to the specified output stream
 149.924 +     *         results in an <tt>IOException</tt>.
 149.925 +     * @throws NullPointerException if <code>os</code> is <code>null</code>,
 149.926 +     *         or if <code>encoding</code> is <code>null</code>.
 149.927 +     * @throws ClassCastException  if this <code>Properties</code> object
 149.928 +     *         contains any keys or values that are not
 149.929 +     *         <code>Strings</code>.
 149.930 +     * @see    #loadFromXML(InputStream)
 149.931 +     * @since 1.5
 149.932 +     */
 149.933 +    public void storeToXML(OutputStream os, String comment, String encoding)
 149.934 +        throws IOException
 149.935 +    {
 149.936 +        if (os == null)
 149.937 +            throw new NullPointerException();
 149.938 +        throw new IOException();
 149.939 +    }
 149.940 +
 149.941 +    /**
 149.942 +     * Searches for the property with the specified key in this property list.
 149.943 +     * If the key is not found in this property list, the default property list,
 149.944 +     * and its defaults, recursively, are then checked. The method returns
 149.945 +     * <code>null</code> if the property is not found.
 149.946 +     *
 149.947 +     * @param   key   the property key.
 149.948 +     * @return  the value in this property list with the specified key value.
 149.949 +     * @see     #setProperty
 149.950 +     * @see     #defaults
 149.951 +     */
 149.952 +    public String getProperty(String key) {
 149.953 +        Object oval = super.get(key);
 149.954 +        String sval = (oval instanceof String) ? (String)oval : null;
 149.955 +        return ((sval == null) && (defaults != null)) ? defaults.getProperty(key) : sval;
 149.956 +    }
 149.957 +
 149.958 +    /**
 149.959 +     * Searches for the property with the specified key in this property list.
 149.960 +     * If the key is not found in this property list, the default property list,
 149.961 +     * and its defaults, recursively, are then checked. The method returns the
 149.962 +     * default value argument if the property is not found.
 149.963 +     *
 149.964 +     * @param   key            the hashtable key.
 149.965 +     * @param   defaultValue   a default value.
 149.966 +     *
 149.967 +     * @return  the value in this property list with the specified key value.
 149.968 +     * @see     #setProperty
 149.969 +     * @see     #defaults
 149.970 +     */
 149.971 +    public String getProperty(String key, String defaultValue) {
 149.972 +        String val = getProperty(key);
 149.973 +        return (val == null) ? defaultValue : val;
 149.974 +    }
 149.975 +
 149.976 +    /**
 149.977 +     * Returns an enumeration of all the keys in this property list,
 149.978 +     * including distinct keys in the default property list if a key
 149.979 +     * of the same name has not already been found from the main
 149.980 +     * properties list.
 149.981 +     *
 149.982 +     * @return  an enumeration of all the keys in this property list, including
 149.983 +     *          the keys in the default property list.
 149.984 +     * @throws  ClassCastException if any key in this property list
 149.985 +     *          is not a string.
 149.986 +     * @see     java.util.Enumeration
 149.987 +     * @see     java.util.Properties#defaults
 149.988 +     * @see     #stringPropertyNames
 149.989 +     */
 149.990 +    public Enumeration<?> propertyNames() {
 149.991 +        Hashtable h = new Hashtable();
 149.992 +        enumerate(h);
 149.993 +        return h.keys();
 149.994 +    }
 149.995 +
 149.996 +    /**
 149.997 +     * Returns a set of keys in this property list where
 149.998 +     * the key and its corresponding value are strings,
 149.999 +     * including distinct keys in the default property list if a key
149.1000 +     * of the same name has not already been found from the main
149.1001 +     * properties list.  Properties whose key or value is not
149.1002 +     * of type <tt>String</tt> are omitted.
149.1003 +     * <p>
149.1004 +     * The returned set is not backed by the <tt>Properties</tt> object.
149.1005 +     * Changes to this <tt>Properties</tt> are not reflected in the set,
149.1006 +     * or vice versa.
149.1007 +     *
149.1008 +     * @return  a set of keys in this property list where
149.1009 +     *          the key and its corresponding value are strings,
149.1010 +     *          including the keys in the default property list.
149.1011 +     * @see     java.util.Properties#defaults
149.1012 +     * @since   1.6
149.1013 +     */
149.1014 +    public Set<String> stringPropertyNames() {
149.1015 +        Hashtable<String, String> h = new Hashtable<>();
149.1016 +        enumerateStringProperties(h);
149.1017 +        return h.keySet();
149.1018 +    }
149.1019 +
149.1020 +    /**
149.1021 +     * Prints this property list out to the specified output stream.
149.1022 +     * This method is useful for debugging.
149.1023 +     *
149.1024 +     * @param   out   an output stream.
149.1025 +     * @throws  ClassCastException if any key in this property list
149.1026 +     *          is not a string.
149.1027 +     */
149.1028 +    public void list(PrintStream out) {
149.1029 +        out.println("-- listing properties --");
149.1030 +        Hashtable h = new Hashtable();
149.1031 +        enumerate(h);
149.1032 +        for (Enumeration e = h.keys() ; e.hasMoreElements() ;) {
149.1033 +            String key = (String)e.nextElement();
149.1034 +            String val = (String)h.get(key);
149.1035 +            if (val.length() > 40) {
149.1036 +                val = val.substring(0, 37) + "...";
149.1037 +            }
149.1038 +            out.println(key + "=" + val);
149.1039 +        }
149.1040 +    }
149.1041 +
149.1042 +    /**
149.1043 +     * Prints this property list out to the specified output stream.
149.1044 +     * This method is useful for debugging.
149.1045 +     *
149.1046 +     * @param   out   an output stream.
149.1047 +     * @throws  ClassCastException if any key in this property list
149.1048 +     *          is not a string.
149.1049 +     * @since   JDK1.1
149.1050 +     */
149.1051 +    /*
149.1052 +     * Rather than use an anonymous inner class to share common code, this
149.1053 +     * method is duplicated in order to ensure that a non-1.1 compiler can
149.1054 +     * compile this file.
149.1055 +     */
149.1056 +    public void list(PrintWriter out) {
149.1057 +        out.println("-- listing properties --");
149.1058 +        Hashtable h = new Hashtable();
149.1059 +        enumerate(h);
149.1060 +        for (Enumeration e = h.keys() ; e.hasMoreElements() ;) {
149.1061 +            String key = (String)e.nextElement();
149.1062 +            String val = (String)h.get(key);
149.1063 +            if (val.length() > 40) {
149.1064 +                val = val.substring(0, 37) + "...";
149.1065 +            }
149.1066 +            out.println(key + "=" + val);
149.1067 +        }
149.1068 +    }
149.1069 +
149.1070 +    /**
149.1071 +     * Enumerates all key/value pairs in the specified hashtable.
149.1072 +     * @param h the hashtable
149.1073 +     * @throws ClassCastException if any of the property keys
149.1074 +     *         is not of String type.
149.1075 +     */
149.1076 +    private synchronized void enumerate(Hashtable h) {
149.1077 +        if (defaults != null) {
149.1078 +            defaults.enumerate(h);
149.1079 +        }
149.1080 +        for (Enumeration e = keys() ; e.hasMoreElements() ;) {
149.1081 +            String key = (String)e.nextElement();
149.1082 +            h.put(key, get(key));
149.1083 +        }
149.1084 +    }
149.1085 +
149.1086 +    /**
149.1087 +     * Enumerates all key/value pairs in the specified hashtable
149.1088 +     * and omits the property if the key or value is not a string.
149.1089 +     * @param h the hashtable
149.1090 +     */
149.1091 +    private synchronized void enumerateStringProperties(Hashtable<String, String> h) {
149.1092 +        if (defaults != null) {
149.1093 +            defaults.enumerateStringProperties(h);
149.1094 +        }
149.1095 +        for (Enumeration e = keys() ; e.hasMoreElements() ;) {
149.1096 +            Object k = e.nextElement();
149.1097 +            Object v = get(k);
149.1098 +            if (k instanceof String && v instanceof String) {
149.1099 +                h.put((String) k, (String) v);
149.1100 +            }
149.1101 +        }
149.1102 +    }
149.1103 +
149.1104 +    /**
149.1105 +     * Convert a nibble to a hex character
149.1106 +     * @param   nibble  the nibble to convert.
149.1107 +     */
149.1108 +    private static char toHex(int nibble) {
149.1109 +        return hexDigit[(nibble & 0xF)];
149.1110 +    }
149.1111 +
149.1112 +    /** A table of hex digits */
149.1113 +    private static final char[] hexDigit = {
149.1114 +        '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
149.1115 +    };
149.1116 +}
   150.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   150.2 +++ b/rt/emul/compact/src/main/java/java/util/PropertyResourceBundle.java	Tue Feb 11 13:31:42 2014 +0100
   150.3 @@ -0,0 +1,242 @@
   150.4 +/*
   150.5 + * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
   150.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   150.7 + *
   150.8 + * This code is free software; you can redistribute it and/or modify it
   150.9 + * under the terms of the GNU General Public License version 2 only, as
  150.10 + * published by the Free Software Foundation.  Oracle designates this
  150.11 + * particular file as subject to the "Classpath" exception as provided
  150.12 + * by Oracle in the LICENSE file that accompanied this code.
  150.13 + *
  150.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  150.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  150.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  150.17 + * version 2 for more details (a copy is included in the LICENSE file that
  150.18 + * accompanied this code).
  150.19 + *
  150.20 + * You should have received a copy of the GNU General Public License version
  150.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  150.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  150.23 + *
  150.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  150.25 + * or visit www.oracle.com if you need additional information or have any
  150.26 + * questions.
  150.27 + */
  150.28 +
  150.29 +/*
  150.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
  150.31 + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
  150.32 + *
  150.33 + * The original version of this source code and documentation
  150.34 + * is copyrighted and owned by Taligent, Inc., a wholly-owned
  150.35 + * subsidiary of IBM. These materials are provided under terms
  150.36 + * of a License Agreement between Taligent and Sun. This technology
  150.37 + * is protected by multiple US and International patents.
  150.38 + *
  150.39 + * This notice and attribution to Taligent may not be removed.
  150.40 + * Taligent is a registered trademark of Taligent, Inc.
  150.41 + */
  150.42 +
  150.43 +package java.util;
  150.44 +
  150.45 +import java.io.InputStream;
  150.46 +import java.io.Reader;
  150.47 +import java.io.IOException;
  150.48 +
  150.49 +/**
  150.50 + * <code>PropertyResourceBundle</code> is a concrete subclass of
  150.51 + * <code>ResourceBundle</code> that manages resources for a locale
  150.52 + * using a set of static strings from a property file. See
  150.53 + * {@link ResourceBundle ResourceBundle} for more information about resource
  150.54 + * bundles.
  150.55 + *
  150.56 + * <p>
  150.57 + * Unlike other types of resource bundle, you don't subclass
  150.58 + * <code>PropertyResourceBundle</code>.  Instead, you supply properties
  150.59 + * files containing the resource data.  <code>ResourceBundle.getBundle</code>
  150.60 + * will automatically look for the appropriate properties file and create a
  150.61 + * <code>PropertyResourceBundle</code> that refers to it. See
  150.62 + * {@link ResourceBundle#getBundle(java.lang.String, java.util.Locale, java.lang.ClassLoader) ResourceBundle.getBundle}
  150.63 + * for a complete description of the search and instantiation strategy.
  150.64 + *
  150.65 + * <p>
  150.66 + * The following <a name="sample">example</a> shows a member of a resource
  150.67 + * bundle family with the base name "MyResources".
  150.68 + * The text defines the bundle "MyResources_de",
  150.69 + * the German member of the bundle family.
  150.70 + * This member is based on <code>PropertyResourceBundle</code>, and the text
  150.71 + * therefore is the content of the file "MyResources_de.properties"
  150.72 + * (a related <a href="ListResourceBundle.html#sample">example</a> shows
  150.73 + * how you can add bundles to this family that are implemented as subclasses
  150.74 + * of <code>ListResourceBundle</code>).
  150.75 + * The keys in this example are of the form "s1" etc. The actual
  150.76 + * keys are entirely up to your choice, so long as they are the same as
  150.77 + * the keys you use in your program to retrieve the objects from the bundle.
  150.78 + * Keys are case-sensitive.
  150.79 + * <blockquote>
  150.80 + * <pre>
  150.81 + * # MessageFormat pattern
  150.82 + * s1=Die Platte \"{1}\" enth&auml;lt {0}.
  150.83 + *
  150.84 + * # location of {0} in pattern
  150.85 + * s2=1
  150.86 + *
  150.87 + * # sample disk name
  150.88 + * s3=Meine Platte
  150.89 + *
  150.90 + * # first ChoiceFormat choice
  150.91 + * s4=keine Dateien
  150.92 + *
  150.93 + * # second ChoiceFormat choice
  150.94 + * s5=eine Datei
  150.95 + *
  150.96 + * # third ChoiceFormat choice
  150.97 + * s6={0,number} Dateien
  150.98 + *
  150.99 + * # sample date
 150.100 + * s7=3. M&auml;rz 1996
 150.101 + * </pre>
 150.102 + * </blockquote>
 150.103 + *
 150.104 + * <p>
 150.105 + * <strong>Note:</strong> PropertyResourceBundle can be constructed either
 150.106 + * from an InputStream or a Reader, which represents a property file.
 150.107 + * Constructing a PropertyResourceBundle instance from an InputStream requires
 150.108 + * that the input stream be encoded in ISO-8859-1.  In that case, characters
 150.109 + * that cannot be represented in ISO-8859-1 encoding must be represented by Unicode Escapes
 150.110 + * as defined in section 3.3 of
 150.111 + * <cite>The Java&trade; Language Specification</cite>
 150.112 + * whereas the other constructor which takes a Reader does not have that limitation.
 150.113 + *
 150.114 + * @see ResourceBundle
 150.115 + * @see ListResourceBundle
 150.116 + * @see Properties
 150.117 + * @since JDK1.1
 150.118 + */
 150.119 +public class PropertyResourceBundle extends ResourceBundle {
 150.120 +    /**
 150.121 +     * Creates a property resource bundle from an {@link java.io.InputStream
 150.122 +     * InputStream}.  The property file read with this constructor
 150.123 +     * must be encoded in ISO-8859-1.
 150.124 +     *
 150.125 +     * @param stream an InputStream that represents a property file
 150.126 +     *        to read from.
 150.127 +     * @throws IOException if an I/O error occurs
 150.128 +     * @throws NullPointerException if <code>stream</code> is null
 150.129 +     */
 150.130 +    public PropertyResourceBundle (InputStream stream) throws IOException {
 150.131 +        Properties properties = new Properties();
 150.132 +        properties.load(stream);
 150.133 +        lookup = new HashMap(properties);
 150.134 +    }
 150.135 +
 150.136 +    /**
 150.137 +     * Creates a property resource bundle from a {@link java.io.Reader
 150.138 +     * Reader}.  Unlike the constructor
 150.139 +     * {@link #PropertyResourceBundle(java.io.InputStream) PropertyResourceBundle(InputStream)},
 150.140 +     * there is no limitation as to the encoding of the input property file.
 150.141 +     *
 150.142 +     * @param reader a Reader that represents a property file to
 150.143 +     *        read from.
 150.144 +     * @throws IOException if an I/O error occurs
 150.145 +     * @throws NullPointerException if <code>reader</code> is null
 150.146 +     * @since 1.6
 150.147 +     */
 150.148 +    public PropertyResourceBundle (Reader reader) throws IOException {
 150.149 +        Properties properties = new Properties();
 150.150 +        properties.load(reader);
 150.151 +        lookup = new HashMap(properties);
 150.152 +    }
 150.153 +
 150.154 +    // Implements java.util.ResourceBundle.handleGetObject; inherits javadoc specification.
 150.155 +    public Object handleGetObject(String key) {
 150.156 +        if (key == null) {
 150.157 +            throw new NullPointerException();
 150.158 +        }
 150.159 +        return lookup.get(key);
 150.160 +    }
 150.161 +
 150.162 +    /**
 150.163 +     * Returns an <code>Enumeration</code> of the keys contained in
 150.164 +     * this <code>ResourceBundle</code> and its parent bundles.
 150.165 +     *
 150.166 +     * @return an <code>Enumeration</code> of the keys contained in
 150.167 +     *         this <code>ResourceBundle</code> and its parent bundles.
 150.168 +     * @see #keySet()
 150.169 +     */
 150.170 +    public Enumeration<String> getKeys() {
 150.171 +        ResourceBundle parent = this.parent;
 150.172 +        return new ResourceBundleEnumeration(lookup.keySet(),
 150.173 +                (parent != null) ? parent.getKeys() : null);
 150.174 +    }
 150.175 +
 150.176 +    /**
 150.177 +     * Returns a <code>Set</code> of the keys contained
 150.178 +     * <em>only</em> in this <code>ResourceBundle</code>.
 150.179 +     *
 150.180 +     * @return a <code>Set</code> of the keys contained only in this
 150.181 +     *         <code>ResourceBundle</code>
 150.182 +     * @since 1.6
 150.183 +     * @see #keySet()
 150.184 +     */
 150.185 +    protected Set<String> handleKeySet() {
 150.186 +        return lookup.keySet();
 150.187 +    }
 150.188 +
 150.189 +    // ==================privates====================
 150.190 +
 150.191 +    private Map<String,Object> lookup;
 150.192 +    
 150.193 +
 150.194 +    /**
 150.195 +     * Implements an Enumeration that combines elements from a Set and
 150.196 +     * an Enumeration. Used by ListResourceBundle and PropertyResourceBundle.
 150.197 +     */
 150.198 +    static class ResourceBundleEnumeration implements Enumeration<String> {
 150.199 +
 150.200 +        Set<String> set;
 150.201 +        Iterator<String> iterator;
 150.202 +        Enumeration<String> enumeration; // may remain null
 150.203 +
 150.204 +        /**
 150.205 +         * Constructs a resource bundle enumeration.
 150.206 +         * @param set an set providing some elements of the enumeration
 150.207 +         * @param enumeration an enumeration providing more elements of the enumeration.
 150.208 +         *        enumeration may be null.
 150.209 +         */
 150.210 +        public ResourceBundleEnumeration(Set<String> set, Enumeration<String> enumeration) {
 150.211 +            this.set = set;
 150.212 +            this.iterator = set.iterator();
 150.213 +            this.enumeration = enumeration;
 150.214 +        }
 150.215 +
 150.216 +        String next = null;
 150.217 +
 150.218 +        public boolean hasMoreElements() {
 150.219 +            if (next == null) {
 150.220 +                if (iterator.hasNext()) {
 150.221 +                    next = iterator.next();
 150.222 +                } else if (enumeration != null) {
 150.223 +                    while (next == null && enumeration.hasMoreElements()) {
 150.224 +                        next = enumeration.nextElement();
 150.225 +                        if (set.contains(next)) {
 150.226 +                            next = null;
 150.227 +                        }
 150.228 +                    }
 150.229 +                }
 150.230 +            }
 150.231 +            return next != null;
 150.232 +        }
 150.233 +
 150.234 +        public String nextElement() {
 150.235 +            if (hasMoreElements()) {
 150.236 +                String result = next;
 150.237 +                next = null;
 150.238 +                return result;
 150.239 +            } else {
 150.240 +                throw new NoSuchElementException();
 150.241 +            }
 150.242 +        }
 150.243 +    }
 150.244 +    
 150.245 +}
   151.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   151.2 +++ b/rt/emul/compact/src/main/java/java/util/RegularEnumSet.java	Tue Feb 11 13:31:42 2014 +0100
   151.3 @@ -0,0 +1,303 @@
   151.4 +/*
   151.5 + * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
   151.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   151.7 + *
   151.8 + * This code is free software; you can redistribute it and/or modify it
   151.9 + * under the terms of the GNU General Public License version 2 only, as
  151.10 + * published by the Free Software Foundation.  Oracle designates this
  151.11 + * particular file as subject to the "Classpath" exception as provided
  151.12 + * by Oracle in the LICENSE file that accompanied this code.
  151.13 + *
  151.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  151.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  151.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  151.17 + * version 2 for more details (a copy is included in the LICENSE file that
  151.18 + * accompanied this code).
  151.19 + *
  151.20 + * You should have received a copy of the GNU General Public License version
  151.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  151.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  151.23 + *
  151.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  151.25 + * or visit www.oracle.com if you need additional information or have any
  151.26 + * questions.
  151.27 + */
  151.28 +
  151.29 +package java.util;
  151.30 +
  151.31 +/**
  151.32 + * Private implementation class for EnumSet, for "regular sized" enum types
  151.33 + * (i.e., those with 64 or fewer enum constants).
  151.34 + *
  151.35 + * @author Josh Bloch
  151.36 + * @since 1.5
  151.37 + * @serial exclude
  151.38 + */
  151.39 +class RegularEnumSet<E extends Enum<E>> extends EnumSet<E> {
  151.40 +    private static final long serialVersionUID = 3411599620347842686L;
  151.41 +    /**
  151.42 +     * Bit vector representation of this set.  The 2^k bit indicates the
  151.43 +     * presence of universe[k] in this set.
  151.44 +     */
  151.45 +    private long elements = 0L;
  151.46 +
  151.47 +    RegularEnumSet(Class<E>elementType, Enum[] universe) {
  151.48 +        super(elementType, universe);
  151.49 +    }
  151.50 +
  151.51 +    void addRange(E from, E to) {
  151.52 +        elements = (-1L >>>  (from.ordinal() - to.ordinal() - 1)) << from.ordinal();
  151.53 +    }
  151.54 +
  151.55 +    void addAll() {
  151.56 +        if (universe.length != 0)
  151.57 +            elements = -1L >>> -universe.length;
  151.58 +    }
  151.59 +
  151.60 +    void complement() {
  151.61 +        if (universe.length != 0) {
  151.62 +            elements = ~elements;
  151.63 +            elements &= -1L >>> -universe.length;  // Mask unused bits
  151.64 +        }
  151.65 +    }
  151.66 +
  151.67 +    /**
  151.68 +     * Returns an iterator over the elements contained in this set.  The
  151.69 +     * iterator traverses the elements in their <i>natural order</i> (which is
  151.70 +     * the order in which the enum constants are declared). The returned
  151.71 +     * Iterator is a "snapshot" iterator that will never throw {@link
  151.72 +     * ConcurrentModificationException}; the elements are traversed as they
  151.73 +     * existed when this call was invoked.
  151.74 +     *
  151.75 +     * @return an iterator over the elements contained in this set
  151.76 +     */
  151.77 +    public Iterator<E> iterator() {
  151.78 +        return new EnumSetIterator<>();
  151.79 +    }
  151.80 +
  151.81 +    private class EnumSetIterator<E extends Enum<E>> implements Iterator<E> {
  151.82 +        /**
  151.83 +         * A bit vector representing the elements in the set not yet
  151.84 +         * returned by this iterator.
  151.85 +         */
  151.86 +        long unseen;
  151.87 +
  151.88 +        /**
  151.89 +         * The bit representing the last element returned by this iterator
  151.90 +         * but not removed, or zero if no such element exists.
  151.91 +         */
  151.92 +        long lastReturned = 0;
  151.93 +
  151.94 +        EnumSetIterator() {
  151.95 +            unseen = elements;
  151.96 +        }
  151.97 +
  151.98 +        public boolean hasNext() {
  151.99 +            return unseen != 0;
 151.100 +        }
 151.101 +
 151.102 +        public E next() {
 151.103 +            if (unseen == 0)
 151.104 +                throw new NoSuchElementException();
 151.105 +            lastReturned = unseen & -unseen;
 151.106 +            unseen -= lastReturned;
 151.107 +            return (E) universe[Long.numberOfTrailingZeros(lastReturned)];
 151.108 +        }
 151.109 +
 151.110 +        public void remove() {
 151.111 +            if (lastReturned == 0)
 151.112 +                throw new IllegalStateException();
 151.113 +            elements &= ~lastReturned;
 151.114 +            lastReturned = 0;
 151.115 +        }
 151.116 +    }
 151.117 +
 151.118 +    /**
 151.119 +     * Returns the number of elements in this set.
 151.120 +     *
 151.121 +     * @return the number of elements in this set
 151.122 +     */
 151.123 +    public int size() {
 151.124 +        return Long.bitCount(elements);
 151.125 +    }
 151.126 +
 151.127 +    /**
 151.128 +     * Returns <tt>true</tt> if this set contains no elements.
 151.129 +     *
 151.130 +     * @return <tt>true</tt> if this set contains no elements
 151.131 +     */
 151.132 +    public boolean isEmpty() {
 151.133 +        return elements == 0;
 151.134 +    }
 151.135 +
 151.136 +    /**
 151.137 +     * Returns <tt>true</tt> if this set contains the specified element.
 151.138 +     *
 151.139 +     * @param e element to be checked for containment in this collection
 151.140 +     * @return <tt>true</tt> if this set contains the specified element
 151.141 +     */
 151.142 +    public boolean contains(Object e) {
 151.143 +        if (e == null)
 151.144 +            return false;
 151.145 +        Class eClass = e.getClass();
 151.146 +        if (eClass != elementType && eClass.getSuperclass() != elementType)
 151.147 +            return false;
 151.148 +
 151.149 +        return (elements & (1L << ((Enum)e).ordinal())) != 0;
 151.150 +    }
 151.151 +
 151.152 +    // Modification Operations
 151.153 +
 151.154 +    /**
 151.155 +     * Adds the specified element to this set if it is not already present.
 151.156 +     *
 151.157 +     * @param e element to be added to this set
 151.158 +     * @return <tt>true</tt> if the set changed as a result of the call
 151.159 +     *
 151.160 +     * @throws NullPointerException if <tt>e</tt> is null
 151.161 +     */
 151.162 +    public boolean add(E e) {
 151.163 +        typeCheck(e);
 151.164 +
 151.165 +        long oldElements = elements;
 151.166 +        elements |= (1L << ((Enum)e).ordinal());
 151.167 +        return elements != oldElements;
 151.168 +    }
 151.169 +
 151.170 +    /**
 151.171 +     * Removes the specified element from this set if it is present.
 151.172 +     *
 151.173 +     * @param e element to be removed from this set, if present
 151.174 +     * @return <tt>true</tt> if the set contained the specified element
 151.175 +     */
 151.176 +    public boolean remove(Object e) {
 151.177 +        if (e == null)
 151.178 +            return false;
 151.179 +        Class eClass = e.getClass();
 151.180 +        if (eClass != elementType && eClass.getSuperclass() != elementType)
 151.181 +            return false;
 151.182 +
 151.183 +        long oldElements = elements;
 151.184 +        elements &= ~(1L << ((Enum)e).ordinal());
 151.185 +        return elements != oldElements;
 151.186 +    }
 151.187 +
 151.188 +    // Bulk Operations
 151.189 +
 151.190 +    /**
 151.191 +     * Returns <tt>true</tt> if this set contains all of the elements
 151.192 +     * in the specified collection.
 151.193 +     *
 151.194 +     * @param c collection to be checked for containment in this set
 151.195 +     * @return <tt>true</tt> if this set contains all of the elements
 151.196 +     *        in the specified collection
 151.197 +     * @throws NullPointerException if the specified collection is null
 151.198 +     */
 151.199 +    public boolean containsAll(Collection<?> c) {
 151.200 +        if (!(c instanceof RegularEnumSet))
 151.201 +            return super.containsAll(c);
 151.202 +
 151.203 +        RegularEnumSet es = (RegularEnumSet)c;
 151.204 +        if (es.elementType != elementType)
 151.205 +            return es.isEmpty();
 151.206 +
 151.207 +        return (es.elements & ~elements) == 0;
 151.208 +    }
 151.209 +
 151.210 +    /**
 151.211 +     * Adds all of the elements in the specified collection to this set.
 151.212 +     *
 151.213 +     * @param c collection whose elements are to be added to this set
 151.214 +     * @return <tt>true</tt> if this set changed as a result of the call
 151.215 +     * @throws NullPointerException if the specified collection or any
 151.216 +     *     of its elements are null
 151.217 +     */
 151.218 +    public boolean addAll(Collection<? extends E> c) {
 151.219 +        if (!(c instanceof RegularEnumSet))
 151.220 +            return super.addAll(c);
 151.221 +
 151.222 +        RegularEnumSet es = (RegularEnumSet)c;
 151.223 +        if (es.elementType != elementType) {
 151.224 +            if (es.isEmpty())
 151.225 +                return false;
 151.226 +            else
 151.227 +                throw new ClassCastException(
 151.228 +                    es.elementType + " != " + elementType);
 151.229 +        }
 151.230 +
 151.231 +        long oldElements = elements;
 151.232 +        elements |= es.elements;
 151.233 +        return elements != oldElements;
 151.234 +    }
 151.235 +
 151.236 +    /**
 151.237 +     * Removes from this set all of its elements that are contained in
 151.238 +     * the specified collection.
 151.239 +     *
 151.240 +     * @param c elements to be removed from this set
 151.241 +     * @return <tt>true</tt> if this set changed as a result of the call
 151.242 +     * @throws NullPointerException if the specified collection is null
 151.243 +     */
 151.244 +    public boolean removeAll(Collection<?> c) {
 151.245 +        if (!(c instanceof RegularEnumSet))
 151.246 +            return super.removeAll(c);
 151.247 +
 151.248 +        RegularEnumSet es = (RegularEnumSet)c;
 151.249 +        if (es.elementType != elementType)
 151.250 +            return false;
 151.251 +
 151.252 +        long oldElements = elements;
 151.253 +        elements &= ~es.elements;
 151.254 +        return elements != oldElements;
 151.255 +    }
 151.256 +
 151.257 +    /**
 151.258 +     * Retains only the elements in this set that are contained in the
 151.259 +     * specified collection.
 151.260 +     *
 151.261 +     * @param c elements to be retained in this set
 151.262 +     * @return <tt>true</tt> if this set changed as a result of the call
 151.263 +     * @throws NullPointerException if the specified collection is null
 151.264 +     */
 151.265 +    public boolean retainAll(Collection<?> c) {
 151.266 +        if (!(c instanceof RegularEnumSet))
 151.267 +            return super.retainAll(c);
 151.268 +
 151.269 +        RegularEnumSet<?> es = (RegularEnumSet<?>)c;
 151.270 +        if (es.elementType != elementType) {
 151.271 +            boolean changed = (elements != 0);
 151.272 +            elements = 0;
 151.273 +            return changed;
 151.274 +        }
 151.275 +
 151.276 +        long oldElements = elements;
 151.277 +        elements &= es.elements;
 151.278 +        return elements != oldElements;
 151.279 +    }
 151.280 +
 151.281 +    /**
 151.282 +     * Removes all of the elements from this set.
 151.283 +     */
 151.284 +    public void clear() {
 151.285 +        elements = 0;
 151.286 +    }
 151.287 +
 151.288 +    /**
 151.289 +     * Compares the specified object with this set for equality.  Returns
 151.290 +     * <tt>true</tt> if the given object is also a set, the two sets have
 151.291 +     * the same size, and every member of the given set is contained in
 151.292 +     * this set.
 151.293 +     *
 151.294 +     * @param e object to be compared for equality with this set
 151.295 +     * @return <tt>true</tt> if the specified object is equal to this set
 151.296 +     */
 151.297 +    public boolean equals(Object o) {
 151.298 +        if (!(o instanceof RegularEnumSet))
 151.299 +            return super.equals(o);
 151.300 +
 151.301 +        RegularEnumSet es = (RegularEnumSet)o;
 151.302 +        if (es.elementType != elementType)
 151.303 +            return elements == 0 && es.elements == 0;
 151.304 +        return es.elements == elements;
 151.305 +    }
 151.306 +}
   152.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   152.2 +++ b/rt/emul/compact/src/main/java/java/util/ResourceBundle.java	Tue Feb 11 13:31:42 2014 +0100
   152.3 @@ -0,0 +1,2778 @@
   152.4 +/*
   152.5 + * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
   152.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   152.7 + *
   152.8 + * This code is free software; you can redistribute it and/or modify it
   152.9 + * under the terms of the GNU General Public License version 2 only, as
  152.10 + * published by the Free Software Foundation.  Oracle designates this
  152.11 + * particular file as subject to the "Classpath" exception as provided
  152.12 + * by Oracle in the LICENSE file that accompanied this code.
  152.13 + *
  152.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  152.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  152.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  152.17 + * version 2 for more details (a copy is included in the LICENSE file that
  152.18 + * accompanied this code).
  152.19 + *
  152.20 + * You should have received a copy of the GNU General Public License version
  152.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  152.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  152.23 + *
  152.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  152.25 + * or visit www.oracle.com if you need additional information or have any
  152.26 + * questions.
  152.27 + */
  152.28 +
  152.29 +/*
  152.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
  152.31 + * (C) Copyright IBM Corp. 1996 - 1999 - All Rights Reserved
  152.32 + *
  152.33 + * The original version of this source code and documentation
  152.34 + * is copyrighted and owned by Taligent, Inc., a wholly-owned
  152.35 + * subsidiary of IBM. These materials are provided under terms
  152.36 + * of a License Agreement between Taligent and Sun. This technology
  152.37 + * is protected by multiple US and International patents.
  152.38 + *
  152.39 + * This notice and attribution to Taligent may not be removed.
  152.40 + * Taligent is a registered trademark of Taligent, Inc.
  152.41 + *
  152.42 + */
  152.43 +
  152.44 +package java.util;
  152.45 +
  152.46 +import java.io.IOException;
  152.47 +import java.io.InputStream;
  152.48 +import java.lang.ref.ReferenceQueue;
  152.49 +import java.lang.ref.SoftReference;
  152.50 +import java.lang.ref.WeakReference;
  152.51 +import java.net.URL;
  152.52 +
  152.53 +
  152.54 +/**
  152.55 + *
  152.56 + * Resource bundles contain locale-specific objects.  When your program needs a
  152.57 + * locale-specific resource, a <code>String</code> for example, your program can
  152.58 + * load it from the resource bundle that is appropriate for the current user's
  152.59 + * locale. In this way, you can write program code that is largely independent
  152.60 + * of the user's locale isolating most, if not all, of the locale-specific
  152.61 + * information in resource bundles.
  152.62 + *
  152.63 + * <p>
  152.64 + * This allows you to write programs that can:
  152.65 + * <UL type=SQUARE>
  152.66 + * <LI> be easily localized, or translated, into different languages
  152.67 + * <LI> handle multiple locales at once
  152.68 + * <LI> be easily modified later to support even more locales
  152.69 + * </UL>
  152.70 + *
  152.71 + * <P>
  152.72 + * Resource bundles belong to families whose members share a common base
  152.73 + * name, but whose names also have additional components that identify
  152.74 + * their locales. For example, the base name of a family of resource
  152.75 + * bundles might be "MyResources". The family should have a default
  152.76 + * resource bundle which simply has the same name as its family -
  152.77 + * "MyResources" - and will be used as the bundle of last resort if a
  152.78 + * specific locale is not supported. The family can then provide as
  152.79 + * many locale-specific members as needed, for example a German one
  152.80 + * named "MyResources_de".
  152.81 + *
  152.82 + * <P>
  152.83 + * Each resource bundle in a family contains the same items, but the items have
  152.84 + * been translated for the locale represented by that resource bundle.
  152.85 + * For example, both "MyResources" and "MyResources_de" may have a
  152.86 + * <code>String</code> that's used on a button for canceling operations.
  152.87 + * In "MyResources" the <code>String</code> may contain "Cancel" and in
  152.88 + * "MyResources_de" it may contain "Abbrechen".
  152.89 + *
  152.90 + * <P>
  152.91 + * If there are different resources for different countries, you
  152.92 + * can make specializations: for example, "MyResources_de_CH" contains objects for
  152.93 + * the German language (de) in Switzerland (CH). If you want to only
  152.94 + * modify some of the resources
  152.95 + * in the specialization, you can do so.
  152.96 + *
  152.97 + * <P>
  152.98 + * When your program needs a locale-specific object, it loads
  152.99 + * the <code>ResourceBundle</code> class using the
 152.100 + * {@link #getBundle(java.lang.String, java.util.Locale) getBundle}
 152.101 + * method:
 152.102 + * <blockquote>
 152.103 + * <pre>
 152.104 + * ResourceBundle myResources =
 152.105 + *      ResourceBundle.getBundle("MyResources", currentLocale);
 152.106 + * </pre>
 152.107 + * </blockquote>
 152.108 + *
 152.109 + * <P>
 152.110 + * Resource bundles contain key/value pairs. The keys uniquely
 152.111 + * identify a locale-specific object in the bundle. Here's an
 152.112 + * example of a <code>ListResourceBundle</code> that contains
 152.113 + * two key/value pairs:
 152.114 + * <blockquote>
 152.115 + * <pre>
 152.116 + * public class MyResources extends ListResourceBundle {
 152.117 + *     protected Object[][] getContents() {
 152.118 + *         return new Object[][] {
 152.119 + *             // LOCALIZE THE SECOND STRING OF EACH ARRAY (e.g., "OK")
 152.120 + *             {"OkKey", "OK"},
 152.121 + *             {"CancelKey", "Cancel"},
 152.122 + *             // END OF MATERIAL TO LOCALIZE
 152.123 + *        };
 152.124 + *     }
 152.125 + * }
 152.126 + * </pre>
 152.127 + * </blockquote>
 152.128 + * Keys are always <code>String</code>s.
 152.129 + * In this example, the keys are "OkKey" and "CancelKey".
 152.130 + * In the above example, the values
 152.131 + * are also <code>String</code>s--"OK" and "Cancel"--but
 152.132 + * they don't have to be. The values can be any type of object.
 152.133 + *
 152.134 + * <P>
 152.135 + * You retrieve an object from resource bundle using the appropriate
 152.136 + * getter method. Because "OkKey" and "CancelKey"
 152.137 + * are both strings, you would use <code>getString</code> to retrieve them:
 152.138 + * <blockquote>
 152.139 + * <pre>
 152.140 + * button1 = new Button(myResources.getString("OkKey"));
 152.141 + * button2 = new Button(myResources.getString("CancelKey"));
 152.142 + * </pre>
 152.143 + * </blockquote>
 152.144 + * The getter methods all require the key as an argument and return
 152.145 + * the object if found. If the object is not found, the getter method
 152.146 + * throws a <code>MissingResourceException</code>.
 152.147 + *
 152.148 + * <P>
 152.149 + * Besides <code>getString</code>, <code>ResourceBundle</code> also provides
 152.150 + * a method for getting string arrays, <code>getStringArray</code>,
 152.151 + * as well as a generic <code>getObject</code> method for any other
 152.152 + * type of object. When using <code>getObject</code>, you'll
 152.153 + * have to cast the result to the appropriate type. For example:
 152.154 + * <blockquote>
 152.155 + * <pre>
 152.156 + * int[] myIntegers = (int[]) myResources.getObject("intList");
 152.157 + * </pre>
 152.158 + * </blockquote>
 152.159 + *
 152.160 + * <P>
 152.161 + * The Java Platform provides two subclasses of <code>ResourceBundle</code>,
 152.162 + * <code>ListResourceBundle</code> and <code>PropertyResourceBundle</code>,
 152.163 + * that provide a fairly simple way to create resources.
 152.164 + * As you saw briefly in a previous example, <code>ListResourceBundle</code>
 152.165 + * manages its resource as a list of key/value pairs.
 152.166 + * <code>PropertyResourceBundle</code> uses a properties file to manage
 152.167 + * its resources.
 152.168 + *
 152.169 + * <p>
 152.170 + * If <code>ListResourceBundle</code> or <code>PropertyResourceBundle</code>
 152.171 + * do not suit your needs, you can write your own <code>ResourceBundle</code>
 152.172 + * subclass.  Your subclasses must override two methods: <code>handleGetObject</code>
 152.173 + * and <code>getKeys()</code>.
 152.174 + *
 152.175 + * <h4>ResourceBundle.Control</h4>
 152.176 + *
 152.177 + * The {@link ResourceBundle.Control} class provides information necessary
 152.178 + * to perform the bundle loading process by the <code>getBundle</code>
 152.179 + * factory methods that take a <code>ResourceBundle.Control</code>
 152.180 + * instance. You can implement your own subclass in order to enable
 152.181 + * non-standard resource bundle formats, change the search strategy, or
 152.182 + * define caching parameters. Refer to the descriptions of the class and the
 152.183 + * {@link #getBundle(String, Locale, ClassLoader, Control) getBundle}
 152.184 + * factory method for details.
 152.185 + *
 152.186 + * <h4>Cache Management</h4>
 152.187 + *
 152.188 + * Resource bundle instances created by the <code>getBundle</code> factory
 152.189 + * methods are cached by default, and the factory methods return the same
 152.190 + * resource bundle instance multiple times if it has been
 152.191 + * cached. <code>getBundle</code> clients may clear the cache, manage the
 152.192 + * lifetime of cached resource bundle instances using time-to-live values,
 152.193 + * or specify not to cache resource bundle instances. Refer to the
 152.194 + * descriptions of the {@linkplain #getBundle(String, Locale, ClassLoader,
 152.195 + * Control) <code>getBundle</code> factory method}, {@link
 152.196 + * #clearCache(ClassLoader) clearCache}, {@link
 152.197 + * Control#getTimeToLive(String, Locale)
 152.198 + * ResourceBundle.Control.getTimeToLive}, and {@link
 152.199 + * Control#needsReload(String, Locale, String, ClassLoader, ResourceBundle,
 152.200 + * long) ResourceBundle.Control.needsReload} for details.
 152.201 + *
 152.202 + * <h4>Example</h4>
 152.203 + *
 152.204 + * The following is a very simple example of a <code>ResourceBundle</code>
 152.205 + * subclass, <code>MyResources</code>, that manages two resources (for a larger number of
 152.206 + * resources you would probably use a <code>Map</code>).
 152.207 + * Notice that you don't need to supply a value if
 152.208 + * a "parent-level" <code>ResourceBundle</code> handles the same
 152.209 + * key with the same value (as for the okKey below).
 152.210 + * <blockquote>
 152.211 + * <pre>
 152.212 + * // default (English language, United States)
 152.213 + * public class MyResources extends ResourceBundle {
 152.214 + *     public Object handleGetObject(String key) {
 152.215 + *         if (key.equals("okKey")) return "Ok";
 152.216 + *         if (key.equals("cancelKey")) return "Cancel";
 152.217 + *         return null;
 152.218 + *     }
 152.219 + *
 152.220 + *     public Enumeration&lt;String&gt; getKeys() {
 152.221 + *         return Collections.enumeration(keySet());
 152.222 + *     }
 152.223 + *
 152.224 + *     // Overrides handleKeySet() so that the getKeys() implementation
 152.225 + *     // can rely on the keySet() value.
 152.226 + *     protected Set&lt;String&gt; handleKeySet() {
 152.227 + *         return new HashSet&lt;String&gt;(Arrays.asList("okKey", "cancelKey"));
 152.228 + *     }
 152.229 + * }
 152.230 + *
 152.231 + * // German language
 152.232 + * public class MyResources_de extends MyResources {
 152.233 + *     public Object handleGetObject(String key) {
 152.234 + *         // don't need okKey, since parent level handles it.
 152.235 + *         if (key.equals("cancelKey")) return "Abbrechen";
 152.236 + *         return null;
 152.237 + *     }
 152.238 + *
 152.239 + *     protected Set&lt;String&gt; handleKeySet() {
 152.240 + *         return new HashSet&lt;String&gt;(Arrays.asList("cancelKey"));
 152.241 + *     }
 152.242 + * }
 152.243 + * </pre>
 152.244 + * </blockquote>
 152.245 + * You do not have to restrict yourself to using a single family of
 152.246 + * <code>ResourceBundle</code>s. For example, you could have a set of bundles for
 152.247 + * exception messages, <code>ExceptionResources</code>
 152.248 + * (<code>ExceptionResources_fr</code>, <code>ExceptionResources_de</code>, ...),
 152.249 + * and one for widgets, <code>WidgetResource</code> (<code>WidgetResources_fr</code>,
 152.250 + * <code>WidgetResources_de</code>, ...); breaking up the resources however you like.
 152.251 + *
 152.252 + * @see ListResourceBundle
 152.253 + * @see PropertyResourceBundle
 152.254 + * @see MissingResourceException
 152.255 + * @since JDK1.1
 152.256 + */
 152.257 +public abstract class ResourceBundle {
 152.258 +
 152.259 +    /** initial size of the bundle cache */
 152.260 +    private static final int INITIAL_CACHE_SIZE = 32;
 152.261 +
 152.262 +    /** constant indicating that no resource bundle exists */
 152.263 +    private static final ResourceBundle NONEXISTENT_BUNDLE = new ResourceBundle() {
 152.264 +            public Enumeration<String> getKeys() { return null; }
 152.265 +            protected Object handleGetObject(String key) { return null; }
 152.266 +            public String toString() { return "NONEXISTENT_BUNDLE"; }
 152.267 +        };
 152.268 +
 152.269 +
 152.270 +    /**
 152.271 +     * The cache is a map from cache keys (with bundle base name, locale, and
 152.272 +     * class loader) to either a resource bundle or NONEXISTENT_BUNDLE wrapped by a
 152.273 +     * BundleReference.
 152.274 +     *
 152.275 +     * The cache is a ConcurrentMap, allowing the cache to be searched
 152.276 +     * concurrently by multiple threads.  This will also allow the cache keys
 152.277 +     * to be reclaimed along with the ClassLoaders they reference.
 152.278 +     *
 152.279 +     * This variable would be better named "cache", but we keep the old
 152.280 +     * name for compatibility with some workarounds for bug 4212439.
 152.281 +     */
 152.282 +    private static final Map<CacheKey, BundleReference> cacheList
 152.283 +        = new HashMap<>(INITIAL_CACHE_SIZE);
 152.284 +
 152.285 +    /**
 152.286 +     * Queue for reference objects referring to class loaders or bundles.
 152.287 +     */
 152.288 +    private static final ReferenceQueue referenceQueue = new ReferenceQueue();
 152.289 +
 152.290 +    /**
 152.291 +     * The parent bundle of this bundle.
 152.292 +     * The parent bundle is searched by {@link #getObject getObject}
 152.293 +     * when this bundle does not contain a particular resource.
 152.294 +     */
 152.295 +    protected ResourceBundle parent = null;
 152.296 +
 152.297 +    /**
 152.298 +     * The locale for this bundle.
 152.299 +     */
 152.300 +    private Locale locale = null;
 152.301 +
 152.302 +    /**
 152.303 +     * The base bundle name for this bundle.
 152.304 +     */
 152.305 +    private String name;
 152.306 +
 152.307 +    /**
 152.308 +     * The flag indicating this bundle has expired in the cache.
 152.309 +     */
 152.310 +    private volatile boolean expired;
 152.311 +
 152.312 +    /**
 152.313 +     * The back link to the cache key. null if this bundle isn't in
 152.314 +     * the cache (yet) or has expired.
 152.315 +     */
 152.316 +    private volatile CacheKey cacheKey;
 152.317 +
 152.318 +    /**
 152.319 +     * A Set of the keys contained only in this ResourceBundle.
 152.320 +     */
 152.321 +    private volatile Set<String> keySet;
 152.322 +
 152.323 +    /**
 152.324 +     * Sole constructor.  (For invocation by subclass constructors, typically
 152.325 +     * implicit.)
 152.326 +     */
 152.327 +    public ResourceBundle() {
 152.328 +    }
 152.329 +
 152.330 +    /**
 152.331 +     * Gets a string for the given key from this resource bundle or one of its parents.
 152.332 +     * Calling this method is equivalent to calling
 152.333 +     * <blockquote>
 152.334 +     * <code>(String) {@link #getObject(java.lang.String) getObject}(key)</code>.
 152.335 +     * </blockquote>
 152.336 +     *
 152.337 +     * @param key the key for the desired string
 152.338 +     * @exception NullPointerException if <code>key</code> is <code>null</code>
 152.339 +     * @exception MissingResourceException if no object for the given key can be found
 152.340 +     * @exception ClassCastException if the object found for the given key is not a string
 152.341 +     * @return the string for the given key
 152.342 +     */
 152.343 +    public final String getString(String key) {
 152.344 +        return (String) getObject(key);
 152.345 +    }
 152.346 +
 152.347 +    /**
 152.348 +     * Gets a string array for the given key from this resource bundle or one of its parents.
 152.349 +     * Calling this method is equivalent to calling
 152.350 +     * <blockquote>
 152.351 +     * <code>(String[]) {@link #getObject(java.lang.String) getObject}(key)</code>.
 152.352 +     * </blockquote>
 152.353 +     *
 152.354 +     * @param key the key for the desired string array
 152.355 +     * @exception NullPointerException if <code>key</code> is <code>null</code>
 152.356 +     * @exception MissingResourceException if no object for the given key can be found
 152.357 +     * @exception ClassCastException if the object found for the given key is not a string array
 152.358 +     * @return the string array for the given key
 152.359 +     */
 152.360 +    public final String[] getStringArray(String key) {
 152.361 +        return (String[]) getObject(key);
 152.362 +    }
 152.363 +
 152.364 +    /**
 152.365 +     * Gets an object for the given key from this resource bundle or one of its parents.
 152.366 +     * This method first tries to obtain the object from this resource bundle using
 152.367 +     * {@link #handleGetObject(java.lang.String) handleGetObject}.
 152.368 +     * If not successful, and the parent resource bundle is not null,
 152.369 +     * it calls the parent's <code>getObject</code> method.
 152.370 +     * If still not successful, it throws a MissingResourceException.
 152.371 +     *
 152.372 +     * @param key the key for the desired object
 152.373 +     * @exception NullPointerException if <code>key</code> is <code>null</code>
 152.374 +     * @exception MissingResourceException if no object for the given key can be found
 152.375 +     * @return the object for the given key
 152.376 +     */
 152.377 +    public final Object getObject(String key) {
 152.378 +        Object obj = handleGetObject(key);
 152.379 +        if (obj == null) {
 152.380 +            if (parent != null) {
 152.381 +                obj = parent.getObject(key);
 152.382 +            }
 152.383 +            if (obj == null)
 152.384 +                throw new MissingResourceException("Can't find resource for bundle "
 152.385 +                                                   +this.getClass().getName()
 152.386 +                                                   +", key "+key,
 152.387 +                                                   this.getClass().getName(),
 152.388 +                                                   key);
 152.389 +        }
 152.390 +        return obj;
 152.391 +    }
 152.392 +
 152.393 +    /**
 152.394 +     * Returns the locale of this resource bundle. This method can be used after a
 152.395 +     * call to getBundle() to determine whether the resource bundle returned really
 152.396 +     * corresponds to the requested locale or is a fallback.
 152.397 +     *
 152.398 +     * @return the locale of this resource bundle
 152.399 +     */
 152.400 +    public Locale getLocale() {
 152.401 +        return locale;
 152.402 +    }
 152.403 +
 152.404 +    /**
 152.405 +     * Sets the parent bundle of this bundle.
 152.406 +     * The parent bundle is searched by {@link #getObject getObject}
 152.407 +     * when this bundle does not contain a particular resource.
 152.408 +     *
 152.409 +     * @param parent this bundle's parent bundle.
 152.410 +     */
 152.411 +    protected void setParent(ResourceBundle parent) {
 152.412 +        assert parent != NONEXISTENT_BUNDLE;
 152.413 +        this.parent = parent;
 152.414 +    }
 152.415 +
 152.416 +    /**
 152.417 +     * Key used for cached resource bundles.  The key checks the base
 152.418 +     * name, the locale, and the class loader to determine if the
 152.419 +     * resource is a match to the requested one. The loader may be
 152.420 +     * null, but the base name and the locale must have a non-null
 152.421 +     * value.
 152.422 +     */
 152.423 +    private static final class CacheKey implements Cloneable {
 152.424 +        // These three are the actual keys for lookup in Map.
 152.425 +        private String name;
 152.426 +        private Locale locale;
 152.427 +
 152.428 +        // bundle format which is necessary for calling
 152.429 +        // Control.needsReload().
 152.430 +        private String format;
 152.431 +
 152.432 +        // These time values are in CacheKey so that NONEXISTENT_BUNDLE
 152.433 +        // doesn't need to be cloned for caching.
 152.434 +
 152.435 +        // The time when the bundle has been loaded
 152.436 +        private volatile long loadTime;
 152.437 +
 152.438 +        // The time when the bundle expires in the cache, or either
 152.439 +        // Control.TTL_DONT_CACHE or Control.TTL_NO_EXPIRATION_CONTROL.
 152.440 +        private volatile long expirationTime;
 152.441 +
 152.442 +        // Placeholder for an error report by a Throwable
 152.443 +        private Throwable cause;
 152.444 +
 152.445 +        // Hash code value cache to avoid recalculating the hash code
 152.446 +        // of this instance.
 152.447 +        private int hashCodeCache;
 152.448 +
 152.449 +        CacheKey(String baseName, Locale locale) {
 152.450 +            this.name = baseName;
 152.451 +            this.locale = locale;
 152.452 +            calculateHashCode();
 152.453 +        }
 152.454 +
 152.455 +        String getName() {
 152.456 +            return name;
 152.457 +        }
 152.458 +
 152.459 +        CacheKey setName(String baseName) {
 152.460 +            if (!this.name.equals(baseName)) {
 152.461 +                this.name = baseName;
 152.462 +                calculateHashCode();
 152.463 +            }
 152.464 +            return this;
 152.465 +        }
 152.466 +
 152.467 +        Locale getLocale() {
 152.468 +            return locale;
 152.469 +        }
 152.470 +
 152.471 +        CacheKey setLocale(Locale locale) {
 152.472 +            if (!this.locale.equals(locale)) {
 152.473 +                this.locale = locale;
 152.474 +                calculateHashCode();
 152.475 +            }
 152.476 +            return this;
 152.477 +        }
 152.478 +
 152.479 +        public boolean equals(Object other) {
 152.480 +            if (this == other) {
 152.481 +                return true;
 152.482 +            }
 152.483 +            try {
 152.484 +                final CacheKey otherEntry = (CacheKey)other;
 152.485 +                //quick check to see if they are not equal
 152.486 +                if (hashCodeCache != otherEntry.hashCodeCache) {
 152.487 +                    return false;
 152.488 +                }
 152.489 +                //are the names the same?
 152.490 +                if (!name.equals(otherEntry.name)) {
 152.491 +                    return false;
 152.492 +                }
 152.493 +                // are the locales the same?
 152.494 +                if (!locale.equals(otherEntry.locale)) {
 152.495 +                    return false;
 152.496 +                }
 152.497 +                return true;
 152.498 +            } catch (NullPointerException e) {
 152.499 +            } catch (ClassCastException e) {
 152.500 +            }
 152.501 +            return false;
 152.502 +        }
 152.503 +
 152.504 +        public int hashCode() {
 152.505 +            return hashCodeCache;
 152.506 +        }
 152.507 +
 152.508 +        private void calculateHashCode() {
 152.509 +            hashCodeCache = name.hashCode() << 3;
 152.510 +            hashCodeCache ^= locale.hashCode();
 152.511 +        }
 152.512 +
 152.513 +        public Object clone() {
 152.514 +            try {
 152.515 +                CacheKey clone = (CacheKey) super.clone();
 152.516 +                // Clear the reference to a Throwable
 152.517 +                clone.cause = null;
 152.518 +                return clone;
 152.519 +            } catch (CloneNotSupportedException e) {
 152.520 +                //this should never happen
 152.521 +                throw new InternalError();
 152.522 +            }
 152.523 +        }
 152.524 +
 152.525 +        String getFormat() {
 152.526 +            return format;
 152.527 +        }
 152.528 +
 152.529 +        void setFormat(String format) {
 152.530 +            this.format = format;
 152.531 +        }
 152.532 +
 152.533 +        private void setCause(Throwable cause) {
 152.534 +            if (this.cause == null) {
 152.535 +                this.cause = cause;
 152.536 +            } else {
 152.537 +                // Override the cause if the previous one is
 152.538 +                // ClassNotFoundException.
 152.539 +                if (this.cause instanceof ClassNotFoundException) {
 152.540 +                    this.cause = cause;
 152.541 +                }
 152.542 +            }
 152.543 +        }
 152.544 +
 152.545 +        private Throwable getCause() {
 152.546 +            return cause;
 152.547 +        }
 152.548 +
 152.549 +        public String toString() {
 152.550 +            String l = locale.toString();
 152.551 +            if (l.length() == 0) {
 152.552 +                if (locale.getVariant().length() != 0) {
 152.553 +                    l = "__" + locale.getVariant();
 152.554 +                } else {
 152.555 +                    l = "\"\"";
 152.556 +                }
 152.557 +            }
 152.558 +            return "CacheKey[" + name + ", lc=" + l
 152.559 +                + "(format=" + format + ")]";
 152.560 +        }
 152.561 +    }
 152.562 +
 152.563 +    /**
 152.564 +     * The common interface to get a CacheKey in LoaderReference and
 152.565 +     * BundleReference.
 152.566 +     */
 152.567 +    private static interface CacheKeyReference {
 152.568 +        public CacheKey getCacheKey();
 152.569 +    }
 152.570 +
 152.571 +    /**
 152.572 +     * References to bundles are soft references so that they can be garbage
 152.573 +     * collected when they have no hard references.
 152.574 +     */
 152.575 +    private static final class BundleReference extends SoftReference<ResourceBundle>
 152.576 +                                               implements CacheKeyReference {
 152.577 +        private CacheKey cacheKey;
 152.578 +
 152.579 +        BundleReference(ResourceBundle referent, ReferenceQueue q, CacheKey key) {
 152.580 +            super(referent, q);
 152.581 +            cacheKey = key;
 152.582 +        }
 152.583 +
 152.584 +        public CacheKey getCacheKey() {
 152.585 +            return cacheKey;
 152.586 +        }
 152.587 +    }
 152.588 +
 152.589 +    /**
 152.590 +     * Gets a resource bundle using the specified base name, the default locale,
 152.591 +     * and the caller's class loader. Calling this method is equivalent to calling
 152.592 +     * <blockquote>
 152.593 +     * <code>getBundle(baseName, Locale.getDefault(), this.getClass().getClassLoader())</code>,
 152.594 +     * </blockquote>
 152.595 +     * except that <code>getClassLoader()</code> is run with the security
 152.596 +     * privileges of <code>ResourceBundle</code>.
 152.597 +     * See {@link #getBundle(String, Locale, ClassLoader) getBundle}
 152.598 +     * for a complete description of the search and instantiation strategy.
 152.599 +     *
 152.600 +     * @param baseName the base name of the resource bundle, a fully qualified class name
 152.601 +     * @exception java.lang.NullPointerException
 152.602 +     *     if <code>baseName</code> is <code>null</code>
 152.603 +     * @exception MissingResourceException
 152.604 +     *     if no resource bundle for the specified base name can be found
 152.605 +     * @return a resource bundle for the given base name and the default locale
 152.606 +     */
 152.607 +    public static final ResourceBundle getBundle(String baseName)
 152.608 +    {
 152.609 +        return getBundleImpl(baseName, Locale.getDefault(),
 152.610 +                             Control.INSTANCE);
 152.611 +    }
 152.612 +
 152.613 +    /**
 152.614 +     * Returns a resource bundle using the specified base name, the
 152.615 +     * default locale and the specified control. Calling this method
 152.616 +     * is equivalent to calling
 152.617 +     * <pre>
 152.618 +     * getBundle(baseName, Locale.getDefault(),
 152.619 +     *           this.getClass().getClassLoader(), control),
 152.620 +     * </pre>
 152.621 +     * except that <code>getClassLoader()</code> is run with the security
 152.622 +     * privileges of <code>ResourceBundle</code>.  See {@link
 152.623 +     * #getBundle(String, Locale, ClassLoader, Control) getBundle} for the
 152.624 +     * complete description of the resource bundle loading process with a
 152.625 +     * <code>ResourceBundle.Control</code>.
 152.626 +     *
 152.627 +     * @param baseName
 152.628 +     *        the base name of the resource bundle, a fully qualified class
 152.629 +     *        name
 152.630 +     * @param control
 152.631 +     *        the control which gives information for the resource bundle
 152.632 +     *        loading process
 152.633 +     * @return a resource bundle for the given base name and the default
 152.634 +     *        locale
 152.635 +     * @exception NullPointerException
 152.636 +     *        if <code>baseName</code> or <code>control</code> is
 152.637 +     *        <code>null</code>
 152.638 +     * @exception MissingResourceException
 152.639 +     *        if no resource bundle for the specified base name can be found
 152.640 +     * @exception IllegalArgumentException
 152.641 +     *        if the given <code>control</code> doesn't perform properly
 152.642 +     *        (e.g., <code>control.getCandidateLocales</code> returns null.)
 152.643 +     *        Note that validation of <code>control</code> is performed as
 152.644 +     *        needed.
 152.645 +     * @since 1.6
 152.646 +     */
 152.647 +    public static final ResourceBundle getBundle(String baseName,
 152.648 +                                                 Control control) {
 152.649 +        return getBundleImpl(baseName, Locale.getDefault(),
 152.650 +                             /* must determine loader here, else we break stack invariant */
 152.651 +                             control);
 152.652 +    }
 152.653 +
 152.654 +    /**
 152.655 +     * Gets a resource bundle using the specified base name and locale,
 152.656 +     * and the caller's class loader. Calling this method is equivalent to calling
 152.657 +     * <blockquote>
 152.658 +     * <code>getBundle(baseName, locale, this.getClass().getClassLoader())</code>,
 152.659 +     * </blockquote>
 152.660 +     * except that <code>getClassLoader()</code> is run with the security
 152.661 +     * privileges of <code>ResourceBundle</code>.
 152.662 +     * See {@link #getBundle(String, Locale, ClassLoader) getBundle}
 152.663 +     * for a complete description of the search and instantiation strategy.
 152.664 +     *
 152.665 +     * @param baseName
 152.666 +     *        the base name of the resource bundle, a fully qualified class name
 152.667 +     * @param locale
 152.668 +     *        the locale for which a resource bundle is desired
 152.669 +     * @exception NullPointerException
 152.670 +     *        if <code>baseName</code> or <code>locale</code> is <code>null</code>
 152.671 +     * @exception MissingResourceException
 152.672 +     *        if no resource bundle for the specified base name can be found
 152.673 +     * @return a resource bundle for the given base name and locale
 152.674 +     */
 152.675 +    public static final ResourceBundle getBundle(String baseName,
 152.676 +                                                 Locale locale)
 152.677 +    {
 152.678 +        return getBundleImpl(baseName, locale,
 152.679 +                             /* must determine loader here, else we break stack invariant */
 152.680 +                             Control.INSTANCE);
 152.681 +    }
 152.682 +
 152.683 +    /**
 152.684 +     * Returns a resource bundle using the specified base name, target
 152.685 +     * locale and control, and the caller's class loader. Calling this
 152.686 +     * method is equivalent to calling
 152.687 +     * <pre>
 152.688 +     * getBundle(baseName, targetLocale, this.getClass().getClassLoader(),
 152.689 +     *           control),
 152.690 +     * </pre>
 152.691 +     * except that <code>getClassLoader()</code> is run with the security
 152.692 +     * privileges of <code>ResourceBundle</code>.  See {@link
 152.693 +     * #getBundle(String, Locale, ClassLoader, Control) getBundle} for the
 152.694 +     * complete description of the resource bundle loading process with a
 152.695 +     * <code>ResourceBundle.Control</code>.
 152.696 +     *
 152.697 +     * @param baseName
 152.698 +     *        the base name of the resource bundle, a fully qualified
 152.699 +     *        class name
 152.700 +     * @param targetLocale
 152.701 +     *        the locale for which a resource bundle is desired
 152.702 +     * @param control
 152.703 +     *        the control which gives information for the resource
 152.704 +     *        bundle loading process
 152.705 +     * @return a resource bundle for the given base name and a
 152.706 +     *        <code>Locale</code> in <code>locales</code>
 152.707 +     * @exception NullPointerException
 152.708 +     *        if <code>baseName</code>, <code>locales</code> or
 152.709 +     *        <code>control</code> is <code>null</code>
 152.710 +     * @exception MissingResourceException
 152.711 +     *        if no resource bundle for the specified base name in any
 152.712 +     *        of the <code>locales</code> can be found.
 152.713 +     * @exception IllegalArgumentException
 152.714 +     *        if the given <code>control</code> doesn't perform properly
 152.715 +     *        (e.g., <code>control.getCandidateLocales</code> returns null.)
 152.716 +     *        Note that validation of <code>control</code> is performed as
 152.717 +     *        needed.
 152.718 +     * @since 1.6
 152.719 +     */
 152.720 +    public static final ResourceBundle getBundle(String baseName, Locale targetLocale,
 152.721 +                                                 Control control) {
 152.722 +        return getBundleImpl(baseName, targetLocale,
 152.723 +                             /* must determine loader here, else we break stack invariant */
 152.724 +                             control);
 152.725 +    }
 152.726 +
 152.727 +    /**
 152.728 +     * Gets a resource bundle using the specified base name, locale, and class
 152.729 +     * loader.
 152.730 +     *
 152.731 +     * <p><a name="default_behavior"/>This method behaves the same as calling
 152.732 +     * {@link #getBundle(String, Locale, ClassLoader, Control)} passing a
 152.733 +     * default instance of {@link Control}. The following describes this behavior.
 152.734 +     *
 152.735 +     * <p><code>getBundle</code> uses the base name, the specified locale, and
 152.736 +     * the default locale (obtained from {@link java.util.Locale#getDefault()
 152.737 +     * Locale.getDefault}) to generate a sequence of <a
 152.738 +     * name="candidates"><em>candidate bundle names</em></a>.  If the specified
 152.739 +     * locale's language, script, country, and variant are all empty strings,
 152.740 +     * then the base name is the only candidate bundle name.  Otherwise, a list
 152.741 +     * of candidate locales is generated from the attribute values of the
 152.742 +     * specified locale (language, script, country and variant) and appended to
 152.743 +     * the base name.  Typically, this will look like the following:
 152.744 +     *
 152.745 +     * <pre>
 152.746 +     *     baseName + "_" + language + "_" + script + "_" + country + "_" + variant
 152.747 +     *     baseName + "_" + language + "_" + script + "_" + country
 152.748 +     *     baseName + "_" + language + "_" + script
 152.749 +     *     baseName + "_" + language + "_" + country + "_" + variant
 152.750 +     *     baseName + "_" + language + "_" + country
 152.751 +     *     baseName + "_" + language
 152.752 +     * </pre>
 152.753 +     *
 152.754 +     * <p>Candidate bundle names where the final component is an empty string
 152.755 +     * are omitted, along with the underscore.  For example, if country is an
 152.756 +     * empty string, the second and the fifth candidate bundle names above
 152.757 +     * would be omitted.  Also, if script is an empty string, the candidate names
 152.758 +     * including script are omitted.  For example, a locale with language "de"
 152.759 +     * and variant "JAVA" will produce candidate names with base name
 152.760 +     * "MyResource" below.
 152.761 +     *
 152.762 +     * <pre>
 152.763 +     *     MyResource_de__JAVA
 152.764 +     *     MyResource_de
 152.765 +     * </pre>
 152.766 +     *
 152.767 +     * In the case that the variant contains one or more underscores ('_'), a
 152.768 +     * sequence of bundle names generated by truncating the last underscore and
 152.769 +     * the part following it is inserted after a candidate bundle name with the
 152.770 +     * original variant.  For example, for a locale with language "en", script
 152.771 +     * "Latn, country "US" and variant "WINDOWS_VISTA", and bundle base name
 152.772 +     * "MyResource", the list of candidate bundle names below is generated:
 152.773 +     *
 152.774 +     * <pre>
 152.775 +     * MyResource_en_Latn_US_WINDOWS_VISTA
 152.776 +     * MyResource_en_Latn_US_WINDOWS
 152.777 +     * MyResource_en_Latn_US
 152.778 +     * MyResource_en_Latn
 152.779 +     * MyResource_en_US_WINDOWS_VISTA
 152.780 +     * MyResource_en_US_WINDOWS
 152.781 +     * MyResource_en_US
 152.782 +     * MyResource_en
 152.783 +     * </pre>
 152.784 +     *
 152.785 +     * <blockquote><b>Note:</b> For some <code>Locale</code>s, the list of
 152.786 +     * candidate bundle names contains extra names, or the order of bundle names
 152.787 +     * is slightly modified.  See the description of the default implementation
 152.788 +     * of {@link Control#getCandidateLocales(String, Locale)
 152.789 +     * getCandidateLocales} for details.</blockquote>
 152.790 +     *
 152.791 +     * <p><code>getBundle</code> then iterates over the candidate bundle names
 152.792 +     * to find the first one for which it can <em>instantiate</em> an actual
 152.793 +     * resource bundle. It uses the default controls' {@link Control#getFormats
 152.794 +     * getFormats} method, which generates two bundle names for each generated
 152.795 +     * name, the first a class name and the second a properties file name. For
 152.796 +     * each candidate bundle name, it attempts to create a resource bundle:
 152.797 +     *
 152.798 +     * <ul><li>First, it attempts to load a class using the generated class name.
 152.799 +     * If such a class can be found and loaded using the specified class
 152.800 +     * loader, is assignment compatible with ResourceBundle, is accessible from
 152.801 +     * ResourceBundle, and can be instantiated, <code>getBundle</code> creates a
 152.802 +     * new instance of this class and uses it as the <em>result resource
 152.803 +     * bundle</em>.
 152.804 +     *
 152.805 +     * <li>Otherwise, <code>getBundle</code> attempts to locate a property
 152.806 +     * resource file using the generated properties file name.  It generates a
 152.807 +     * path name from the candidate bundle name by replacing all "." characters
 152.808 +     * with "/" and appending the string ".properties".  It attempts to find a
 152.809 +     * "resource" with this name using {@link
 152.810 +     * java.lang.ClassLoader#getResource(java.lang.String)
 152.811 +     * ClassLoader.getResource}.  (Note that a "resource" in the sense of
 152.812 +     * <code>getResource</code> has nothing to do with the contents of a
 152.813 +     * resource bundle, it is just a container of data, such as a file.)  If it
 152.814 +     * finds a "resource", it attempts to create a new {@link
 152.815 +     * PropertyResourceBundle} instance from its contents.  If successful, this
 152.816 +     * instance becomes the <em>result resource bundle</em>.  </ul>
 152.817 +     *
 152.818 +     * <p>This continues until a result resource bundle is instantiated or the
 152.819 +     * list of candidate bundle names is exhausted.  If no matching resource
 152.820 +     * bundle is found, the default control's {@link Control#getFallbackLocale
 152.821 +     * getFallbackLocale} method is called, which returns the current default
 152.822 +     * locale.  A new sequence of candidate locale names is generated using this
 152.823 +     * locale and and searched again, as above.
 152.824 +     *
 152.825 +     * <p>If still no result bundle is found, the base name alone is looked up. If
 152.826 +     * this still fails, a <code>MissingResourceException</code> is thrown.
 152.827 +     *
 152.828 +     * <p><a name="parent_chain"/> Once a result resource bundle has been found,
 152.829 +     * its <em>parent chain</em> is instantiated.  If the result bundle already
 152.830 +     * has a parent (perhaps because it was returned from a cache) the chain is
 152.831 +     * complete.
 152.832 +     *
 152.833 +     * <p>Otherwise, <code>getBundle</code> examines the remainder of the
 152.834 +     * candidate locale list that was used during the pass that generated the
 152.835 +     * result resource bundle.  (As before, candidate bundle names where the
 152.836 +     * final component is an empty string are omitted.)  When it comes to the
 152.837 +     * end of the candidate list, it tries the plain bundle name.  With each of the
 152.838 +     * candidate bundle names it attempts to instantiate a resource bundle (first
 152.839 +     * looking for a class and then a properties file, as described above).
 152.840 +     *
 152.841 +     * <p>Whenever it succeeds, it calls the previously instantiated resource
 152.842 +     * bundle's {@link #setParent(java.util.ResourceBundle) setParent} method
 152.843 +     * with the new resource bundle.  This continues until the list of names
 152.844 +     * is exhausted or the current bundle already has a non-null parent.
 152.845 +     *
 152.846 +     * <p>Once the parent chain is complete, the bundle is returned.
 152.847 +     *
 152.848 +     * <p><b>Note:</b> <code>getBundle</code> caches instantiated resource
 152.849 +     * bundles and might return the same resource bundle instance multiple times.
 152.850 +     *
 152.851 +     * <p><b>Note:</b>The <code>baseName</code> argument should be a fully
 152.852 +     * qualified class name. However, for compatibility with earlier versions,
 152.853 +     * Sun's Java SE Runtime Environments do not verify this, and so it is
 152.854 +     * possible to access <code>PropertyResourceBundle</code>s by specifying a
 152.855 +     * path name (using "/") instead of a fully qualified class name (using
 152.856 +     * ".").
 152.857 +     *
 152.858 +     * <p><a name="default_behavior_example"/>
 152.859 +     * <strong>Example:</strong>
 152.860 +     * <p>
 152.861 +     * The following class and property files are provided:
 152.862 +     * <pre>
 152.863 +     *     MyResources.class
 152.864 +     *     MyResources.properties
 152.865 +     *     MyResources_fr.properties
 152.866 +     *     MyResources_fr_CH.class
 152.867 +     *     MyResources_fr_CH.properties
 152.868 +     *     MyResources_en.properties
 152.869 +     *     MyResources_es_ES.class
 152.870 +     * </pre>
 152.871 +     *
 152.872 +     * The contents of all files are valid (that is, public non-abstract
 152.873 +     * subclasses of <code>ResourceBundle</code> for the ".class" files,
 152.874 +     * syntactically correct ".properties" files).  The default locale is
 152.875 +     * <code>Locale("en", "GB")</code>.
 152.876 +     *
 152.877 +     * <p>Calling <code>getBundle</code> with the locale arguments below will
 152.878 +     * instantiate resource bundles as follows:
 152.879 +     *
 152.880 +     * <table>
 152.881 +     * <tr><td>Locale("fr", "CH")</td><td>MyResources_fr_CH.class, parent MyResources_fr.properties, parent MyResources.class</td></tr>
 152.882 +     * <tr><td>Locale("fr", "FR")</td><td>MyResources_fr.properties, parent MyResources.class</td></tr>
 152.883 +     * <tr><td>Locale("de", "DE")</td><td>MyResources_en.properties, parent MyResources.class</td></tr>
 152.884 +     * <tr><td>Locale("en", "US")</td><td>MyResources_en.properties, parent MyResources.class</td></tr>
 152.885 +     * <tr><td>Locale("es", "ES")</td><td>MyResources_es_ES.class, parent MyResources.class</td></tr>
 152.886 +     * </table>
 152.887 +     *
 152.888 +     * <p>The file MyResources_fr_CH.properties is never used because it is
 152.889 +     * hidden by the MyResources_fr_CH.class. Likewise, MyResources.properties
 152.890 +     * is also hidden by MyResources.class.
 152.891 +     *
 152.892 +     * @param baseName the base name of the resource bundle, a fully qualified class name
 152.893 +     * @param locale the locale for which a resource bundle is desired
 152.894 +     * @param loader the class loader from which to load the resource bundle
 152.895 +     * @return a resource bundle for the given base name and locale
 152.896 +     * @exception java.lang.NullPointerException
 152.897 +     *        if <code>baseName</code>, <code>locale</code>, or <code>loader</code> is <code>null</code>
 152.898 +     * @exception MissingResourceException
 152.899 +     *        if no resource bundle for the specified base name can be found
 152.900 +     * @since 1.2
 152.901 +     */
 152.902 +    public static ResourceBundle getBundle(String baseName, Locale locale,
 152.903 +                                           ClassLoader loader)
 152.904 +    {
 152.905 +        if (loader == null) {
 152.906 +            throw new NullPointerException();
 152.907 +        }
 152.908 +        return getBundleImpl(baseName, locale, Control.INSTANCE);
 152.909 +    }
 152.910 +
 152.911 +    /**
 152.912 +     * Returns a resource bundle using the specified base name, target
 152.913 +     * locale, class loader and control. Unlike the {@linkplain
 152.914 +     * #getBundle(String, Locale, ClassLoader) <code>getBundle</code>
 152.915 +     * factory methods with no <code>control</code> argument}, the given
 152.916 +     * <code>control</code> specifies how to locate and instantiate resource
 152.917 +     * bundles. Conceptually, the bundle loading process with the given
 152.918 +     * <code>control</code> is performed in the following steps.
 152.919 +     *
 152.920 +     * <p>
 152.921 +     * <ol>
 152.922 +     * <li>This factory method looks up the resource bundle in the cache for
 152.923 +     * the specified <code>baseName</code>, <code>targetLocale</code> and
 152.924 +     * <code>loader</code>.  If the requested resource bundle instance is
 152.925 +     * found in the cache and the time-to-live periods of the instance and
 152.926 +     * all of its parent instances have not expired, the instance is returned
 152.927 +     * to the caller. Otherwise, this factory method proceeds with the
 152.928 +     * loading process below.</li>
 152.929 +     *
 152.930 +     * <li>The {@link ResourceBundle.Control#getFormats(String)
 152.931 +     * control.getFormats} method is called to get resource bundle formats
 152.932 +     * to produce bundle or resource names. The strings
 152.933 +     * <code>"java.class"</code> and <code>"java.properties"</code>
 152.934 +     * designate class-based and {@linkplain PropertyResourceBundle
 152.935 +     * property}-based resource bundles, respectively. Other strings
 152.936 +     * starting with <code>"java."</code> are reserved for future extensions
 152.937 +     * and must not be used for application-defined formats. Other strings
 152.938 +     * designate application-defined formats.</li>
 152.939 +     *
 152.940 +     * <li>The {@link ResourceBundle.Control#getCandidateLocales(String,
 152.941 +     * Locale) control.getCandidateLocales} method is called with the target
 152.942 +     * locale to get a list of <em>candidate <code>Locale</code>s</em> for
 152.943 +     * which resource bundles are searched.</li>
 152.944 +     *
 152.945 +     * <li>The {@link ResourceBundle.Control#newBundle(String, Locale,
 152.946 +     * String, ClassLoader, boolean) control.newBundle} method is called to
 152.947 +     * instantiate a <code>ResourceBundle</code> for the base bundle name, a
 152.948 +     * candidate locale, and a format. (Refer to the note on the cache
 152.949 +     * lookup below.) This step is iterated over all combinations of the
 152.950 +     * candidate locales and formats until the <code>newBundle</code> method
 152.951 +     * returns a <code>ResourceBundle</code> instance or the iteration has
 152.952 +     * used up all the combinations. For example, if the candidate locales
 152.953 +     * are <code>Locale("de", "DE")</code>, <code>Locale("de")</code> and
 152.954 +     * <code>Locale("")</code> and the formats are <code>"java.class"</code>
 152.955 +     * and <code>"java.properties"</code>, then the following is the
 152.956 +     * sequence of locale-format combinations to be used to call
 152.957 +     * <code>control.newBundle</code>.
 152.958 +     *
 152.959 +     * <table style="width: 50%; text-align: left; margin-left: 40px;"
 152.960 +     *  border="0" cellpadding="2" cellspacing="2">
 152.961 +     * <tbody><code>
 152.962 +     * <tr>
 152.963 +     * <td
 152.964 +     * style="vertical-align: top; text-align: left; font-weight: bold; width: 50%;">Locale<br>
 152.965 +     * </td>
 152.966 +     * <td
 152.967 +     * style="vertical-align: top; text-align: left; font-weight: bold; width: 50%;">format<br>
 152.968 +     * </td>
 152.969 +     * </tr>
 152.970 +     * <tr>
 152.971 +     * <td style="vertical-align: top; width: 50%;">Locale("de", "DE")<br>
 152.972 +     * </td>
 152.973 +     * <td style="vertical-align: top; width: 50%;">java.class<br>
 152.974 +     * </td>
 152.975 +     * </tr>
 152.976 +     * <tr>
 152.977 +     * <td style="vertical-align: top; width: 50%;">Locale("de", "DE")</td>
 152.978 +     * <td style="vertical-align: top; width: 50%;">java.properties<br>
 152.979 +     * </td>
 152.980 +     * </tr>
 152.981 +     * <tr>
 152.982 +     * <td style="vertical-align: top; width: 50%;">Locale("de")</td>
 152.983 +     * <td style="vertical-align: top; width: 50%;">java.class</td>
 152.984 +     * </tr>
 152.985 +     * <tr>
 152.986 +     * <td style="vertical-align: top; width: 50%;">Locale("de")</td>
 152.987 +     * <td style="vertical-align: top; width: 50%;">java.properties</td>
 152.988 +     * </tr>
 152.989 +     * <tr>
 152.990 +     * <td style="vertical-align: top; width: 50%;">Locale("")<br>
 152.991 +     * </td>
 152.992 +     * <td style="vertical-align: top; width: 50%;">java.class</td>
 152.993 +     * </tr>
 152.994 +     * <tr>
 152.995 +     * <td style="vertical-align: top; width: 50%;">Locale("")</td>
 152.996 +     * <td style="vertical-align: top; width: 50%;">java.properties</td>
 152.997 +     * </tr>
 152.998 +     * </code></tbody>
 152.999 +     * </table>
152.1000 +     * </li>
152.1001 +     *
152.1002 +     * <li>If the previous step has found no resource bundle, proceed to
152.1003 +     * Step 6. If a bundle has been found that is a base bundle (a bundle
152.1004 +     * for <code>Locale("")</code>), and the candidate locale list only contained
152.1005 +     * <code>Locale("")</code>, return the bundle to the caller. If a bundle
152.1006 +     * has been found that is a base bundle, but the candidate locale list
152.1007 +     * contained locales other than Locale(""), put the bundle on hold and
152.1008 +     * proceed to Step 6. If a bundle has been found that is not a base
152.1009 +     * bundle, proceed to Step 7.</li>
152.1010 +     *
152.1011 +     * <li>The {@link ResourceBundle.Control#getFallbackLocale(String,
152.1012 +     * Locale) control.getFallbackLocale} method is called to get a fallback
152.1013 +     * locale (alternative to the current target locale) to try further
152.1014 +     * finding a resource bundle. If the method returns a non-null locale,
152.1015 +     * it becomes the next target locale and the loading process starts over
152.1016 +     * from Step 3. Otherwise, if a base bundle was found and put on hold in
152.1017 +     * a previous Step 5, it is returned to the caller now. Otherwise, a
152.1018 +     * MissingResourceException is thrown.</li>
152.1019 +     *
152.1020 +     * <li>At this point, we have found a resource bundle that's not the
152.1021 +     * base bundle. If this bundle set its parent during its instantiation,
152.1022 +     * it is returned to the caller. Otherwise, its <a
152.1023 +     * href="./ResourceBundle.html#parent_chain">parent chain</a> is
152.1024 +     * instantiated based on the list of candidate locales from which it was
152.1025 +     * found. Finally, the bundle is returned to the caller.</li>
152.1026 +     * </ol>
152.1027 +     *
152.1028 +     * <p>During the resource bundle loading process above, this factory
152.1029 +     * method looks up the cache before calling the {@link
152.1030 +     * Control#newBundle(String, Locale, String, ClassLoader, boolean)
152.1031 +     * control.newBundle} method.  If the time-to-live period of the
152.1032 +     * resource bundle found in the cache has expired, the factory method
152.1033 +     * calls the {@link ResourceBundle.Control#needsReload(String, Locale,
152.1034 +     * String, ClassLoader, ResourceBundle, long) control.needsReload}
152.1035 +     * method to determine whether the resource bundle needs to be reloaded.
152.1036 +     * If reloading is required, the factory method calls
152.1037 +     * <code>control.newBundle</code> to reload the resource bundle.  If
152.1038 +     * <code>control.newBundle</code> returns <code>null</code>, the factory
152.1039 +     * method puts a dummy resource bundle in the cache as a mark of
152.1040 +     * nonexistent resource bundles in order to avoid lookup overhead for
152.1041 +     * subsequent requests. Such dummy resource bundles are under the same
152.1042 +     * expiration control as specified by <code>control</code>.
152.1043 +     *
152.1044 +     * <p>All resource bundles loaded are cached by default. Refer to
152.1045 +     * {@link Control#getTimeToLive(String,Locale)
152.1046 +     * control.getTimeToLive} for details.
152.1047 +     *
152.1048 +     * <p>The following is an example of the bundle loading process with the
152.1049 +     * default <code>ResourceBundle.Control</code> implementation.
152.1050 +     *
152.1051 +     * <p>Conditions:
152.1052 +     * <ul>
152.1053 +     * <li>Base bundle name: <code>foo.bar.Messages</code>
152.1054 +     * <li>Requested <code>Locale</code>: {@link Locale#ITALY}</li>
152.1055 +     * <li>Default <code>Locale</code>: {@link Locale#FRENCH}</li>
152.1056 +     * <li>Available resource bundles:
152.1057 +     * <code>foo/bar/Messages_fr.properties</code> and
152.1058 +     * <code>foo/bar/Messages.properties</code></li>
152.1059 +     * </ul>
152.1060 +     *
152.1061 +     * <p>First, <code>getBundle</code> tries loading a resource bundle in
152.1062 +     * the following sequence.
152.1063 +     *
152.1064 +     * <ul>
152.1065 +     * <li>class <code>foo.bar.Messages_it_IT</code>
152.1066 +     * <li>file <code>foo/bar/Messages_it_IT.properties</code>
152.1067 +     * <li>class <code>foo.bar.Messages_it</code></li>
152.1068 +     * <li>file <code>foo/bar/Messages_it.properties</code></li>
152.1069 +     * <li>class <code>foo.bar.Messages</code></li>
152.1070 +     * <li>file <code>foo/bar/Messages.properties</code></li>
152.1071 +     * </ul>
152.1072 +     *
152.1073 +     * <p>At this point, <code>getBundle</code> finds
152.1074 +     * <code>foo/bar/Messages.properties</code>, which is put on hold
152.1075 +     * because it's the base bundle.  <code>getBundle</code> calls {@link
152.1076 +     * Control#getFallbackLocale(String, Locale)
152.1077 +     * control.getFallbackLocale("foo.bar.Messages", Locale.ITALY)} which
152.1078 +     * returns <code>Locale.FRENCH</code>. Next, <code>getBundle</code>
152.1079 +     * tries loading a bundle in the following sequence.
152.1080 +     *
152.1081 +     * <ul>
152.1082 +     * <li>class <code>foo.bar.Messages_fr</code></li>
152.1083 +     * <li>file <code>foo/bar/Messages_fr.properties</code></li>
152.1084 +     * <li>class <code>foo.bar.Messages</code></li>
152.1085 +     * <li>file <code>foo/bar/Messages.properties</code></li>
152.1086 +     * </ul>
152.1087 +     *
152.1088 +     * <p><code>getBundle</code> finds
152.1089 +     * <code>foo/bar/Messages_fr.properties</code> and creates a
152.1090 +     * <code>ResourceBundle</code> instance. Then, <code>getBundle</code>
152.1091 +     * sets up its parent chain from the list of the candiate locales.  Only
152.1092 +     * <code>foo/bar/Messages.properties</code> is found in the list and
152.1093 +     * <code>getBundle</code> creates a <code>ResourceBundle</code> instance
152.1094 +     * that becomes the parent of the instance for
152.1095 +     * <code>foo/bar/Messages_fr.properties</code>.
152.1096 +     *
152.1097 +     * @param baseName
152.1098 +     *        the base name of the resource bundle, a fully qualified
152.1099 +     *        class name
152.1100 +     * @param targetLocale
152.1101 +     *        the locale for which a resource bundle is desired
152.1102 +     * @param loader
152.1103 +     *        the class loader from which to load the resource bundle
152.1104 +     * @param control
152.1105 +     *        the control which gives information for the resource
152.1106 +     *        bundle loading process
152.1107 +     * @return a resource bundle for the given base name and locale
152.1108 +     * @exception NullPointerException
152.1109 +     *        if <code>baseName</code>, <code>targetLocale</code>,
152.1110 +     *        <code>loader</code>, or <code>control</code> is
152.1111 +     *        <code>null</code>
152.1112 +     * @exception MissingResourceException
152.1113 +     *        if no resource bundle for the specified base name can be found
152.1114 +     * @exception IllegalArgumentException
152.1115 +     *        if the given <code>control</code> doesn't perform properly
152.1116 +     *        (e.g., <code>control.getCandidateLocales</code> returns null.)
152.1117 +     *        Note that validation of <code>control</code> is performed as
152.1118 +     *        needed.
152.1119 +     * @since 1.6
152.1120 +     */
152.1121 +    public static ResourceBundle getBundle(String baseName, Locale targetLocale,
152.1122 +                                           ClassLoader loader, Control control) {
152.1123 +        if (loader == null || control == null) {
152.1124 +            throw new NullPointerException();
152.1125 +        }
152.1126 +        return getBundleImpl(baseName, targetLocale, control);
152.1127 +    }
152.1128 +
152.1129 +    private static ResourceBundle getBundleImpl(String baseName, Locale locale,
152.1130 +                                                Control control) {
152.1131 +        if (locale == null || control == null) {
152.1132 +            throw new NullPointerException();
152.1133 +        }
152.1134 +
152.1135 +        // We create a CacheKey here for use by this call. The base
152.1136 +        // name and loader will never change during the bundle loading
152.1137 +        // process. We have to make sure that the locale is set before
152.1138 +        // using it as a cache key.
152.1139 +        CacheKey cacheKey = new CacheKey(baseName, locale);
152.1140 +        ResourceBundle bundle = null;
152.1141 +
152.1142 +        // Quick lookup of the cache.
152.1143 +        BundleReference bundleRef = cacheList.get(cacheKey);
152.1144 +        if (bundleRef != null) {
152.1145 +            bundle = bundleRef.get();
152.1146 +            bundleRef = null;
152.1147 +        }
152.1148 +
152.1149 +        // If this bundle and all of its parents are valid (not expired),
152.1150 +        // then return this bundle. If any of the bundles is expired, we
152.1151 +        // don't call control.needsReload here but instead drop into the
152.1152 +        // complete loading process below.
152.1153 +        if (isValidBundle(bundle) && hasValidParentChain(bundle)) {
152.1154 +            return bundle;
152.1155 +        }
152.1156 +
152.1157 +        // No valid bundle was found in the cache, so we need to load the
152.1158 +        // resource bundle and its parents.
152.1159 +
152.1160 +        boolean isKnownControl = (control == Control.INSTANCE) ||
152.1161 +                                   (control instanceof SingleFormatControl);
152.1162 +        List<String> formats = control.getFormats(baseName);
152.1163 +        if (!isKnownControl && !checkList(formats)) {
152.1164 +            throw new IllegalArgumentException("Invalid Control: getFormats");
152.1165 +        }
152.1166 +
152.1167 +        ResourceBundle baseBundle = null;
152.1168 +        for (Locale targetLocale = locale;
152.1169 +             targetLocale != null;
152.1170 +             targetLocale = control.getFallbackLocale(baseName, targetLocale)) {
152.1171 +            List<Locale> candidateLocales = control.getCandidateLocales(baseName, targetLocale);
152.1172 +            if (!isKnownControl && !checkList(candidateLocales)) {
152.1173 +                throw new IllegalArgumentException("Invalid Control: getCandidateLocales");
152.1174 +            }
152.1175 +
152.1176 +            bundle = findBundle(cacheKey, candidateLocales, formats, 0, control, baseBundle);
152.1177 +
152.1178 +            // If the loaded bundle is the base bundle and exactly for the
152.1179 +            // requested locale or the only candidate locale, then take the
152.1180 +            // bundle as the resulting one. If the loaded bundle is the base
152.1181 +            // bundle, it's put on hold until we finish processing all
152.1182 +            // fallback locales.
152.1183 +            if (isValidBundle(bundle)) {
152.1184 +                boolean isBaseBundle = Locale.ROOT.equals(bundle.locale);
152.1185 +                if (!isBaseBundle || bundle.locale.equals(locale)
152.1186 +                    || (candidateLocales.size() == 1
152.1187 +                        && bundle.locale.equals(candidateLocales.get(0)))) {
152.1188 +                    break;
152.1189 +                }
152.1190 +
152.1191 +                // If the base bundle has been loaded, keep the reference in
152.1192 +                // baseBundle so that we can avoid any redundant loading in case
152.1193 +                // the control specify not to cache bundles.
152.1194 +                if (isBaseBundle && baseBundle == null) {
152.1195 +                    baseBundle = bundle;
152.1196 +                }
152.1197 +            }
152.1198 +        }
152.1199 +
152.1200 +        if (bundle == null) {
152.1201 +            if (baseBundle == null) {
152.1202 +                throwMissingResourceException(baseName, locale, cacheKey.getCause());
152.1203 +            }
152.1204 +            bundle = baseBundle;
152.1205 +        }
152.1206 +
152.1207 +        return bundle;
152.1208 +    }
152.1209 +
152.1210 +    /**
152.1211 +     * Checks if the given <code>List</code> is not null, not empty,
152.1212 +     * not having null in its elements.
152.1213 +     */
152.1214 +    private static final boolean checkList(List a) {
152.1215 +        boolean valid = (a != null && a.size() != 0);
152.1216 +        if (valid) {
152.1217 +            int size = a.size();
152.1218 +            for (int i = 0; valid && i < size; i++) {
152.1219 +                valid = (a.get(i) != null);
152.1220 +            }
152.1221 +        }
152.1222 +        return valid;
152.1223 +    }
152.1224 +
152.1225 +    private static final ResourceBundle findBundle(CacheKey cacheKey,
152.1226 +                                                   List<Locale> candidateLocales,
152.1227 +                                                   List<String> formats,
152.1228 +                                                   int index,
152.1229 +                                                   Control control,
152.1230 +                                                   ResourceBundle baseBundle) {
152.1231 +        Locale targetLocale = candidateLocales.get(index);
152.1232 +        ResourceBundle parent = null;
152.1233 +        if (index != candidateLocales.size() - 1) {
152.1234 +            parent = findBundle(cacheKey, candidateLocales, formats, index + 1,
152.1235 +                                control, baseBundle);
152.1236 +        } else if (baseBundle != null && Locale.ROOT.equals(targetLocale)) {
152.1237 +            return baseBundle;
152.1238 +        }
152.1239 +
152.1240 +        // Before we do the real loading work, see whether we need to
152.1241 +        // do some housekeeping: If references to class loaders or
152.1242 +        // resource bundles have been nulled out, remove all related
152.1243 +        // information from the cache.
152.1244 +        Object ref;
152.1245 +        while ((ref = referenceQueue.poll()) != null) {
152.1246 +            cacheList.remove(((CacheKeyReference)ref).getCacheKey());
152.1247 +        }
152.1248 +
152.1249 +        // flag indicating the resource bundle has expired in the cache
152.1250 +        boolean expiredBundle = false;
152.1251 +
152.1252 +        // First, look up the cache to see if it's in the cache, without
152.1253 +        // attempting to load bundle.
152.1254 +        cacheKey.setLocale(targetLocale);
152.1255 +        ResourceBundle bundle = findBundleInCache(cacheKey, control);
152.1256 +        if (isValidBundle(bundle)) {
152.1257 +            expiredBundle = bundle.expired;
152.1258 +            if (!expiredBundle) {
152.1259 +                // If its parent is the one asked for by the candidate
152.1260 +                // locales (the runtime lookup path), we can take the cached
152.1261 +                // one. (If it's not identical, then we'd have to check the
152.1262 +                // parent's parents to be consistent with what's been
152.1263 +                // requested.)
152.1264 +                if (bundle.parent == parent) {
152.1265 +                    return bundle;
152.1266 +                }
152.1267 +                // Otherwise, remove the cached one since we can't keep
152.1268 +                // the same bundles having different parents.
152.1269 +                BundleReference bundleRef = cacheList.get(cacheKey);
152.1270 +                if (bundleRef != null && bundleRef.get() == bundle) {
152.1271 +                    cacheList.remove(cacheKey);
152.1272 +                }
152.1273 +            }
152.1274 +        }
152.1275 +
152.1276 +        if (bundle != NONEXISTENT_BUNDLE) {
152.1277 +            CacheKey constKey = (CacheKey) cacheKey.clone();
152.1278 +
152.1279 +            try {
152.1280 +                bundle = loadBundle(cacheKey, formats, control, expiredBundle);
152.1281 +                if (bundle != null) {
152.1282 +                    if (bundle.parent == null) {
152.1283 +                        bundle.setParent(parent);
152.1284 +                    }
152.1285 +                    bundle.locale = targetLocale;
152.1286 +                    bundle = putBundleInCache(cacheKey, bundle, control);
152.1287 +                    return bundle;
152.1288 +                }
152.1289 +
152.1290 +                // Put NONEXISTENT_BUNDLE in the cache as a mark that there's no bundle
152.1291 +                // instance for the locale.
152.1292 +                putBundleInCache(cacheKey, NONEXISTENT_BUNDLE, control);
152.1293 +            } finally {
152.1294 +                if (constKey.getCause() instanceof InterruptedException) {
152.1295 +                    Thread.currentThread().interrupt();
152.1296 +                }
152.1297 +            }
152.1298 +        }
152.1299 +        return parent;
152.1300 +    }
152.1301 +
152.1302 +    private static final ResourceBundle loadBundle(CacheKey cacheKey,
152.1303 +                                                   List<String> formats,
152.1304 +                                                   Control control,
152.1305 +                                                   boolean reload) {
152.1306 +
152.1307 +        // Here we actually load the bundle in the order of formats
152.1308 +        // specified by the getFormats() value.
152.1309 +        Locale targetLocale = cacheKey.getLocale();
152.1310 +
152.1311 +        ResourceBundle bundle = null;
152.1312 +        int size = formats.size();
152.1313 +        for (int i = 0; i < size; i++) {
152.1314 +            String format = formats.get(i);
152.1315 +            try {
152.1316 +                bundle = control.newBundle(cacheKey.getName(), targetLocale, format,
152.1317 +                                           null, reload);
152.1318 +            } catch (LinkageError error) {
152.1319 +                // We need to handle the LinkageError case due to
152.1320 +                // inconsistent case-sensitivity in ClassLoader.
152.1321 +                // See 6572242 for details.
152.1322 +                cacheKey.setCause(error);
152.1323 +            } catch (Exception cause) {
152.1324 +                cacheKey.setCause(cause);
152.1325 +            }
152.1326 +            if (bundle != null) {
152.1327 +                // Set the format in the cache key so that it can be
152.1328 +                // used when calling needsReload later.
152.1329 +                cacheKey.setFormat(format);
152.1330 +                bundle.name = cacheKey.getName();
152.1331 +                bundle.locale = targetLocale;
152.1332 +                // Bundle provider might reuse instances. So we should make
152.1333 +                // sure to clear the expired flag here.
152.1334 +                bundle.expired = false;
152.1335 +                break;
152.1336 +            }
152.1337 +        }
152.1338 +
152.1339 +        return bundle;
152.1340 +    }
152.1341 +
152.1342 +    private static final boolean isValidBundle(ResourceBundle bundle) {
152.1343 +        return bundle != null && bundle != NONEXISTENT_BUNDLE;
152.1344 +    }
152.1345 +
152.1346 +    /**
152.1347 +     * Determines whether any of resource bundles in the parent chain,
152.1348 +     * including the leaf, have expired.
152.1349 +     */
152.1350 +    private static final boolean hasValidParentChain(ResourceBundle bundle) {
152.1351 +        long now = System.currentTimeMillis();
152.1352 +        while (bundle != null) {
152.1353 +            if (bundle.expired) {
152.1354 +                return false;
152.1355 +            }
152.1356 +            CacheKey key = bundle.cacheKey;
152.1357 +            if (key != null) {
152.1358 +                long expirationTime = key.expirationTime;
152.1359 +                if (expirationTime >= 0 && expirationTime <= now) {
152.1360 +                    return false;
152.1361 +                }
152.1362 +            }
152.1363 +            bundle = bundle.parent;
152.1364 +        }
152.1365 +        return true;
152.1366 +    }
152.1367 +
152.1368 +    /**
152.1369 +     * Throw a MissingResourceException with proper message
152.1370 +     */
152.1371 +    private static final void throwMissingResourceException(String baseName,
152.1372 +                                                            Locale locale,
152.1373 +                                                            Throwable cause) {
152.1374 +        // If the cause is a MissingResourceException, avoid creating
152.1375 +        // a long chain. (6355009)
152.1376 +        if (cause instanceof MissingResourceException) {
152.1377 +            cause = null;
152.1378 +        }
152.1379 +        throw new MissingResourceException("Can't find bundle for base name "
152.1380 +                                           + baseName + ", locale " + locale,
152.1381 +                                           baseName + "_" + locale, // className
152.1382 +                                           "",                      // key
152.1383 +                                           cause);
152.1384 +    }
152.1385 +
152.1386 +    /**
152.1387 +     * Finds a bundle in the cache. Any expired bundles are marked as
152.1388 +     * `expired' and removed from the cache upon return.
152.1389 +     *
152.1390 +     * @param cacheKey the key to look up the cache
152.1391 +     * @param control the Control to be used for the expiration control
152.1392 +     * @return the cached bundle, or null if the bundle is not found in the
152.1393 +     * cache or its parent has expired. <code>bundle.expire</code> is true
152.1394 +     * upon return if the bundle in the cache has expired.
152.1395 +     */
152.1396 +    private static final ResourceBundle findBundleInCache(CacheKey cacheKey,
152.1397 +                                                          Control control) {
152.1398 +        BundleReference bundleRef = cacheList.get(cacheKey);
152.1399 +        if (bundleRef == null) {
152.1400 +            return null;
152.1401 +        }
152.1402 +        ResourceBundle bundle = bundleRef.get();
152.1403 +        if (bundle == null) {
152.1404 +            return null;
152.1405 +        }
152.1406 +        ResourceBundle p = bundle.parent;
152.1407 +        assert p != NONEXISTENT_BUNDLE;
152.1408 +        // If the parent has expired, then this one must also expire. We
152.1409 +        // check only the immediate parent because the actual loading is
152.1410 +        // done from the root (base) to leaf (child) and the purpose of
152.1411 +        // checking is to propagate expiration towards the leaf. For
152.1412 +        // example, if the requested locale is ja_JP_JP and there are
152.1413 +        // bundles for all of the candidates in the cache, we have a list,
152.1414 +        //
152.1415 +        // base <- ja <- ja_JP <- ja_JP_JP
152.1416 +        //
152.1417 +        // If ja has expired, then it will reload ja and the list becomes a
152.1418 +        // tree.
152.1419 +        //
152.1420 +        // base <- ja (new)
152.1421 +        //  "   <- ja (expired) <- ja_JP <- ja_JP_JP
152.1422 +        //
152.1423 +        // When looking up ja_JP in the cache, it finds ja_JP in the cache
152.1424 +        // which references to the expired ja. Then, ja_JP is marked as
152.1425 +        // expired and removed from the cache. This will be propagated to
152.1426 +        // ja_JP_JP.
152.1427 +        //
152.1428 +        // Now, it's possible, for example, that while loading new ja_JP,
152.1429 +        // someone else has started loading the same bundle and finds the
152.1430 +        // base bundle has expired. Then, what we get from the first
152.1431 +        // getBundle call includes the expired base bundle. However, if
152.1432 +        // someone else didn't start its loading, we wouldn't know if the
152.1433 +        // base bundle has expired at the end of the loading process. The
152.1434 +        // expiration control doesn't guarantee that the returned bundle and
152.1435 +        // its parents haven't expired.
152.1436 +        //
152.1437 +        // We could check the entire parent chain to see if there's any in
152.1438 +        // the chain that has expired. But this process may never end. An
152.1439 +        // extreme case would be that getTimeToLive returns 0 and
152.1440 +        // needsReload always returns true.
152.1441 +        if (p != null && p.expired) {
152.1442 +            assert bundle != NONEXISTENT_BUNDLE;
152.1443 +            bundle.expired = true;
152.1444 +            bundle.cacheKey = null;
152.1445 +            cacheList.remove(cacheKey);
152.1446 +            bundle = null;
152.1447 +        } else {
152.1448 +            CacheKey key = bundleRef.getCacheKey();
152.1449 +            long expirationTime = key.expirationTime;
152.1450 +            if (!bundle.expired && expirationTime >= 0 &&
152.1451 +                expirationTime <= System.currentTimeMillis()) {
152.1452 +                // its TTL period has expired.
152.1453 +                if (bundle != NONEXISTENT_BUNDLE) {
152.1454 +                    // Synchronize here to call needsReload to avoid
152.1455 +                    // redundant concurrent calls for the same bundle.
152.1456 +                    synchronized (bundle) {
152.1457 +                        expirationTime = key.expirationTime;
152.1458 +                        if (!bundle.expired && expirationTime >= 0 &&
152.1459 +                            expirationTime <= System.currentTimeMillis()) {
152.1460 +                            try {
152.1461 +                                bundle.expired = control.needsReload(key.getName(),
152.1462 +                                                                     key.getLocale(),
152.1463 +                                                                     key.getFormat(),
152.1464 +                                                                     null,
152.1465 +                                                                     bundle,
152.1466 +                                                                     key.loadTime);
152.1467 +                            } catch (Exception e) {
152.1468 +                                cacheKey.setCause(e);
152.1469 +                            }
152.1470 +                            if (bundle.expired) {
152.1471 +                                // If the bundle needs to be reloaded, then
152.1472 +                                // remove the bundle from the cache, but
152.1473 +                                // return the bundle with the expired flag
152.1474 +                                // on.
152.1475 +                                bundle.cacheKey = null;
152.1476 +                                cacheList.remove(cacheKey);
152.1477 +                            } else {
152.1478 +                                // Update the expiration control info. and reuse
152.1479 +                                // the same bundle instance
152.1480 +                                setExpirationTime(key, control);
152.1481 +                            }
152.1482 +                        }
152.1483 +                    }
152.1484 +                } else {
152.1485 +                    // We just remove NONEXISTENT_BUNDLE from the cache.
152.1486 +                    cacheList.remove(cacheKey);
152.1487 +                    bundle = null;
152.1488 +                }
152.1489 +            }
152.1490 +        }
152.1491 +        return bundle;
152.1492 +    }
152.1493 +
152.1494 +    /**
152.1495 +     * Put a new bundle in the cache.
152.1496 +     *
152.1497 +     * @param cacheKey the key for the resource bundle
152.1498 +     * @param bundle the resource bundle to be put in the cache
152.1499 +     * @return the ResourceBundle for the cacheKey; if someone has put
152.1500 +     * the bundle before this call, the one found in the cache is
152.1501 +     * returned.
152.1502 +     */
152.1503 +    private static final ResourceBundle putBundleInCache(CacheKey cacheKey,
152.1504 +                                                         ResourceBundle bundle,
152.1505 +                                                         Control control) {
152.1506 +        setExpirationTime(cacheKey, control);
152.1507 +        if (cacheKey.expirationTime != Control.TTL_DONT_CACHE) {
152.1508 +            CacheKey key = (CacheKey) cacheKey.clone();
152.1509 +            BundleReference bundleRef = new BundleReference(bundle, referenceQueue, key);
152.1510 +            bundle.cacheKey = key;
152.1511 +
152.1512 +            // Put the bundle in the cache if it's not been in the cache.
152.1513 +            BundleReference result = cacheList.put(key, bundleRef);
152.1514 +
152.1515 +            // If someone else has put the same bundle in the cache before
152.1516 +            // us and it has not expired, we should use the one in the cache.
152.1517 +            if (result != null) {
152.1518 +                ResourceBundle rb = result.get();
152.1519 +                if (rb != null && !rb.expired) {
152.1520 +                    // Clear the back link to the cache key
152.1521 +                    bundle.cacheKey = null;
152.1522 +                    bundle = rb;
152.1523 +                    // Clear the reference in the BundleReference so that
152.1524 +                    // it won't be enqueued.
152.1525 +                    bundleRef.clear();
152.1526 +                } else {
152.1527 +                    // Replace the invalid (garbage collected or expired)
152.1528 +                    // instance with the valid one.
152.1529 +                    cacheList.put(key, bundleRef);
152.1530 +                }
152.1531 +            }
152.1532 +        }
152.1533 +        return bundle;
152.1534 +    }
152.1535 +
152.1536 +    private static final void setExpirationTime(CacheKey cacheKey, Control control) {
152.1537 +        long ttl = control.getTimeToLive(cacheKey.getName(),
152.1538 +                                         cacheKey.getLocale());
152.1539 +        if (ttl >= 0) {
152.1540 +            // If any expiration time is specified, set the time to be
152.1541 +            // expired in the cache.
152.1542 +            long now = System.currentTimeMillis();
152.1543 +            cacheKey.loadTime = now;
152.1544 +            cacheKey.expirationTime = now + ttl;
152.1545 +        } else if (ttl >= Control.TTL_NO_EXPIRATION_CONTROL) {
152.1546 +            cacheKey.expirationTime = ttl;
152.1547 +        } else {
152.1548 +            throw new IllegalArgumentException("Invalid Control: TTL=" + ttl);
152.1549 +        }
152.1550 +    }
152.1551 +
152.1552 +    /**
152.1553 +     * Removes all resource bundles from the cache that have been loaded
152.1554 +     * using the caller's class loader.
152.1555 +     *
152.1556 +     * @since 1.6
152.1557 +     * @see ResourceBundle.Control#getTimeToLive(String,Locale)
152.1558 +     */
152.1559 +    public static final void clearCache() {
152.1560 +        clearCache(null);
152.1561 +    }
152.1562 +
152.1563 +    /**
152.1564 +     * Removes all resource bundles from the cache that have been loaded
152.1565 +     * using the given class loader.
152.1566 +     *
152.1567 +     * @param loader the class loader
152.1568 +     * @exception NullPointerException if <code>loader</code> is null
152.1569 +     * @since 1.6
152.1570 +     * @see ResourceBundle.Control#getTimeToLive(String,Locale)
152.1571 +     */
152.1572 +    public static final void clearCache(ClassLoader loader) {
152.1573 +        if (loader == null) {
152.1574 +            throw new NullPointerException();
152.1575 +        }
152.1576 +        Set<CacheKey> set = cacheList.keySet();
152.1577 +        for (CacheKey key : set) {
152.1578 +            set.remove(key);
152.1579 +        }
152.1580 +    }
152.1581 +
152.1582 +    /**
152.1583 +     * Gets an object for the given key from this resource bundle.
152.1584 +     * Returns null if this resource bundle does not contain an
152.1585 +     * object for the given key.
152.1586 +     *
152.1587 +     * @param key the key for the desired object
152.1588 +     * @exception NullPointerException if <code>key</code> is <code>null</code>
152.1589 +     * @return the object for the given key, or null
152.1590 +     */
152.1591 +    protected abstract Object handleGetObject(String key);
152.1592 +
152.1593 +    /**
152.1594 +     * Returns an enumeration of the keys.
152.1595 +     *
152.1596 +     * @return an <code>Enumeration</code> of the keys contained in
152.1597 +     *         this <code>ResourceBundle</code> and its parent bundles.
152.1598 +     */
152.1599 +    public abstract Enumeration<String> getKeys();
152.1600 +
152.1601 +    /**
152.1602 +     * Determines whether the given <code>key</code> is contained in
152.1603 +     * this <code>ResourceBundle</code> or its parent bundles.
152.1604 +     *
152.1605 +     * @param key
152.1606 +     *        the resource <code>key</code>
152.1607 +     * @return <code>true</code> if the given <code>key</code> is
152.1608 +     *        contained in this <code>ResourceBundle</code> or its
152.1609 +     *        parent bundles; <code>false</code> otherwise.
152.1610 +     * @exception NullPointerException
152.1611 +     *         if <code>key</code> is <code>null</code>
152.1612 +     * @since 1.6
152.1613 +     */
152.1614 +    public boolean containsKey(String key) {
152.1615 +        if (key == null) {
152.1616 +            throw new NullPointerException();
152.1617 +        }
152.1618 +        for (ResourceBundle rb = this; rb != null; rb = rb.parent) {
152.1619 +            if (rb.handleKeySet().contains(key)) {
152.1620 +                return true;
152.1621 +            }
152.1622 +        }
152.1623 +        return false;
152.1624 +    }
152.1625 +
152.1626 +    /**
152.1627 +     * Returns a <code>Set</code> of all keys contained in this
152.1628 +     * <code>ResourceBundle</code> and its parent bundles.
152.1629 +     *
152.1630 +     * @return a <code>Set</code> of all keys contained in this
152.1631 +     *         <code>ResourceBundle</code> and its parent bundles.
152.1632 +     * @since 1.6
152.1633 +     */
152.1634 +    public Set<String> keySet() {
152.1635 +        Set<String> keys = new HashSet<>();
152.1636 +        for (ResourceBundle rb = this; rb != null; rb = rb.parent) {
152.1637 +            keys.addAll(rb.handleKeySet());
152.1638 +        }
152.1639 +        return keys;
152.1640 +    }
152.1641 +
152.1642 +    /**
152.1643 +     * Returns a <code>Set</code> of the keys contained <em>only</em>
152.1644 +     * in this <code>ResourceBundle</code>.
152.1645 +     *
152.1646 +     * <p>The default implementation returns a <code>Set</code> of the
152.1647 +     * keys returned by the {@link #getKeys() getKeys} method except
152.1648 +     * for the ones for which the {@link #handleGetObject(String)
152.1649 +     * handleGetObject} method returns <code>null</code>. Once the
152.1650 +     * <code>Set</code> has been created, the value is kept in this
152.1651 +     * <code>ResourceBundle</code> in order to avoid producing the
152.1652 +     * same <code>Set</code> in subsequent calls. Subclasses can
152.1653 +     * override this method for faster handling.
152.1654 +     *
152.1655 +     * @return a <code>Set</code> of the keys contained only in this
152.1656 +     *        <code>ResourceBundle</code>
152.1657 +     * @since 1.6
152.1658 +     */
152.1659 +    protected Set<String> handleKeySet() {
152.1660 +        if (keySet == null) {
152.1661 +            synchronized (this) {
152.1662 +                if (keySet == null) {
152.1663 +                    Set<String> keys = new HashSet<>();
152.1664 +                    Enumeration<String> enumKeys = getKeys();
152.1665 +                    while (enumKeys.hasMoreElements()) {
152.1666 +                        String key = enumKeys.nextElement();
152.1667 +                        if (handleGetObject(key) != null) {
152.1668 +                            keys.add(key);
152.1669 +                        }
152.1670 +                    }
152.1671 +                    keySet = keys;
152.1672 +                }
152.1673 +            }
152.1674 +        }
152.1675 +        return keySet;
152.1676 +    }
152.1677 +
152.1678 +
152.1679 +
152.1680 +    /**
152.1681 +     * <code>ResourceBundle.Control</code> defines a set of callback methods
152.1682 +     * that are invoked by the {@link ResourceBundle#getBundle(String,
152.1683 +     * Locale, ClassLoader, Control) ResourceBundle.getBundle} factory
152.1684 +     * methods during the bundle loading process. In other words, a
152.1685 +     * <code>ResourceBundle.Control</code> collaborates with the factory
152.1686 +     * methods for loading resource bundles. The default implementation of
152.1687 +     * the callback methods provides the information necessary for the
152.1688 +     * factory methods to perform the <a
152.1689 +     * href="./ResourceBundle.html#default_behavior">default behavior</a>.
152.1690 +     *
152.1691 +     * <p>In addition to the callback methods, the {@link
152.1692 +     * #toBundleName(String, Locale) toBundleName} and {@link
152.1693 +     * #toResourceName(String, String) toResourceName} methods are defined
152.1694 +     * primarily for convenience in implementing the callback
152.1695 +     * methods. However, the <code>toBundleName</code> method could be
152.1696 +     * overridden to provide different conventions in the organization and
152.1697 +     * packaging of localized resources.  The <code>toResourceName</code>
152.1698 +     * method is <code>final</code> to avoid use of wrong resource and class
152.1699 +     * name separators.
152.1700 +     *
152.1701 +     * <p>Two factory methods, {@link #getControl(List)} and {@link
152.1702 +     * #getNoFallbackControl(List)}, provide
152.1703 +     * <code>ResourceBundle.Control</code> instances that implement common
152.1704 +     * variations of the default bundle loading process.
152.1705 +     *
152.1706 +     * <p>The formats returned by the {@link Control#getFormats(String)
152.1707 +     * getFormats} method and candidate locales returned by the {@link
152.1708 +     * ResourceBundle.Control#getCandidateLocales(String, Locale)
152.1709 +     * getCandidateLocales} method must be consistent in all
152.1710 +     * <code>ResourceBundle.getBundle</code> invocations for the same base
152.1711 +     * bundle. Otherwise, the <code>ResourceBundle.getBundle</code> methods
152.1712 +     * may return unintended bundles. For example, if only
152.1713 +     * <code>"java.class"</code> is returned by the <code>getFormats</code>
152.1714 +     * method for the first call to <code>ResourceBundle.getBundle</code>
152.1715 +     * and only <code>"java.properties"</code> for the second call, then the
152.1716 +     * second call will return the class-based one that has been cached
152.1717 +     * during the first call.
152.1718 +     *
152.1719 +     * <p>A <code>ResourceBundle.Control</code> instance must be thread-safe
152.1720 +     * if it's simultaneously used by multiple threads.
152.1721 +     * <code>ResourceBundle.getBundle</code> does not synchronize to call
152.1722 +     * the <code>ResourceBundle.Control</code> methods. The default
152.1723 +     * implementations of the methods are thread-safe.
152.1724 +     *
152.1725 +     * <p>Applications can specify <code>ResourceBundle.Control</code>
152.1726 +     * instances returned by the <code>getControl</code> factory methods or
152.1727 +     * created from a subclass of <code>ResourceBundle.Control</code> to
152.1728 +     * customize the bundle loading process. The following are examples of
152.1729 +     * changing the default bundle loading process.
152.1730 +     *
152.1731 +     * <p><b>Example 1</b>
152.1732 +     *
152.1733 +     * <p>The following code lets <code>ResourceBundle.getBundle</code> look
152.1734 +     * up only properties-based resources.
152.1735 +     *
152.1736 +     * <pre>
152.1737 +     * import java.util.*;
152.1738 +     * import static java.util.ResourceBundle.Control.*;
152.1739 +     * ...
152.1740 +     * ResourceBundle bundle =
152.1741 +     *   ResourceBundle.getBundle("MyResources", new Locale("fr", "CH"),
152.1742 +     *                            ResourceBundle.Control.getControl(FORMAT_PROPERTIES));
152.1743 +     * </pre>
152.1744 +     *
152.1745 +     * Given the resource bundles in the <a
152.1746 +     * href="./ResourceBundle.html#default_behavior_example">example</a> in
152.1747 +     * the <code>ResourceBundle.getBundle</code> description, this
152.1748 +     * <code>ResourceBundle.getBundle</code> call loads
152.1749 +     * <code>MyResources_fr_CH.properties</code> whose parent is
152.1750 +     * <code>MyResources_fr.properties</code> whose parent is
152.1751 +     * <code>MyResources.properties</code>. (<code>MyResources_fr_CH.properties</code>
152.1752 +     * is not hidden, but <code>MyResources_fr_CH.class</code> is.)
152.1753 +     *
152.1754 +     * <p><b>Example 2</b>
152.1755 +     *
152.1756 +     * <p>The following is an example of loading XML-based bundles
152.1757 +     * using {@link Properties#loadFromXML(java.io.InputStream)
152.1758 +     * Properties.loadFromXML}.
152.1759 +     *
152.1760 +     * <pre>
152.1761 +     * ResourceBundle rb = ResourceBundle.getBundle("Messages",
152.1762 +     *     new ResourceBundle.Control() {
152.1763 +     *         public List&lt;String&gt; getFormats(String baseName) {
152.1764 +     *             if (baseName == null)
152.1765 +     *                 throw new NullPointerException();
152.1766 +     *             return Arrays.asList("xml");
152.1767 +     *         }
152.1768 +     *         public ResourceBundle newBundle(String baseName,
152.1769 +     *                                         Locale locale,
152.1770 +     *                                         String format,
152.1771 +     *                                         ClassLoader loader,
152.1772 +     *                                         boolean reload)
152.1773 +     *                          throws IllegalAccessException,
152.1774 +     *                                 InstantiationException,
152.1775 +     *                                 IOException {
152.1776 +     *             if (baseName == null || locale == null
152.1777 +     *                   || format == null || loader == null)
152.1778 +     *                 throw new NullPointerException();
152.1779 +     *             ResourceBundle bundle = null;
152.1780 +     *             if (format.equals("xml")) {
152.1781 +     *                 String bundleName = toBundleName(baseName, locale);
152.1782 +     *                 String resourceName = toResourceName(bundleName, format);
152.1783 +     *                 InputStream stream = null;
152.1784 +     *                 if (reload) {
152.1785 +     *                     URL url = loader.getResource(resourceName);
152.1786 +     *                     if (url != null) {
152.1787 +     *                         URLConnection connection = url.openConnection();
152.1788 +     *                         if (connection != null) {
152.1789 +     *                             // Disable caches to get fresh data for
152.1790 +     *                             // reloading.
152.1791 +     *                             connection.setUseCaches(false);
152.1792 +     *                             stream = connection.getInputStream();
152.1793 +     *                         }
152.1794 +     *                     }
152.1795 +     *                 } else {
152.1796 +     *                     stream = loader.getResourceAsStream(resourceName);
152.1797 +     *                 }
152.1798 +     *                 if (stream != null) {
152.1799 +     *                     BufferedInputStream bis = new BufferedInputStream(stream);
152.1800 +     *                     bundle = new XMLResourceBundle(bis);
152.1801 +     *                     bis.close();
152.1802 +     *                 }
152.1803 +     *             }
152.1804 +     *             return bundle;
152.1805 +     *         }
152.1806 +     *     });
152.1807 +     *
152.1808 +     * ...
152.1809 +     *
152.1810 +     * private static class XMLResourceBundle extends ResourceBundle {
152.1811 +     *     private Properties props;
152.1812 +     *     XMLResourceBundle(InputStream stream) throws IOException {
152.1813 +     *         props = new Properties();
152.1814 +     *         props.loadFromXML(stream);
152.1815 +     *     }
152.1816 +     *     protected Object handleGetObject(String key) {
152.1817 +     *         return props.getProperty(key);
152.1818 +     *     }
152.1819 +     *     public Enumeration&lt;String&gt; getKeys() {
152.1820 +     *         ...
152.1821 +     *     }
152.1822 +     * }
152.1823 +     * </pre>
152.1824 +     *
152.1825 +     * @since 1.6
152.1826 +     */
152.1827 +    public static class Control {
152.1828 +        /**
152.1829 +         * The default format <code>List</code>, which contains the strings
152.1830 +         * <code>"java.class"</code> and <code>"java.properties"</code>, in
152.1831 +         * this order. This <code>List</code> is {@linkplain
152.1832 +         * Collections#unmodifiableList(List) unmodifiable}.
152.1833 +         *
152.1834 +         * @see #getFormats(String)
152.1835 +         */
152.1836 +        public static final List<String> FORMAT_DEFAULT
152.1837 +            = Collections.unmodifiableList(Arrays.asList("java.class",
152.1838 +                                                         "java.properties"));
152.1839 +
152.1840 +        /**
152.1841 +         * The class-only format <code>List</code> containing
152.1842 +         * <code>"java.class"</code>. This <code>List</code> is {@linkplain
152.1843 +         * Collections#unmodifiableList(List) unmodifiable}.
152.1844 +         *
152.1845 +         * @see #getFormats(String)
152.1846 +         */
152.1847 +        public static final List<String> FORMAT_CLASS
152.1848 +            = Collections.unmodifiableList(Arrays.asList("java.class"));
152.1849 +
152.1850 +        /**
152.1851 +         * The properties-only format <code>List</code> containing
152.1852 +         * <code>"java.properties"</code>. This <code>List</code> is
152.1853 +         * {@linkplain Collections#unmodifiableList(List) unmodifiable}.
152.1854 +         *
152.1855 +         * @see #getFormats(String)
152.1856 +         */
152.1857 +        public static final List<String> FORMAT_PROPERTIES
152.1858 +            = Collections.unmodifiableList(Arrays.asList("java.properties"));
152.1859 +
152.1860 +        /**
152.1861 +         * The time-to-live constant for not caching loaded resource bundle
152.1862 +         * instances.
152.1863 +         *
152.1864 +         * @see #getTimeToLive(String, Locale)
152.1865 +         */
152.1866 +        public static final long TTL_DONT_CACHE = -1;
152.1867 +
152.1868 +        /**
152.1869 +         * The time-to-live constant for disabling the expiration control
152.1870 +         * for loaded resource bundle instances in the cache.
152.1871 +         *
152.1872 +         * @see #getTimeToLive(String, Locale)
152.1873 +         */
152.1874 +        public static final long TTL_NO_EXPIRATION_CONTROL = -2;
152.1875 +
152.1876 +        private static final Control INSTANCE = new Control();
152.1877 +
152.1878 +        /**
152.1879 +         * Sole constructor. (For invocation by subclass constructors,
152.1880 +         * typically implicit.)
152.1881 +         */
152.1882 +        protected Control() {
152.1883 +        }
152.1884 +
152.1885 +        /**
152.1886 +         * Returns a <code>ResourceBundle.Control</code> in which the {@link
152.1887 +         * #getFormats(String) getFormats} method returns the specified
152.1888 +         * <code>formats</code>. The <code>formats</code> must be equal to
152.1889 +         * one of {@link Control#FORMAT_PROPERTIES}, {@link
152.1890 +         * Control#FORMAT_CLASS} or {@link
152.1891 +         * Control#FORMAT_DEFAULT}. <code>ResourceBundle.Control</code>
152.1892 +         * instances returned by this method are singletons and thread-safe.
152.1893 +         *
152.1894 +         * <p>Specifying {@link Control#FORMAT_DEFAULT} is equivalent to
152.1895 +         * instantiating the <code>ResourceBundle.Control</code> class,
152.1896 +         * except that this method returns a singleton.
152.1897 +         *
152.1898 +         * @param formats
152.1899 +         *        the formats to be returned by the
152.1900 +         *        <code>ResourceBundle.Control.getFormats</code> method
152.1901 +         * @return a <code>ResourceBundle.Control</code> supporting the
152.1902 +         *        specified <code>formats</code>
152.1903 +         * @exception NullPointerException
152.1904 +         *        if <code>formats</code> is <code>null</code>
152.1905 +         * @exception IllegalArgumentException
152.1906 +         *        if <code>formats</code> is unknown
152.1907 +         */
152.1908 +        public static final Control getControl(List<String> formats) {
152.1909 +            if (formats.equals(Control.FORMAT_PROPERTIES)) {
152.1910 +                return SingleFormatControl.PROPERTIES_ONLY;
152.1911 +            }
152.1912 +            if (formats.equals(Control.FORMAT_CLASS)) {
152.1913 +                return SingleFormatControl.CLASS_ONLY;
152.1914 +            }
152.1915 +            if (formats.equals(Control.FORMAT_DEFAULT)) {
152.1916 +                return Control.INSTANCE;
152.1917 +            }
152.1918 +            throw new IllegalArgumentException();
152.1919 +        }
152.1920 +
152.1921 +        /**
152.1922 +         * Returns a <code>ResourceBundle.Control</code> in which the {@link
152.1923 +         * #getFormats(String) getFormats} method returns the specified
152.1924 +         * <code>formats</code> and the {@link
152.1925 +         * Control#getFallbackLocale(String, Locale) getFallbackLocale}
152.1926 +         * method returns <code>null</code>. The <code>formats</code> must
152.1927 +         * be equal to one of {@link Control#FORMAT_PROPERTIES}, {@link
152.1928 +         * Control#FORMAT_CLASS} or {@link Control#FORMAT_DEFAULT}.
152.1929 +         * <code>ResourceBundle.Control</code> instances returned by this
152.1930 +         * method are singletons and thread-safe.
152.1931 +         *
152.1932 +         * @param formats
152.1933 +         *        the formats to be returned by the
152.1934 +         *        <code>ResourceBundle.Control.getFormats</code> method
152.1935 +         * @return a <code>ResourceBundle.Control</code> supporting the
152.1936 +         *        specified <code>formats</code> with no fallback
152.1937 +         *        <code>Locale</code> support
152.1938 +         * @exception NullPointerException
152.1939 +         *        if <code>formats</code> is <code>null</code>
152.1940 +         * @exception IllegalArgumentException
152.1941 +         *        if <code>formats</code> is unknown
152.1942 +         */
152.1943 +        public static final Control getNoFallbackControl(List<String> formats) {
152.1944 +            if (formats.equals(Control.FORMAT_DEFAULT)) {
152.1945 +                return NoFallbackControl.NO_FALLBACK;
152.1946 +            }
152.1947 +            if (formats.equals(Control.FORMAT_PROPERTIES)) {
152.1948 +                return NoFallbackControl.PROPERTIES_ONLY_NO_FALLBACK;
152.1949 +            }
152.1950 +            if (formats.equals(Control.FORMAT_CLASS)) {
152.1951 +                return NoFallbackControl.CLASS_ONLY_NO_FALLBACK;
152.1952 +            }
152.1953 +            throw new IllegalArgumentException();
152.1954 +        }
152.1955 +
152.1956 +        /**
152.1957 +         * Returns a <code>List</code> of <code>String</code>s containing
152.1958 +         * formats to be used to load resource bundles for the given
152.1959 +         * <code>baseName</code>. The <code>ResourceBundle.getBundle</code>
152.1960 +         * factory method tries to load resource bundles with formats in the
152.1961 +         * order specified by the list. The list returned by this method
152.1962 +         * must have at least one <code>String</code>. The predefined
152.1963 +         * formats are <code>"java.class"</code> for class-based resource
152.1964 +         * bundles and <code>"java.properties"</code> for {@linkplain
152.1965 +         * PropertyResourceBundle properties-based} ones. Strings starting
152.1966 +         * with <code>"java."</code> are reserved for future extensions and
152.1967 +         * must not be used by application-defined formats.
152.1968 +         *
152.1969 +         * <p>It is not a requirement to return an immutable (unmodifiable)
152.1970 +         * <code>List</code>.  However, the returned <code>List</code> must
152.1971 +         * not be mutated after it has been returned by
152.1972 +         * <code>getFormats</code>.
152.1973 +         *
152.1974 +         * <p>The default implementation returns {@link #FORMAT_DEFAULT} so
152.1975 +         * that the <code>ResourceBundle.getBundle</code> factory method
152.1976 +         * looks up first class-based resource bundles, then
152.1977 +         * properties-based ones.
152.1978 +         *
152.1979 +         * @param baseName
152.1980 +         *        the base name of the resource bundle, a fully qualified class
152.1981 +         *        name
152.1982 +         * @return a <code>List</code> of <code>String</code>s containing
152.1983 +         *        formats for loading resource bundles.
152.1984 +         * @exception NullPointerException
152.1985 +         *        if <code>baseName</code> is null
152.1986 +         * @see #FORMAT_DEFAULT
152.1987 +         * @see #FORMAT_CLASS
152.1988 +         * @see #FORMAT_PROPERTIES
152.1989 +         */
152.1990 +        public List<String> getFormats(String baseName) {
152.1991 +            if (baseName == null) {
152.1992 +                throw new NullPointerException();
152.1993 +            }
152.1994 +            return FORMAT_DEFAULT;
152.1995 +        }
152.1996 +
152.1997 +        /**
152.1998 +         * Returns a <code>List</code> of <code>Locale</code>s as candidate
152.1999 +         * locales for <code>baseName</code> and <code>locale</code>. This
152.2000 +         * method is called by the <code>ResourceBundle.getBundle</code>
152.2001 +         * factory method each time the factory method tries finding a
152.2002 +         * resource bundle for a target <code>Locale</code>.
152.2003 +         *
152.2004 +         * <p>The sequence of the candidate locales also corresponds to the
152.2005 +         * runtime resource lookup path (also known as the <I>parent
152.2006 +         * chain</I>), if the corresponding resource bundles for the
152.2007 +         * candidate locales exist and their parents are not defined by
152.2008 +         * loaded resource bundles themselves.  The last element of the list
152.2009 +         * must be a {@linkplain Locale#ROOT root locale} if it is desired to
152.2010 +         * have the base bundle as the terminal of the parent chain.
152.2011 +         *
152.2012 +         * <p>If the given locale is equal to <code>Locale.ROOT</code> (the
152.2013 +         * root locale), a <code>List</code> containing only the root
152.2014 +         * <code>Locale</code> must be returned. In this case, the
152.2015 +         * <code>ResourceBundle.getBundle</code> factory method loads only
152.2016 +         * the base bundle as the resulting resource bundle.
152.2017 +         *
152.2018 +         * <p>It is not a requirement to return an immutable (unmodifiable)
152.2019 +         * <code>List</code>. However, the returned <code>List</code> must not
152.2020 +         * be mutated after it has been returned by
152.2021 +         * <code>getCandidateLocales</code>.
152.2022 +         *
152.2023 +         * <p>The default implementation returns a <code>List</code> containing
152.2024 +         * <code>Locale</code>s using the rules described below.  In the
152.2025 +         * description below, <em>L</em>, <em>S</em>, <em>C</em> and <em>V</em>
152.2026 +         * respectively represent non-empty language, script, country, and
152.2027 +         * variant.  For example, [<em>L</em>, <em>C</em>] represents a
152.2028 +         * <code>Locale</code> that has non-empty values only for language and
152.2029 +         * country.  The form <em>L</em>("xx") represents the (non-empty)
152.2030 +         * language value is "xx".  For all cases, <code>Locale</code>s whose
152.2031 +         * final component values are empty strings are omitted.
152.2032 +         *
152.2033 +         * <ol><li>For an input <code>Locale</code> with an empty script value,
152.2034 +         * append candidate <code>Locale</code>s by omitting the final component
152.2035 +         * one by one as below:
152.2036 +         *
152.2037 +         * <ul>
152.2038 +         * <li> [<em>L</em>, <em>C</em>, <em>V</em>]
152.2039 +         * <li> [<em>L</em>, <em>C</em>]
152.2040 +         * <li> [<em>L</em>]
152.2041 +         * <li> <code>Locale.ROOT</code>
152.2042 +         * </ul>
152.2043 +         *
152.2044 +         * <li>For an input <code>Locale</code> with a non-empty script value,
152.2045 +         * append candidate <code>Locale</code>s by omitting the final component
152.2046 +         * up to language, then append candidates generated from the
152.2047 +         * <code>Locale</code> with country and variant restored:
152.2048 +         *
152.2049 +         * <ul>
152.2050 +         * <li> [<em>L</em>, <em>S</em>, <em>C</em>, <em>V</em>]
152.2051 +         * <li> [<em>L</em>, <em>S</em>, <em>C</em>]
152.2052 +         * <li> [<em>L</em>, <em>S</em>]
152.2053 +         * <li> [<em>L</em>, <em>C</em>, <em>V</em>]
152.2054 +         * <li> [<em>L</em>, <em>C</em>]
152.2055 +         * <li> [<em>L</em>]
152.2056 +         * <li> <code>Locale.ROOT</code>
152.2057 +         * </ul>
152.2058 +         *
152.2059 +         * <li>For an input <code>Locale</code> with a variant value consisting
152.2060 +         * of multiple subtags separated by underscore, generate candidate
152.2061 +         * <code>Locale</code>s by omitting the variant subtags one by one, then
152.2062 +         * insert them after every occurence of <code> Locale</code>s with the
152.2063 +         * full variant value in the original list.  For example, if the
152.2064 +         * the variant consists of two subtags <em>V1</em> and <em>V2</em>:
152.2065 +         *
152.2066 +         * <ul>
152.2067 +         * <li> [<em>L</em>, <em>S</em>, <em>C</em>, <em>V1</em>, <em>V2</em>]
152.2068 +         * <li> [<em>L</em>, <em>S</em>, <em>C</em>, <em>V1</em>]
152.2069 +         * <li> [<em>L</em>, <em>S</em>, <em>C</em>]
152.2070 +         * <li> [<em>L</em>, <em>S</em>]
152.2071 +         * <li> [<em>L</em>, <em>C</em>, <em>V1</em>, <em>V2</em>]
152.2072 +         * <li> [<em>L</em>, <em>C</em>, <em>V1</em>]
152.2073 +         * <li> [<em>L</em>, <em>C</em>]
152.2074 +         * <li> [<em>L</em>]
152.2075 +         * <li> <code>Locale.ROOT</code>
152.2076 +         * </ul>
152.2077 +         *
152.2078 +         * <li>Special cases for Chinese.  When an input <code>Locale</code> has the
152.2079 +         * language "zh" (Chinese) and an empty script value, either "Hans" (Simplified) or
152.2080 +         * "Hant" (Traditional) might be supplied, depending on the country.
152.2081 +         * When the country is "CN" (China) or "SG" (Singapore), "Hans" is supplied.
152.2082 +         * When the country is "HK" (Hong Kong SAR China), "MO" (Macau SAR China),
152.2083 +         * or "TW" (Taiwan), "Hant" is supplied.  For all other countries or when the country
152.2084 +         * is empty, no script is supplied.  For example, for <code>Locale("zh", "CN")
152.2085 +         * </code>, the candidate list will be:
152.2086 +         * <ul>
152.2087 +         * <li> [<em>L</em>("zh"), <em>S</em>("Hans"), <em>C</em>("CN")]
152.2088 +         * <li> [<em>L</em>("zh"), <em>S</em>("Hans")]
152.2089 +         * <li> [<em>L</em>("zh"), <em>C</em>("CN")]
152.2090 +         * <li> [<em>L</em>("zh")]
152.2091 +         * <li> <code>Locale.ROOT</code>
152.2092 +         * </ul>
152.2093 +         *
152.2094 +         * For <code>Locale("zh", "TW")</code>, the candidate list will be:
152.2095 +         * <ul>
152.2096 +         * <li> [<em>L</em>("zh"), <em>S</em>("Hant"), <em>C</em>("TW")]
152.2097 +         * <li> [<em>L</em>("zh"), <em>S</em>("Hant")]
152.2098 +         * <li> [<em>L</em>("zh"), <em>C</em>("TW")]
152.2099 +         * <li> [<em>L</em>("zh")]
152.2100 +         * <li> <code>Locale.ROOT</code>
152.2101 +         * </ul>
152.2102 +         *
152.2103 +         * <li>Special cases for Norwegian.  Both <code>Locale("no", "NO",
152.2104 +         * "NY")</code> and <code>Locale("nn", "NO")</code> represent Norwegian
152.2105 +         * Nynorsk.  When a locale's language is "nn", the standard candidate
152.2106 +         * list is generated up to [<em>L</em>("nn")], and then the following
152.2107 +         * candidates are added:
152.2108 +         *
152.2109 +         * <ul><li> [<em>L</em>("no"), <em>C</em>("NO"), <em>V</em>("NY")]
152.2110 +         * <li> [<em>L</em>("no"), <em>C</em>("NO")]
152.2111 +         * <li> [<em>L</em>("no")]
152.2112 +         * <li> <code>Locale.ROOT</code>
152.2113 +         * </ul>
152.2114 +         *
152.2115 +         * If the locale is exactly <code>Locale("no", "NO", "NY")</code>, it is first
152.2116 +         * converted to <code>Locale("nn", "NO")</code> and then the above procedure is
152.2117 +         * followed.
152.2118 +         *
152.2119 +         * <p>Also, Java treats the language "no" as a synonym of Norwegian
152.2120 +         * Bokm&#xE5;l "nb".  Except for the single case <code>Locale("no",
152.2121 +         * "NO", "NY")</code> (handled above), when an input <code>Locale</code>
152.2122 +         * has language "no" or "nb", candidate <code>Locale</code>s with
152.2123 +         * language code "no" and "nb" are interleaved, first using the
152.2124 +         * requested language, then using its synonym. For example,
152.2125 +         * <code>Locale("nb", "NO", "POSIX")</code> generates the following
152.2126 +         * candidate list:
152.2127 +         *
152.2128 +         * <ul>
152.2129 +         * <li> [<em>L</em>("nb"), <em>C</em>("NO"), <em>V</em>("POSIX")]
152.2130 +         * <li> [<em>L</em>("no"), <em>C</em>("NO"), <em>V</em>("POSIX")]
152.2131 +         * <li> [<em>L</em>("nb"), <em>C</em>("NO")]
152.2132 +         * <li> [<em>L</em>("no"), <em>C</em>("NO")]
152.2133 +         * <li> [<em>L</em>("nb")]
152.2134 +         * <li> [<em>L</em>("no")]
152.2135 +         * <li> <code>Locale.ROOT</code>
152.2136 +         * </ul>
152.2137 +         *
152.2138 +         * <code>Locale("no", "NO", "POSIX")</code> would generate the same list
152.2139 +         * except that locales with "no" would appear before the corresponding
152.2140 +         * locales with "nb".</li>
152.2141 +         *
152.2142 +         * </li>
152.2143 +         * </ol>
152.2144 +         *
152.2145 +         * <p>The default implementation uses an {@link ArrayList} that
152.2146 +         * overriding implementations may modify before returning it to the
152.2147 +         * caller. However, a subclass must not modify it after it has
152.2148 +         * been returned by <code>getCandidateLocales</code>.
152.2149 +         *
152.2150 +         * <p>For example, if the given <code>baseName</code> is "Messages"
152.2151 +         * and the given <code>locale</code> is
152.2152 +         * <code>Locale("ja",&nbsp;"",&nbsp;"XX")</code>, then a
152.2153 +         * <code>List</code> of <code>Locale</code>s:
152.2154 +         * <pre>
152.2155 +         *     Locale("ja", "", "XX")
152.2156 +         *     Locale("ja")
152.2157 +         *     Locale.ROOT
152.2158 +         * </pre>
152.2159 +         * is returned. And if the resource bundles for the "ja" and
152.2160 +         * "" <code>Locale</code>s are found, then the runtime resource
152.2161 +         * lookup path (parent chain) is:
152.2162 +         * <pre>
152.2163 +         *     Messages_ja -> Messages
152.2164 +         * </pre>
152.2165 +         *
152.2166 +         * @param baseName
152.2167 +         *        the base name of the resource bundle, a fully
152.2168 +         *        qualified class name
152.2169 +         * @param locale
152.2170 +         *        the locale for which a resource bundle is desired
152.2171 +         * @return a <code>List</code> of candidate
152.2172 +         *        <code>Locale</code>s for the given <code>locale</code>
152.2173 +         * @exception NullPointerException
152.2174 +         *        if <code>baseName</code> or <code>locale</code> is
152.2175 +         *        <code>null</code>
152.2176 +         */
152.2177 +        public List<Locale> getCandidateLocales(String baseName, Locale locale) {
152.2178 +            if (baseName == null) {
152.2179 +                throw new NullPointerException();
152.2180 +            }
152.2181 +            return new ArrayList<>(CANDIDATES_CACHE.get(locale));
152.2182 +        }
152.2183 +
152.2184 +        private static final CandidateListCache CANDIDATES_CACHE = new CandidateListCache();
152.2185 +
152.2186 +        private static class CandidateListCache {
152.2187 +            private Locale prevQuery;
152.2188 +            private List<Locale> prevResult;
152.2189 +            
152.2190 +            public List<Locale> get(Locale l) {
152.2191 +                if (prevQuery == l) {
152.2192 +                    return prevResult;
152.2193 +                }
152.2194 +                prevResult = createObject(l);
152.2195 +                prevQuery = l;
152.2196 +                return prevResult;
152.2197 +            }
152.2198 +            
152.2199 +            protected List<Locale> createObject(Locale base) {
152.2200 +                String language = base.getLanguage();
152.2201 +                String script = base.getScript();
152.2202 +                String region = base.getRegion();
152.2203 +                String variant = base.getVariant();
152.2204 +
152.2205 +                // Special handling for Norwegian
152.2206 +                boolean isNorwegianBokmal = false;
152.2207 +                boolean isNorwegianNynorsk = false;
152.2208 +                if (language.equals("no")) {
152.2209 +                    if (region.equals("NO") && variant.equals("NY")) {
152.2210 +                        variant = "";
152.2211 +                        isNorwegianNynorsk = true;
152.2212 +                    } else {
152.2213 +                        isNorwegianBokmal = true;
152.2214 +                    }
152.2215 +                }
152.2216 +                if (language.equals("nb") || isNorwegianBokmal) {
152.2217 +                    List<Locale> tmpList = getDefaultList("nb", script, region, variant);
152.2218 +                    // Insert a locale replacing "nb" with "no" for every list entry
152.2219 +                    List<Locale> bokmalList = new LinkedList<>();
152.2220 +                    for (Locale l : tmpList) {
152.2221 +                        bokmalList.add(l);
152.2222 +                        if (l.getLanguage().length() == 0) {
152.2223 +                            break;
152.2224 +                        }
152.2225 +                        bokmalList.add(Locale.getInstance("no", l.getScript(), l.getCountry(),
152.2226 +                                l.getVariant(), null));
152.2227 +                    }
152.2228 +                    return bokmalList;
152.2229 +                } else if (language.equals("nn") || isNorwegianNynorsk) {
152.2230 +                    // Insert no_NO_NY, no_NO, no after nn
152.2231 +                    List<Locale> nynorskList = getDefaultList("nn", script, region, variant);
152.2232 +                    int idx = nynorskList.size() - 1;
152.2233 +                    nynorskList.add(idx++, Locale.getInstance("no", "NO", "NY"));
152.2234 +                    nynorskList.add(idx++, Locale.getInstance("no", "NO", ""));
152.2235 +                    nynorskList.add(idx++, Locale.getInstance("no", "", ""));
152.2236 +                    return nynorskList;
152.2237 +                }
152.2238 +                // Special handling for Chinese
152.2239 +                else if (language.equals("zh")) {
152.2240 +                    if (script.length() == 0 && region.length() > 0) {
152.2241 +                        // Supply script for users who want to use zh_Hans/zh_Hant
152.2242 +                        // as bundle names (recommended for Java7+)
152.2243 +                        if (region.equals("TW") || region.equals("HK") || region.equals("MO")) {
152.2244 +                            script = "Hant";
152.2245 +                        } else if (region.equals("CN") || region.equals("SG")) {
152.2246 +                            script = "Hans";
152.2247 +                        }
152.2248 +                    } else if (script.length() > 0 && region.length() == 0) {
152.2249 +                        // Supply region(country) for users who still package Chinese
152.2250 +                        // bundles using old convension.
152.2251 +                        if (script.equals("Hans")) {
152.2252 +                            region = "CN";
152.2253 +                        } else if (script.equals("Hant")) {
152.2254 +                            region = "TW";
152.2255 +                        }
152.2256 +                    }
152.2257 +                }
152.2258 +
152.2259 +                return getDefaultList(language, script, region, variant);
152.2260 +            }
152.2261 +
152.2262 +            private static List<Locale> getDefaultList(String language, String script, String region, String variant) {
152.2263 +                List<String> variants = null;
152.2264 +
152.2265 +                if (variant.length() > 0) {
152.2266 +                    variants = new LinkedList<>();
152.2267 +                    int idx = variant.length();
152.2268 +                    while (idx != -1) {
152.2269 +                        variants.add(variant.substring(0, idx));
152.2270 +                        idx = variant.lastIndexOf('_', --idx);
152.2271 +                    }
152.2272 +                }
152.2273 +
152.2274 +                List<Locale> list = new LinkedList<>();
152.2275 +
152.2276 +                if (variants != null) {
152.2277 +                    for (String v : variants) {
152.2278 +                        list.add(Locale.getInstance(language, script, region, v, null));
152.2279 +                    }
152.2280 +                }
152.2281 +                if (region.length() > 0) {
152.2282 +                    list.add(Locale.getInstance(language, script, region, "", null));
152.2283 +                }
152.2284 +                if (script.length() > 0) {
152.2285 +                    list.add(Locale.getInstance(language, script, "", "", null));
152.2286 +
152.2287 +                    // With script, after truncating variant, region and script,
152.2288 +                    // start over without script.
152.2289 +                    if (variants != null) {
152.2290 +                        for (String v : variants) {
152.2291 +                            list.add(Locale.getInstance(language, "", region, v, null));
152.2292 +                        }
152.2293 +                    }
152.2294 +                    if (region.length() > 0) {
152.2295 +                        list.add(Locale.getInstance(language, "", region, "", null));
152.2296 +                    }
152.2297 +                }
152.2298 +                if (language.length() > 0) {
152.2299 +                    list.add(Locale.getInstance(language, "", "", "", null));
152.2300 +                }
152.2301 +                // Add root locale at the end
152.2302 +                list.add(Locale.ROOT);
152.2303 +
152.2304 +                return list;
152.2305 +            }
152.2306 +        }
152.2307 +
152.2308 +        /**
152.2309 +         * Returns a <code>Locale</code> to be used as a fallback locale for
152.2310 +         * further resource bundle searches by the
152.2311 +         * <code>ResourceBundle.getBundle</code> factory method. This method
152.2312 +         * is called from the factory method every time when no resulting
152.2313 +         * resource bundle has been found for <code>baseName</code> and
152.2314 +         * <code>locale</code>, where locale is either the parameter for
152.2315 +         * <code>ResourceBundle.getBundle</code> or the previous fallback
152.2316 +         * locale returned by this method.
152.2317 +         *
152.2318 +         * <p>The method returns <code>null</code> if no further fallback
152.2319 +         * search is desired.
152.2320 +         *
152.2321 +         * <p>The default implementation returns the {@linkplain
152.2322 +         * Locale#getDefault() default <code>Locale</code>} if the given
152.2323 +         * <code>locale</code> isn't the default one.  Otherwise,
152.2324 +         * <code>null</code> is returned.
152.2325 +         *
152.2326 +         * @param baseName
152.2327 +         *        the base name of the resource bundle, a fully
152.2328 +         *        qualified class name for which
152.2329 +         *        <code>ResourceBundle.getBundle</code> has been
152.2330 +         *        unable to find any resource bundles (except for the
152.2331 +         *        base bundle)
152.2332 +         * @param locale
152.2333 +         *        the <code>Locale</code> for which
152.2334 +         *        <code>ResourceBundle.getBundle</code> has been
152.2335 +         *        unable to find any resource bundles (except for the
152.2336 +         *        base bundle)
152.2337 +         * @return a <code>Locale</code> for the fallback search,
152.2338 +         *        or <code>null</code> if no further fallback search
152.2339 +         *        is desired.
152.2340 +         * @exception NullPointerException
152.2341 +         *        if <code>baseName</code> or <code>locale</code>
152.2342 +         *        is <code>null</code>
152.2343 +         */
152.2344 +        public Locale getFallbackLocale(String baseName, Locale locale) {
152.2345 +            if (baseName == null) {
152.2346 +                throw new NullPointerException();
152.2347 +            }
152.2348 +            Locale defaultLocale = Locale.getDefault();
152.2349 +            return locale.equals(defaultLocale) ? null : defaultLocale;
152.2350 +        }
152.2351 +
152.2352 +        /**
152.2353 +         * Instantiates a resource bundle for the given bundle name of the
152.2354 +         * given format and locale, using the given class loader if
152.2355 +         * necessary. This method returns <code>null</code> if there is no
152.2356 +         * resource bundle available for the given parameters. If a resource
152.2357 +         * bundle can't be instantiated due to an unexpected error, the
152.2358 +         * error must be reported by throwing an <code>Error</code> or
152.2359 +         * <code>Exception</code> rather than simply returning
152.2360 +         * <code>null</code>.
152.2361 +         *
152.2362 +         * <p>If the <code>reload</code> flag is <code>true</code>, it
152.2363 +         * indicates that this method is being called because the previously
152.2364 +         * loaded resource bundle has expired.
152.2365 +         *
152.2366 +         * <p>The default implementation instantiates a
152.2367 +         * <code>ResourceBundle</code> as follows.
152.2368 +         *
152.2369 +         * <ul>
152.2370 +         *
152.2371 +         * <li>The bundle name is obtained by calling {@link
152.2372 +         * #toBundleName(String, Locale) toBundleName(baseName,
152.2373 +         * locale)}.</li>
152.2374 +         *
152.2375 +         * <li>If <code>format</code> is <code>"java.class"</code>, the
152.2376 +         * {@link Class} specified by the bundle name is loaded by calling
152.2377 +         * {@link ClassLoader#loadClass(String)}. Then, a
152.2378 +         * <code>ResourceBundle</code> is instantiated by calling {@link
152.2379 +         * Class#newInstance()}.  Note that the <code>reload</code> flag is
152.2380 +         * ignored for loading class-based resource bundles in this default
152.2381 +         * implementation.</li>
152.2382 +         *
152.2383 +         * <li>If <code>format</code> is <code>"java.properties"</code>,
152.2384 +         * {@link #toResourceName(String, String) toResourceName(bundlename,
152.2385 +         * "properties")} is called to get the resource name.
152.2386 +         * If <code>reload</code> is <code>true</code>, {@link
152.2387 +         * ClassLoader#getResource(String) load.getResource} is called
152.2388 +         * to get a {@link URL} for creating a {@link
152.2389 +         * URLConnection}. This <code>URLConnection</code> is used to
152.2390 +         * {@linkplain URLConnection#setUseCaches(boolean) disable the
152.2391 +         * caches} of the underlying resource loading layers,
152.2392 +         * and to {@linkplain URLConnection#getInputStream() get an
152.2393 +         * <code>InputStream</code>}.
152.2394 +         * Otherwise, {@link ClassLoader#getResourceAsStream(String)
152.2395 +         * loader.getResourceAsStream} is called to get an {@link
152.2396 +         * InputStream}. Then, a {@link
152.2397 +         * PropertyResourceBundle} is constructed with the
152.2398 +         * <code>InputStream</code>.</li>
152.2399 +         *
152.2400 +         * <li>If <code>format</code> is neither <code>"java.class"</code>
152.2401 +         * nor <code>"java.properties"</code>, an
152.2402 +         * <code>IllegalArgumentException</code> is thrown.</li>
152.2403 +         *
152.2404 +         * </ul>
152.2405 +         *
152.2406 +         * @param baseName
152.2407 +         *        the base bundle name of the resource bundle, a fully
152.2408 +         *        qualified class name
152.2409 +         * @param locale
152.2410 +         *        the locale for which the resource bundle should be
152.2411 +         *        instantiated
152.2412 +         * @param format
152.2413 +         *        the resource bundle format to be loaded
152.2414 +         * @param loader
152.2415 +         *        the <code>ClassLoader</code> to use to load the bundle
152.2416 +         * @param reload
152.2417 +         *        the flag to indicate bundle reloading; <code>true</code>
152.2418 +         *        if reloading an expired resource bundle,
152.2419 +         *        <code>false</code> otherwise
152.2420 +         * @return the resource bundle instance,
152.2421 +         *        or <code>null</code> if none could be found.
152.2422 +         * @exception NullPointerException
152.2423 +         *        if <code>bundleName</code>, <code>locale</code>,
152.2424 +         *        <code>format</code>, or <code>loader</code> is
152.2425 +         *        <code>null</code>, or if <code>null</code> is returned by
152.2426 +         *        {@link #toBundleName(String, Locale) toBundleName}
152.2427 +         * @exception IllegalArgumentException
152.2428 +         *        if <code>format</code> is unknown, or if the resource
152.2429 +         *        found for the given parameters contains malformed data.
152.2430 +         * @exception ClassCastException
152.2431 +         *        if the loaded class cannot be cast to <code>ResourceBundle</code>
152.2432 +         * @exception IllegalAccessException
152.2433 +         *        if the class or its nullary constructor is not
152.2434 +         *        accessible.
152.2435 +         * @exception InstantiationException
152.2436 +         *        if the instantiation of a class fails for some other
152.2437 +         *        reason.
152.2438 +         * @exception ExceptionInInitializerError
152.2439 +         *        if the initialization provoked by this method fails.
152.2440 +         * @exception SecurityException
152.2441 +         *        If a security manager is present and creation of new
152.2442 +         *        instances is denied. See {@link Class#newInstance()}
152.2443 +         *        for details.
152.2444 +         * @exception IOException
152.2445 +         *        if an error occurred when reading resources using
152.2446 +         *        any I/O operations
152.2447 +         */
152.2448 +        public ResourceBundle newBundle(String baseName, Locale locale, String format,
152.2449 +                                        ClassLoader loader, boolean reload)
152.2450 +                    throws IllegalAccessException, InstantiationException, IOException {
152.2451 +            String bundleName = toBundleName(baseName, locale);
152.2452 +            ResourceBundle bundle = null;
152.2453 +            if (format.equals("java.class")) {
152.2454 +                try {
152.2455 +                    Class<? extends ResourceBundle> bundleClass
152.2456 +                        = (Class<? extends ResourceBundle>)(loader != null ? 
152.2457 +                        loader.loadClass(bundleName) :
152.2458 +                        Class.forName(bundleName));
152.2459 +
152.2460 +                    // If the class isn't a ResourceBundle subclass, throw a
152.2461 +                    // ClassCastException.
152.2462 +                    if (ResourceBundle.class.isAssignableFrom(bundleClass)) {
152.2463 +                        bundle = bundleClass.newInstance();
152.2464 +                    } else {
152.2465 +                        throw new ClassCastException(bundleClass.getName()
152.2466 +                                     + " cannot be cast to ResourceBundle");
152.2467 +                    }
152.2468 +                } catch (ClassNotFoundException e) {
152.2469 +                }
152.2470 +            } else if (format.equals("java.properties")) {
152.2471 +                final String resourceName = toResourceName(bundleName, "properties");
152.2472 +                final ClassLoader classLoader = loader;
152.2473 +                final boolean reloadFlag = reload;
152.2474 +                InputStream stream = classLoader != null ? classLoader.getResourceAsStream(resourceName) :
152.2475 +                    ResourceBundle.class.getResourceAsStream("/" + resourceName);
152.2476 +                if (stream != null) {
152.2477 +                    try {
152.2478 +                        bundle = new PropertyResourceBundle(stream);
152.2479 +                    } finally {
152.2480 +                        stream.close();
152.2481 +                    }
152.2482 +                }   
152.2483 +            } else {
152.2484 +                throw new IllegalArgumentException("unknown format: " + format);
152.2485 +            }
152.2486 +            return bundle;
152.2487 +        }
152.2488 +
152.2489 +        /**
152.2490 +         * Returns the time-to-live (TTL) value for resource bundles that
152.2491 +         * are loaded under this
152.2492 +         * <code>ResourceBundle.Control</code>. Positive time-to-live values
152.2493 +         * specify the number of milliseconds a bundle can remain in the
152.2494 +         * cache without being validated against the source data from which
152.2495 +         * it was constructed. The value 0 indicates that a bundle must be
152.2496 +         * validated each time it is retrieved from the cache. {@link
152.2497 +         * #TTL_DONT_CACHE} specifies that loaded resource bundles are not
152.2498 +         * put in the cache. {@link #TTL_NO_EXPIRATION_CONTROL} specifies
152.2499 +         * that loaded resource bundles are put in the cache with no
152.2500 +         * expiration control.
152.2501 +         *
152.2502 +         * <p>The expiration affects only the bundle loading process by the
152.2503 +         * <code>ResourceBundle.getBundle</code> factory method.  That is,
152.2504 +         * if the factory method finds a resource bundle in the cache that
152.2505 +         * has expired, the factory method calls the {@link
152.2506 +         * #needsReload(String, Locale, String, ClassLoader, ResourceBundle,
152.2507 +         * long) needsReload} method to determine whether the resource
152.2508 +         * bundle needs to be reloaded. If <code>needsReload</code> returns
152.2509 +         * <code>true</code>, the cached resource bundle instance is removed
152.2510 +         * from the cache. Otherwise, the instance stays in the cache,
152.2511 +         * updated with the new TTL value returned by this method.
152.2512 +         *
152.2513 +         * <p>All cached resource bundles are subject to removal from the
152.2514 +         * cache due to memory constraints of the runtime environment.
152.2515 +         * Returning a large positive value doesn't mean to lock loaded
152.2516 +         * resource bundles in the cache.
152.2517 +         *
152.2518 +         * <p>The default implementation returns {@link #TTL_NO_EXPIRATION_CONTROL}.
152.2519 +         *
152.2520 +         * @param baseName
152.2521 +         *        the base name of the resource bundle for which the
152.2522 +         *        expiration value is specified.
152.2523 +         * @param locale
152.2524 +         *        the locale of the resource bundle for which the
152.2525 +         *        expiration value is specified.
152.2526 +         * @return the time (0 or a positive millisecond offset from the
152.2527 +         *        cached time) to get loaded bundles expired in the cache,
152.2528 +         *        {@link #TTL_NO_EXPIRATION_CONTROL} to disable the
152.2529 +         *        expiration control, or {@link #TTL_DONT_CACHE} to disable
152.2530 +         *        caching.
152.2531 +         * @exception NullPointerException
152.2532 +         *        if <code>baseName</code> or <code>locale</code> is
152.2533 +         *        <code>null</code>
152.2534 +         */
152.2535 +        public long getTimeToLive(String baseName, Locale locale) {
152.2536 +            if (baseName == null || locale == null) {
152.2537 +                throw new NullPointerException();
152.2538 +            }
152.2539 +            return TTL_NO_EXPIRATION_CONTROL;
152.2540 +        }
152.2541 +
152.2542 +        /**
152.2543 +         * Determines if the expired <code>bundle</code> in the cache needs
152.2544 +         * to be reloaded based on the loading time given by
152.2545 +         * <code>loadTime</code> or some other criteria. The method returns
152.2546 +         * <code>true</code> if reloading is required; <code>false</code>
152.2547 +         * otherwise. <code>loadTime</code> is a millisecond offset since
152.2548 +         * the <a href="Calendar.html#Epoch"> <code>Calendar</code>
152.2549 +         * Epoch</a>.
152.2550 +         *
152.2551 +         * The calling <code>ResourceBundle.getBundle</code> factory method
152.2552 +         * calls this method on the <code>ResourceBundle.Control</code>
152.2553 +         * instance used for its current invocation, not on the instance
152.2554 +         * used in the invocation that originally loaded the resource
152.2555 +         * bundle.
152.2556 +         *
152.2557 +         * <p>The default implementation compares <code>loadTime</code> and
152.2558 +         * the last modified time of the source data of the resource
152.2559 +         * bundle. If it's determined that the source data has been modified
152.2560 +         * since <code>loadTime</code>, <code>true</code> is
152.2561 +         * returned. Otherwise, <code>false</code> is returned. This
152.2562 +         * implementation assumes that the given <code>format</code> is the
152.2563 +         * same string as its file suffix if it's not one of the default
152.2564 +         * formats, <code>"java.class"</code> or
152.2565 +         * <code>"java.properties"</code>.
152.2566 +         *
152.2567 +         * @param baseName
152.2568 +         *        the base bundle name of the resource bundle, a
152.2569 +         *        fully qualified class name
152.2570 +         * @param locale
152.2571 +         *        the locale for which the resource bundle
152.2572 +         *        should be instantiated
152.2573 +         * @param format
152.2574 +         *        the resource bundle format to be loaded
152.2575 +         * @param loader
152.2576 +         *        the <code>ClassLoader</code> to use to load the bundle
152.2577 +         * @param bundle
152.2578 +         *        the resource bundle instance that has been expired
152.2579 +         *        in the cache
152.2580 +         * @param loadTime
152.2581 +         *        the time when <code>bundle</code> was loaded and put
152.2582 +         *        in the cache
152.2583 +         * @return <code>true</code> if the expired bundle needs to be
152.2584 +         *        reloaded; <code>false</code> otherwise.
152.2585 +         * @exception NullPointerException
152.2586 +         *        if <code>baseName</code>, <code>locale</code>,
152.2587 +         *        <code>format</code>, <code>loader</code>, or
152.2588 +         *        <code>bundle</code> is <code>null</code>
152.2589 +         */
152.2590 +        public boolean needsReload(String baseName, Locale locale,
152.2591 +                                   String format, ClassLoader loader,
152.2592 +                                   ResourceBundle bundle, long loadTime) {
152.2593 +            if (bundle == null) {
152.2594 +                throw new NullPointerException();
152.2595 +            }
152.2596 +            if (format.equals("java.class") || format.equals("java.properties")) {
152.2597 +                format = format.substring(5);
152.2598 +            }
152.2599 +            boolean result = false;
152.2600 +            try {
152.2601 +/*
152.2602 +                String resourceName = toResourceName(toBundleName(baseName, locale), format);
152.2603 +                URL url = loader.getResource(resourceName);
152.2604 +                if (url != null) {
152.2605 +                    long lastModified = 0;
152.2606 +                    URLConnection connection = url.openConnection();
152.2607 +                    if (connection != null) {
152.2608 +                        // disable caches to get the correct data
152.2609 +                        connection.setUseCaches(false);
152.2610 +                        if (connection instanceof JarURLConnection) {
152.2611 +                            JarEntry ent = ((JarURLConnection)connection).getJarEntry();
152.2612 +                            if (ent != null) {
152.2613 +                                lastModified = ent.getTime();
152.2614 +                                if (lastModified == -1) {
152.2615 +                                    lastModified = 0;
152.2616 +                                }
152.2617 +                            }
152.2618 +                        } else {
152.2619 +                            lastModified = connection.getLastModified();
152.2620 +                        }
152.2621 +                    }
152.2622 +                    result = lastModified >= loadTime;
152.2623 +                }
152.2624 +                */
152.2625 +            } catch (NullPointerException npe) {
152.2626 +                throw npe;
152.2627 +            } catch (Exception e) {
152.2628 +                // ignore other exceptions
152.2629 +            }
152.2630 +            return result;
152.2631 +        }
152.2632 +
152.2633 +        /**
152.2634 +         * Converts the given <code>baseName</code> and <code>locale</code>
152.2635 +         * to the bundle name. This method is called from the default
152.2636 +         * implementation of the {@link #newBundle(String, Locale, String,
152.2637 +         * ClassLoader, boolean) newBundle} and {@link #needsReload(String,
152.2638 +         * Locale, String, ClassLoader, ResourceBundle, long) needsReload}
152.2639 +         * methods.
152.2640 +         *
152.2641 +         * <p>This implementation returns the following value:
152.2642 +         * <pre>
152.2643 +         *     baseName + "_" + language + "_" + script + "_" + country + "_" + variant
152.2644 +         * </pre>
152.2645 +         * where <code>language</code>, <code>script</code>, <code>country</code>,
152.2646 +         * and <code>variant</code> are the language, script, country, and variant
152.2647 +         * values of <code>locale</code>, respectively. Final component values that
152.2648 +         * are empty Strings are omitted along with the preceding '_'.  When the
152.2649 +         * script is empty, the script value is ommitted along with the preceding '_'.
152.2650 +         * If all of the values are empty strings, then <code>baseName</code>
152.2651 +         * is returned.
152.2652 +         *
152.2653 +         * <p>For example, if <code>baseName</code> is
152.2654 +         * <code>"baseName"</code> and <code>locale</code> is
152.2655 +         * <code>Locale("ja",&nbsp;"",&nbsp;"XX")</code>, then
152.2656 +         * <code>"baseName_ja_&thinsp;_XX"</code> is returned. If the given
152.2657 +         * locale is <code>Locale("en")</code>, then
152.2658 +         * <code>"baseName_en"</code> is returned.
152.2659 +         *
152.2660 +         * <p>Overriding this method allows applications to use different
152.2661 +         * conventions in the organization and packaging of localized
152.2662 +         * resources.
152.2663 +         *
152.2664 +         * @param baseName
152.2665 +         *        the base name of the resource bundle, a fully
152.2666 +         *        qualified class name
152.2667 +         * @param locale
152.2668 +         *        the locale for which a resource bundle should be
152.2669 +         *        loaded
152.2670 +         * @return the bundle name for the resource bundle
152.2671 +         * @exception NullPointerException
152.2672 +         *        if <code>baseName</code> or <code>locale</code>
152.2673 +         *        is <code>null</code>
152.2674 +         */
152.2675 +        public String toBundleName(String baseName, Locale locale) {
152.2676 +            if (locale == Locale.ROOT) {
152.2677 +                return baseName;
152.2678 +            }
152.2679 +
152.2680 +            String language = locale.getLanguage();
152.2681 +            String script = locale.getScript();
152.2682 +            String country = locale.getCountry();
152.2683 +            String variant = locale.getVariant();
152.2684 +
152.2685 +            if (language == "" && country == "" && variant == "") {
152.2686 +                return baseName;
152.2687 +            }
152.2688 +
152.2689 +            StringBuilder sb = new StringBuilder(baseName);
152.2690 +            sb.append('_');
152.2691 +            if (script != "") {
152.2692 +                if (variant != "") {
152.2693 +                    sb.append(language).append('_').append(script).append('_').append(country).append('_').append(variant);
152.2694 +                } else if (country != "") {
152.2695 +                    sb.append(language).append('_').append(script).append('_').append(country);
152.2696 +                } else {
152.2697 +                    sb.append(language).append('_').append(script);
152.2698 +                }
152.2699 +            } else {
152.2700 +                if (variant != "") {
152.2701 +                    sb.append(language).append('_').append(country).append('_').append(variant);
152.2702 +                } else if (country != "") {
152.2703 +                    sb.append(language).append('_').append(country);
152.2704 +                } else {
152.2705 +                    sb.append(language);
152.2706 +                }
152.2707 +            }
152.2708 +            return sb.toString();
152.2709 +
152.2710 +        }
152.2711 +
152.2712 +        /**
152.2713 +         * Converts the given <code>bundleName</code> to the form required
152.2714 +         * by the {@link ClassLoader#getResource ClassLoader.getResource}
152.2715 +         * method by replacing all occurrences of <code>'.'</code> in
152.2716 +         * <code>bundleName</code> with <code>'/'</code> and appending a
152.2717 +         * <code>'.'</code> and the given file <code>suffix</code>. For
152.2718 +         * example, if <code>bundleName</code> is
152.2719 +         * <code>"foo.bar.MyResources_ja_JP"</code> and <code>suffix</code>
152.2720 +         * is <code>"properties"</code>, then
152.2721 +         * <code>"foo/bar/MyResources_ja_JP.properties"</code> is returned.
152.2722 +         *
152.2723 +         * @param bundleName
152.2724 +         *        the bundle name
152.2725 +         * @param suffix
152.2726 +         *        the file type suffix
152.2727 +         * @return the converted resource name
152.2728 +         * @exception NullPointerException
152.2729 +         *         if <code>bundleName</code> or <code>suffix</code>
152.2730 +         *         is <code>null</code>
152.2731 +         */
152.2732 +        public final String toResourceName(String bundleName, String suffix) {
152.2733 +            StringBuilder sb = new StringBuilder(bundleName.length() + 1 + suffix.length());
152.2734 +            sb.append(bundleName.replace('.', '/')).append('.').append(suffix);
152.2735 +            return sb.toString();
152.2736 +        }
152.2737 +    }
152.2738 +
152.2739 +    private static class SingleFormatControl extends Control {
152.2740 +        private static final Control PROPERTIES_ONLY
152.2741 +            = new SingleFormatControl(FORMAT_PROPERTIES);
152.2742 +
152.2743 +        private static final Control CLASS_ONLY
152.2744 +            = new SingleFormatControl(FORMAT_CLASS);
152.2745 +
152.2746 +        private final List<String> formats;
152.2747 +
152.2748 +        protected SingleFormatControl(List<String> formats) {
152.2749 +            this.formats = formats;
152.2750 +        }
152.2751 +
152.2752 +        public List<String> getFormats(String baseName) {
152.2753 +            if (baseName == null) {
152.2754 +                throw new NullPointerException();
152.2755 +            }
152.2756 +            return formats;
152.2757 +        }
152.2758 +    }
152.2759 +
152.2760 +    private static final class NoFallbackControl extends SingleFormatControl {
152.2761 +        private static final Control NO_FALLBACK
152.2762 +            = new NoFallbackControl(FORMAT_DEFAULT);
152.2763 +
152.2764 +        private static final Control PROPERTIES_ONLY_NO_FALLBACK
152.2765 +            = new NoFallbackControl(FORMAT_PROPERTIES);
152.2766 +
152.2767 +        private static final Control CLASS_ONLY_NO_FALLBACK
152.2768 +            = new NoFallbackControl(FORMAT_CLASS);
152.2769 +
152.2770 +        protected NoFallbackControl(List<String> formats) {
152.2771 +            super(formats);
152.2772 +        }
152.2773 +
152.2774 +        public Locale getFallbackLocale(String baseName, Locale locale) {
152.2775 +            if (baseName == null || locale == null) {
152.2776 +                throw new NullPointerException();
152.2777 +            }
152.2778 +            return null;
152.2779 +        }
152.2780 +    }
152.2781 +}
   153.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   153.2 +++ b/rt/emul/compact/src/main/java/java/util/SimpleTimeZone.java	Tue Feb 11 13:31:42 2014 +0100
   153.3 @@ -0,0 +1,1737 @@
   153.4 +/*
   153.5 + * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
   153.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   153.7 + *
   153.8 + * This code is free software; you can redistribute it and/or modify it
   153.9 + * under the terms of the GNU General Public License version 2 only, as
  153.10 + * published by the Free Software Foundation.  Oracle designates this
  153.11 + * particular file as subject to the "Classpath" exception as provided
  153.12 + * by Oracle in the LICENSE file that accompanied this code.
  153.13 + *
  153.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  153.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  153.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  153.17 + * version 2 for more details (a copy is included in the LICENSE file that
  153.18 + * accompanied this code).
  153.19 + *
  153.20 + * You should have received a copy of the GNU General Public License version
  153.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  153.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  153.23 + *
  153.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  153.25 + * or visit www.oracle.com if you need additional information or have any
  153.26 + * questions.
  153.27 + */
  153.28 +
  153.29 +/*
  153.30 + * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
  153.31 + * (C) Copyright IBM Corp. 1996 - All Rights Reserved
  153.32 + *
  153.33 + *   The original version of this source code and documentation is copyrighted
  153.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
  153.35 + * materials are provided under terms of a License Agreement between Taligent
  153.36 + * and Sun. This technology is protected by multiple US and International
  153.37 + * patents. This notice and attribution to Taligent may not be removed.
  153.38 + *   Taligent is a registered trademark of Taligent, Inc.
  153.39 + *
  153.40 + */
  153.41 +
  153.42 +package java.util;
  153.43 +
  153.44 +import java.io.ObjectInputStream;
  153.45 +import java.io.ObjectOutputStream;
  153.46 +import java.io.IOException;
  153.47 +import java.util.Date.BaseCalendar;
  153.48 +
  153.49 +/**
  153.50 + * <code>SimpleTimeZone</code> is a concrete subclass of <code>TimeZone</code>
  153.51 + * that represents a time zone for use with a Gregorian calendar.
  153.52 + * The class holds an offset from GMT, called <em>raw offset</em>, and start
  153.53 + * and end rules for a daylight saving time schedule.  Since it only holds
  153.54 + * single values for each, it cannot handle historical changes in the offset
  153.55 + * from GMT and the daylight saving schedule, except that the {@link
  153.56 + * #setStartYear setStartYear} method can specify the year when the daylight
  153.57 + * saving time schedule starts in effect.
  153.58 + * <p>
  153.59 + * To construct a <code>SimpleTimeZone</code> with a daylight saving time
  153.60 + * schedule, the schedule can be described with a set of rules,
  153.61 + * <em>start-rule</em> and <em>end-rule</em>. A day when daylight saving time
  153.62 + * starts or ends is specified by a combination of <em>month</em>,
  153.63 + * <em>day-of-month</em>, and <em>day-of-week</em> values. The <em>month</em>
  153.64 + * value is represented by a Calendar {@link Calendar#MONTH MONTH} field
  153.65 + * value, such as {@link Calendar#MARCH}. The <em>day-of-week</em> value is
  153.66 + * represented by a Calendar {@link Calendar#DAY_OF_WEEK DAY_OF_WEEK} value,
  153.67 + * such as {@link Calendar#SUNDAY SUNDAY}. The meanings of value combinations
  153.68 + * are as follows.
  153.69 + *
  153.70 + * <ul>
  153.71 + * <li><b>Exact day of month</b><br>
  153.72 + * To specify an exact day of month, set the <em>month</em> and
  153.73 + * <em>day-of-month</em> to an exact value, and <em>day-of-week</em> to zero. For
  153.74 + * example, to specify March 1, set the <em>month</em> to {@link Calendar#MARCH
  153.75 + * MARCH}, <em>day-of-month</em> to 1, and <em>day-of-week</em> to 0.</li>
  153.76 + *
  153.77 + * <li><b>Day of week on or after day of month</b><br>
  153.78 + * To specify a day of week on or after an exact day of month, set the
  153.79 + * <em>month</em> to an exact month value, <em>day-of-month</em> to the day on
  153.80 + * or after which the rule is applied, and <em>day-of-week</em> to a negative {@link
  153.81 + * Calendar#DAY_OF_WEEK DAY_OF_WEEK} field value. For example, to specify the
  153.82 + * second Sunday of April, set <em>month</em> to {@link Calendar#APRIL APRIL},
  153.83 + * <em>day-of-month</em> to 8, and <em>day-of-week</em> to <code>-</code>{@link
  153.84 + * Calendar#SUNDAY SUNDAY}.</li>
  153.85 + *
  153.86 + * <li><b>Day of week on or before day of month</b><br>
  153.87 + * To specify a day of the week on or before an exact day of the month, set
  153.88 + * <em>day-of-month</em> and <em>day-of-week</em> to a negative value. For
  153.89 + * example, to specify the last Wednesday on or before the 21st of March, set
  153.90 + * <em>month</em> to {@link Calendar#MARCH MARCH}, <em>day-of-month</em> is -21
  153.91 + * and <em>day-of-week</em> is <code>-</code>{@link Calendar#WEDNESDAY WEDNESDAY}. </li>
  153.92 + *
  153.93 + * <li><b>Last day-of-week of month</b><br>
  153.94 + * To specify, the last day-of-week of the month, set <em>day-of-week</em> to a
  153.95 + * {@link Calendar#DAY_OF_WEEK DAY_OF_WEEK} value and <em>day-of-month</em> to
  153.96 + * -1. For example, to specify the last Sunday of October, set <em>month</em>
  153.97 + * to {@link Calendar#OCTOBER OCTOBER}, <em>day-of-week</em> to {@link
  153.98 + * Calendar#SUNDAY SUNDAY} and <em>day-of-month</em> to -1.  </li>
  153.99 + *
 153.100 + * </ul>
 153.101 + * The time of the day at which daylight saving time starts or ends is
 153.102 + * specified by a millisecond value within the day. There are three kinds of
 153.103 + * <em>mode</em>s to specify the time: {@link #WALL_TIME}, {@link
 153.104 + * #STANDARD_TIME} and {@link #UTC_TIME}. For example, if daylight
 153.105 + * saving time ends
 153.106 + * at 2:00 am in the wall clock time, it can be specified by 7200000
 153.107 + * milliseconds in the {@link #WALL_TIME} mode. In this case, the wall clock time
 153.108 + * for an <em>end-rule</em> means the same thing as the daylight time.
 153.109 + * <p>
 153.110 + * The following are examples of parameters for constructing time zone objects.
 153.111 + * <pre><code>
 153.112 + *      // Base GMT offset: -8:00
 153.113 + *      // DST starts:      at 2:00am in standard time
 153.114 + *      //                  on the first Sunday in April
 153.115 + *      // DST ends:        at 2:00am in daylight time
 153.116 + *      //                  on the last Sunday in October
 153.117 + *      // Save:            1 hour
 153.118 + *      SimpleTimeZone(-28800000,
 153.119 + *                     "America/Los_Angeles",
 153.120 + *                     Calendar.APRIL, 1, -Calendar.SUNDAY,
 153.121 + *                     7200000,
 153.122 + *                     Calendar.OCTOBER, -1, Calendar.SUNDAY,
 153.123 + *                     7200000,
 153.124 + *                     3600000)
 153.125 + *
 153.126 + *      // Base GMT offset: +1:00
 153.127 + *      // DST starts:      at 1:00am in UTC time
 153.128 + *      //                  on the last Sunday in March
 153.129 + *      // DST ends:        at 1:00am in UTC time
 153.130 + *      //                  on the last Sunday in October
 153.131 + *      // Save:            1 hour
 153.132 + *      SimpleTimeZone(3600000,
 153.133 + *                     "Europe/Paris",
 153.134 + *                     Calendar.MARCH, -1, Calendar.SUNDAY,
 153.135 + *                     3600000, SimpleTimeZone.UTC_TIME,
 153.136 + *                     Calendar.OCTOBER, -1, Calendar.SUNDAY,
 153.137 + *                     3600000, SimpleTimeZone.UTC_TIME,
 153.138 + *                     3600000)
 153.139 + * </code></pre>
 153.140 + * These parameter rules are also applicable to the set rule methods, such as
 153.141 + * <code>setStartRule</code>.
 153.142 + *
 153.143 + * @since 1.1
 153.144 + * @see      Calendar
 153.145 + * @see      GregorianCalendar
 153.146 + * @see      TimeZone
 153.147 + * @author   David Goldsmith, Mark Davis, Chen-Lieh Huang, Alan Liu
 153.148 + */
 153.149 +
 153.150 +public class SimpleTimeZone extends TimeZone {
 153.151 +    /**
 153.152 +     * Constructs a SimpleTimeZone with the given base time zone offset from GMT
 153.153 +     * and time zone ID with no daylight saving time schedule.
 153.154 +     *
 153.155 +     * @param rawOffset  The base time zone offset in milliseconds to GMT.
 153.156 +     * @param ID         The time zone name that is given to this instance.
 153.157 +     */
 153.158 +    public SimpleTimeZone(int rawOffset, String ID)
 153.159 +    {
 153.160 +        this.rawOffset = rawOffset;
 153.161 +        setID (ID);
 153.162 +        dstSavings = millisPerHour; // In case user sets rules later
 153.163 +    }
 153.164 +
 153.165 +    /**
 153.166 +     * Constructs a SimpleTimeZone with the given base time zone offset from
 153.167 +     * GMT, time zone ID, and rules for starting and ending the daylight
 153.168 +     * time.
 153.169 +     * Both <code>startTime</code> and <code>endTime</code> are specified to be
 153.170 +     * represented in the wall clock time. The amount of daylight saving is
 153.171 +     * assumed to be 3600000 milliseconds (i.e., one hour). This constructor is
 153.172 +     * equivalent to:
 153.173 +     * <pre><code>
 153.174 +     *     SimpleTimeZone(rawOffset,
 153.175 +     *                    ID,
 153.176 +     *                    startMonth,
 153.177 +     *                    startDay,
 153.178 +     *                    startDayOfWeek,
 153.179 +     *                    startTime,
 153.180 +     *                    SimpleTimeZone.{@link #WALL_TIME},
 153.181 +     *                    endMonth,
 153.182 +     *                    endDay,
 153.183 +     *                    endDayOfWeek,
 153.184 +     *                    endTime,
 153.185 +     *                    SimpleTimeZone.{@link #WALL_TIME},
 153.186 +     *                    3600000)
 153.187 +     * </code></pre>
 153.188 +     *
 153.189 +     * @param rawOffset       The given base time zone offset from GMT.
 153.190 +     * @param ID              The time zone ID which is given to this object.
 153.191 +     * @param startMonth      The daylight saving time starting month. Month is
 153.192 +     *                        a {@link Calendar#MONTH MONTH} field value (0-based. e.g., 0
 153.193 +     *                        for January).
 153.194 +     * @param startDay        The day of the month on which the daylight saving time starts.
 153.195 +     *                        See the class description for the special cases of this parameter.
 153.196 +     * @param startDayOfWeek  The daylight saving time starting day-of-week.
 153.197 +     *                        See the class description for the special cases of this parameter.
 153.198 +     * @param startTime       The daylight saving time starting time in local wall clock
 153.199 +     *                        time (in milliseconds within the day), which is local
 153.200 +     *                        standard time in this case.
 153.201 +     * @param endMonth        The daylight saving time ending month. Month is
 153.202 +     *                        a {@link Calendar#MONTH MONTH} field
 153.203 +     *                        value (0-based. e.g., 9 for October).
 153.204 +     * @param endDay          The day of the month on which the daylight saving time ends.
 153.205 +     *                        See the class description for the special cases of this parameter.
 153.206 +     * @param endDayOfWeek    The daylight saving time ending day-of-week.
 153.207 +     *                        See the class description for the special cases of this parameter.
 153.208 +     * @param endTime         The daylight saving ending time in local wall clock time,
 153.209 +     *                        (in milliseconds within the day) which is local daylight
 153.210 +     *                        time in this case.
 153.211 +     * @exception IllegalArgumentException if the month, day, dayOfWeek, or time
 153.212 +     * parameters are out of range for the start or end rule
 153.213 +     */
 153.214 +    public SimpleTimeZone(int rawOffset, String ID,
 153.215 +                          int startMonth, int startDay, int startDayOfWeek, int startTime,
 153.216 +                          int endMonth, int endDay, int endDayOfWeek, int endTime)
 153.217 +    {
 153.218 +        this(rawOffset, ID,
 153.219 +             startMonth, startDay, startDayOfWeek, startTime, WALL_TIME,
 153.220 +             endMonth, endDay, endDayOfWeek, endTime, WALL_TIME,
 153.221 +             millisPerHour);
 153.222 +    }
 153.223 +
 153.224 +    /**
 153.225 +     * Constructs a SimpleTimeZone with the given base time zone offset from
 153.226 +     * GMT, time zone ID, and rules for starting and ending the daylight
 153.227 +     * time.
 153.228 +     * Both <code>startTime</code> and <code>endTime</code> are assumed to be
 153.229 +     * represented in the wall clock time. This constructor is equivalent to:
 153.230 +     * <pre><code>
 153.231 +     *     SimpleTimeZone(rawOffset,
 153.232 +     *                    ID,
 153.233 +     *                    startMonth,
 153.234 +     *                    startDay,
 153.235 +     *                    startDayOfWeek,
 153.236 +     *                    startTime,
 153.237 +     *                    SimpleTimeZone.{@link #WALL_TIME},
 153.238 +     *                    endMonth,
 153.239 +     *                    endDay,
 153.240 +     *                    endDayOfWeek,
 153.241 +     *                    endTime,
 153.242 +     *                    SimpleTimeZone.{@link #WALL_TIME},
 153.243 +     *                    dstSavings)
 153.244 +     * </code></pre>
 153.245 +     *
 153.246 +     * @param rawOffset       The given base time zone offset from GMT.
 153.247 +     * @param ID              The time zone ID which is given to this object.
 153.248 +     * @param startMonth      The daylight saving time starting month. Month is
 153.249 +     *                        a {@link Calendar#MONTH MONTH} field
 153.250 +     *                        value (0-based. e.g., 0 for January).
 153.251 +     * @param startDay        The day of the month on which the daylight saving time starts.
 153.252 +     *                        See the class description for the special cases of this parameter.
 153.253 +     * @param startDayOfWeek  The daylight saving time starting day-of-week.
 153.254 +     *                        See the class description for the special cases of this parameter.
 153.255 +     * @param startTime       The daylight saving time starting time in local wall clock
 153.256 +     *                        time, which is local standard time in this case.
 153.257 +     * @param endMonth        The daylight saving time ending month. Month is
 153.258 +     *                        a {@link Calendar#MONTH MONTH} field
 153.259 +     *                        value (0-based. e.g., 9 for October).
 153.260 +     * @param endDay          The day of the month on which the daylight saving time ends.
 153.261 +     *                        See the class description for the special cases of this parameter.
 153.262 +     * @param endDayOfWeek    The daylight saving time ending day-of-week.
 153.263 +     *                        See the class description for the special cases of this parameter.
 153.264 +     * @param endTime         The daylight saving ending time in local wall clock time,
 153.265 +     *                        which is local daylight time in this case.
 153.266 +     * @param dstSavings      The amount of time in milliseconds saved during
 153.267 +     *                        daylight saving time.
 153.268 +     * @exception IllegalArgumentException if the month, day, dayOfWeek, or time
 153.269 +     * parameters are out of range for the start or end rule
 153.270 +     * @since 1.2
 153.271 +     */
 153.272 +    public SimpleTimeZone(int rawOffset, String ID,
 153.273 +                          int startMonth, int startDay, int startDayOfWeek, int startTime,
 153.274 +                          int endMonth, int endDay, int endDayOfWeek, int endTime,
 153.275 +                          int dstSavings)
 153.276 +    {
 153.277 +        this(rawOffset, ID,
 153.278 +             startMonth, startDay, startDayOfWeek, startTime, WALL_TIME,
 153.279 +             endMonth, endDay, endDayOfWeek, endTime, WALL_TIME,
 153.280 +             dstSavings);
 153.281 +    }
 153.282 +
 153.283 +    /**
 153.284 +     * Constructs a SimpleTimeZone with the given base time zone offset from
 153.285 +     * GMT, time zone ID, and rules for starting and ending the daylight
 153.286 +     * time.
 153.287 +     * This constructor takes the full set of the start and end rules
 153.288 +     * parameters, including modes of <code>startTime</code> and
 153.289 +     * <code>endTime</code>. The mode specifies either {@link #WALL_TIME wall
 153.290 +     * time} or {@link #STANDARD_TIME standard time} or {@link #UTC_TIME UTC
 153.291 +     * time}.
 153.292 +     *
 153.293 +     * @param rawOffset       The given base time zone offset from GMT.
 153.294 +     * @param ID              The time zone ID which is given to this object.
 153.295 +     * @param startMonth      The daylight saving time starting month. Month is
 153.296 +     *                        a {@link Calendar#MONTH MONTH} field
 153.297 +     *                        value (0-based. e.g., 0 for January).
 153.298 +     * @param startDay        The day of the month on which the daylight saving time starts.
 153.299 +     *                        See the class description for the special cases of this parameter.
 153.300 +     * @param startDayOfWeek  The daylight saving time starting day-of-week.
 153.301 +     *                        See the class description for the special cases of this parameter.
 153.302 +     * @param startTime       The daylight saving time starting time in the time mode
 153.303 +     *                        specified by <code>startTimeMode</code>.
 153.304 +     * @param startTimeMode   The mode of the start time specified by startTime.
 153.305 +     * @param endMonth        The daylight saving time ending month. Month is
 153.306 +     *                        a {@link Calendar#MONTH MONTH} field
 153.307 +     *                        value (0-based. e.g., 9 for October).
 153.308 +     * @param endDay          The day of the month on which the daylight saving time ends.
 153.309 +     *                        See the class description for the special cases of this parameter.
 153.310 +     * @param endDayOfWeek    The daylight saving time ending day-of-week.
 153.311 +     *                        See the class description for the special cases of this parameter.
 153.312 +     * @param endTime         The daylight saving ending time in time time mode
 153.313 +     *                        specified by <code>endTimeMode</code>.
 153.314 +     * @param endTimeMode     The mode of the end time specified by endTime
 153.315 +     * @param dstSavings      The amount of time in milliseconds saved during
 153.316 +     *                        daylight saving time.
 153.317 +     *
 153.318 +     * @exception IllegalArgumentException if the month, day, dayOfWeek, time more, or
 153.319 +     * time parameters are out of range for the start or end rule, or if a time mode
 153.320 +     * value is invalid.
 153.321 +     *
 153.322 +     * @see #WALL_TIME
 153.323 +     * @see #STANDARD_TIME
 153.324 +     * @see #UTC_TIME
 153.325 +     *
 153.326 +     * @since 1.4
 153.327 +     */
 153.328 +    public SimpleTimeZone(int rawOffset, String ID,
 153.329 +                          int startMonth, int startDay, int startDayOfWeek,
 153.330 +                          int startTime, int startTimeMode,
 153.331 +                          int endMonth, int endDay, int endDayOfWeek,
 153.332 +                          int endTime, int endTimeMode,
 153.333 +                          int dstSavings) {
 153.334 +
 153.335 +        setID(ID);
 153.336 +        this.rawOffset      = rawOffset;
 153.337 +        this.startMonth     = startMonth;
 153.338 +        this.startDay       = startDay;
 153.339 +        this.startDayOfWeek = startDayOfWeek;
 153.340 +        this.startTime      = startTime;
 153.341 +        this.startTimeMode  = startTimeMode;
 153.342 +        this.endMonth       = endMonth;
 153.343 +        this.endDay         = endDay;
 153.344 +        this.endDayOfWeek   = endDayOfWeek;
 153.345 +        this.endTime        = endTime;
 153.346 +        this.endTimeMode    = endTimeMode;
 153.347 +        this.dstSavings     = dstSavings;
 153.348 +
 153.349 +        // this.useDaylight is set by decodeRules
 153.350 +        decodeRules();
 153.351 +        if (dstSavings <= 0) {
 153.352 +            throw new IllegalArgumentException("Illegal daylight saving value: " + dstSavings);
 153.353 +        }
 153.354 +    }
 153.355 +
 153.356 +    /**
 153.357 +     * Sets the daylight saving time starting year.
 153.358 +     *
 153.359 +     * @param year  The daylight saving starting year.
 153.360 +     */
 153.361 +    public void setStartYear(int year)
 153.362 +    {
 153.363 +        startYear = year;
 153.364 +        invalidateCache();
 153.365 +    }
 153.366 +
 153.367 +    /**
 153.368 +     * Sets the daylight saving time start rule. For example, if daylight saving
 153.369 +     * time starts on the first Sunday in April at 2 am in local wall clock
 153.370 +     * time, you can set the start rule by calling:
 153.371 +     * <pre><code>setStartRule(Calendar.APRIL, 1, Calendar.SUNDAY, 2*60*60*1000);</code></pre>
 153.372 +     *
 153.373 +     * @param startMonth      The daylight saving time starting month. Month is
 153.374 +     *                        a {@link Calendar#MONTH MONTH} field
 153.375 +     *                        value (0-based. e.g., 0 for January).
 153.376 +     * @param startDay        The day of the month on which the daylight saving time starts.
 153.377 +     *                        See the class description for the special cases of this parameter.
 153.378 +     * @param startDayOfWeek  The daylight saving time starting day-of-week.
 153.379 +     *                        See the class description for the special cases of this parameter.
 153.380 +     * @param startTime       The daylight saving time starting time in local wall clock
 153.381 +     *                        time, which is local standard time in this case.
 153.382 +     * @exception IllegalArgumentException if the <code>startMonth</code>, <code>startDay</code>,
 153.383 +     * <code>startDayOfWeek</code>, or <code>startTime</code> parameters are out of range
 153.384 +     */
 153.385 +    public void setStartRule(int startMonth, int startDay, int startDayOfWeek, int startTime)
 153.386 +    {
 153.387 +        this.startMonth = startMonth;
 153.388 +        this.startDay = startDay;
 153.389 +        this.startDayOfWeek = startDayOfWeek;
 153.390 +        this.startTime = startTime;
 153.391 +        startTimeMode = WALL_TIME;
 153.392 +        decodeStartRule();
 153.393 +        invalidateCache();
 153.394 +    }
 153.395 +
 153.396 +    /**
 153.397 +     * Sets the daylight saving time start rule to a fixed date within a month.
 153.398 +     * This method is equivalent to:
 153.399 +     * <pre><code>setStartRule(startMonth, startDay, 0, startTime)</code></pre>
 153.400 +     *
 153.401 +     * @param startMonth      The daylight saving time starting month. Month is
 153.402 +     *                        a {@link Calendar#MONTH MONTH} field
 153.403 +     *                        value (0-based. e.g., 0 for January).
 153.404 +     * @param startDay        The day of the month on which the daylight saving time starts.
 153.405 +     * @param startTime       The daylight saving time starting time in local wall clock
 153.406 +     *                        time, which is local standard time in this case.
 153.407 +     *                        See the class description for the special cases of this parameter.
 153.408 +     * @exception IllegalArgumentException if the <code>startMonth</code>,
 153.409 +     * <code>startDayOfMonth</code>, or <code>startTime</code> parameters are out of range
 153.410 +     * @since 1.2
 153.411 +     */
 153.412 +    public void setStartRule(int startMonth, int startDay, int startTime) {
 153.413 +        setStartRule(startMonth, startDay, 0, startTime);
 153.414 +    }
 153.415 +
 153.416 +    /**
 153.417 +     * Sets the daylight saving time start rule to a weekday before or after the given date within
 153.418 +     * a month, e.g., the first Monday on or after the 8th.
 153.419 +     *
 153.420 +     * @param startMonth      The daylight saving time starting month. Month is
 153.421 +     *                        a {@link Calendar#MONTH MONTH} field
 153.422 +     *                        value (0-based. e.g., 0 for January).
 153.423 +     * @param startDay        The day of the month on which the daylight saving time starts.
 153.424 +     * @param startDayOfWeek  The daylight saving time starting day-of-week.
 153.425 +     * @param startTime       The daylight saving time starting time in local wall clock
 153.426 +     *                        time, which is local standard time in this case.
 153.427 +     * @param after           If true, this rule selects the first <code>dayOfWeek</code> on or
 153.428 +     *                        <em>after</em> <code>dayOfMonth</code>.  If false, this rule
 153.429 +     *                        selects the last <code>dayOfWeek</code> on or <em>before</em>
 153.430 +     *                        <code>dayOfMonth</code>.
 153.431 +     * @exception IllegalArgumentException if the <code>startMonth</code>, <code>startDay</code>,
 153.432 +     * <code>startDayOfWeek</code>, or <code>startTime</code> parameters are out of range
 153.433 +     * @since 1.2
 153.434 +     */
 153.435 +    public void setStartRule(int startMonth, int startDay, int startDayOfWeek,
 153.436 +                             int startTime, boolean after)
 153.437 +    {
 153.438 +        // TODO: this method doesn't check the initial values of dayOfMonth or dayOfWeek.
 153.439 +        if (after) {
 153.440 +            setStartRule(startMonth, startDay, -startDayOfWeek, startTime);
 153.441 +        } else {
 153.442 +            setStartRule(startMonth, -startDay, -startDayOfWeek, startTime);
 153.443 +        }
 153.444 +    }
 153.445 +
 153.446 +    /**
 153.447 +     * Sets the daylight saving time end rule. For example, if daylight saving time
 153.448 +     * ends on the last Sunday in October at 2 am in wall clock time,
 153.449 +     * you can set the end rule by calling:
 153.450 +     * <code>setEndRule(Calendar.OCTOBER, -1, Calendar.SUNDAY, 2*60*60*1000);</code>
 153.451 +     *
 153.452 +     * @param endMonth        The daylight saving time ending month. Month is
 153.453 +     *                        a {@link Calendar#MONTH MONTH} field
 153.454 +     *                        value (0-based. e.g., 9 for October).
 153.455 +     * @param endDay          The day of the month on which the daylight saving time ends.
 153.456 +     *                        See the class description for the special cases of this parameter.
 153.457 +     * @param endDayOfWeek    The daylight saving time ending day-of-week.
 153.458 +     *                        See the class description for the special cases of this parameter.
 153.459 +     * @param endTime         The daylight saving ending time in local wall clock time,
 153.460 +     *                        (in milliseconds within the day) which is local daylight
 153.461 +     *                        time in this case.
 153.462 +     * @exception IllegalArgumentException if the <code>endMonth</code>, <code>endDay</code>,
 153.463 +     * <code>endDayOfWeek</code>, or <code>endTime</code> parameters are out of range
 153.464 +     */
 153.465 +    public void setEndRule(int endMonth, int endDay, int endDayOfWeek,
 153.466 +                           int endTime)
 153.467 +    {
 153.468 +        this.endMonth = endMonth;
 153.469 +        this.endDay = endDay;
 153.470 +        this.endDayOfWeek = endDayOfWeek;
 153.471 +        this.endTime = endTime;
 153.472 +        this.endTimeMode = WALL_TIME;
 153.473 +        decodeEndRule();
 153.474 +        invalidateCache();
 153.475 +    }
 153.476 +
 153.477 +    /**
 153.478 +     * Sets the daylight saving time end rule to a fixed date within a month.
 153.479 +     * This method is equivalent to:
 153.480 +     * <pre><code>setEndRule(endMonth, endDay, 0, endTime)</code></pre>
 153.481 +     *
 153.482 +     * @param endMonth        The daylight saving time ending month. Month is
 153.483 +     *                        a {@link Calendar#MONTH MONTH} field
 153.484 +     *                        value (0-based. e.g., 9 for October).
 153.485 +     * @param endDay          The day of the month on which the daylight saving time ends.
 153.486 +     * @param endTime         The daylight saving ending time in local wall clock time,
 153.487 +     *                        (in milliseconds within the day) which is local daylight
 153.488 +     *                        time in this case.
 153.489 +     * @exception IllegalArgumentException the <code>endMonth</code>, <code>endDay</code>,
 153.490 +     * or <code>endTime</code> parameters are out of range
 153.491 +     * @since 1.2
 153.492 +     */
 153.493 +    public void setEndRule(int endMonth, int endDay, int endTime)
 153.494 +    {
 153.495 +        setEndRule(endMonth, endDay, 0, endTime);
 153.496 +    }
 153.497 +
 153.498 +    /**
 153.499 +     * Sets the daylight saving time end rule to a weekday before or after the given date within
 153.500 +     * a month, e.g., the first Monday on or after the 8th.
 153.501 +     *
 153.502 +     * @param endMonth        The daylight saving time ending month. Month is
 153.503 +     *                        a {@link Calendar#MONTH MONTH} field
 153.504 +     *                        value (0-based. e.g., 9 for October).
 153.505 +     * @param endDay          The day of the month on which the daylight saving time ends.
 153.506 +     * @param endDayOfWeek    The daylight saving time ending day-of-week.
 153.507 +     * @param endTime         The daylight saving ending time in local wall clock time,
 153.508 +     *                        (in milliseconds within the day) which is local daylight
 153.509 +     *                        time in this case.
 153.510 +     * @param after           If true, this rule selects the first <code>endDayOfWeek</code> on
 153.511 +     *                        or <em>after</em> <code>endDay</code>.  If false, this rule
 153.512 +     *                        selects the last <code>endDayOfWeek</code> on or before
 153.513 +     *                        <code>endDay</code> of the month.
 153.514 +     * @exception IllegalArgumentException the <code>endMonth</code>, <code>endDay</code>,
 153.515 +     * <code>endDayOfWeek</code>, or <code>endTime</code> parameters are out of range
 153.516 +     * @since 1.2
 153.517 +     */
 153.518 +    public void setEndRule(int endMonth, int endDay, int endDayOfWeek, int endTime, boolean after)
 153.519 +    {
 153.520 +        if (after) {
 153.521 +            setEndRule(endMonth, endDay, -endDayOfWeek, endTime);
 153.522 +        } else {
 153.523 +            setEndRule(endMonth, -endDay, -endDayOfWeek, endTime);
 153.524 +        }
 153.525 +    }
 153.526 +
 153.527 +    /**
 153.528 +     * Returns the offset of this time zone from UTC at the given
 153.529 +     * time. If daylight saving time is in effect at the given time,
 153.530 +     * the offset value is adjusted with the amount of daylight
 153.531 +     * saving.
 153.532 +     *
 153.533 +     * @param date the time at which the time zone offset is found
 153.534 +     * @return the amount of time in milliseconds to add to UTC to get
 153.535 +     * local time.
 153.536 +     * @since 1.4
 153.537 +     */
 153.538 +    public int getOffset(long date) {
 153.539 +        return getOffsets(date, null);
 153.540 +    }
 153.541 +
 153.542 +    /**
 153.543 +     * @see TimeZone#getOffsets
 153.544 +     */
 153.545 +    int getOffsets(long date, int[] offsets) {
 153.546 +        int offset = rawOffset;
 153.547 +
 153.548 +      computeOffset:
 153.549 +        if (useDaylight) {
 153.550 +            synchronized (this) {
 153.551 +                if (cacheStart != 0) {
 153.552 +                    if (date >= cacheStart && date < cacheEnd) {
 153.553 +                        offset += dstSavings;
 153.554 +                        break computeOffset;
 153.555 +                    }
 153.556 +                }
 153.557 +            }
 153.558 +            BaseCalendar cal = gcal;
 153.559 +//            date >= GregorianCalendar.DEFAULT_GREGORIAN_CUTOVER ?
 153.560 +//                gcal : (BaseCalendar) CalendarSystem.forName("julian");
 153.561 +            BaseCalendar.Datum cdate = (BaseCalendar.Datum) cal.newCalendarDate(TimeZone.NO_TIMEZONE);
 153.562 +            // Get the year in local time
 153.563 +            cal.getCalendarDate(date + rawOffset, cdate);
 153.564 +            int year = cdate.getNormalizedYear();
 153.565 +            if (year >= startYear) {
 153.566 +                // Clear time elements for the transition calculations
 153.567 +                cdate.setTimeOfDay(0, 0, 0, 0);
 153.568 +                offset = getOffset(cal, cdate, year, date);
 153.569 +            }
 153.570 +        }
 153.571 +
 153.572 +        if (offsets != null) {
 153.573 +            offsets[0] = rawOffset;
 153.574 +            offsets[1] = offset - rawOffset;
 153.575 +        }
 153.576 +        return offset;
 153.577 +    }
 153.578 +
 153.579 +   /**
 153.580 +     * Returns the difference in milliseconds between local time and
 153.581 +     * UTC, taking into account both the raw offset and the effect of
 153.582 +     * daylight saving, for the specified date and time.  This method
 153.583 +     * assumes that the start and end month are distinct.  It also
 153.584 +     * uses a default {@link GregorianCalendar} object as its
 153.585 +     * underlying calendar, such as for determining leap years.  Do
 153.586 +     * not use the result of this method with a calendar other than a
 153.587 +     * default <code>GregorianCalendar</code>.
 153.588 +     *
 153.589 +     * <p><em>Note:  In general, clients should use
 153.590 +     * <code>Calendar.get(ZONE_OFFSET) + Calendar.get(DST_OFFSET)</code>
 153.591 +     * instead of calling this method.</em>
 153.592 +     *
 153.593 +     * @param era       The era of the given date.
 153.594 +     * @param year      The year in the given date.
 153.595 +     * @param month     The month in the given date. Month is 0-based. e.g.,
 153.596 +     *                  0 for January.
 153.597 +     * @param day       The day-in-month of the given date.
 153.598 +     * @param dayOfWeek The day-of-week of the given date.
 153.599 +     * @param millis    The milliseconds in day in <em>standard</em> local time.
 153.600 +     * @return          The milliseconds to add to UTC to get local time.
 153.601 +     * @exception       IllegalArgumentException the <code>era</code>,
 153.602 +     *                  <code>month</code>, <code>day</code>, <code>dayOfWeek</code>,
 153.603 +     *                  or <code>millis</code> parameters are out of range
 153.604 +     */
 153.605 +    public int getOffset(int era, int year, int month, int day, int dayOfWeek,
 153.606 +                         int millis)
 153.607 +    {
 153.608 +        if (era != GregorianCalendar.AD && era != GregorianCalendar.BC) {
 153.609 +            throw new IllegalArgumentException("Illegal era " + era);
 153.610 +        }
 153.611 +
 153.612 +        int y = year;
 153.613 +        if (era == GregorianCalendar.BC) {
 153.614 +            // adjust y with the GregorianCalendar-style year numbering.
 153.615 +            y = 1 - y;
 153.616 +        }
 153.617 +
 153.618 +        // If the year isn't representable with the 64-bit long
 153.619 +        // integer in milliseconds, convert the year to an
 153.620 +        // equivalent year. This is required to pass some JCK test cases
 153.621 +        // which are actually useless though because the specified years
 153.622 +        // can't be supported by the Java time system.
 153.623 +        if (y >= 292278994) {
 153.624 +            y = 2800 + y % 2800;
 153.625 +        } else if (y <= -292269054) {
 153.626 +            // y %= 28 also produces an equivalent year, but positive
 153.627 +            // year numbers would be convenient to use the UNIX cal
 153.628 +            // command.
 153.629 +            y = (int) (long) y % 28;
 153.630 +        }
 153.631 +
 153.632 +        // convert year to its 1-based month value
 153.633 +        int m = month + 1;
 153.634 +
 153.635 +        // First, calculate time as a Gregorian date.
 153.636 +        BaseCalendar cal = gcal;
 153.637 +        BaseCalendar.Datum cdate = (BaseCalendar.Datum) cal.newCalendarDate(TimeZone.NO_TIMEZONE);
 153.638 +        cdate.setDate(y, m, day);
 153.639 +        long time = cal.getTime(cdate); // normalize cdate
 153.640 +        time += millis - rawOffset; // UTC time
 153.641 +
 153.642 +        // If the time value represents a time before the default
 153.643 +        // Gregorian cutover, recalculate time using the Julian
 153.644 +        // calendar system. For the Julian calendar system, the
 153.645 +        // normalized year numbering is ..., -2 (BCE 2), -1 (BCE 1),
 153.646 +        // 1, 2 ... which is different from the GregorianCalendar
 153.647 +        // style year numbering (..., -1, 0 (BCE 1), 1, 2, ...).
 153.648 +//        if (time < GregorianCalendar.DEFAULT_GREGORIAN_CUTOVER) {
 153.649 +//            cal = (BaseCalendar) CalendarSystem.forName("julian");
 153.650 +//            cdate = (BaseCalendar.Datum) cal.newCalendarDate(TimeZone.NO_TIMEZONE);
 153.651 +//            cdate.setNormalizedDate(y, m, day);
 153.652 +//            time = cal.getTime(cdate) + millis - rawOffset;
 153.653 +//        }
 153.654 +
 153.655 +        if ((cdate.getNormalizedYear() != y)
 153.656 +            || (cdate.getMonth() != m)
 153.657 +            || (cdate.getDayOfMonth() != day)
 153.658 +            // The validation should be cdate.getDayOfWeek() ==
 153.659 +            // dayOfWeek. However, we don't check dayOfWeek for
 153.660 +            // compatibility.
 153.661 +            || (dayOfWeek < Calendar.SUNDAY || dayOfWeek > Calendar.SATURDAY)
 153.662 +            || (millis < 0 || millis >= (24*60*60*1000))) {
 153.663 +            throw new IllegalArgumentException();
 153.664 +        }
 153.665 +
 153.666 +        if (!useDaylight || year < startYear || era != GregorianCalendar.CE) {
 153.667 +            return rawOffset;
 153.668 +        }
 153.669 +
 153.670 +        return getOffset(cal, cdate, y, time);
 153.671 +    }
 153.672 +
 153.673 +    private int getOffset(BaseCalendar cal, BaseCalendar.Datum cdate, int year, long time) {
 153.674 +        synchronized (this) {
 153.675 +            if (cacheStart != 0) {
 153.676 +                if (time >= cacheStart && time < cacheEnd) {
 153.677 +                    return rawOffset + dstSavings;
 153.678 +                }
 153.679 +                if (year == cacheYear) {
 153.680 +                    return rawOffset;
 153.681 +                }
 153.682 +            }
 153.683 +        }
 153.684 +
 153.685 +        long start = getStart(cal, cdate, year);
 153.686 +        long end = getEnd(cal, cdate, year);
 153.687 +        int offset = rawOffset;
 153.688 +        if (start <= end) {
 153.689 +            if (time >= start && time < end) {
 153.690 +                offset += dstSavings;
 153.691 +            }
 153.692 +            synchronized (this) {
 153.693 +                cacheYear = year;
 153.694 +                cacheStart = start;
 153.695 +                cacheEnd = end;
 153.696 +            }
 153.697 +        } else {
 153.698 +            if (time < end) {
 153.699 +                // TODO: support Gregorian cutover. The previous year
 153.700 +                // may be in the other calendar system.
 153.701 +                start = getStart(cal, cdate, year - 1);
 153.702 +                if (time >= start) {
 153.703 +                    offset += dstSavings;
 153.704 +                }
 153.705 +            } else if (time >= start) {
 153.706 +                // TODO: support Gregorian cutover. The next year
 153.707 +                // may be in the other calendar system.
 153.708 +                end = getEnd(cal, cdate, year + 1);
 153.709 +                if (time < end) {
 153.710 +                    offset += dstSavings;
 153.711 +                }
 153.712 +            }
 153.713 +            if (start <= end) {
 153.714 +                synchronized (this) {
 153.715 +                    // The start and end transitions are in multiple years.
 153.716 +                    cacheYear = (long) startYear - 1;
 153.717 +                    cacheStart = start;
 153.718 +                    cacheEnd = end;
 153.719 +                }
 153.720 +            }
 153.721 +        }
 153.722 +        return offset;
 153.723 +    }
 153.724 +
 153.725 +    private long getStart(BaseCalendar cal, BaseCalendar.Datum cdate, int year) {
 153.726 +        int time = startTime;
 153.727 +        if (startTimeMode != UTC_TIME) {
 153.728 +            time -= rawOffset;
 153.729 +        }
 153.730 +        return getTransition(cal, cdate, startMode, year, startMonth, startDay,
 153.731 +                             startDayOfWeek, time);
 153.732 +    }
 153.733 +
 153.734 +    private long getEnd(BaseCalendar cal, BaseCalendar.Datum cdate, int year) {
 153.735 +        int time = endTime;
 153.736 +        if (endTimeMode != UTC_TIME) {
 153.737 +            time -= rawOffset;
 153.738 +        }
 153.739 +        if (endTimeMode == WALL_TIME) {
 153.740 +            time -= dstSavings;
 153.741 +        }
 153.742 +        return getTransition(cal, cdate, endMode, year, endMonth, endDay,
 153.743 +                                        endDayOfWeek, time);
 153.744 +    }
 153.745 +
 153.746 +    private long getTransition(BaseCalendar cal, BaseCalendar.Datum cdate,
 153.747 +                               int mode, int year, int month, int dayOfMonth,
 153.748 +                               int dayOfWeek, int timeOfDay) {
 153.749 +        cdate.setNormalizedYear(year);
 153.750 +        cdate.setMonth(month + 1);
 153.751 +        switch (mode) {
 153.752 +        case DOM_MODE:
 153.753 +            cdate.setDayOfMonth(dayOfMonth);
 153.754 +            break;
 153.755 +
 153.756 +        case DOW_IN_MONTH_MODE:
 153.757 +            cdate.setDayOfMonth(1);
 153.758 +            if (dayOfMonth < 0) {
 153.759 +                cdate.setDayOfMonth(cal.getMonthLength(cdate));
 153.760 +            }
 153.761 +            cdate = (BaseCalendar.Datum) cal.getNthDayOfWeek(dayOfMonth, dayOfWeek, cdate);
 153.762 +            break;
 153.763 +
 153.764 +        case DOW_GE_DOM_MODE:
 153.765 +            cdate.setDayOfMonth(dayOfMonth);
 153.766 +            cdate = (BaseCalendar.Datum) cal.getNthDayOfWeek(1, dayOfWeek, cdate);
 153.767 +            break;
 153.768 +
 153.769 +        case DOW_LE_DOM_MODE:
 153.770 +            cdate.setDayOfMonth(dayOfMonth);
 153.771 +            cdate = (BaseCalendar.Datum) cal.getNthDayOfWeek(-1, dayOfWeek, cdate);
 153.772 +            break;
 153.773 +        }
 153.774 +        return cal.getTime(cdate) + timeOfDay;
 153.775 +    }
 153.776 +
 153.777 +    /**
 153.778 +     * Gets the GMT offset for this time zone.
 153.779 +     * @return the GMT offset value in milliseconds
 153.780 +     * @see #setRawOffset
 153.781 +     */
 153.782 +    public int getRawOffset()
 153.783 +    {
 153.784 +        // The given date will be taken into account while
 153.785 +        // we have the historical time zone data in place.
 153.786 +        return rawOffset;
 153.787 +    }
 153.788 +
 153.789 +    /**
 153.790 +     * Sets the base time zone offset to GMT.
 153.791 +     * This is the offset to add to UTC to get local time.
 153.792 +     * @see #getRawOffset
 153.793 +     */
 153.794 +    public void setRawOffset(int offsetMillis)
 153.795 +    {
 153.796 +        this.rawOffset = offsetMillis;
 153.797 +    }
 153.798 +
 153.799 +    /**
 153.800 +     * Sets the amount of time in milliseconds that the clock is advanced
 153.801 +     * during daylight saving time.
 153.802 +     * @param millisSavedDuringDST the number of milliseconds the time is
 153.803 +     * advanced with respect to standard time when the daylight saving time rules
 153.804 +     * are in effect. A positive number, typically one hour (3600000).
 153.805 +     * @see #getDSTSavings
 153.806 +     * @since 1.2
 153.807 +     */
 153.808 +    public void setDSTSavings(int millisSavedDuringDST) {
 153.809 +        if (millisSavedDuringDST <= 0) {
 153.810 +            throw new IllegalArgumentException("Illegal daylight saving value: "
 153.811 +                                               + millisSavedDuringDST);
 153.812 +        }
 153.813 +        dstSavings = millisSavedDuringDST;
 153.814 +    }
 153.815 +
 153.816 +    /**
 153.817 +     * Returns the amount of time in milliseconds that the clock is
 153.818 +     * advanced during daylight saving time.
 153.819 +     *
 153.820 +     * @return the number of milliseconds the time is advanced with
 153.821 +     * respect to standard time when the daylight saving rules are in
 153.822 +     * effect, or 0 (zero) if this time zone doesn't observe daylight
 153.823 +     * saving time.
 153.824 +     *
 153.825 +     * @see #setDSTSavings
 153.826 +     * @since 1.2
 153.827 +     */
 153.828 +    public int getDSTSavings() {
 153.829 +        return useDaylight ? dstSavings : 0;
 153.830 +    }
 153.831 +
 153.832 +    /**
 153.833 +     * Queries if this time zone uses daylight saving time.
 153.834 +     * @return true if this time zone uses daylight saving time;
 153.835 +     * false otherwise.
 153.836 +     */
 153.837 +    public boolean useDaylightTime()
 153.838 +    {
 153.839 +        return useDaylight;
 153.840 +    }
 153.841 +
 153.842 +    /**
 153.843 +     * Returns {@code true} if this {@code SimpleTimeZone} observes
 153.844 +     * Daylight Saving Time. This method is equivalent to {@link
 153.845 +     * #useDaylightTime()}.
 153.846 +     *
 153.847 +     * @return {@code true} if this {@code SimpleTimeZone} observes
 153.848 +     * Daylight Saving Time; {@code false} otherwise.
 153.849 +     * @since 1.7
 153.850 +     */
 153.851 +    @Override
 153.852 +    public boolean observesDaylightTime() {
 153.853 +        return useDaylightTime();
 153.854 +    }
 153.855 +
 153.856 +    /**
 153.857 +     * Queries if the given date is in daylight saving time.
 153.858 +     * @return true if daylight saving time is in effective at the
 153.859 +     * given date; false otherwise.
 153.860 +     */
 153.861 +    public boolean inDaylightTime(Date date)
 153.862 +    {
 153.863 +        return (getOffset(date.getTime()) != rawOffset);
 153.864 +    }
 153.865 +
 153.866 +    /**
 153.867 +     * Returns a clone of this <code>SimpleTimeZone</code> instance.
 153.868 +     * @return a clone of this instance.
 153.869 +     */
 153.870 +    public Object clone()
 153.871 +    {
 153.872 +        return super.clone();
 153.873 +    }
 153.874 +
 153.875 +    /**
 153.876 +     * Generates the hash code for the SimpleDateFormat object.
 153.877 +     * @return the hash code for this object
 153.878 +     */
 153.879 +    public synchronized int hashCode()
 153.880 +    {
 153.881 +        return startMonth ^ startDay ^ startDayOfWeek ^ startTime ^
 153.882 +            endMonth ^ endDay ^ endDayOfWeek ^ endTime ^ rawOffset;
 153.883 +    }
 153.884 +
 153.885 +    /**
 153.886 +     * Compares the equality of two <code>SimpleTimeZone</code> objects.
 153.887 +     *
 153.888 +     * @param obj  The <code>SimpleTimeZone</code> object to be compared with.
 153.889 +     * @return     True if the given <code>obj</code> is the same as this
 153.890 +     *             <code>SimpleTimeZone</code> object; false otherwise.
 153.891 +     */
 153.892 +    public boolean equals(Object obj)
 153.893 +    {
 153.894 +        if (this == obj) {
 153.895 +            return true;
 153.896 +        }
 153.897 +        if (!(obj instanceof SimpleTimeZone)) {
 153.898 +            return false;
 153.899 +        }
 153.900 +
 153.901 +        SimpleTimeZone that = (SimpleTimeZone) obj;
 153.902 +
 153.903 +        return getID().equals(that.getID()) &&
 153.904 +            hasSameRules(that);
 153.905 +    }
 153.906 +
 153.907 +    /**
 153.908 +     * Returns <code>true</code> if this zone has the same rules and offset as another zone.
 153.909 +     * @param other the TimeZone object to be compared with
 153.910 +     * @return <code>true</code> if the given zone is a SimpleTimeZone and has the
 153.911 +     * same rules and offset as this one
 153.912 +     * @since 1.2
 153.913 +     */
 153.914 +    public boolean hasSameRules(TimeZone other) {
 153.915 +        if (this == other) {
 153.916 +            return true;
 153.917 +        }
 153.918 +        if (!(other instanceof SimpleTimeZone)) {
 153.919 +            return false;
 153.920 +        }
 153.921 +        SimpleTimeZone that = (SimpleTimeZone) other;
 153.922 +        return rawOffset == that.rawOffset &&
 153.923 +            useDaylight == that.useDaylight &&
 153.924 +            (!useDaylight
 153.925 +             // Only check rules if using DST
 153.926 +             || (dstSavings == that.dstSavings &&
 153.927 +                 startMode == that.startMode &&
 153.928 +                 startMonth == that.startMonth &&
 153.929 +                 startDay == that.startDay &&
 153.930 +                 startDayOfWeek == that.startDayOfWeek &&
 153.931 +                 startTime == that.startTime &&
 153.932 +                 startTimeMode == that.startTimeMode &&
 153.933 +                 endMode == that.endMode &&
 153.934 +                 endMonth == that.endMonth &&
 153.935 +                 endDay == that.endDay &&
 153.936 +                 endDayOfWeek == that.endDayOfWeek &&
 153.937 +                 endTime == that.endTime &&
 153.938 +                 endTimeMode == that.endTimeMode &&
 153.939 +                 startYear == that.startYear));
 153.940 +    }
 153.941 +
 153.942 +    /**
 153.943 +     * Returns a string representation of this time zone.
 153.944 +     * @return a string representation of this time zone.
 153.945 +     */
 153.946 +    public String toString() {
 153.947 +        return getClass().getName() +
 153.948 +            "[id=" + getID() +
 153.949 +            ",offset=" + rawOffset +
 153.950 +            ",dstSavings=" + dstSavings +
 153.951 +            ",useDaylight=" + useDaylight +
 153.952 +            ",startYear=" + startYear +
 153.953 +            ",startMode=" + startMode +
 153.954 +            ",startMonth=" + startMonth +
 153.955 +            ",startDay=" + startDay +
 153.956 +            ",startDayOfWeek=" + startDayOfWeek +
 153.957 +            ",startTime=" + startTime +
 153.958 +            ",startTimeMode=" + startTimeMode +
 153.959 +            ",endMode=" + endMode +
 153.960 +            ",endMonth=" + endMonth +
 153.961 +            ",endDay=" + endDay +
 153.962 +            ",endDayOfWeek=" + endDayOfWeek +
 153.963 +            ",endTime=" + endTime +
 153.964 +            ",endTimeMode=" + endTimeMode + ']';
 153.965 +    }
 153.966 +
 153.967 +    // =======================privates===============================
 153.968 +
 153.969 +    /**
 153.970 +     * The month in which daylight saving time starts.  This value must be
 153.971 +     * between <code>Calendar.JANUARY</code> and
 153.972 +     * <code>Calendar.DECEMBER</code> inclusive.  This value must not equal
 153.973 +     * <code>endMonth</code>.
 153.974 +     * <p>If <code>useDaylight</code> is false, this value is ignored.
 153.975 +     * @serial
 153.976 +     */
 153.977 +    private int startMonth;
 153.978 +
 153.979 +    /**
 153.980 +     * This field has two possible interpretations:
 153.981 +     * <dl>
 153.982 +     * <dt><code>startMode == DOW_IN_MONTH</code></dt>
 153.983 +     * <dd>
 153.984 +     * <code>startDay</code> indicates the day of the month of
 153.985 +     * <code>startMonth</code> on which daylight
 153.986 +     * saving time starts, from 1 to 28, 30, or 31, depending on the
 153.987 +     * <code>startMonth</code>.
 153.988 +     * </dd>
 153.989 +     * <dt><code>startMode != DOW_IN_MONTH</code></dt>
 153.990 +     * <dd>
 153.991 +     * <code>startDay</code> indicates which <code>startDayOfWeek</code> in the
 153.992 +     * month <code>startMonth</code> daylight
 153.993 +     * saving time starts on.  For example, a value of +1 and a
 153.994 +     * <code>startDayOfWeek</code> of <code>Calendar.SUNDAY</code> indicates the
 153.995 +     * first Sunday of <code>startMonth</code>.  Likewise, +2 would indicate the
 153.996 +     * second Sunday, and -1 the last Sunday.  A value of 0 is illegal.
 153.997 +     * </dd>
 153.998 +     * </dl>
 153.999 +     * <p>If <code>useDaylight</code> is false, this value is ignored.
153.1000 +     * @serial
153.1001 +     */
153.1002 +    private int startDay;
153.1003 +
153.1004 +    /**
153.1005 +     * The day of the week on which daylight saving time starts.  This value
153.1006 +     * must be between <code>Calendar.SUNDAY</code> and
153.1007 +     * <code>Calendar.SATURDAY</code> inclusive.
153.1008 +     * <p>If <code>useDaylight</code> is false or
153.1009 +     * <code>startMode == DAY_OF_MONTH</code>, this value is ignored.
153.1010 +     * @serial
153.1011 +     */
153.1012 +    private int startDayOfWeek;
153.1013 +
153.1014 +    /**
153.1015 +     * The time in milliseconds after midnight at which daylight saving
153.1016 +     * time starts.  This value is expressed as wall time, standard time,
153.1017 +     * or UTC time, depending on the setting of <code>startTimeMode</code>.
153.1018 +     * <p>If <code>useDaylight</code> is false, this value is ignored.
153.1019 +     * @serial
153.1020 +     */
153.1021 +    private int startTime;
153.1022 +
153.1023 +    /**
153.1024 +     * The format of startTime, either WALL_TIME, STANDARD_TIME, or UTC_TIME.
153.1025 +     * @serial
153.1026 +     * @since 1.3
153.1027 +     */
153.1028 +    private int startTimeMode;
153.1029 +
153.1030 +    /**
153.1031 +     * The month in which daylight saving time ends.  This value must be
153.1032 +     * between <code>Calendar.JANUARY</code> and
153.1033 +     * <code>Calendar.UNDECIMBER</code>.  This value must not equal
153.1034 +     * <code>startMonth</code>.
153.1035 +     * <p>If <code>useDaylight</code> is false, this value is ignored.
153.1036 +     * @serial
153.1037 +     */
153.1038 +    private int endMonth;
153.1039 +
153.1040 +    /**
153.1041 +     * This field has two possible interpretations:
153.1042 +     * <dl>
153.1043 +     * <dt><code>endMode == DOW_IN_MONTH</code></dt>
153.1044 +     * <dd>
153.1045 +     * <code>endDay</code> indicates the day of the month of
153.1046 +     * <code>endMonth</code> on which daylight
153.1047 +     * saving time ends, from 1 to 28, 30, or 31, depending on the
153.1048 +     * <code>endMonth</code>.
153.1049 +     * </dd>
153.1050 +     * <dt><code>endMode != DOW_IN_MONTH</code></dt>
153.1051 +     * <dd>
153.1052 +     * <code>endDay</code> indicates which <code>endDayOfWeek</code> in th
153.1053 +     * month <code>endMonth</code> daylight
153.1054 +     * saving time ends on.  For example, a value of +1 and a
153.1055 +     * <code>endDayOfWeek</code> of <code>Calendar.SUNDAY</code> indicates the
153.1056 +     * first Sunday of <code>endMonth</code>.  Likewise, +2 would indicate the
153.1057 +     * second Sunday, and -1 the last Sunday.  A value of 0 is illegal.
153.1058 +     * </dd>
153.1059 +     * </dl>
153.1060 +     * <p>If <code>useDaylight</code> is false, this value is ignored.
153.1061 +     * @serial
153.1062 +     */
153.1063 +    private int endDay;
153.1064 +
153.1065 +    /**
153.1066 +     * The day of the week on which daylight saving time ends.  This value
153.1067 +     * must be between <code>Calendar.SUNDAY</code> and
153.1068 +     * <code>Calendar.SATURDAY</code> inclusive.
153.1069 +     * <p>If <code>useDaylight</code> is false or
153.1070 +     * <code>endMode == DAY_OF_MONTH</code>, this value is ignored.
153.1071 +     * @serial
153.1072 +     */
153.1073 +    private int endDayOfWeek;
153.1074 +
153.1075 +    /**
153.1076 +     * The time in milliseconds after midnight at which daylight saving
153.1077 +     * time ends.  This value is expressed as wall time, standard time,
153.1078 +     * or UTC time, depending on the setting of <code>endTimeMode</code>.
153.1079 +     * <p>If <code>useDaylight</code> is false, this value is ignored.
153.1080 +     * @serial
153.1081 +     */
153.1082 +    private int endTime;
153.1083 +
153.1084 +    /**
153.1085 +     * The format of endTime, either <code>WALL_TIME</code>,
153.1086 +     * <code>STANDARD_TIME</code>, or <code>UTC_TIME</code>.
153.1087 +     * @serial
153.1088 +     * @since 1.3
153.1089 +     */
153.1090 +    private int endTimeMode;
153.1091 +
153.1092 +    /**
153.1093 +     * The year in which daylight saving time is first observed.  This is an {@link GregorianCalendar#AD AD}
153.1094 +     * value.  If this value is less than 1 then daylight saving time is observed
153.1095 +     * for all <code>AD</code> years.
153.1096 +     * <p>If <code>useDaylight</code> is false, this value is ignored.
153.1097 +     * @serial
153.1098 +     */
153.1099 +    private int startYear;
153.1100 +
153.1101 +    /**
153.1102 +     * The offset in milliseconds between this zone and GMT.  Negative offsets
153.1103 +     * are to the west of Greenwich.  To obtain local <em>standard</em> time,
153.1104 +     * add the offset to GMT time.  To obtain local wall time it may also be
153.1105 +     * necessary to add <code>dstSavings</code>.
153.1106 +     * @serial
153.1107 +     */
153.1108 +    private int rawOffset;
153.1109 +
153.1110 +    /**
153.1111 +     * A boolean value which is true if and only if this zone uses daylight
153.1112 +     * saving time.  If this value is false, several other fields are ignored.
153.1113 +     * @serial
153.1114 +     */
153.1115 +    private boolean useDaylight=false; // indicate if this time zone uses DST
153.1116 +
153.1117 +    private static final int millisPerHour = 60*60*1000;
153.1118 +    private static final int millisPerDay  = 24*millisPerHour;
153.1119 +
153.1120 +    /**
153.1121 +     * This field was serialized in JDK 1.1, so we have to keep it that way
153.1122 +     * to maintain serialization compatibility. However, there's no need to
153.1123 +     * recreate the array each time we create a new time zone.
153.1124 +     * @serial An array of bytes containing the values {31, 28, 31, 30, 31, 30,
153.1125 +     * 31, 31, 30, 31, 30, 31}.  This is ignored as of the Java 2 platform v1.2, however, it must
153.1126 +     * be streamed out for compatibility with JDK 1.1.
153.1127 +     */
153.1128 +    private final byte monthLength[] = staticMonthLength;
153.1129 +    private final static byte staticMonthLength[] = {31,28,31,30,31,30,31,31,30,31,30,31};
153.1130 +    private final static byte staticLeapMonthLength[] = {31,29,31,30,31,30,31,31,30,31,30,31};
153.1131 +
153.1132 +    /**
153.1133 +     * Variables specifying the mode of the start rule.  Takes the following
153.1134 +     * values:
153.1135 +     * <dl>
153.1136 +     * <dt><code>DOM_MODE</code></dt>
153.1137 +     * <dd>
153.1138 +     * Exact day of week; e.g., March 1.
153.1139 +     * </dd>
153.1140 +     * <dt><code>DOW_IN_MONTH_MODE</code></dt>
153.1141 +     * <dd>
153.1142 +     * Day of week in month; e.g., last Sunday in March.
153.1143 +     * </dd>
153.1144 +     * <dt><code>DOW_GE_DOM_MODE</code></dt>
153.1145 +     * <dd>
153.1146 +     * Day of week after day of month; e.g., Sunday on or after March 15.
153.1147 +     * </dd>
153.1148 +     * <dt><code>DOW_LE_DOM_MODE</code></dt>
153.1149 +     * <dd>
153.1150 +     * Day of week before day of month; e.g., Sunday on or before March 15.
153.1151 +     * </dd>
153.1152 +     * </dl>
153.1153 +     * The setting of this field affects the interpretation of the
153.1154 +     * <code>startDay</code> field.
153.1155 +     * <p>If <code>useDaylight</code> is false, this value is ignored.
153.1156 +     * @serial
153.1157 +     * @since 1.1.4
153.1158 +     */
153.1159 +    private int startMode;
153.1160 +
153.1161 +    /**
153.1162 +     * Variables specifying the mode of the end rule.  Takes the following
153.1163 +     * values:
153.1164 +     * <dl>
153.1165 +     * <dt><code>DOM_MODE</code></dt>
153.1166 +     * <dd>
153.1167 +     * Exact day of week; e.g., March 1.
153.1168 +     * </dd>
153.1169 +     * <dt><code>DOW_IN_MONTH_MODE</code></dt>
153.1170 +     * <dd>
153.1171 +     * Day of week in month; e.g., last Sunday in March.
153.1172 +     * </dd>
153.1173 +     * <dt><code>DOW_GE_DOM_MODE</code></dt>
153.1174 +     * <dd>
153.1175 +     * Day of week after day of month; e.g., Sunday on or after March 15.
153.1176 +     * </dd>
153.1177 +     * <dt><code>DOW_LE_DOM_MODE</code></dt>
153.1178 +     * <dd>
153.1179 +     * Day of week before day of month; e.g., Sunday on or before March 15.
153.1180 +     * </dd>
153.1181 +     * </dl>
153.1182 +     * The setting of this field affects the interpretation of the
153.1183 +     * <code>endDay</code> field.
153.1184 +     * <p>If <code>useDaylight</code> is false, this value is ignored.
153.1185 +     * @serial
153.1186 +     * @since 1.1.4
153.1187 +     */
153.1188 +    private int endMode;
153.1189 +
153.1190 +    /**
153.1191 +     * A positive value indicating the amount of time saved during DST in
153.1192 +     * milliseconds.
153.1193 +     * Typically one hour (3600000); sometimes 30 minutes (1800000).
153.1194 +     * <p>If <code>useDaylight</code> is false, this value is ignored.
153.1195 +     * @serial
153.1196 +     * @since 1.1.4
153.1197 +     */
153.1198 +    private int dstSavings;
153.1199 +
153.1200 +    private static final BaseCalendar gcal = new BaseCalendar();//CalendarSystem.getGregorianCalendar();
153.1201 +
153.1202 +    /**
153.1203 +     * Cache values representing a single period of daylight saving
153.1204 +     * time. When the cache values are valid, cacheStart is the start
153.1205 +     * time (inclusive) of daylight saving time and cacheEnd is the
153.1206 +     * end time (exclusive).
153.1207 +     *
153.1208 +     * cacheYear has a year value if both cacheStart and cacheEnd are
153.1209 +     * in the same year. cacheYear is set to startYear - 1 if
153.1210 +     * cacheStart and cacheEnd are in different years. cacheStart is 0
153.1211 +     * if the cache values are void. cacheYear is a long to support
153.1212 +     * Integer.MIN_VALUE - 1 (JCK requirement).
153.1213 +     */
153.1214 +    private transient long cacheYear;
153.1215 +    private transient long cacheStart;
153.1216 +    private transient long cacheEnd;
153.1217 +
153.1218 +    /**
153.1219 +     * Constants specifying values of startMode and endMode.
153.1220 +     */
153.1221 +    private static final int DOM_MODE          = 1; // Exact day of month, "Mar 1"
153.1222 +    private static final int DOW_IN_MONTH_MODE = 2; // Day of week in month, "lastSun"
153.1223 +    private static final int DOW_GE_DOM_MODE   = 3; // Day of week after day of month, "Sun>=15"
153.1224 +    private static final int DOW_LE_DOM_MODE   = 4; // Day of week before day of month, "Sun<=21"
153.1225 +
153.1226 +    /**
153.1227 +     * Constant for a mode of start or end time specified as wall clock
153.1228 +     * time.  Wall clock time is standard time for the onset rule, and
153.1229 +     * daylight time for the end rule.
153.1230 +     * @since 1.4
153.1231 +     */
153.1232 +    public static final int WALL_TIME = 0; // Zero for backward compatibility
153.1233 +
153.1234 +    /**
153.1235 +     * Constant for a mode of start or end time specified as standard time.
153.1236 +     * @since 1.4
153.1237 +     */
153.1238 +    public static final int STANDARD_TIME = 1;
153.1239 +
153.1240 +    /**
153.1241 +     * Constant for a mode of start or end time specified as UTC. European
153.1242 +     * Union rules are specified as UTC time, for example.
153.1243 +     * @since 1.4
153.1244 +     */
153.1245 +    public static final int UTC_TIME = 2;
153.1246 +
153.1247 +    // Proclaim compatibility with 1.1
153.1248 +    static final long serialVersionUID = -403250971215465050L;
153.1249 +
153.1250 +    // the internal serial version which says which version was written
153.1251 +    // - 0 (default) for version up to JDK 1.1.3
153.1252 +    // - 1 for version from JDK 1.1.4, which includes 3 new fields
153.1253 +    // - 2 for JDK 1.3, which includes 2 new fields
153.1254 +    static final int currentSerialVersion = 2;
153.1255 +
153.1256 +    /**
153.1257 +     * The version of the serialized data on the stream.  Possible values:
153.1258 +     * <dl>
153.1259 +     * <dt><b>0</b> or not present on stream</dt>
153.1260 +     * <dd>
153.1261 +     * JDK 1.1.3 or earlier.
153.1262 +     * </dd>
153.1263 +     * <dt><b>1</b></dt>
153.1264 +     * <dd>
153.1265 +     * JDK 1.1.4 or later.  Includes three new fields: <code>startMode</code>,
153.1266 +     * <code>endMode</code>, and <code>dstSavings</code>.
153.1267 +     * </dd>
153.1268 +     * <dt><b>2</b></dt>
153.1269 +     * <dd>
153.1270 +     * JDK 1.3 or later.  Includes two new fields: <code>startTimeMode</code>
153.1271 +     * and <code>endTimeMode</code>.
153.1272 +     * </dd>
153.1273 +     * </dl>
153.1274 +     * When streaming out this class, the most recent format
153.1275 +     * and the highest allowable <code>serialVersionOnStream</code>
153.1276 +     * is written.
153.1277 +     * @serial
153.1278 +     * @since 1.1.4
153.1279 +     */
153.1280 +    private int serialVersionOnStream = currentSerialVersion;
153.1281 +
153.1282 +    synchronized private void invalidateCache() {
153.1283 +        cacheYear = startYear - 1;
153.1284 +        cacheStart = cacheEnd = 0;
153.1285 +    }
153.1286 +
153.1287 +    //----------------------------------------------------------------------
153.1288 +    // Rule representation
153.1289 +    //
153.1290 +    // We represent the following flavors of rules:
153.1291 +    //       5        the fifth of the month
153.1292 +    //       lastSun  the last Sunday in the month
153.1293 +    //       lastMon  the last Monday in the month
153.1294 +    //       Sun>=8   first Sunday on or after the eighth
153.1295 +    //       Sun<=25  last Sunday on or before the 25th
153.1296 +    // This is further complicated by the fact that we need to remain
153.1297 +    // backward compatible with the 1.1 FCS.  Finally, we need to minimize
153.1298 +    // API changes.  In order to satisfy these requirements, we support
153.1299 +    // three representation systems, and we translate between them.
153.1300 +    //
153.1301 +    // INTERNAL REPRESENTATION
153.1302 +    // This is the format SimpleTimeZone objects take after construction or
153.1303 +    // streaming in is complete.  Rules are represented directly, using an
153.1304 +    // unencoded format.  We will discuss the start rule only below; the end
153.1305 +    // rule is analogous.
153.1306 +    //   startMode      Takes on enumerated values DAY_OF_MONTH,
153.1307 +    //                  DOW_IN_MONTH, DOW_AFTER_DOM, or DOW_BEFORE_DOM.
153.1308 +    //   startDay       The day of the month, or for DOW_IN_MONTH mode, a
153.1309 +    //                  value indicating which DOW, such as +1 for first,
153.1310 +    //                  +2 for second, -1 for last, etc.
153.1311 +    //   startDayOfWeek The day of the week.  Ignored for DAY_OF_MONTH.
153.1312 +    //
153.1313 +    // ENCODED REPRESENTATION
153.1314 +    // This is the format accepted by the constructor and by setStartRule()
153.1315 +    // and setEndRule().  It uses various combinations of positive, negative,
153.1316 +    // and zero values to encode the different rules.  This representation
153.1317 +    // allows us to specify all the different rule flavors without altering
153.1318 +    // the API.
153.1319 +    //   MODE              startMonth    startDay    startDayOfWeek
153.1320 +    //   DOW_IN_MONTH_MODE >=0           !=0         >0
153.1321 +    //   DOM_MODE          >=0           >0          ==0
153.1322 +    //   DOW_GE_DOM_MODE   >=0           >0          <0
153.1323 +    //   DOW_LE_DOM_MODE   >=0           <0          <0
153.1324 +    //   (no DST)          don't care    ==0         don't care
153.1325 +    //
153.1326 +    // STREAMED REPRESENTATION
153.1327 +    // We must retain binary compatibility with the 1.1 FCS.  The 1.1 code only
153.1328 +    // handles DOW_IN_MONTH_MODE and non-DST mode, the latter indicated by the
153.1329 +    // flag useDaylight.  When we stream an object out, we translate into an
153.1330 +    // approximate DOW_IN_MONTH_MODE representation so the object can be parsed
153.1331 +    // and used by 1.1 code.  Following that, we write out the full
153.1332 +    // representation separately so that contemporary code can recognize and
153.1333 +    // parse it.  The full representation is written in a "packed" format,
153.1334 +    // consisting of a version number, a length, and an array of bytes.  Future
153.1335 +    // versions of this class may specify different versions.  If they wish to
153.1336 +    // include additional data, they should do so by storing them after the
153.1337 +    // packed representation below.
153.1338 +    //----------------------------------------------------------------------
153.1339 +
153.1340 +    /**
153.1341 +     * Given a set of encoded rules in startDay and startDayOfMonth, decode
153.1342 +     * them and set the startMode appropriately.  Do the same for endDay and
153.1343 +     * endDayOfMonth.  Upon entry, the day of week variables may be zero or
153.1344 +     * negative, in order to indicate special modes.  The day of month
153.1345 +     * variables may also be negative.  Upon exit, the mode variables will be
153.1346 +     * set, and the day of week and day of month variables will be positive.
153.1347 +     * This method also recognizes a startDay or endDay of zero as indicating
153.1348 +     * no DST.
153.1349 +     */
153.1350 +    private void decodeRules()
153.1351 +    {
153.1352 +        decodeStartRule();
153.1353 +        decodeEndRule();
153.1354 +    }
153.1355 +
153.1356 +    /**
153.1357 +     * Decode the start rule and validate the parameters.  The parameters are
153.1358 +     * expected to be in encoded form, which represents the various rule modes
153.1359 +     * by negating or zeroing certain values.  Representation formats are:
153.1360 +     * <p>
153.1361 +     * <pre>
153.1362 +     *            DOW_IN_MONTH  DOM    DOW>=DOM  DOW<=DOM  no DST
153.1363 +     *            ------------  -----  --------  --------  ----------
153.1364 +     * month       0..11        same    same      same     don't care
153.1365 +     * day        -5..5         1..31   1..31    -1..-31   0
153.1366 +     * dayOfWeek   1..7         0      -1..-7    -1..-7    don't care
153.1367 +     * time        0..ONEDAY    same    same      same     don't care
153.1368 +     * </pre>
153.1369 +     * The range for month does not include UNDECIMBER since this class is
153.1370 +     * really specific to GregorianCalendar, which does not use that month.
153.1371 +     * The range for time includes ONEDAY (vs. ending at ONEDAY-1) because the
153.1372 +     * end rule is an exclusive limit point.  That is, the range of times that
153.1373 +     * are in DST include those >= the start and < the end.  For this reason,
153.1374 +     * it should be possible to specify an end of ONEDAY in order to include the
153.1375 +     * entire day.  Although this is equivalent to time 0 of the following day,
153.1376 +     * it's not always possible to specify that, for example, on December 31.
153.1377 +     * While arguably the start range should still be 0..ONEDAY-1, we keep
153.1378 +     * the start and end ranges the same for consistency.
153.1379 +     */
153.1380 +    private void decodeStartRule() {
153.1381 +        useDaylight = (startDay != 0) && (endDay != 0);
153.1382 +        if (startDay != 0) {
153.1383 +            if (startMonth < Calendar.JANUARY || startMonth > Calendar.DECEMBER) {
153.1384 +                throw new IllegalArgumentException(
153.1385 +                        "Illegal start month " + startMonth);
153.1386 +            }
153.1387 +            if (startTime < 0 || startTime > millisPerDay) {
153.1388 +                throw new IllegalArgumentException(
153.1389 +                        "Illegal start time " + startTime);
153.1390 +            }
153.1391 +            if (startDayOfWeek == 0) {
153.1392 +                startMode = DOM_MODE;
153.1393 +            } else {
153.1394 +                if (startDayOfWeek > 0) {
153.1395 +                    startMode = DOW_IN_MONTH_MODE;
153.1396 +                } else {
153.1397 +                    startDayOfWeek = -startDayOfWeek;
153.1398 +                    if (startDay > 0) {
153.1399 +                        startMode = DOW_GE_DOM_MODE;
153.1400 +                    } else {
153.1401 +                        startDay = -startDay;
153.1402 +                        startMode = DOW_LE_DOM_MODE;
153.1403 +                    }
153.1404 +                }
153.1405 +                if (startDayOfWeek > Calendar.SATURDAY) {
153.1406 +                    throw new IllegalArgumentException(
153.1407 +                           "Illegal start day of week " + startDayOfWeek);
153.1408 +                }
153.1409 +            }
153.1410 +            if (startMode == DOW_IN_MONTH_MODE) {
153.1411 +                if (startDay < -5 || startDay > 5) {
153.1412 +                    throw new IllegalArgumentException(
153.1413 +                            "Illegal start day of week in month " + startDay);
153.1414 +                }
153.1415 +            } else if (startDay < 1 || startDay > staticMonthLength[startMonth]) {
153.1416 +                throw new IllegalArgumentException(
153.1417 +                        "Illegal start day " + startDay);
153.1418 +            }
153.1419 +        }
153.1420 +    }
153.1421 +
153.1422 +    /**
153.1423 +     * Decode the end rule and validate the parameters.  This method is exactly
153.1424 +     * analogous to decodeStartRule().
153.1425 +     * @see decodeStartRule
153.1426 +     */
153.1427 +    private void decodeEndRule() {
153.1428 +        useDaylight = (startDay != 0) && (endDay != 0);
153.1429 +        if (endDay != 0) {
153.1430 +            if (endMonth < Calendar.JANUARY || endMonth > Calendar.DECEMBER) {
153.1431 +                throw new IllegalArgumentException(
153.1432 +                        "Illegal end month " + endMonth);
153.1433 +            }
153.1434 +            if (endTime < 0 || endTime > millisPerDay) {
153.1435 +                throw new IllegalArgumentException(
153.1436 +                        "Illegal end time " + endTime);
153.1437 +            }
153.1438 +            if (endDayOfWeek == 0) {
153.1439 +                endMode = DOM_MODE;
153.1440 +            } else {
153.1441 +                if (endDayOfWeek > 0) {
153.1442 +                    endMode = DOW_IN_MONTH_MODE;
153.1443 +                } else {
153.1444 +                    endDayOfWeek = -endDayOfWeek;
153.1445 +                    if (endDay > 0) {
153.1446 +                        endMode = DOW_GE_DOM_MODE;
153.1447 +                    } else {
153.1448 +                        endDay = -endDay;
153.1449 +                        endMode = DOW_LE_DOM_MODE;
153.1450 +                    }
153.1451 +                }
153.1452 +                if (endDayOfWeek > Calendar.SATURDAY) {
153.1453 +                    throw new IllegalArgumentException(
153.1454 +                           "Illegal end day of week " + endDayOfWeek);
153.1455 +                }
153.1456 +            }
153.1457 +            if (endMode == DOW_IN_MONTH_MODE) {
153.1458 +                if (endDay < -5 || endDay > 5) {
153.1459 +                    throw new IllegalArgumentException(
153.1460 +                            "Illegal end day of week in month " + endDay);
153.1461 +                }
153.1462 +            } else if (endDay < 1 || endDay > staticMonthLength[endMonth]) {
153.1463 +                throw new IllegalArgumentException(
153.1464 +                        "Illegal end day " + endDay);
153.1465 +            }
153.1466 +        }
153.1467 +    }
153.1468 +
153.1469 +    /**
153.1470 +     * Make rules compatible to 1.1 FCS code.  Since 1.1 FCS code only understands
153.1471 +     * day-of-week-in-month rules, we must modify other modes of rules to their
153.1472 +     * approximate equivalent in 1.1 FCS terms.  This method is used when streaming
153.1473 +     * out objects of this class.  After it is called, the rules will be modified,
153.1474 +     * with a possible loss of information.  startMode and endMode will NOT be
153.1475 +     * altered, even though semantically they should be set to DOW_IN_MONTH_MODE,
153.1476 +     * since the rule modification is only intended to be temporary.
153.1477 +     */
153.1478 +    private void makeRulesCompatible()
153.1479 +    {
153.1480 +        switch (startMode) {
153.1481 +        case DOM_MODE:
153.1482 +            startDay = 1 + (startDay / 7);
153.1483 +            startDayOfWeek = Calendar.SUNDAY;
153.1484 +            break;
153.1485 +
153.1486 +        case DOW_GE_DOM_MODE:
153.1487 +            // A day-of-month of 1 is equivalent to DOW_IN_MONTH_MODE
153.1488 +            // that is, Sun>=1 == firstSun.
153.1489 +            if (startDay != 1) {
153.1490 +                startDay = 1 + (startDay / 7);
153.1491 +            }
153.1492 +            break;
153.1493 +
153.1494 +        case DOW_LE_DOM_MODE:
153.1495 +            if (startDay >= 30) {
153.1496 +                startDay = -1;
153.1497 +            } else {
153.1498 +                startDay = 1 + (startDay / 7);
153.1499 +            }
153.1500 +            break;
153.1501 +        }
153.1502 +
153.1503 +        switch (endMode) {
153.1504 +        case DOM_MODE:
153.1505 +            endDay = 1 + (endDay / 7);
153.1506 +            endDayOfWeek = Calendar.SUNDAY;
153.1507 +            break;
153.1508 +
153.1509 +        case DOW_GE_DOM_MODE:
153.1510 +            // A day-of-month of 1 is equivalent to DOW_IN_MONTH_MODE
153.1511 +            // that is, Sun>=1 == firstSun.
153.1512 +            if (endDay != 1) {
153.1513 +                endDay = 1 + (endDay / 7);
153.1514 +            }
153.1515 +            break;
153.1516 +
153.1517 +        case DOW_LE_DOM_MODE:
153.1518 +            if (endDay >= 30) {
153.1519 +                endDay = -1;
153.1520 +            } else {
153.1521 +                endDay = 1 + (endDay / 7);
153.1522 +            }
153.1523 +            break;
153.1524 +        }
153.1525 +
153.1526 +        /*
153.1527 +         * Adjust the start and end times to wall time.  This works perfectly
153.1528 +         * well unless it pushes into the next or previous day.  If that
153.1529 +         * happens, we attempt to adjust the day rule somewhat crudely.  The day
153.1530 +         * rules have been forced into DOW_IN_MONTH mode already, so we change
153.1531 +         * the day of week to move forward or back by a day.  It's possible to
153.1532 +         * make a more refined adjustment of the original rules first, but in
153.1533 +         * most cases this extra effort will go to waste once we adjust the day
153.1534 +         * rules anyway.
153.1535 +         */
153.1536 +        switch (startTimeMode) {
153.1537 +        case UTC_TIME:
153.1538 +            startTime += rawOffset;
153.1539 +            break;
153.1540 +        }
153.1541 +        while (startTime < 0) {
153.1542 +            startTime += millisPerDay;
153.1543 +            startDayOfWeek = 1 + ((startDayOfWeek+5) % 7); // Back 1 day
153.1544 +        }
153.1545 +        while (startTime >= millisPerDay) {
153.1546 +            startTime -= millisPerDay;
153.1547 +            startDayOfWeek = 1 + (startDayOfWeek % 7); // Forward 1 day
153.1548 +        }
153.1549 +
153.1550 +        switch (endTimeMode) {
153.1551 +        case UTC_TIME:
153.1552 +            endTime += rawOffset + dstSavings;
153.1553 +            break;
153.1554 +        case STANDARD_TIME:
153.1555 +            endTime += dstSavings;
153.1556 +        }
153.1557 +        while (endTime < 0) {
153.1558 +            endTime += millisPerDay;
153.1559 +            endDayOfWeek = 1 + ((endDayOfWeek+5) % 7); // Back 1 day
153.1560 +        }
153.1561 +        while (endTime >= millisPerDay) {
153.1562 +            endTime -= millisPerDay;
153.1563 +            endDayOfWeek = 1 + (endDayOfWeek % 7); // Forward 1 day
153.1564 +        }
153.1565 +    }
153.1566 +
153.1567 +    /**
153.1568 +     * Pack the start and end rules into an array of bytes.  Only pack
153.1569 +     * data which is not preserved by makeRulesCompatible.
153.1570 +     */
153.1571 +    private byte[] packRules()
153.1572 +    {
153.1573 +        byte[] rules = new byte[6];
153.1574 +        rules[0] = (byte)startDay;
153.1575 +        rules[1] = (byte)startDayOfWeek;
153.1576 +        rules[2] = (byte)endDay;
153.1577 +        rules[3] = (byte)endDayOfWeek;
153.1578 +
153.1579 +        // As of serial version 2, include time modes
153.1580 +        rules[4] = (byte)startTimeMode;
153.1581 +        rules[5] = (byte)endTimeMode;
153.1582 +
153.1583 +        return rules;
153.1584 +    }
153.1585 +
153.1586 +    /**
153.1587 +     * Given an array of bytes produced by packRules, interpret them
153.1588 +     * as the start and end rules.
153.1589 +     */
153.1590 +    private void unpackRules(byte[] rules)
153.1591 +    {
153.1592 +        startDay       = rules[0];
153.1593 +        startDayOfWeek = rules[1];
153.1594 +        endDay         = rules[2];
153.1595 +        endDayOfWeek   = rules[3];
153.1596 +
153.1597 +        // As of serial version 2, include time modes
153.1598 +        if (rules.length >= 6) {
153.1599 +            startTimeMode = rules[4];
153.1600 +            endTimeMode   = rules[5];
153.1601 +        }
153.1602 +    }
153.1603 +
153.1604 +    /**
153.1605 +     * Pack the start and end times into an array of bytes.  This is required
153.1606 +     * as of serial version 2.
153.1607 +     */
153.1608 +    private int[] packTimes() {
153.1609 +        int[] times = new int[2];
153.1610 +        times[0] = startTime;
153.1611 +        times[1] = endTime;
153.1612 +        return times;
153.1613 +    }
153.1614 +
153.1615 +    /**
153.1616 +     * Unpack the start and end times from an array of bytes.  This is required
153.1617 +     * as of serial version 2.
153.1618 +     */
153.1619 +    private void unpackTimes(int[] times) {
153.1620 +        startTime = times[0];
153.1621 +        endTime = times[1];
153.1622 +    }
153.1623 +
153.1624 +    /**
153.1625 +     * Save the state of this object to a stream (i.e., serialize it).
153.1626 +     *
153.1627 +     * @serialData We write out two formats, a JDK 1.1 compatible format, using
153.1628 +     * <code>DOW_IN_MONTH_MODE</code> rules, in the required section, followed
153.1629 +     * by the full rules, in packed format, in the optional section.  The
153.1630 +     * optional section will be ignored by JDK 1.1 code upon stream in.
153.1631 +     * <p> Contents of the optional section: The length of a byte array is
153.1632 +     * emitted (int); this is 4 as of this release. The byte array of the given
153.1633 +     * length is emitted. The contents of the byte array are the true values of
153.1634 +     * the fields <code>startDay</code>, <code>startDayOfWeek</code>,
153.1635 +     * <code>endDay</code>, and <code>endDayOfWeek</code>.  The values of these
153.1636 +     * fields in the required section are approximate values suited to the rule
153.1637 +     * mode <code>DOW_IN_MONTH_MODE</code>, which is the only mode recognized by
153.1638 +     * JDK 1.1.
153.1639 +     */
153.1640 +    private void writeObject(ObjectOutputStream stream)
153.1641 +         throws IOException
153.1642 +    {
153.1643 +        // Construct a binary rule
153.1644 +        byte[] rules = packRules();
153.1645 +        int[] times = packTimes();
153.1646 +
153.1647 +        // Convert to 1.1 FCS rules.  This step may cause us to lose information.
153.1648 +        makeRulesCompatible();
153.1649 +
153.1650 +        // Write out the 1.1 FCS rules
153.1651 +        stream.defaultWriteObject();
153.1652 +
153.1653 +        // Write out the binary rules in the optional data area of the stream.
153.1654 +        stream.writeInt(rules.length);
153.1655 +        stream.write(rules);
153.1656 +        stream.writeObject(times);
153.1657 +
153.1658 +        // Recover the original rules.  This recovers the information lost
153.1659 +        // by makeRulesCompatible.
153.1660 +        unpackRules(rules);
153.1661 +        unpackTimes(times);
153.1662 +    }
153.1663 +
153.1664 +    /**
153.1665 +     * Reconstitute this object from a stream (i.e., deserialize it).
153.1666 +     *
153.1667 +     * We handle both JDK 1.1
153.1668 +     * binary formats and full formats with a packed byte array.
153.1669 +     */
153.1670 +    private void readObject(ObjectInputStream stream)
153.1671 +         throws IOException, ClassNotFoundException
153.1672 +    {
153.1673 +        stream.defaultReadObject();
153.1674 +
153.1675 +        if (serialVersionOnStream < 1) {
153.1676 +            // Fix a bug in the 1.1 SimpleTimeZone code -- namely,
153.1677 +            // startDayOfWeek and endDayOfWeek were usually uninitialized.  We can't do
153.1678 +            // too much, so we assume SUNDAY, which actually works most of the time.
153.1679 +            if (startDayOfWeek == 0) {
153.1680 +                startDayOfWeek = Calendar.SUNDAY;
153.1681 +            }
153.1682 +            if (endDayOfWeek == 0) {
153.1683 +                endDayOfWeek = Calendar.SUNDAY;
153.1684 +            }
153.1685 +
153.1686 +            // The variables dstSavings, startMode, and endMode are post-1.1, so they
153.1687 +            // won't be present if we're reading from a 1.1 stream.  Fix them up.
153.1688 +            startMode = endMode = DOW_IN_MONTH_MODE;
153.1689 +            dstSavings = millisPerHour;
153.1690 +        } else {
153.1691 +            // For 1.1.4, in addition to the 3 new instance variables, we also
153.1692 +            // store the actual rules (which have not be made compatible with 1.1)
153.1693 +            // in the optional area.  Read them in here and parse them.
153.1694 +            int length = stream.readInt();
153.1695 +            byte[] rules = new byte[length];
153.1696 +            stream.readFully(rules);
153.1697 +            unpackRules(rules);
153.1698 +        }
153.1699 +
153.1700 +        if (serialVersionOnStream >= 2) {
153.1701 +            int[] times = (int[]) stream.readObject();
153.1702 +            unpackTimes(times);
153.1703 +        }
153.1704 +
153.1705 +        serialVersionOnStream = currentSerialVersion;
153.1706 +    }
153.1707 +    
153.1708 +    static final class GregorianCalendar {
153.1709 +        public static final int BC = 0;
153.1710 +
153.1711 +        /**
153.1712 +         * Value of the {@link #ERA} field indicating the period before the
153.1713 +         * common era, the same value as {@link #BC}.
153.1714 +         *
153.1715 +         * @see #CE
153.1716 +         */
153.1717 +        static final int BCE = 0;
153.1718 +
153.1719 +        /**
153.1720 +         * Value of the <code>ERA</code> field indicating the common era (Anno
153.1721 +         * Domini), also known as CE. The sequence of years at the transition
153.1722 +         * from <code>BC</code> to <code>AD</code> is ..., 2 BC, 1 BC, 1 AD, 2
153.1723 +         * AD,...
153.1724 +         *
153.1725 +         * @see #ERA
153.1726 +         */
153.1727 +        public static final int AD = 1;
153.1728 +
153.1729 +        // The default value of gregorianCutover.
153.1730 +        static final long DEFAULT_GREGORIAN_CUTOVER = -12219292800000L;
153.1731 +        /**
153.1732 +         * Value of the {@link #ERA} field indicating
153.1733 +         * the common era, the same value as {@link #AD}.
153.1734 +         *
153.1735 +         * @see #BCE
153.1736 +         */
153.1737 +        static final int CE = 1;
153.1738 +        
153.1739 +    }
153.1740 +}
   154.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   154.2 +++ b/rt/emul/compact/src/main/java/java/util/TimeZone.java	Tue Feb 11 13:31:42 2014 +0100
   154.3 @@ -0,0 +1,715 @@
   154.4 +/*
   154.5 + * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
   154.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   154.7 + *
   154.8 + * This code is free software; you can redistribute it and/or modify it
   154.9 + * under the terms of the GNU General Public License version 2 only, as
  154.10 + * published by the Free Software Foundation.  Oracle designates this
  154.11 + * particular file as subject to the "Classpath" exception as provided
  154.12 + * by Oracle in the LICENSE file that accompanied this code.
  154.13 + *
  154.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  154.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  154.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  154.17 + * version 2 for more details (a copy is included in the LICENSE file that
  154.18 + * accompanied this code).
  154.19 + *
  154.20 + * You should have received a copy of the GNU General Public License version
  154.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  154.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  154.23 + *
  154.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  154.25 + * or visit www.oracle.com if you need additional information or have any
  154.26 + * questions.
  154.27 + */
  154.28 +
  154.29 +/*
  154.30 + * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
  154.31 + * (C) Copyright IBM Corp. 1996 - All Rights Reserved
  154.32 + *
  154.33 + *   The original version of this source code and documentation is copyrighted
  154.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
  154.35 + * materials are provided under terms of a License Agreement between Taligent
  154.36 + * and Sun. This technology is protected by multiple US and International
  154.37 + * patents. This notice and attribution to Taligent may not be removed.
  154.38 + *   Taligent is a registered trademark of Taligent, Inc.
  154.39 + *
  154.40 + */
  154.41 +
  154.42 +package java.util;
  154.43 +
  154.44 +import java.io.Serializable;
  154.45 +import java.lang.ref.SoftReference;
  154.46 +import java.security.AccessController;
  154.47 +import java.security.PrivilegedAction;
  154.48 +import java.util.concurrent.ConcurrentHashMap;
  154.49 +
  154.50 +/**
  154.51 + * <code>TimeZone</code> represents a time zone offset, and also figures out daylight
  154.52 + * savings.
  154.53 + *
  154.54 + * <p>
  154.55 + * Typically, you get a <code>TimeZone</code> using <code>getDefault</code>
  154.56 + * which creates a <code>TimeZone</code> based on the time zone where the program
  154.57 + * is running. For example, for a program running in Japan, <code>getDefault</code>
  154.58 + * creates a <code>TimeZone</code> object based on Japanese Standard Time.
  154.59 + *
  154.60 + * <p>
  154.61 + * You can also get a <code>TimeZone</code> using <code>getTimeZone</code>
  154.62 + * along with a time zone ID. For instance, the time zone ID for the
  154.63 + * U.S. Pacific Time zone is "America/Los_Angeles". So, you can get a
  154.64 + * U.S. Pacific Time <code>TimeZone</code> object with:
  154.65 + * <blockquote><pre>
  154.66 + * TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
  154.67 + * </pre></blockquote>
  154.68 + * You can use the <code>getAvailableIDs</code> method to iterate through
  154.69 + * all the supported time zone IDs. You can then choose a
  154.70 + * supported ID to get a <code>TimeZone</code>.
  154.71 + * If the time zone you want is not represented by one of the
  154.72 + * supported IDs, then a custom time zone ID can be specified to
  154.73 + * produce a TimeZone. The syntax of a custom time zone ID is:
  154.74 + *
  154.75 + * <blockquote><pre>
  154.76 + * <a name="CustomID"><i>CustomID:</i></a>
  154.77 + *         <code>GMT</code> <i>Sign</i> <i>Hours</i> <code>:</code> <i>Minutes</i>
  154.78 + *         <code>GMT</code> <i>Sign</i> <i>Hours</i> <i>Minutes</i>
  154.79 + *         <code>GMT</code> <i>Sign</i> <i>Hours</i>
  154.80 + * <i>Sign:</i> one of
  154.81 + *         <code>+ -</code>
  154.82 + * <i>Hours:</i>
  154.83 + *         <i>Digit</i>
  154.84 + *         <i>Digit</i> <i>Digit</i>
  154.85 + * <i>Minutes:</i>
  154.86 + *         <i>Digit</i> <i>Digit</i>
  154.87 + * <i>Digit:</i> one of
  154.88 + *         <code>0 1 2 3 4 5 6 7 8 9</code>
  154.89 + * </pre></blockquote>
  154.90 + *
  154.91 + * <i>Hours</i> must be between 0 to 23 and <i>Minutes</i> must be
  154.92 + * between 00 to 59.  For example, "GMT+10" and "GMT+0010" mean ten
  154.93 + * hours and ten minutes ahead of GMT, respectively.
  154.94 + * <p>
  154.95 + * The format is locale independent and digits must be taken from the
  154.96 + * Basic Latin block of the Unicode standard. No daylight saving time
  154.97 + * transition schedule can be specified with a custom time zone ID. If
  154.98 + * the specified string doesn't match the syntax, <code>"GMT"</code>
  154.99 + * is used.
 154.100 + * <p>
 154.101 + * When creating a <code>TimeZone</code>, the specified custom time
 154.102 + * zone ID is normalized in the following syntax:
 154.103 + * <blockquote><pre>
 154.104 + * <a name="NormalizedCustomID"><i>NormalizedCustomID:</i></a>
 154.105 + *         <code>GMT</code> <i>Sign</i> <i>TwoDigitHours</i> <code>:</code> <i>Minutes</i>
 154.106 + * <i>Sign:</i> one of
 154.107 + *         <code>+ -</code>
 154.108 + * <i>TwoDigitHours:</i>
 154.109 + *         <i>Digit</i> <i>Digit</i>
 154.110 + * <i>Minutes:</i>
 154.111 + *         <i>Digit</i> <i>Digit</i>
 154.112 + * <i>Digit:</i> one of
 154.113 + *         <code>0 1 2 3 4 5 6 7 8 9</code>
 154.114 + * </pre></blockquote>
 154.115 + * For example, TimeZone.getTimeZone("GMT-8").getID() returns "GMT-08:00".
 154.116 + *
 154.117 + * <h4>Three-letter time zone IDs</h4>
 154.118 + *
 154.119 + * For compatibility with JDK 1.1.x, some other three-letter time zone IDs
 154.120 + * (such as "PST", "CTT", "AST") are also supported. However, <strong>their
 154.121 + * use is deprecated</strong> because the same abbreviation is often used
 154.122 + * for multiple time zones (for example, "CST" could be U.S. "Central Standard
 154.123 + * Time" and "China Standard Time"), and the Java platform can then only
 154.124 + * recognize one of them.
 154.125 + *
 154.126 + *
 154.127 + * @see          Calendar
 154.128 + * @see          GregorianCalendar
 154.129 + * @see          SimpleTimeZone
 154.130 + * @author       Mark Davis, David Goldsmith, Chen-Lieh Huang, Alan Liu
 154.131 + * @since        JDK1.1
 154.132 + */
 154.133 +abstract public class TimeZone implements Serializable, Cloneable {
 154.134 +    /**
 154.135 +     * Sole constructor.  (For invocation by subclass constructors, typically
 154.136 +     * implicit.)
 154.137 +     */
 154.138 +    public TimeZone() {
 154.139 +    }
 154.140 +
 154.141 +    /**
 154.142 +     * A style specifier for <code>getDisplayName()</code> indicating
 154.143 +     * a short name, such as "PST."
 154.144 +     * @see #LONG
 154.145 +     * @since 1.2
 154.146 +     */
 154.147 +    public static final int SHORT = 0;
 154.148 +
 154.149 +    /**
 154.150 +     * A style specifier for <code>getDisplayName()</code> indicating
 154.151 +     * a long name, such as "Pacific Standard Time."
 154.152 +     * @see #SHORT
 154.153 +     * @since 1.2
 154.154 +     */
 154.155 +    public static final int LONG  = 1;
 154.156 +
 154.157 +    // Constants used internally; unit is milliseconds
 154.158 +    private static final int ONE_MINUTE = 60*1000;
 154.159 +    private static final int ONE_HOUR   = 60*ONE_MINUTE;
 154.160 +    private static final int ONE_DAY    = 24*ONE_HOUR;
 154.161 +
 154.162 +    // Proclaim serialization compatibility with JDK 1.1
 154.163 +    static final long serialVersionUID = 3581463369166924961L;
 154.164 +
 154.165 +    /**
 154.166 +     * Gets the time zone offset, for current date, modified in case of
 154.167 +     * daylight savings. This is the offset to add to UTC to get local time.
 154.168 +     * <p>
 154.169 +     * This method returns a historically correct offset if an
 154.170 +     * underlying <code>TimeZone</code> implementation subclass
 154.171 +     * supports historical Daylight Saving Time schedule and GMT
 154.172 +     * offset changes.
 154.173 +     *
 154.174 +     * @param era the era of the given date.
 154.175 +     * @param year the year in the given date.
 154.176 +     * @param month the month in the given date.
 154.177 +     * Month is 0-based. e.g., 0 for January.
 154.178 +     * @param day the day-in-month of the given date.
 154.179 +     * @param dayOfWeek the day-of-week of the given date.
 154.180 +     * @param milliseconds the milliseconds in day in <em>standard</em>
 154.181 +     * local time.
 154.182 +     *
 154.183 +     * @return the offset in milliseconds to add to GMT to get local time.
 154.184 +     *
 154.185 +     * @see Calendar#ZONE_OFFSET
 154.186 +     * @see Calendar#DST_OFFSET
 154.187 +     */
 154.188 +    public abstract int getOffset(int era, int year, int month, int day,
 154.189 +                                  int dayOfWeek, int milliseconds);
 154.190 +
 154.191 +    /**
 154.192 +     * Returns the offset of this time zone from UTC at the specified
 154.193 +     * date. If Daylight Saving Time is in effect at the specified
 154.194 +     * date, the offset value is adjusted with the amount of daylight
 154.195 +     * saving.
 154.196 +     * <p>
 154.197 +     * This method returns a historically correct offset value if an
 154.198 +     * underlying TimeZone implementation subclass supports historical
 154.199 +     * Daylight Saving Time schedule and GMT offset changes.
 154.200 +     *
 154.201 +     * @param date the date represented in milliseconds since January 1, 1970 00:00:00 GMT
 154.202 +     * @return the amount of time in milliseconds to add to UTC to get local time.
 154.203 +     *
 154.204 +     * @see Calendar#ZONE_OFFSET
 154.205 +     * @see Calendar#DST_OFFSET
 154.206 +     * @since 1.4
 154.207 +     */
 154.208 +    public int getOffset(long date) {
 154.209 +        if (inDaylightTime(new Date(date))) {
 154.210 +            return getRawOffset() + getDSTSavings();
 154.211 +        }
 154.212 +        return getRawOffset();
 154.213 +    }
 154.214 +
 154.215 +    /**
 154.216 +     * Gets the raw GMT offset and the amount of daylight saving of this
 154.217 +     * time zone at the given time.
 154.218 +     * @param date the milliseconds (since January 1, 1970,
 154.219 +     * 00:00:00.000 GMT) at which the time zone offset and daylight
 154.220 +     * saving amount are found
 154.221 +     * @param offset an array of int where the raw GMT offset
 154.222 +     * (offset[0]) and daylight saving amount (offset[1]) are stored,
 154.223 +     * or null if those values are not needed. The method assumes that
 154.224 +     * the length of the given array is two or larger.
 154.225 +     * @return the total amount of the raw GMT offset and daylight
 154.226 +     * saving at the specified date.
 154.227 +     *
 154.228 +     * @see Calendar#ZONE_OFFSET
 154.229 +     * @see Calendar#DST_OFFSET
 154.230 +     */
 154.231 +    int getOffsets(long date, int[] offsets) {
 154.232 +        int rawoffset = getRawOffset();
 154.233 +        int dstoffset = 0;
 154.234 +        if (inDaylightTime(new Date(date))) {
 154.235 +            dstoffset = getDSTSavings();
 154.236 +        }
 154.237 +        if (offsets != null) {
 154.238 +            offsets[0] = rawoffset;
 154.239 +            offsets[1] = dstoffset;
 154.240 +        }
 154.241 +        return rawoffset + dstoffset;
 154.242 +    }
 154.243 +
 154.244 +    /**
 154.245 +     * Sets the base time zone offset to GMT.
 154.246 +     * This is the offset to add to UTC to get local time.
 154.247 +     * <p>
 154.248 +     * If an underlying <code>TimeZone</code> implementation subclass
 154.249 +     * supports historical GMT offset changes, the specified GMT
 154.250 +     * offset is set as the latest GMT offset and the difference from
 154.251 +     * the known latest GMT offset value is used to adjust all
 154.252 +     * historical GMT offset values.
 154.253 +     *
 154.254 +     * @param offsetMillis the given base time zone offset to GMT.
 154.255 +     */
 154.256 +    abstract public void setRawOffset(int offsetMillis);
 154.257 +
 154.258 +    /**
 154.259 +     * Returns the amount of time in milliseconds to add to UTC to get
 154.260 +     * standard time in this time zone. Because this value is not
 154.261 +     * affected by daylight saving time, it is called <I>raw
 154.262 +     * offset</I>.
 154.263 +     * <p>
 154.264 +     * If an underlying <code>TimeZone</code> implementation subclass
 154.265 +     * supports historical GMT offset changes, the method returns the
 154.266 +     * raw offset value of the current date. In Honolulu, for example,
 154.267 +     * its raw offset changed from GMT-10:30 to GMT-10:00 in 1947, and
 154.268 +     * this method always returns -36000000 milliseconds (i.e., -10
 154.269 +     * hours).
 154.270 +     *
 154.271 +     * @return the amount of raw offset time in milliseconds to add to UTC.
 154.272 +     * @see Calendar#ZONE_OFFSET
 154.273 +     */
 154.274 +    public abstract int getRawOffset();
 154.275 +
 154.276 +    /**
 154.277 +     * Gets the ID of this time zone.
 154.278 +     * @return the ID of this time zone.
 154.279 +     */
 154.280 +    public String getID()
 154.281 +    {
 154.282 +        return ID;
 154.283 +    }
 154.284 +
 154.285 +    /**
 154.286 +     * Sets the time zone ID. This does not change any other data in
 154.287 +     * the time zone object.
 154.288 +     * @param ID the new time zone ID.
 154.289 +     */
 154.290 +    public void setID(String ID)
 154.291 +    {
 154.292 +        if (ID == null) {
 154.293 +            throw new NullPointerException();
 154.294 +        }
 154.295 +        this.ID = ID;
 154.296 +    }
 154.297 +
 154.298 +    /**
 154.299 +     * Returns a long standard time name of this {@code TimeZone} suitable for
 154.300 +     * presentation to the user in the default locale.
 154.301 +     *
 154.302 +     * <p>This method is equivalent to:
 154.303 +     * <pre><blockquote>
 154.304 +     * getDisplayName(false, {@link #LONG},
 154.305 +     *                Locale.getDefault({@link Locale.Category#DISPLAY}))
 154.306 +     * </blockquote></pre>
 154.307 +     *
 154.308 +     * @return the human-readable name of this time zone in the default locale.
 154.309 +     * @since 1.2
 154.310 +     * @see #getDisplayName(boolean, int, Locale)
 154.311 +     * @see Locale#getDefault(Locale.Category)
 154.312 +     * @see Locale.Category
 154.313 +     */
 154.314 +    public final String getDisplayName() {
 154.315 +        return getDisplayName(false, LONG,
 154.316 +                              Locale.getDefault(Locale.Category.DISPLAY));
 154.317 +    }
 154.318 +
 154.319 +    /**
 154.320 +     * Returns a long standard time name of this {@code TimeZone} suitable for
 154.321 +     * presentation to the user in the specified {@code locale}.
 154.322 +     *
 154.323 +     * <p>This method is equivalent to:
 154.324 +     * <pre><blockquote>
 154.325 +     * getDisplayName(false, {@link #LONG}, locale)
 154.326 +     * </blockquote></pre>
 154.327 +     *
 154.328 +     * @param locale the locale in which to supply the display name.
 154.329 +     * @return the human-readable name of this time zone in the given locale.
 154.330 +     * @exception NullPointerException if {@code locale} is {@code null}.
 154.331 +     * @since 1.2
 154.332 +     * @see #getDisplayName(boolean, int, Locale)
 154.333 +     */
 154.334 +    public final String getDisplayName(Locale locale) {
 154.335 +        return getDisplayName(false, LONG, locale);
 154.336 +    }
 154.337 +
 154.338 +    /**
 154.339 +     * Returns a name in the specified {@code style} of this {@code TimeZone}
 154.340 +     * suitable for presentation to the user in the default locale. If the
 154.341 +     * specified {@code daylight} is {@code true}, a Daylight Saving Time name
 154.342 +     * is returned (even if this {@code TimeZone} doesn't observe Daylight Saving
 154.343 +     * Time). Otherwise, a Standard Time name is returned.
 154.344 +     *
 154.345 +     * <p>This method is equivalent to:
 154.346 +     * <pre><blockquote>
 154.347 +     * getDisplayName(daylight, style,
 154.348 +     *                Locale.getDefault({@link Locale.Category#DISPLAY}))
 154.349 +     * </blockquote></pre>
 154.350 +     *
 154.351 +     * @param daylight {@code true} specifying a Daylight Saving Time name, or
 154.352 +     *                 {@code false} specifying a Standard Time name
 154.353 +     * @param style either {@link #LONG} or {@link #SHORT}
 154.354 +     * @return the human-readable name of this time zone in the default locale.
 154.355 +     * @exception IllegalArgumentException if {@code style} is invalid.
 154.356 +     * @since 1.2
 154.357 +     * @see #getDisplayName(boolean, int, Locale)
 154.358 +     * @see Locale#getDefault(Locale.Category)
 154.359 +     * @see Locale.Category
 154.360 +     * @see java.text.DateFormatSymbols#getZoneStrings()
 154.361 +     */
 154.362 +    public final String getDisplayName(boolean daylight, int style) {
 154.363 +        return getDisplayName(daylight, style,
 154.364 +                              Locale.getDefault(Locale.Category.DISPLAY));
 154.365 +    }
 154.366 +
 154.367 +    /**
 154.368 +     * Returns a name in the specified {@code style} of this {@code TimeZone}
 154.369 +     * suitable for presentation to the user in the specified {@code
 154.370 +     * locale}. If the specified {@code daylight} is {@code true}, a Daylight
 154.371 +     * Saving Time name is returned (even if this {@code TimeZone} doesn't
 154.372 +     * observe Daylight Saving Time). Otherwise, a Standard Time name is
 154.373 +     * returned.
 154.374 +     *
 154.375 +     * <p>When looking up a time zone name, the {@linkplain
 154.376 +     * ResourceBundle.Control#getCandidateLocales(String,Locale) default
 154.377 +     * <code>Locale</code> search path of <code>ResourceBundle</code>} derived
 154.378 +     * from the specified {@code locale} is used. (No {@linkplain
 154.379 +     * ResourceBundle.Control#getFallbackLocale(String,Locale) fallback
 154.380 +     * <code>Locale</code>} search is performed.) If a time zone name in any
 154.381 +     * {@code Locale} of the search path, including {@link Locale#ROOT}, is
 154.382 +     * found, the name is returned. Otherwise, a string in the
 154.383 +     * <a href="#NormalizedCustomID">normalized custom ID format</a> is returned.
 154.384 +     *
 154.385 +     * @param daylight {@code true} specifying a Daylight Saving Time name, or
 154.386 +     *                 {@code false} specifying a Standard Time name
 154.387 +     * @param style either {@link #LONG} or {@link #SHORT}
 154.388 +     * @param locale   the locale in which to supply the display name.
 154.389 +     * @return the human-readable name of this time zone in the given locale.
 154.390 +     * @exception IllegalArgumentException if {@code style} is invalid.
 154.391 +     * @exception NullPointerException if {@code locale} is {@code null}.
 154.392 +     * @since 1.2
 154.393 +     * @see java.text.DateFormatSymbols#getZoneStrings()
 154.394 +     */
 154.395 +    public String getDisplayName(boolean daylight, int style, Locale locale) {
 154.396 +        if (style != SHORT && style != LONG) {
 154.397 +            throw new IllegalArgumentException("Illegal style: " + style);
 154.398 +        }
 154.399 +
 154.400 +        String id = getID();
 154.401 +        String[] names = getDisplayNames(id, locale);
 154.402 +        if (names == null) {
 154.403 +            if (id.startsWith("GMT")) {
 154.404 +                char sign = id.charAt(3);
 154.405 +                if (sign == '+' || sign == '-') {
 154.406 +                    return id;
 154.407 +                }
 154.408 +            }
 154.409 +            int offset = getRawOffset();
 154.410 +            if (daylight) {
 154.411 +                offset += getDSTSavings();
 154.412 +            }
 154.413 +          //  return ZoneInfoFile.toCustomID(offset);
 154.414 +        }
 154.415 +
 154.416 +        int index = daylight ? 3 : 1;
 154.417 +        if (style == SHORT) {
 154.418 +            index++;
 154.419 +        }
 154.420 +        return names[index];
 154.421 +    }
 154.422 +
 154.423 +    private static class DisplayNames {
 154.424 +        // Cache for managing display names per timezone per locale
 154.425 +        // The structure is:
 154.426 +        //   Map(key=id, value=SoftReference(Map(key=locale, value=displaynames)))
 154.427 +        private static final Map<String, SoftReference<Map<Locale, String[]>>> CACHE =
 154.428 +            new ConcurrentHashMap<String, SoftReference<Map<Locale, String[]>>>();
 154.429 +    }
 154.430 +
 154.431 +    private static final String[] getDisplayNames(String id, Locale locale) {
 154.432 +        Map<String, SoftReference<Map<Locale, String[]>>> displayNames = DisplayNames.CACHE;
 154.433 +
 154.434 +        SoftReference<Map<Locale, String[]>> ref = displayNames.get(id);
 154.435 +        if (ref != null) {
 154.436 +            Map<Locale, String[]> perLocale = ref.get();
 154.437 +            if (perLocale != null) {
 154.438 +                String[] names = perLocale.get(locale);
 154.439 +                if (names != null) {
 154.440 +                    return names;
 154.441 +                }
 154.442 +                names = null; // TimeZoneNameUtility.retrieveDisplayNames(id, locale);
 154.443 +                if (names != null) {
 154.444 +                    perLocale.put(locale, names);
 154.445 +                }
 154.446 +                return names;
 154.447 +            }
 154.448 +        }
 154.449 +
 154.450 +        String[] names = null; // TimeZoneNameUtility.retrieveDisplayNames(id, locale);
 154.451 +        if (names != null) {
 154.452 +            Map<Locale, String[]> perLocale = new ConcurrentHashMap<Locale, String[]>();
 154.453 +            perLocale.put(locale, names);
 154.454 +            ref = new SoftReference<Map<Locale, String[]>>(perLocale);
 154.455 +            displayNames.put(id, ref);
 154.456 +        }
 154.457 +        return names;
 154.458 +    }
 154.459 +
 154.460 +    /**
 154.461 +     * Returns the amount of time to be added to local standard time
 154.462 +     * to get local wall clock time.
 154.463 +     *
 154.464 +     * <p>The default implementation returns 3600000 milliseconds
 154.465 +     * (i.e., one hour) if a call to {@link #useDaylightTime()}
 154.466 +     * returns {@code true}. Otherwise, 0 (zero) is returned.
 154.467 +     *
 154.468 +     * <p>If an underlying {@code TimeZone} implementation subclass
 154.469 +     * supports historical and future Daylight Saving Time schedule
 154.470 +     * changes, this method returns the amount of saving time of the
 154.471 +     * last known Daylight Saving Time rule that can be a future
 154.472 +     * prediction.
 154.473 +     *
 154.474 +     * <p>If the amount of saving time at any given time stamp is
 154.475 +     * required, construct a {@link Calendar} with this {@code
 154.476 +     * TimeZone} and the time stamp, and call {@link Calendar#get(int)
 154.477 +     * Calendar.get}{@code (}{@link Calendar#DST_OFFSET}{@code )}.
 154.478 +     *
 154.479 +     * @return the amount of saving time in milliseconds
 154.480 +     * @since 1.4
 154.481 +     * @see #inDaylightTime(Date)
 154.482 +     * @see #getOffset(long)
 154.483 +     * @see #getOffset(int,int,int,int,int,int)
 154.484 +     * @see Calendar#ZONE_OFFSET
 154.485 +     */
 154.486 +    public int getDSTSavings() {
 154.487 +        if (useDaylightTime()) {
 154.488 +            return 3600000;
 154.489 +        }
 154.490 +        return 0;
 154.491 +    }
 154.492 +
 154.493 +    /**
 154.494 +     * Queries if this {@code TimeZone} uses Daylight Saving Time.
 154.495 +     *
 154.496 +     * <p>If an underlying {@code TimeZone} implementation subclass
 154.497 +     * supports historical and future Daylight Saving Time schedule
 154.498 +     * changes, this method refers to the last known Daylight Saving Time
 154.499 +     * rule that can be a future prediction and may not be the same as
 154.500 +     * the current rule. Consider calling {@link #observesDaylightTime()}
 154.501 +     * if the current rule should also be taken into account.
 154.502 +     *
 154.503 +     * @return {@code true} if this {@code TimeZone} uses Daylight Saving Time,
 154.504 +     *         {@code false}, otherwise.
 154.505 +     * @see #inDaylightTime(Date)
 154.506 +     * @see Calendar#DST_OFFSET
 154.507 +     */
 154.508 +    public abstract boolean useDaylightTime();
 154.509 +
 154.510 +    /**
 154.511 +     * Returns {@code true} if this {@code TimeZone} is currently in
 154.512 +     * Daylight Saving Time, or if a transition from Standard Time to
 154.513 +     * Daylight Saving Time occurs at any future time.
 154.514 +     *
 154.515 +     * <p>The default implementation returns {@code true} if
 154.516 +     * {@code useDaylightTime()} or {@code inDaylightTime(new Date())}
 154.517 +     * returns {@code true}.
 154.518 +     *
 154.519 +     * @return {@code true} if this {@code TimeZone} is currently in
 154.520 +     * Daylight Saving Time, or if a transition from Standard Time to
 154.521 +     * Daylight Saving Time occurs at any future time; {@code false}
 154.522 +     * otherwise.
 154.523 +     * @since 1.7
 154.524 +     * @see #useDaylightTime()
 154.525 +     * @see #inDaylightTime(Date)
 154.526 +     * @see Calendar#DST_OFFSET
 154.527 +     */
 154.528 +    public boolean observesDaylightTime() {
 154.529 +        return useDaylightTime() || inDaylightTime(new Date());
 154.530 +    }
 154.531 +
 154.532 +    /**
 154.533 +     * Queries if the given {@code date} is in Daylight Saving Time in
 154.534 +     * this time zone.
 154.535 +     *
 154.536 +     * @param date the given Date.
 154.537 +     * @return {@code true} if the given date is in Daylight Saving Time,
 154.538 +     *         {@code false}, otherwise.
 154.539 +     */
 154.540 +    abstract public boolean inDaylightTime(Date date);
 154.541 +
 154.542 +    /**
 154.543 +     * Gets the <code>TimeZone</code> for the given ID.
 154.544 +     *
 154.545 +     * @param ID the ID for a <code>TimeZone</code>, either an abbreviation
 154.546 +     * such as "PST", a full name such as "America/Los_Angeles", or a custom
 154.547 +     * ID such as "GMT-8:00". Note that the support of abbreviations is
 154.548 +     * for JDK 1.1.x compatibility only and full names should be used.
 154.549 +     *
 154.550 +     * @return the specified <code>TimeZone</code>, or the GMT zone if the given ID
 154.551 +     * cannot be understood.
 154.552 +     */
 154.553 +    public static synchronized TimeZone getTimeZone(String ID) {
 154.554 +        return getTimeZone(ID, true);
 154.555 +    }
 154.556 +
 154.557 +    private static TimeZone getTimeZone(String ID, boolean fallback) {
 154.558 +//        TimeZone tz = ZoneInfo.getTimeZone(ID);
 154.559 +//        if (tz == null) {
 154.560 +//            tz = parseCustomTimeZone(ID);
 154.561 +//            if (tz == null && fallback) {
 154.562 +//                tz = new ZoneInfo(GMT_ID, 0);
 154.563 +//            }
 154.564 +//        }
 154.565 +//        return tz;
 154.566 +        return TimeZone.NO_TIMEZONE;
 154.567 +    }
 154.568 +
 154.569 +    /**
 154.570 +     * Gets the available IDs according to the given time zone offset in milliseconds.
 154.571 +     *
 154.572 +     * @param rawOffset the given time zone GMT offset in milliseconds.
 154.573 +     * @return an array of IDs, where the time zone for that ID has
 154.574 +     * the specified GMT offset. For example, "America/Phoenix" and "America/Denver"
 154.575 +     * both have GMT-07:00, but differ in daylight saving behavior.
 154.576 +     * @see #getRawOffset()
 154.577 +     */
 154.578 +    public static synchronized String[] getAvailableIDs(int rawOffset) {
 154.579 +        return new String[0];//ZoneInfo.getAvailableIDs(rawOffset);
 154.580 +    }
 154.581 +
 154.582 +    /**
 154.583 +     * Gets all the available IDs supported.
 154.584 +     * @return an array of IDs.
 154.585 +     */
 154.586 +    public static synchronized String[] getAvailableIDs() {
 154.587 +        return new String[0];//return ZoneInfo.getAvailableIDs();
 154.588 +    }
 154.589 +
 154.590 +    /**
 154.591 +     * Gets the platform defined TimeZone ID.
 154.592 +     **/
 154.593 +    private static native String getSystemTimeZoneID(String javaHome,
 154.594 +                                                     String country);
 154.595 +
 154.596 +    /**
 154.597 +     * Gets the custom time zone ID based on the GMT offset of the
 154.598 +     * platform. (e.g., "GMT+08:00")
 154.599 +     */
 154.600 +    private static native String getSystemGMTOffsetID();
 154.601 +
 154.602 +    /**
 154.603 +     * Gets the default <code>TimeZone</code> for this host.
 154.604 +     * The source of the default <code>TimeZone</code>
 154.605 +     * may vary with implementation.
 154.606 +     * @return a default <code>TimeZone</code>.
 154.607 +     * @see #setDefault
 154.608 +     */
 154.609 +    public static TimeZone getDefault() {
 154.610 +        return (TimeZone) getDefaultRef().clone();
 154.611 +    }
 154.612 +
 154.613 +    /**
 154.614 +     * Returns the reference to the default TimeZone object. This
 154.615 +     * method doesn't create a clone.
 154.616 +     */
 154.617 +    static TimeZone getDefaultRef() {
 154.618 +        TimeZone defaultZone = null;//defaultZoneTL.get();
 154.619 +        if (defaultZone == null) {
 154.620 +            defaultZone = defaultTimeZone;
 154.621 +            if (defaultZone == null) {
 154.622 +                // Need to initialize the default time zone.
 154.623 +                defaultZone = TimeZone.NO_TIMEZONE;
 154.624 +                assert defaultZone != null;
 154.625 +            }
 154.626 +        }
 154.627 +        // Don't clone here.
 154.628 +        return defaultZone;
 154.629 +    }
 154.630 +
 154.631 +    private static boolean hasPermission() {
 154.632 +        boolean hasPermission = false;
 154.633 +        return hasPermission;
 154.634 +    }
 154.635 +
 154.636 +    /**
 154.637 +     * Sets the <code>TimeZone</code> that is
 154.638 +     * returned by the <code>getDefault</code> method.  If <code>zone</code>
 154.639 +     * is null, reset the default to the value it had originally when the
 154.640 +     * VM first started.
 154.641 +     * @param zone the new default time zone
 154.642 +     * @see #getDefault
 154.643 +     */
 154.644 +    public static void setDefault(TimeZone zone)
 154.645 +    {
 154.646 +        if (hasPermission()) {
 154.647 +            synchronized (TimeZone.class) {
 154.648 +                defaultTimeZone = zone;
 154.649 +              //  defaultZoneTL.set(null);
 154.650 +            }
 154.651 +        } else {
 154.652 +            //defaultZoneTL.set(zone);
 154.653 +        }
 154.654 +    }
 154.655 +
 154.656 +    /**
 154.657 +     * Returns true if this zone has the same rule and offset as another zone.
 154.658 +     * That is, if this zone differs only in ID, if at all.  Returns false
 154.659 +     * if the other zone is null.
 154.660 +     * @param other the <code>TimeZone</code> object to be compared with
 154.661 +     * @return true if the other zone is not null and is the same as this one,
 154.662 +     * with the possible exception of the ID
 154.663 +     * @since 1.2
 154.664 +     */
 154.665 +    public boolean hasSameRules(TimeZone other) {
 154.666 +        return other != null && getRawOffset() == other.getRawOffset() &&
 154.667 +            useDaylightTime() == other.useDaylightTime();
 154.668 +    }
 154.669 +
 154.670 +    /**
 154.671 +     * Creates a copy of this <code>TimeZone</code>.
 154.672 +     *
 154.673 +     * @return a clone of this <code>TimeZone</code>
 154.674 +     */
 154.675 +    public Object clone()
 154.676 +    {
 154.677 +        try {
 154.678 +            TimeZone other = (TimeZone) super.clone();
 154.679 +            other.ID = ID;
 154.680 +            return other;
 154.681 +        } catch (CloneNotSupportedException e) {
 154.682 +            throw new InternalError();
 154.683 +        }
 154.684 +    }
 154.685 +
 154.686 +    /**
 154.687 +     * The null constant as a TimeZone.
 154.688 +     */
 154.689 +    static final TimeZone NO_TIMEZONE = null;
 154.690 +
 154.691 +    // =======================privates===============================
 154.692 +
 154.693 +    /**
 154.694 +     * The string identifier of this <code>TimeZone</code>.  This is a
 154.695 +     * programmatic identifier used internally to look up <code>TimeZone</code>
 154.696 +     * objects from the system table and also to map them to their localized
 154.697 +     * display names.  <code>ID</code> values are unique in the system
 154.698 +     * table but may not be for dynamically created zones.
 154.699 +     * @serial
 154.700 +     */
 154.701 +    private String           ID;
 154.702 +    private static volatile TimeZone defaultTimeZone;
 154.703 +
 154.704 +    static final String         GMT_ID        = "GMT";
 154.705 +    private static final int    GMT_ID_LENGTH = 3;
 154.706 +
 154.707 +    /**
 154.708 +     * Parses a custom time zone identifier and returns a corresponding zone.
 154.709 +     * This method doesn't support the RFC 822 time zone format. (e.g., +hhmm)
 154.710 +     *
 154.711 +     * @param id a string of the <a href="#CustomID">custom ID form</a>.
 154.712 +     * @return a newly created TimeZone with the given offset and
 154.713 +     * no daylight saving time, or null if the id cannot be parsed.
 154.714 +     */
 154.715 +    private static final TimeZone parseCustomTimeZone(String id) {
 154.716 +        return null;
 154.717 +    }
 154.718 +}
   155.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   155.2 +++ b/rt/emul/compact/src/main/java/java/util/Timer.java	Tue Feb 11 13:31:42 2014 +0100
   155.3 @@ -0,0 +1,731 @@
   155.4 +/*
   155.5 + * Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved.
   155.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   155.7 + *
   155.8 + * This code is free software; you can redistribute it and/or modify it
   155.9 + * under the terms of the GNU General Public License version 2 only, as
  155.10 + * published by the Free Software Foundation.  Oracle designates this
  155.11 + * particular file as subject to the "Classpath" exception as provided
  155.12 + * by Oracle in the LICENSE file that accompanied this code.
  155.13 + *
  155.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  155.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  155.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  155.17 + * version 2 for more details (a copy is included in the LICENSE file that
  155.18 + * accompanied this code).
  155.19 + *
  155.20 + * You should have received a copy of the GNU General Public License version
  155.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  155.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  155.23 + *
  155.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  155.25 + * or visit www.oracle.com if you need additional information or have any
  155.26 + * questions.
  155.27 + */
  155.28 +
  155.29 +package java.util;
  155.30 +import java.util.Date;
  155.31 +import java.util.concurrent.atomic.AtomicInteger;
  155.32 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
  155.33 +
  155.34 +/**
  155.35 + * A facility for threads to schedule tasks for future execution in a
  155.36 + * background thread.  Tasks may be scheduled for one-time execution, or for
  155.37 + * repeated execution at regular intervals.
  155.38 + *
  155.39 + * <p>Corresponding to each <tt>Timer</tt> object is a single background
  155.40 + * thread that is used to execute all of the timer's tasks, sequentially.
  155.41 + * Timer tasks should complete quickly.  If a timer task takes excessive time
  155.42 + * to complete, it "hogs" the timer's task execution thread.  This can, in
  155.43 + * turn, delay the execution of subsequent tasks, which may "bunch up" and
  155.44 + * execute in rapid succession when (and if) the offending task finally
  155.45 + * completes.
  155.46 + *
  155.47 + * <p>After the last live reference to a <tt>Timer</tt> object goes away
  155.48 + * <i>and</i> all outstanding tasks have completed execution, the timer's task
  155.49 + * execution thread terminates gracefully (and becomes subject to garbage
  155.50 + * collection).  However, this can take arbitrarily long to occur.  By
  155.51 + * default, the task execution thread does not run as a <i>daemon thread</i>,
  155.52 + * so it is capable of keeping an application from terminating.  If a caller
  155.53 + * wants to terminate a timer's task execution thread rapidly, the caller
  155.54 + * should invoke the timer's <tt>cancel</tt> method.
  155.55 + *
  155.56 + * <p>If the timer's task execution thread terminates unexpectedly, for
  155.57 + * example, because its <tt>stop</tt> method is invoked, any further
  155.58 + * attempt to schedule a task on the timer will result in an
  155.59 + * <tt>IllegalStateException</tt>, as if the timer's <tt>cancel</tt>
  155.60 + * method had been invoked.
  155.61 + *
  155.62 + * <p>This class is thread-safe: multiple threads can share a single
  155.63 + * <tt>Timer</tt> object without the need for external synchronization.
  155.64 + *
  155.65 + * <p>This class does <i>not</i> offer real-time guarantees: it schedules
  155.66 + * tasks using the <tt>Object.wait(long)</tt> method.
  155.67 + *
  155.68 + * <p>Java 5.0 introduced the {@code java.util.concurrent} package and
  155.69 + * one of the concurrency utilities therein is the {@link
  155.70 + * java.util.concurrent.ScheduledThreadPoolExecutor
  155.71 + * ScheduledThreadPoolExecutor} which is a thread pool for repeatedly
  155.72 + * executing tasks at a given rate or delay.  It is effectively a more
  155.73 + * versatile replacement for the {@code Timer}/{@code TimerTask}
  155.74 + * combination, as it allows multiple service threads, accepts various
  155.75 + * time units, and doesn't require subclassing {@code TimerTask} (just
  155.76 + * implement {@code Runnable}).  Configuring {@code
  155.77 + * ScheduledThreadPoolExecutor} with one thread makes it equivalent to
  155.78 + * {@code Timer}.
  155.79 + *
  155.80 + * <p>Implementation note: This class scales to large numbers of concurrently
  155.81 + * scheduled tasks (thousands should present no problem).  Internally,
  155.82 + * it uses a binary heap to represent its task queue, so the cost to schedule
  155.83 + * a task is O(log n), where n is the number of concurrently scheduled tasks.
  155.84 + *
  155.85 + * <p>Implementation note: All constructors start a timer thread.
  155.86 + *
  155.87 + * @author  Josh Bloch
  155.88 + * @see     TimerTask
  155.89 + * @see     Object#wait(long)
  155.90 + * @since   1.3
  155.91 + */
  155.92 +
  155.93 +public class Timer {
  155.94 +    /**
  155.95 +     * The timer task queue.  This data structure is shared with the timer
  155.96 +     * thread.  The timer produces tasks, via its various schedule calls,
  155.97 +     * and the timer thread consumes, executing timer tasks as appropriate,
  155.98 +     * and removing them from the queue when they're obsolete.
  155.99 +     */
 155.100 +    private final TaskQueue queue = new TaskQueue();
 155.101 +
 155.102 +    /**
 155.103 +     * The timer thread.
 155.104 +     */
 155.105 +    private final TimerThread thread = new TimerThread(queue);
 155.106 +
 155.107 +    /**
 155.108 +     * This object causes the timer's task execution thread to exit
 155.109 +     * gracefully when there are no live references to the Timer object and no
 155.110 +     * tasks in the timer queue.  It is used in preference to a finalizer on
 155.111 +     * Timer as such a finalizer would be susceptible to a subclass's
 155.112 +     * finalizer forgetting to call it.
 155.113 +     */
 155.114 +    private final Object threadReaper = new Object() {
 155.115 +        protected void finalize() throws Throwable {
 155.116 +            synchronized(queue) {
 155.117 +                thread.newTasksMayBeScheduled = false;
 155.118 +                thread.notifyQueue(1); // In case queue is empty.
 155.119 +            }
 155.120 +        }
 155.121 +    };
 155.122 +
 155.123 +    /**
 155.124 +     * This ID is used to generate thread names.
 155.125 +     */
 155.126 +    private final static AtomicInteger nextSerialNumber = new AtomicInteger(0);
 155.127 +    private static int serialNumber() {
 155.128 +        return nextSerialNumber.getAndIncrement();
 155.129 +    }
 155.130 +
 155.131 +    /**
 155.132 +     * Creates a new timer.  The associated thread does <i>not</i>
 155.133 +     * {@linkplain Thread#setDaemon run as a daemon}.
 155.134 +     */
 155.135 +    public Timer() {
 155.136 +        this("Timer-" + serialNumber());
 155.137 +    }
 155.138 +
 155.139 +    /**
 155.140 +     * Creates a new timer whose associated thread may be specified to
 155.141 +     * {@linkplain Thread#setDaemon run as a daemon}.
 155.142 +     * A daemon thread is called for if the timer will be used to
 155.143 +     * schedule repeating "maintenance activities", which must be
 155.144 +     * performed as long as the application is running, but should not
 155.145 +     * prolong the lifetime of the application.
 155.146 +     *
 155.147 +     * @param isDaemon true if the associated thread should run as a daemon.
 155.148 +     */
 155.149 +    public Timer(boolean isDaemon) {
 155.150 +        this("Timer-" + serialNumber(), isDaemon);
 155.151 +    }
 155.152 +
 155.153 +    /**
 155.154 +     * Creates a new timer whose associated thread has the specified name.
 155.155 +     * The associated thread does <i>not</i>
 155.156 +     * {@linkplain Thread#setDaemon run as a daemon}.
 155.157 +     *
 155.158 +     * @param name the name of the associated thread
 155.159 +     * @throws NullPointerException if {@code name} is null
 155.160 +     * @since 1.5
 155.161 +     */
 155.162 +    public Timer(String name) {
 155.163 +    }
 155.164 +
 155.165 +    /**
 155.166 +     * Creates a new timer whose associated thread has the specified name,
 155.167 +     * and may be specified to
 155.168 +     * {@linkplain Thread#setDaemon run as a daemon}.
 155.169 +     *
 155.170 +     * @param name the name of the associated thread
 155.171 +     * @param isDaemon true if the associated thread should run as a daemon
 155.172 +     * @throws NullPointerException if {@code name} is null
 155.173 +     * @since 1.5
 155.174 +     */
 155.175 +    public Timer(String name, boolean isDaemon) {
 155.176 +    }
 155.177 +
 155.178 +    /**
 155.179 +     * Schedules the specified task for execution after the specified delay.
 155.180 +     *
 155.181 +     * @param task  task to be scheduled.
 155.182 +     * @param delay delay in milliseconds before task is to be executed.
 155.183 +     * @throws IllegalArgumentException if <tt>delay</tt> is negative, or
 155.184 +     *         <tt>delay + System.currentTimeMillis()</tt> is negative.
 155.185 +     * @throws IllegalStateException if task was already scheduled or
 155.186 +     *         cancelled, timer was cancelled, or timer thread terminated.
 155.187 +     * @throws NullPointerException if {@code task} is null
 155.188 +     */
 155.189 +    public void schedule(TimerTask task, long delay) {
 155.190 +        if (delay < 0)
 155.191 +            throw new IllegalArgumentException("Negative delay.");
 155.192 +        sched(task, System.currentTimeMillis()+delay, 0);
 155.193 +    }
 155.194 +
 155.195 +    /**
 155.196 +     * Schedules the specified task for execution at the specified time.  If
 155.197 +     * the time is in the past, the task is scheduled for immediate execution.
 155.198 +     *
 155.199 +     * @param task task to be scheduled.
 155.200 +     * @param time time at which task is to be executed.
 155.201 +     * @throws IllegalArgumentException if <tt>time.getTime()</tt> is negative.
 155.202 +     * @throws IllegalStateException if task was already scheduled or
 155.203 +     *         cancelled, timer was cancelled, or timer thread terminated.
 155.204 +     * @throws NullPointerException if {@code task} or {@code time} is null
 155.205 +     */
 155.206 +    public void schedule(TimerTask task, Date time) {
 155.207 +        sched(task, time.getTime(), 0);
 155.208 +    }
 155.209 +
 155.210 +    /**
 155.211 +     * Schedules the specified task for repeated <i>fixed-delay execution</i>,
 155.212 +     * beginning after the specified delay.  Subsequent executions take place
 155.213 +     * at approximately regular intervals separated by the specified period.
 155.214 +     *
 155.215 +     * <p>In fixed-delay execution, each execution is scheduled relative to
 155.216 +     * the actual execution time of the previous execution.  If an execution
 155.217 +     * is delayed for any reason (such as garbage collection or other
 155.218 +     * background activity), subsequent executions will be delayed as well.
 155.219 +     * In the long run, the frequency of execution will generally be slightly
 155.220 +     * lower than the reciprocal of the specified period (assuming the system
 155.221 +     * clock underlying <tt>Object.wait(long)</tt> is accurate).
 155.222 +     *
 155.223 +     * <p>Fixed-delay execution is appropriate for recurring activities
 155.224 +     * that require "smoothness."  In other words, it is appropriate for
 155.225 +     * activities where it is more important to keep the frequency accurate
 155.226 +     * in the short run than in the long run.  This includes most animation
 155.227 +     * tasks, such as blinking a cursor at regular intervals.  It also includes
 155.228 +     * tasks wherein regular activity is performed in response to human
 155.229 +     * input, such as automatically repeating a character as long as a key
 155.230 +     * is held down.
 155.231 +     *
 155.232 +     * @param task   task to be scheduled.
 155.233 +     * @param delay  delay in milliseconds before task is to be executed.
 155.234 +     * @param period time in milliseconds between successive task executions.
 155.235 +     * @throws IllegalArgumentException if {@code delay < 0}, or
 155.236 +     *         {@code delay + System.currentTimeMillis() < 0}, or
 155.237 +     *         {@code period <= 0}
 155.238 +     * @throws IllegalStateException if task was already scheduled or
 155.239 +     *         cancelled, timer was cancelled, or timer thread terminated.
 155.240 +     * @throws NullPointerException if {@code task} is null
 155.241 +     */
 155.242 +    public void schedule(TimerTask task, long delay, long period) {
 155.243 +        if (delay < 0)
 155.244 +            throw new IllegalArgumentException("Negative delay.");
 155.245 +        if (period <= 0)
 155.246 +            throw new IllegalArgumentException("Non-positive period.");
 155.247 +        sched(task, System.currentTimeMillis()+delay, -period);
 155.248 +    }
 155.249 +
 155.250 +    /**
 155.251 +     * Schedules the specified task for repeated <i>fixed-delay execution</i>,
 155.252 +     * beginning at the specified time. Subsequent executions take place at
 155.253 +     * approximately regular intervals, separated by the specified period.
 155.254 +     *
 155.255 +     * <p>In fixed-delay execution, each execution is scheduled relative to
 155.256 +     * the actual execution time of the previous execution.  If an execution
 155.257 +     * is delayed for any reason (such as garbage collection or other
 155.258 +     * background activity), subsequent executions will be delayed as well.
 155.259 +     * In the long run, the frequency of execution will generally be slightly
 155.260 +     * lower than the reciprocal of the specified period (assuming the system
 155.261 +     * clock underlying <tt>Object.wait(long)</tt> is accurate).  As a
 155.262 +     * consequence of the above, if the scheduled first time is in the past,
 155.263 +     * it is scheduled for immediate execution.
 155.264 +     *
 155.265 +     * <p>Fixed-delay execution is appropriate for recurring activities
 155.266 +     * that require "smoothness."  In other words, it is appropriate for
 155.267 +     * activities where it is more important to keep the frequency accurate
 155.268 +     * in the short run than in the long run.  This includes most animation
 155.269 +     * tasks, such as blinking a cursor at regular intervals.  It also includes
 155.270 +     * tasks wherein regular activity is performed in response to human
 155.271 +     * input, such as automatically repeating a character as long as a key
 155.272 +     * is held down.
 155.273 +     *
 155.274 +     * @param task   task to be scheduled.
 155.275 +     * @param firstTime First time at which task is to be executed.
 155.276 +     * @param period time in milliseconds between successive task executions.
 155.277 +     * @throws IllegalArgumentException if {@code firstTime.getTime() < 0}, or
 155.278 +     *         {@code period <= 0}
 155.279 +     * @throws IllegalStateException if task was already scheduled or
 155.280 +     *         cancelled, timer was cancelled, or timer thread terminated.
 155.281 +     * @throws NullPointerException if {@code task} or {@code firstTime} is null
 155.282 +     */
 155.283 +    public void schedule(TimerTask task, Date firstTime, long period) {
 155.284 +        if (period <= 0)
 155.285 +            throw new IllegalArgumentException("Non-positive period.");
 155.286 +        sched(task, firstTime.getTime(), -period);
 155.287 +    }
 155.288 +
 155.289 +    /**
 155.290 +     * Schedules the specified task for repeated <i>fixed-rate execution</i>,
 155.291 +     * beginning after the specified delay.  Subsequent executions take place
 155.292 +     * at approximately regular intervals, separated by the specified period.
 155.293 +     *
 155.294 +     * <p>In fixed-rate execution, each execution is scheduled relative to the
 155.295 +     * scheduled execution time of the initial execution.  If an execution is
 155.296 +     * delayed for any reason (such as garbage collection or other background
 155.297 +     * activity), two or more executions will occur in rapid succession to
 155.298 +     * "catch up."  In the long run, the frequency of execution will be
 155.299 +     * exactly the reciprocal of the specified period (assuming the system
 155.300 +     * clock underlying <tt>Object.wait(long)</tt> is accurate).
 155.301 +     *
 155.302 +     * <p>Fixed-rate execution is appropriate for recurring activities that
 155.303 +     * are sensitive to <i>absolute</i> time, such as ringing a chime every
 155.304 +     * hour on the hour, or running scheduled maintenance every day at a
 155.305 +     * particular time.  It is also appropriate for recurring activities
 155.306 +     * where the total time to perform a fixed number of executions is
 155.307 +     * important, such as a countdown timer that ticks once every second for
 155.308 +     * ten seconds.  Finally, fixed-rate execution is appropriate for
 155.309 +     * scheduling multiple repeating timer tasks that must remain synchronized
 155.310 +     * with respect to one another.
 155.311 +     *
 155.312 +     * @param task   task to be scheduled.
 155.313 +     * @param delay  delay in milliseconds before task is to be executed.
 155.314 +     * @param period time in milliseconds between successive task executions.
 155.315 +     * @throws IllegalArgumentException if {@code delay < 0}, or
 155.316 +     *         {@code delay + System.currentTimeMillis() < 0}, or
 155.317 +     *         {@code period <= 0}
 155.318 +     * @throws IllegalStateException if task was already scheduled or
 155.319 +     *         cancelled, timer was cancelled, or timer thread terminated.
 155.320 +     * @throws NullPointerException if {@code task} is null
 155.321 +     */
 155.322 +    public void scheduleAtFixedRate(TimerTask task, long delay, long period) {
 155.323 +        if (delay < 0)
 155.324 +            throw new IllegalArgumentException("Negative delay.");
 155.325 +        if (period <= 0)
 155.326 +            throw new IllegalArgumentException("Non-positive period.");
 155.327 +        sched(task, System.currentTimeMillis()+delay, period);
 155.328 +    }
 155.329 +
 155.330 +    /**
 155.331 +     * Schedules the specified task for repeated <i>fixed-rate execution</i>,
 155.332 +     * beginning at the specified time. Subsequent executions take place at
 155.333 +     * approximately regular intervals, separated by the specified period.
 155.334 +     *
 155.335 +     * <p>In fixed-rate execution, each execution is scheduled relative to the
 155.336 +     * scheduled execution time of the initial execution.  If an execution is
 155.337 +     * delayed for any reason (such as garbage collection or other background
 155.338 +     * activity), two or more executions will occur in rapid succession to
 155.339 +     * "catch up."  In the long run, the frequency of execution will be
 155.340 +     * exactly the reciprocal of the specified period (assuming the system
 155.341 +     * clock underlying <tt>Object.wait(long)</tt> is accurate).  As a
 155.342 +     * consequence of the above, if the scheduled first time is in the past,
 155.343 +     * then any "missed" executions will be scheduled for immediate "catch up"
 155.344 +     * execution.
 155.345 +     *
 155.346 +     * <p>Fixed-rate execution is appropriate for recurring activities that
 155.347 +     * are sensitive to <i>absolute</i> time, such as ringing a chime every
 155.348 +     * hour on the hour, or running scheduled maintenance every day at a
 155.349 +     * particular time.  It is also appropriate for recurring activities
 155.350 +     * where the total time to perform a fixed number of executions is
 155.351 +     * important, such as a countdown timer that ticks once every second for
 155.352 +     * ten seconds.  Finally, fixed-rate execution is appropriate for
 155.353 +     * scheduling multiple repeating timer tasks that must remain synchronized
 155.354 +     * with respect to one another.
 155.355 +     *
 155.356 +     * @param task   task to be scheduled.
 155.357 +     * @param firstTime First time at which task is to be executed.
 155.358 +     * @param period time in milliseconds between successive task executions.
 155.359 +     * @throws IllegalArgumentException if {@code firstTime.getTime() < 0} or
 155.360 +     *         {@code period <= 0}
 155.361 +     * @throws IllegalStateException if task was already scheduled or
 155.362 +     *         cancelled, timer was cancelled, or timer thread terminated.
 155.363 +     * @throws NullPointerException if {@code task} or {@code firstTime} is null
 155.364 +     */
 155.365 +    public void scheduleAtFixedRate(TimerTask task, Date firstTime,
 155.366 +                                    long period) {
 155.367 +        if (period <= 0)
 155.368 +            throw new IllegalArgumentException("Non-positive period.");
 155.369 +        sched(task, firstTime.getTime(), period);
 155.370 +    }
 155.371 +
 155.372 +    /**
 155.373 +     * Schedule the specified timer task for execution at the specified
 155.374 +     * time with the specified period, in milliseconds.  If period is
 155.375 +     * positive, the task is scheduled for repeated execution; if period is
 155.376 +     * zero, the task is scheduled for one-time execution. Time is specified
 155.377 +     * in Date.getTime() format.  This method checks timer state, task state,
 155.378 +     * and initial execution time, but not period.
 155.379 +     *
 155.380 +     * @throws IllegalArgumentException if <tt>time</tt> is negative.
 155.381 +     * @throws IllegalStateException if task was already scheduled or
 155.382 +     *         cancelled, timer was cancelled, or timer thread terminated.
 155.383 +     * @throws NullPointerException if {@code task} is null
 155.384 +     */
 155.385 +    private void sched(TimerTask task, long time, long period) {
 155.386 +        if (time < 0)
 155.387 +            throw new IllegalArgumentException("Illegal execution time.");
 155.388 +
 155.389 +        // Constrain value of period sufficiently to prevent numeric
 155.390 +        // overflow while still being effectively infinitely large.
 155.391 +        if (Math.abs(period) > (Long.MAX_VALUE >> 1))
 155.392 +            period >>= 1;
 155.393 +
 155.394 +        synchronized(queue) {
 155.395 +            if (!thread.newTasksMayBeScheduled)
 155.396 +                throw new IllegalStateException("Timer already cancelled.");
 155.397 +
 155.398 +            synchronized(task.lock) {
 155.399 +                if (task.state != TimerTask.VIRGIN)
 155.400 +                    throw new IllegalStateException(
 155.401 +                        "Task already scheduled or cancelled");
 155.402 +                task.nextExecutionTime = time;
 155.403 +                task.period = period;
 155.404 +                task.state = TimerTask.SCHEDULED;
 155.405 +            }
 155.406 +
 155.407 +            queue.add(task);
 155.408 +            if (queue.getMin() == task)
 155.409 +                thread.notifyQueue(1);
 155.410 +        }
 155.411 +    }
 155.412 +
 155.413 +    /**
 155.414 +     * Terminates this timer, discarding any currently scheduled tasks.
 155.415 +     * Does not interfere with a currently executing task (if it exists).
 155.416 +     * Once a timer has been terminated, its execution thread terminates
 155.417 +     * gracefully, and no more tasks may be scheduled on it.
 155.418 +     *
 155.419 +     * <p>Note that calling this method from within the run method of a
 155.420 +     * timer task that was invoked by this timer absolutely guarantees that
 155.421 +     * the ongoing task execution is the last task execution that will ever
 155.422 +     * be performed by this timer.
 155.423 +     *
 155.424 +     * <p>This method may be called repeatedly; the second and subsequent
 155.425 +     * calls have no effect.
 155.426 +     */
 155.427 +    public void cancel() {
 155.428 +        synchronized(queue) {
 155.429 +            thread.newTasksMayBeScheduled = false;
 155.430 +            queue.clear();
 155.431 +            thread.notifyQueue(1);  // In case queue was already empty.
 155.432 +        }
 155.433 +    }
 155.434 +    
 155.435 +    /**
 155.436 +     * Removes all cancelled tasks from this timer's task queue.  <i>Calling
 155.437 +     * this method has no effect on the behavior of the timer</i>, but
 155.438 +     * eliminates the references to the cancelled tasks from the queue.
 155.439 +     * If there are no external references to these tasks, they become
 155.440 +     * eligible for garbage collection.
 155.441 +     *
 155.442 +     * <p>Most programs will have no need to call this method.
 155.443 +     * It is designed for use by the rare application that cancels a large
 155.444 +     * number of tasks.  Calling this method trades time for space: the
 155.445 +     * runtime of the method may be proportional to n + c log n, where n
 155.446 +     * is the number of tasks in the queue and c is the number of cancelled
 155.447 +     * tasks.
 155.448 +     *
 155.449 +     * <p>Note that it is permissible to call this method from within a
 155.450 +     * a task scheduled on this timer.
 155.451 +     *
 155.452 +     * @return the number of tasks removed from the queue.
 155.453 +     * @since 1.5
 155.454 +     */
 155.455 +     public int purge() {
 155.456 +         int result = 0;
 155.457 +
 155.458 +         synchronized(queue) {
 155.459 +             for (int i = queue.size(); i > 0; i--) {
 155.460 +                 if (queue.get(i).state == TimerTask.CANCELLED) {
 155.461 +                     queue.quickRemove(i);
 155.462 +                     result++;
 155.463 +                 }
 155.464 +             }
 155.465 +
 155.466 +             if (result != 0)
 155.467 +                 queue.heapify();
 155.468 +         }
 155.469 +
 155.470 +         return result;
 155.471 +     }
 155.472 +}
 155.473 +
 155.474 +/**
 155.475 + * This "helper class" implements the timer's task execution thread, which
 155.476 + * waits for tasks on the timer queue, executions them when they fire,
 155.477 + * reschedules repeating tasks, and removes cancelled tasks and spent
 155.478 + * non-repeating tasks from the queue.
 155.479 + */
 155.480 +class TimerThread implements Runnable {
 155.481 +    /**
 155.482 +     * This flag is set to false by the reaper to inform us that there
 155.483 +     * are no more live references to our Timer object.  Once this flag
 155.484 +     * is true and there are no more tasks in our queue, there is no
 155.485 +     * work left for us to do, so we terminate gracefully.  Note that
 155.486 +     * this field is protected by queue's monitor!
 155.487 +     */
 155.488 +    boolean newTasksMayBeScheduled = true;
 155.489 +
 155.490 +    /**
 155.491 +     * Our Timer's queue.  We store this reference in preference to
 155.492 +     * a reference to the Timer so the reference graph remains acyclic.
 155.493 +     * Otherwise, the Timer would never be garbage-collected and this
 155.494 +     * thread would never go away.
 155.495 +     */
 155.496 +    private TaskQueue queue;
 155.497 +
 155.498 +    TimerThread(TaskQueue queue) {
 155.499 +        this.queue = queue;
 155.500 +    }
 155.501 +
 155.502 +    void notifyQueue(int delay) {
 155.503 +        if (delay < 1) {
 155.504 +            delay = 1;
 155.505 +        }
 155.506 +        setTimeout(delay, this);
 155.507 +    }
 155.508 +    
 155.509 +    @JavaScriptBody(args = { "delay", "r" }, body = "window.setTimeout(function() { r.run__V(); }, delay);")
 155.510 +    private static native void setTimeout(int delay, Runnable r);
 155.511 +    
 155.512 +    public void run() {
 155.513 +        mainLoop(1);
 155.514 +//        try {
 155.515 +//            mainLoop(0);
 155.516 +//        } finally {
 155.517 +//            // Someone killed this Thread, behave as if Timer cancelled
 155.518 +//            synchronized(queue) {
 155.519 +//                newTasksMayBeScheduled = false;
 155.520 +//                queue.clear();  // Eliminate obsolete references
 155.521 +//            }
 155.522 +//        }
 155.523 +    }
 155.524 +
 155.525 +    /**
 155.526 +     * The main timer loop.  (See class comment.)
 155.527 +     */
 155.528 +    private void mainLoop(int inc) {
 155.529 +        for (int i = 0; i < 1; i += inc) {
 155.530 +            try {
 155.531 +                TimerTask task;
 155.532 +                boolean taskFired;
 155.533 +                synchronized(queue) {
 155.534 +                    // Wait for queue to become non-empty
 155.535 +                    while (queue.isEmpty() && newTasksMayBeScheduled)
 155.536 +                        break;
 155.537 +                    if (queue.isEmpty())
 155.538 +                        break; // Queue is empty and will forever remain; die
 155.539 +
 155.540 +                    // Queue nonempty; look at first evt and do the right thing
 155.541 +                    long currentTime, executionTime;
 155.542 +                    task = queue.getMin();
 155.543 +                    synchronized(task.lock) {
 155.544 +                        if (task.state == TimerTask.CANCELLED) {
 155.545 +                            queue.removeMin();
 155.546 +                            continue;  // No action required, poll queue again
 155.547 +                        }
 155.548 +                        currentTime = System.currentTimeMillis();
 155.549 +                        executionTime = task.nextExecutionTime;
 155.550 +                        if (taskFired = (executionTime<=currentTime)) {
 155.551 +                            if (task.period == 0) { // Non-repeating, remove
 155.552 +                                queue.removeMin();
 155.553 +                                task.state = TimerTask.EXECUTED;
 155.554 +                            } else { // Repeating task, reschedule
 155.555 +                                queue.rescheduleMin(
 155.556 +                                  task.period<0 ? currentTime   - task.period
 155.557 +                                                : executionTime + task.period);
 155.558 +                            }
 155.559 +                        }
 155.560 +                    }
 155.561 +                    if (!taskFired) {
 155.562 +                        // Task hasn't yet fired; wait
 155.563 +                        notifyQueue((int)(executionTime - currentTime));
 155.564 +                        return;
 155.565 +                    }
 155.566 +                }
 155.567 +                if (taskFired)  // Task fired; run it, holding no locks
 155.568 +                    task.run();
 155.569 +            } catch(Exception e) {
 155.570 +                e.printStackTrace();
 155.571 +            }
 155.572 +        }
 155.573 +    }
 155.574 +}
 155.575 +
 155.576 +/**
 155.577 + * This class represents a timer task queue: a priority queue of TimerTasks,
 155.578 + * ordered on nextExecutionTime.  Each Timer object has one of these, which it
 155.579 + * shares with its TimerThread.  Internally this class uses a heap, which
 155.580 + * offers log(n) performance for the add, removeMin and rescheduleMin
 155.581 + * operations, and constant time performance for the getMin operation.
 155.582 + */
 155.583 +class TaskQueue {
 155.584 +    /**
 155.585 +     * Priority queue represented as a balanced binary heap: the two children
 155.586 +     * of queue[n] are queue[2*n] and queue[2*n+1].  The priority queue is
 155.587 +     * ordered on the nextExecutionTime field: The TimerTask with the lowest
 155.588 +     * nextExecutionTime is in queue[1] (assuming the queue is nonempty).  For
 155.589 +     * each node n in the heap, and each descendant of n, d,
 155.590 +     * n.nextExecutionTime <= d.nextExecutionTime.
 155.591 +     */
 155.592 +    private TimerTask[] queue = new TimerTask[128];
 155.593 +
 155.594 +    /**
 155.595 +     * The number of tasks in the priority queue.  (The tasks are stored in
 155.596 +     * queue[1] up to queue[size]).
 155.597 +     */
 155.598 +    private int size = 0;
 155.599 +
 155.600 +    /**
 155.601 +     * Returns the number of tasks currently on the queue.
 155.602 +     */
 155.603 +    int size() {
 155.604 +        return size;
 155.605 +    }
 155.606 +
 155.607 +    /**
 155.608 +     * Adds a new task to the priority queue.
 155.609 +     */
 155.610 +    void add(TimerTask task) {
 155.611 +        // Grow backing store if necessary
 155.612 +        if (size + 1 == queue.length)
 155.613 +            queue = Arrays.copyOf(queue, 2*queue.length);
 155.614 +
 155.615 +        queue[++size] = task;
 155.616 +        fixUp(size);
 155.617 +    }
 155.618 +
 155.619 +    /**
 155.620 +     * Return the "head task" of the priority queue.  (The head task is an
 155.621 +     * task with the lowest nextExecutionTime.)
 155.622 +     */
 155.623 +    TimerTask getMin() {
 155.624 +        return queue[1];
 155.625 +    }
 155.626 +
 155.627 +    /**
 155.628 +     * Return the ith task in the priority queue, where i ranges from 1 (the
 155.629 +     * head task, which is returned by getMin) to the number of tasks on the
 155.630 +     * queue, inclusive.
 155.631 +     */
 155.632 +    TimerTask get(int i) {
 155.633 +        return queue[i];
 155.634 +    }
 155.635 +
 155.636 +    /**
 155.637 +     * Remove the head task from the priority queue.
 155.638 +     */
 155.639 +    void removeMin() {
 155.640 +        queue[1] = queue[size];
 155.641 +        queue[size--] = null;  // Drop extra reference to prevent memory leak
 155.642 +        fixDown(1);
 155.643 +    }
 155.644 +
 155.645 +    /**
 155.646 +     * Removes the ith element from queue without regard for maintaining
 155.647 +     * the heap invariant.  Recall that queue is one-based, so
 155.648 +     * 1 <= i <= size.
 155.649 +     */
 155.650 +    void quickRemove(int i) {
 155.651 +        assert i <= size;
 155.652 +
 155.653 +        queue[i] = queue[size];
 155.654 +        queue[size--] = null;  // Drop extra ref to prevent memory leak
 155.655 +    }
 155.656 +
 155.657 +    /**
 155.658 +     * Sets the nextExecutionTime associated with the head task to the
 155.659 +     * specified value, and adjusts priority queue accordingly.
 155.660 +     */
 155.661 +    void rescheduleMin(long newTime) {
 155.662 +        queue[1].nextExecutionTime = newTime;
 155.663 +        fixDown(1);
 155.664 +    }
 155.665 +
 155.666 +    /**
 155.667 +     * Returns true if the priority queue contains no elements.
 155.668 +     */
 155.669 +    boolean isEmpty() {
 155.670 +        return size==0;
 155.671 +    }
 155.672 +
 155.673 +    /**
 155.674 +     * Removes all elements from the priority queue.
 155.675 +     */
 155.676 +    void clear() {
 155.677 +        // Null out task references to prevent memory leak
 155.678 +        for (int i=1; i<=size; i++)
 155.679 +            queue[i] = null;
 155.680 +
 155.681 +        size = 0;
 155.682 +    }
 155.683 +
 155.684 +    /**
 155.685 +     * Establishes the heap invariant (described above) assuming the heap
 155.686 +     * satisfies the invariant except possibly for the leaf-node indexed by k
 155.687 +     * (which may have a nextExecutionTime less than its parent's).
 155.688 +     *
 155.689 +     * This method functions by "promoting" queue[k] up the hierarchy
 155.690 +     * (by swapping it with its parent) repeatedly until queue[k]'s
 155.691 +     * nextExecutionTime is greater than or equal to that of its parent.
 155.692 +     */
 155.693 +    private void fixUp(int k) {
 155.694 +        while (k > 1) {
 155.695 +            int j = k >> 1;
 155.696 +            if (queue[j].nextExecutionTime <= queue[k].nextExecutionTime)
 155.697 +                break;
 155.698 +            TimerTask tmp = queue[j];  queue[j] = queue[k]; queue[k] = tmp;
 155.699 +            k = j;
 155.700 +        }
 155.701 +    }
 155.702 +
 155.703 +    /**
 155.704 +     * Establishes the heap invariant (described above) in the subtree
 155.705 +     * rooted at k, which is assumed to satisfy the heap invariant except
 155.706 +     * possibly for node k itself (which may have a nextExecutionTime greater
 155.707 +     * than its children's).
 155.708 +     *
 155.709 +     * This method functions by "demoting" queue[k] down the hierarchy
 155.710 +     * (by swapping it with its smaller child) repeatedly until queue[k]'s
 155.711 +     * nextExecutionTime is less than or equal to those of its children.
 155.712 +     */
 155.713 +    private void fixDown(int k) {
 155.714 +        int j;
 155.715 +        while ((j = k << 1) <= size && j > 0) {
 155.716 +            if (j < size &&
 155.717 +                queue[j].nextExecutionTime > queue[j+1].nextExecutionTime)
 155.718 +                j++; // j indexes smallest kid
 155.719 +            if (queue[k].nextExecutionTime <= queue[j].nextExecutionTime)
 155.720 +                break;
 155.721 +            TimerTask tmp = queue[j];  queue[j] = queue[k]; queue[k] = tmp;
 155.722 +            k = j;
 155.723 +        }
 155.724 +    }
 155.725 +
 155.726 +    /**
 155.727 +     * Establishes the heap invariant (described above) in the entire tree,
 155.728 +     * assuming nothing about the order of the elements prior to the call.
 155.729 +     */
 155.730 +    void heapify() {
 155.731 +        for (int i = size/2; i >= 1; i--)
 155.732 +            fixDown(i);
 155.733 +    }
 155.734 +}
   156.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   156.2 +++ b/rt/emul/compact/src/main/java/java/util/TimerTask.java	Tue Feb 11 13:31:42 2014 +0100
   156.3 @@ -0,0 +1,158 @@
   156.4 +/*
   156.5 + * Copyright (c) 1999, 2004, Oracle and/or its affiliates. All rights reserved.
   156.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   156.7 + *
   156.8 + * This code is free software; you can redistribute it and/or modify it
   156.9 + * under the terms of the GNU General Public License version 2 only, as
  156.10 + * published by the Free Software Foundation.  Oracle designates this
  156.11 + * particular file as subject to the "Classpath" exception as provided
  156.12 + * by Oracle in the LICENSE file that accompanied this code.
  156.13 + *
  156.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  156.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  156.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  156.17 + * version 2 for more details (a copy is included in the LICENSE file that
  156.18 + * accompanied this code).
  156.19 + *
  156.20 + * You should have received a copy of the GNU General Public License version
  156.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  156.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  156.23 + *
  156.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  156.25 + * or visit www.oracle.com if you need additional information or have any
  156.26 + * questions.
  156.27 + */
  156.28 +
  156.29 +package java.util;
  156.30 +
  156.31 +/**
  156.32 + * A task that can be scheduled for one-time or repeated execution by a Timer.
  156.33 + *
  156.34 + * @author  Josh Bloch
  156.35 + * @see     Timer
  156.36 + * @since   1.3
  156.37 + */
  156.38 +
  156.39 +public abstract class TimerTask implements Runnable {
  156.40 +    /**
  156.41 +     * This object is used to control access to the TimerTask internals.
  156.42 +     */
  156.43 +    final Object lock = new Object();
  156.44 +
  156.45 +    /**
  156.46 +     * The state of this task, chosen from the constants below.
  156.47 +     */
  156.48 +    int state = VIRGIN;
  156.49 +
  156.50 +    /**
  156.51 +     * This task has not yet been scheduled.
  156.52 +     */
  156.53 +    static final int VIRGIN = 0;
  156.54 +
  156.55 +    /**
  156.56 +     * This task is scheduled for execution.  If it is a non-repeating task,
  156.57 +     * it has not yet been executed.
  156.58 +     */
  156.59 +    static final int SCHEDULED   = 1;
  156.60 +
  156.61 +    /**
  156.62 +     * This non-repeating task has already executed (or is currently
  156.63 +     * executing) and has not been cancelled.
  156.64 +     */
  156.65 +    static final int EXECUTED    = 2;
  156.66 +
  156.67 +    /**
  156.68 +     * This task has been cancelled (with a call to TimerTask.cancel).
  156.69 +     */
  156.70 +    static final int CANCELLED   = 3;
  156.71 +
  156.72 +    /**
  156.73 +     * Next execution time for this task in the format returned by
  156.74 +     * System.currentTimeMillis, assuming this task is scheduled for execution.
  156.75 +     * For repeating tasks, this field is updated prior to each task execution.
  156.76 +     */
  156.77 +    long nextExecutionTime;
  156.78 +
  156.79 +    /**
  156.80 +     * Period in milliseconds for repeating tasks.  A positive value indicates
  156.81 +     * fixed-rate execution.  A negative value indicates fixed-delay execution.
  156.82 +     * A value of 0 indicates a non-repeating task.
  156.83 +     */
  156.84 +    long period = 0;
  156.85 +
  156.86 +    /**
  156.87 +     * Creates a new timer task.
  156.88 +     */
  156.89 +    protected TimerTask() {
  156.90 +    }
  156.91 +
  156.92 +    /**
  156.93 +     * The action to be performed by this timer task.
  156.94 +     */
  156.95 +    public abstract void run();
  156.96 +
  156.97 +    /**
  156.98 +     * Cancels this timer task.  If the task has been scheduled for one-time
  156.99 +     * execution and has not yet run, or has not yet been scheduled, it will
 156.100 +     * never run.  If the task has been scheduled for repeated execution, it
 156.101 +     * will never run again.  (If the task is running when this call occurs,
 156.102 +     * the task will run to completion, but will never run again.)
 156.103 +     *
 156.104 +     * <p>Note that calling this method from within the <tt>run</tt> method of
 156.105 +     * a repeating timer task absolutely guarantees that the timer task will
 156.106 +     * not run again.
 156.107 +     *
 156.108 +     * <p>This method may be called repeatedly; the second and subsequent
 156.109 +     * calls have no effect.
 156.110 +     *
 156.111 +     * @return true if this task is scheduled for one-time execution and has
 156.112 +     *         not yet run, or this task is scheduled for repeated execution.
 156.113 +     *         Returns false if the task was scheduled for one-time execution
 156.114 +     *         and has already run, or if the task was never scheduled, or if
 156.115 +     *         the task was already cancelled.  (Loosely speaking, this method
 156.116 +     *         returns <tt>true</tt> if it prevents one or more scheduled
 156.117 +     *         executions from taking place.)
 156.118 +     */
 156.119 +    public boolean cancel() {
 156.120 +        synchronized(lock) {
 156.121 +            boolean result = (state == SCHEDULED);
 156.122 +            state = CANCELLED;
 156.123 +            return result;
 156.124 +        }
 156.125 +    }
 156.126 +
 156.127 +    /**
 156.128 +     * Returns the <i>scheduled</i> execution time of the most recent
 156.129 +     * <i>actual</i> execution of this task.  (If this method is invoked
 156.130 +     * while task execution is in progress, the return value is the scheduled
 156.131 +     * execution time of the ongoing task execution.)
 156.132 +     *
 156.133 +     * <p>This method is typically invoked from within a task's run method, to
 156.134 +     * determine whether the current execution of the task is sufficiently
 156.135 +     * timely to warrant performing the scheduled activity:
 156.136 +     * <pre>
 156.137 +     *   public void run() {
 156.138 +     *       if (System.currentTimeMillis() - scheduledExecutionTime() >=
 156.139 +     *           MAX_TARDINESS)
 156.140 +     *               return;  // Too late; skip this execution.
 156.141 +     *       // Perform the task
 156.142 +     *   }
 156.143 +     * </pre>
 156.144 +     * This method is typically <i>not</i> used in conjunction with
 156.145 +     * <i>fixed-delay execution</i> repeating tasks, as their scheduled
 156.146 +     * execution times are allowed to drift over time, and so are not terribly
 156.147 +     * significant.
 156.148 +     *
 156.149 +     * @return the time at which the most recent execution of this task was
 156.150 +     *         scheduled to occur, in the format returned by Date.getTime().
 156.151 +     *         The return value is undefined if the task has yet to commence
 156.152 +     *         its first execution.
 156.153 +     * @see Date#getTime()
 156.154 +     */
 156.155 +    public long scheduledExecutionTime() {
 156.156 +        synchronized(lock) {
 156.157 +            return (period < 0 ? nextExecutionTime + period
 156.158 +                               : nextExecutionTime - period);
 156.159 +        }
 156.160 +    }
 156.161 +}
   157.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   157.2 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/ConcurrentHashMap.java	Tue Feb 11 13:31:42 2014 +0100
   157.3 @@ -0,0 +1,327 @@
   157.4 +/*
   157.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   157.6 + *
   157.7 + * This code is free software; you can redistribute it and/or modify it
   157.8 + * under the terms of the GNU General Public License version 2 only, as
   157.9 + * published by the Free Software Foundation.  Oracle designates this
  157.10 + * particular file as subject to the "Classpath" exception as provided
  157.11 + * by Oracle in the LICENSE file that accompanied this code.
  157.12 + *
  157.13 + * This code is distributed in the hope that it will be useful, but WITHOUT
  157.14 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  157.15 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  157.16 + * version 2 for more details (a copy is included in the LICENSE file that
  157.17 + * accompanied this code).
  157.18 + *
  157.19 + * You should have received a copy of the GNU General Public License version
  157.20 + * 2 along with this work; if not, write to the Free Software Foundation,
  157.21 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  157.22 + *
  157.23 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  157.24 + * or visit www.oracle.com if you need additional information or have any
  157.25 + * questions.
  157.26 + */
  157.27 +
  157.28 +/*
  157.29 + * This file is available under and governed by the GNU General Public
  157.30 + * License version 2 only, as published by the Free Software Foundation.
  157.31 + * However, the following notice accompanied the original version of this
  157.32 + * file:
  157.33 + *
  157.34 + * Written by Doug Lea with assistance from members of JCP JSR-166
  157.35 + * Expert Group and released to the public domain, as explained at
  157.36 + * http://creativecommons.org/publicdomain/zero/1.0/
  157.37 + */
  157.38 +package java.util.concurrent;
  157.39 +
  157.40 +import java.util.*;
  157.41 +import java.io.Serializable;
  157.42 +import java.io.IOException;
  157.43 +import java.io.ObjectInputStream;
  157.44 +import java.io.ObjectOutputStream;
  157.45 +
  157.46 +/**
  157.47 + * A hash table supporting full concurrency of retrievals and adjustable
  157.48 + * expected concurrency for updates. This class obeys the same functional
  157.49 + * specification as {@link java.util.Hashtable}, and includes versions of
  157.50 + * methods corresponding to each method of
  157.51 + * <tt>Hashtable</tt>. However, even though all operations are thread-safe,
  157.52 + * retrieval operations do <em>not</em> entail locking, and there is
  157.53 + * <em>not</em> any support for locking the entire table in a way that prevents
  157.54 + * all access. This class is fully interoperable with <tt>Hashtable</tt> in
  157.55 + * programs that rely on its thread safety but not on its synchronization
  157.56 + * details.
  157.57 + *
  157.58 + * <p>
  157.59 + * Retrieval operations (including <tt>get</tt>) generally do not block, so may
  157.60 + * overlap with update operations (including
  157.61 + * <tt>put</tt> and <tt>remove</tt>). Retrievals reflect the results of the most
  157.62 + * recently <em>completed</em> update operations holding upon their onset. For
  157.63 + * aggregate operations such as <tt>putAll</tt>
  157.64 + * and <tt>clear</tt>, concurrent retrievals may reflect insertion or removal of
  157.65 + * only some entries. Similarly, Iterators and Enumerations return elements
  157.66 + * reflecting the state of the hash table at some point at or since the creation
  157.67 + * of the iterator/enumeration. They do <em>not</em> throw
  157.68 + * {@link ConcurrentModificationException}. However, iterators are designed to
  157.69 + * be used by only one thread at a time.
  157.70 + *
  157.71 + * <p>
  157.72 + * The allowed concurrency among update operations is guided by the optional
  157.73 + * <tt>concurrencyLevel</tt> constructor argument (default <tt>16</tt>), which
  157.74 + * is used as a hint for internal sizing. The table is internally partitioned to
  157.75 + * try to permit the indicated number of concurrent updates without contention.
  157.76 + * Because placement in hash tables is essentially random, the actual
  157.77 + * concurrency will vary. Ideally, you should choose a value to accommodate as
  157.78 + * many threads as will ever concurrently modify the table. Using a
  157.79 + * significantly higher value than you need can waste space and time, and a
  157.80 + * significantly lower value can lead to thread contention. But overestimates
  157.81 + * and underestimates within an order of magnitude do not usually have much
  157.82 + * noticeable impact. A value of one is appropriate when it is known that only
  157.83 + * one thread will modify and all others will only read. Also, resizing this or
  157.84 + * any other kind of hash table is a relatively slow operation, so, when
  157.85 + * possible, it is a good idea to provide estimates of expected table sizes in
  157.86 + * constructors.
  157.87 + *
  157.88 + * <p>
  157.89 + * This class and its views and iterators implement all of the
  157.90 + * <em>optional</em> methods of the {@link Map} and {@link Iterator} interfaces.
  157.91 + *
  157.92 + * <p>
  157.93 + * Like {@link Hashtable} but unlike {@link HashMap}, this class does
  157.94 + * <em>not</em> allow <tt>null</tt> to be used as a key or value.
  157.95 + *
  157.96 + * <p>
  157.97 + * This class is a member of the
  157.98 + * <a href="{@docRoot}/../technotes/guides/collections/index.html">
  157.99 + * Java Collections Framework</a>.
 157.100 + *
 157.101 + * @since 1.5
 157.102 + * @author Doug Lea
 157.103 + * @param <K> the type of keys maintained by this map
 157.104 + * @param <V> the type of mapped values
 157.105 + */
 157.106 +public class ConcurrentHashMap<K, V> extends AbstractMap<K, V>
 157.107 +    implements ConcurrentMap<K, V>, Serializable {
 157.108 +
 157.109 +    private static final long serialVersionUID = 7249069246763182397L;
 157.110 +    /**
 157.111 +     * The default initial capacity for this table,
 157.112 +     * used when not otherwise specified in a constructor.
 157.113 +     */
 157.114 +    static final int DEFAULT_INITIAL_CAPACITY = 16;
 157.115 +
 157.116 +    /**
 157.117 +     * The default load factor for this table, used when not
 157.118 +     * otherwise specified in a constructor.
 157.119 +     */
 157.120 +    static final float DEFAULT_LOAD_FACTOR = 0.75f;
 157.121 +
 157.122 +    /**
 157.123 +     * The default concurrency level for this table, used when not
 157.124 +     * otherwise specified in a constructor.
 157.125 +     */
 157.126 +    static final int DEFAULT_CONCURRENCY_LEVEL = 16;
 157.127 +
 157.128 +    private final Map<K, V> delegate;
 157.129 +
 157.130 +
 157.131 +    /**
 157.132 +     * Creates a new, empty map with the specified initial
 157.133 +     * capacity, load factor and concurrency level.
 157.134 +     *
 157.135 +     * @param initialCapacity the initial capacity. The implementation
 157.136 +     * performs internal sizing to accommodate this many elements.
 157.137 +     * @param loadFactor  the load factor threshold, used to control resizing.
 157.138 +     * Resizing may be performed when the average number of elements per
 157.139 +     * bin exceeds this threshold.
 157.140 +     * @param concurrencyLevel the estimated number of concurrently
 157.141 +     * updating threads. The implementation performs internal sizing
 157.142 +     * to try to accommodate this many threads.
 157.143 +     * @throws IllegalArgumentException if the initial capacity is
 157.144 +     * negative or the load factor or concurrencyLevel are
 157.145 +     * nonpositive.
 157.146 +     */
 157.147 +    @SuppressWarnings("unchecked")
 157.148 +    public ConcurrentHashMap(int initialCapacity,
 157.149 +                             float loadFactor, int concurrencyLevel) {
 157.150 +        if (!(loadFactor > 0) || initialCapacity < 0 || concurrencyLevel <= 0)
 157.151 +            throw new IllegalArgumentException();
 157.152 +        delegate = new HashMap<>(initialCapacity, loadFactor);
 157.153 +    }
 157.154 +
 157.155 +    /**
 157.156 +     * Creates a new, empty map with the specified initial capacity
 157.157 +     * and load factor and with the default concurrencyLevel (16).
 157.158 +     *
 157.159 +     * @param initialCapacity The implementation performs internal
 157.160 +     * sizing to accommodate this many elements.
 157.161 +     * @param loadFactor  the load factor threshold, used to control resizing.
 157.162 +     * Resizing may be performed when the average number of elements per
 157.163 +     * bin exceeds this threshold.
 157.164 +     * @throws IllegalArgumentException if the initial capacity of
 157.165 +     * elements is negative or the load factor is nonpositive
 157.166 +     *
 157.167 +     * @since 1.6
 157.168 +     */
 157.169 +    public ConcurrentHashMap(int initialCapacity, float loadFactor) {
 157.170 +        this(initialCapacity, loadFactor, DEFAULT_CONCURRENCY_LEVEL);
 157.171 +    }
 157.172 +
 157.173 +    /**
 157.174 +     * Creates a new, empty map with the specified initial capacity,
 157.175 +     * and with default load factor (0.75) and concurrencyLevel (16).
 157.176 +     *
 157.177 +     * @param initialCapacity the initial capacity. The implementation
 157.178 +     * performs internal sizing to accommodate this many elements.
 157.179 +     * @throws IllegalArgumentException if the initial capacity of
 157.180 +     * elements is negative.
 157.181 +     */
 157.182 +    public ConcurrentHashMap(int initialCapacity) {
 157.183 +        this(initialCapacity, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
 157.184 +    }
 157.185 +
 157.186 +    /**
 157.187 +     * Creates a new, empty map with a default initial capacity (16),
 157.188 +     * load factor (0.75) and concurrencyLevel (16).
 157.189 +     */
 157.190 +    public ConcurrentHashMap() {
 157.191 +        this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
 157.192 +    }
 157.193 +
 157.194 +    /**
 157.195 +     * Creates a new map with the same mappings as the given map.
 157.196 +     * The map is created with a capacity of 1.5 times the number
 157.197 +     * of mappings in the given map or 16 (whichever is greater),
 157.198 +     * and a default load factor (0.75) and concurrencyLevel (16).
 157.199 +     *
 157.200 +     * @param m the map
 157.201 +     */
 157.202 +    public ConcurrentHashMap(Map<? extends K, ? extends V> m) {
 157.203 +        this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,
 157.204 +                      DEFAULT_INITIAL_CAPACITY),
 157.205 +             DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
 157.206 +        putAll(m);
 157.207 +    }
 157.208 +    
 157.209 +
 157.210 +    @Override
 157.211 +    public int size() {
 157.212 +        return delegate.size();
 157.213 +    }
 157.214 +
 157.215 +    @Override
 157.216 +    public boolean isEmpty() {
 157.217 +        return delegate.isEmpty();
 157.218 +    }
 157.219 +
 157.220 +    @Override
 157.221 +    public boolean containsKey(Object key) {
 157.222 +        return delegate.containsKey(key);
 157.223 +    }
 157.224 +
 157.225 +    @Override
 157.226 +    public boolean containsValue(Object value) {
 157.227 +        return delegate.containsValue(value);
 157.228 +    }
 157.229 +
 157.230 +    @Override
 157.231 +    public V get(Object key) {
 157.232 +        return delegate.get(key);
 157.233 +    }
 157.234 +
 157.235 +    @Override
 157.236 +    public V put(K key, V value) {
 157.237 +        return delegate.put(key, value);
 157.238 +    }
 157.239 +
 157.240 +    @Override
 157.241 +    public V remove(Object key) {
 157.242 +        return delegate.remove(key);
 157.243 +    }
 157.244 +
 157.245 +    @Override
 157.246 +    public void putAll(Map<? extends K, ? extends V> m) {
 157.247 +        delegate.putAll(m);
 157.248 +    }
 157.249 +
 157.250 +    @Override
 157.251 +    public void clear() {
 157.252 +        delegate.clear();
 157.253 +    }
 157.254 +
 157.255 +    @Override
 157.256 +    public Set<K> keySet() {
 157.257 +        return delegate.keySet();
 157.258 +    }
 157.259 +
 157.260 +    @Override
 157.261 +    public Collection<V> values() {
 157.262 +        return delegate.values();
 157.263 +    }
 157.264 +
 157.265 +    @Override
 157.266 +    public Set<Entry<K, V>> entrySet() {
 157.267 +        return delegate.entrySet();
 157.268 +    }
 157.269 +
 157.270 +    @Override
 157.271 +    public boolean equals(Object o) {
 157.272 +        return delegate.equals(o);
 157.273 +    }
 157.274 +
 157.275 +    @Override
 157.276 +    public int hashCode() {
 157.277 +        return delegate.hashCode();
 157.278 +    }
 157.279 +
 157.280 +    @Override
 157.281 +    public String toString() {
 157.282 +        return delegate.toString();
 157.283 +    }
 157.284 +
 157.285 +    @Override
 157.286 +    public V putIfAbsent(K key, V value) {
 157.287 +        V old = delegate.get(key);
 157.288 +        if (old == null) {
 157.289 +            return delegate.put(key, value);
 157.290 +        }
 157.291 +        return old;
 157.292 +    }
 157.293 +
 157.294 +    @Override
 157.295 +    public boolean remove(Object key, Object value) {
 157.296 +        if (equals(value, delegate.get(key))) {
 157.297 +            delegate.remove(key);
 157.298 +            return true;
 157.299 +        } else {
 157.300 +            return false;
 157.301 +        }
 157.302 +    }
 157.303 +
 157.304 +    @Override
 157.305 +    public boolean replace(K key, V oldValue, V newValue) {
 157.306 +        if (equals(oldValue, delegate.get(key))) {
 157.307 +            delegate.put(key, newValue);
 157.308 +            return true;
 157.309 +        } else {
 157.310 +            return false;
 157.311 +        }
 157.312 +    }
 157.313 +
 157.314 +    @Override
 157.315 +    public V replace(K key, V value) {
 157.316 +        if (delegate.containsKey(key)) {
 157.317 +            return delegate.put(key, value);
 157.318 +        } else {
 157.319 +            return null;
 157.320 +        }
 157.321 +    }
 157.322 +    
 157.323 +    private static boolean equals(Object a, Object b) {
 157.324 +        if (a == null) {
 157.325 +            return b == null;
 157.326 +        } else {
 157.327 +            return a.equals(b);
 157.328 +        }
 157.329 +    }
 157.330 +}
   158.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   158.2 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/ConcurrentMap.java	Tue Feb 11 13:31:42 2014 +0100
   158.3 @@ -0,0 +1,165 @@
   158.4 +/*
   158.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   158.6 + *
   158.7 + * This code is free software; you can redistribute it and/or modify it
   158.8 + * under the terms of the GNU General Public License version 2 only, as
   158.9 + * published by the Free Software Foundation.  Oracle designates this
  158.10 + * particular file as subject to the "Classpath" exception as provided
  158.11 + * by Oracle in the LICENSE file that accompanied this code.
  158.12 + *
  158.13 + * This code is distributed in the hope that it will be useful, but WITHOUT
  158.14 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  158.15 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  158.16 + * version 2 for more details (a copy is included in the LICENSE file that
  158.17 + * accompanied this code).
  158.18 + *
  158.19 + * You should have received a copy of the GNU General Public License version
  158.20 + * 2 along with this work; if not, write to the Free Software Foundation,
  158.21 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  158.22 + *
  158.23 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  158.24 + * or visit www.oracle.com if you need additional information or have any
  158.25 + * questions.
  158.26 + */
  158.27 +
  158.28 +/*
  158.29 + * This file is available under and governed by the GNU General Public
  158.30 + * License version 2 only, as published by the Free Software Foundation.
  158.31 + * However, the following notice accompanied the original version of this
  158.32 + * file:
  158.33 + *
  158.34 + * Written by Doug Lea with assistance from members of JCP JSR-166
  158.35 + * Expert Group and released to the public domain, as explained at
  158.36 + * http://creativecommons.org/publicdomain/zero/1.0/
  158.37 + */
  158.38 +
  158.39 +package java.util.concurrent;
  158.40 +import java.util.Map;
  158.41 +
  158.42 +/**
  158.43 + * A {@link java.util.Map} providing additional atomic
  158.44 + * <tt>putIfAbsent</tt>, <tt>remove</tt>, and <tt>replace</tt> methods.
  158.45 + *
  158.46 + * <p>Memory consistency effects: As with other concurrent
  158.47 + * collections, actions in a thread prior to placing an object into a
  158.48 + * {@code ConcurrentMap} as a key or value
  158.49 + * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
  158.50 + * actions subsequent to the access or removal of that object from
  158.51 + * the {@code ConcurrentMap} in another thread.
  158.52 + *
  158.53 + * <p>This interface is a member of the
  158.54 + * <a href="{@docRoot}/../technotes/guides/collections/index.html">
  158.55 + * Java Collections Framework</a>.
  158.56 + *
  158.57 + * @since 1.5
  158.58 + * @author Doug Lea
  158.59 + * @param <K> the type of keys maintained by this map
  158.60 + * @param <V> the type of mapped values
  158.61 + */
  158.62 +public interface ConcurrentMap<K, V> extends Map<K, V> {
  158.63 +    /**
  158.64 +     * If the specified key is not already associated
  158.65 +     * with a value, associate it with the given value.
  158.66 +     * This is equivalent to
  158.67 +     * <pre>
  158.68 +     *   if (!map.containsKey(key))
  158.69 +     *       return map.put(key, value);
  158.70 +     *   else
  158.71 +     *       return map.get(key);</pre>
  158.72 +     * except that the action is performed atomically.
  158.73 +     *
  158.74 +     * @param key key with which the specified value is to be associated
  158.75 +     * @param value value to be associated with the specified key
  158.76 +     * @return the previous value associated with the specified key, or
  158.77 +     *         <tt>null</tt> if there was no mapping for the key.
  158.78 +     *         (A <tt>null</tt> return can also indicate that the map
  158.79 +     *         previously associated <tt>null</tt> with the key,
  158.80 +     *         if the implementation supports null values.)
  158.81 +     * @throws UnsupportedOperationException if the <tt>put</tt> operation
  158.82 +     *         is not supported by this map
  158.83 +     * @throws ClassCastException if the class of the specified key or value
  158.84 +     *         prevents it from being stored in this map
  158.85 +     * @throws NullPointerException if the specified key or value is null,
  158.86 +     *         and this map does not permit null keys or values
  158.87 +     * @throws IllegalArgumentException if some property of the specified key
  158.88 +     *         or value prevents it from being stored in this map
  158.89 +     *
  158.90 +     */
  158.91 +    V putIfAbsent(K key, V value);
  158.92 +
  158.93 +    /**
  158.94 +     * Removes the entry for a key only if currently mapped to a given value.
  158.95 +     * This is equivalent to
  158.96 +     * <pre>
  158.97 +     *   if (map.containsKey(key) &amp;&amp; map.get(key).equals(value)) {
  158.98 +     *       map.remove(key);
  158.99 +     *       return true;
 158.100 +     *   } else return false;</pre>
 158.101 +     * except that the action is performed atomically.
 158.102 +     *
 158.103 +     * @param key key with which the specified value is associated
 158.104 +     * @param value value expected to be associated with the specified key
 158.105 +     * @return <tt>true</tt> if the value was removed
 158.106 +     * @throws UnsupportedOperationException if the <tt>remove</tt> operation
 158.107 +     *         is not supported by this map
 158.108 +     * @throws ClassCastException if the key or value is of an inappropriate
 158.109 +     *         type for this map
 158.110 +     *         (<a href="../Collection.html#optional-restrictions">optional</a>)
 158.111 +     * @throws NullPointerException if the specified key or value is null,
 158.112 +     *         and this map does not permit null keys or values
 158.113 +     *         (<a href="../Collection.html#optional-restrictions">optional</a>)
 158.114 +     */
 158.115 +    boolean remove(Object key, Object value);
 158.116 +
 158.117 +    /**
 158.118 +     * Replaces the entry for a key only if currently mapped to a given value.
 158.119 +     * This is equivalent to
 158.120 +     * <pre>
 158.121 +     *   if (map.containsKey(key) &amp;&amp; map.get(key).equals(oldValue)) {
 158.122 +     *       map.put(key, newValue);
 158.123 +     *       return true;
 158.124 +     *   } else return false;</pre>
 158.125 +     * except that the action is performed atomically.
 158.126 +     *
 158.127 +     * @param key key with which the specified value is associated
 158.128 +     * @param oldValue value expected to be associated with the specified key
 158.129 +     * @param newValue value to be associated with the specified key
 158.130 +     * @return <tt>true</tt> if the value was replaced
 158.131 +     * @throws UnsupportedOperationException if the <tt>put</tt> operation
 158.132 +     *         is not supported by this map
 158.133 +     * @throws ClassCastException if the class of a specified key or value
 158.134 +     *         prevents it from being stored in this map
 158.135 +     * @throws NullPointerException if a specified key or value is null,
 158.136 +     *         and this map does not permit null keys or values
 158.137 +     * @throws IllegalArgumentException if some property of a specified key
 158.138 +     *         or value prevents it from being stored in this map
 158.139 +     */
 158.140 +    boolean replace(K key, V oldValue, V newValue);
 158.141 +
 158.142 +    /**
 158.143 +     * Replaces the entry for a key only if currently mapped to some value.
 158.144 +     * This is equivalent to
 158.145 +     * <pre>
 158.146 +     *   if (map.containsKey(key)) {
 158.147 +     *       return map.put(key, value);
 158.148 +     *   } else return null;</pre>
 158.149 +     * except that the action is performed atomically.
 158.150 +     *
 158.151 +     * @param key key with which the specified value is associated
 158.152 +     * @param value value to be associated with the specified key
 158.153 +     * @return the previous value associated with the specified key, or
 158.154 +     *         <tt>null</tt> if there was no mapping for the key.
 158.155 +     *         (A <tt>null</tt> return can also indicate that the map
 158.156 +     *         previously associated <tt>null</tt> with the key,
 158.157 +     *         if the implementation supports null values.)
 158.158 +     * @throws UnsupportedOperationException if the <tt>put</tt> operation
 158.159 +     *         is not supported by this map
 158.160 +     * @throws ClassCastException if the class of the specified key or value
 158.161 +     *         prevents it from being stored in this map
 158.162 +     * @throws NullPointerException if the specified key or value is null,
 158.163 +     *         and this map does not permit null keys or values
 158.164 +     * @throws IllegalArgumentException if some property of the specified key
 158.165 +     *         or value prevents it from being stored in this map
 158.166 +     */
 158.167 +    V replace(K key, V value);
 158.168 +}
   159.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   159.2 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/atomic/AtomicBoolean.java	Tue Feb 11 13:31:42 2014 +0100
   159.3 @@ -0,0 +1,155 @@
   159.4 +/*
   159.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   159.6 + *
   159.7 + * This code is free software; you can redistribute it and/or modify it
   159.8 + * under the terms of the GNU General Public License version 2 only, as
   159.9 + * published by the Free Software Foundation.  Oracle designates this
  159.10 + * particular file as subject to the "Classpath" exception as provided
  159.11 + * by Oracle in the LICENSE file that accompanied this code.
  159.12 + *
  159.13 + * This code is distributed in the hope that it will be useful, but WITHOUT
  159.14 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  159.15 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  159.16 + * version 2 for more details (a copy is included in the LICENSE file that
  159.17 + * accompanied this code).
  159.18 + *
  159.19 + * You should have received a copy of the GNU General Public License version
  159.20 + * 2 along with this work; if not, write to the Free Software Foundation,
  159.21 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  159.22 + *
  159.23 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  159.24 + * or visit www.oracle.com if you need additional information or have any
  159.25 + * questions.
  159.26 + */
  159.27 +
  159.28 +/*
  159.29 + * This file is available under and governed by the GNU General Public
  159.30 + * License version 2 only, as published by the Free Software Foundation.
  159.31 + * However, the following notice accompanied the original version of this
  159.32 + * file:
  159.33 + *
  159.34 + * Written by Doug Lea with assistance from members of JCP JSR-166
  159.35 + * Expert Group and released to the public domain, as explained at
  159.36 + * http://creativecommons.org/publicdomain/zero/1.0/
  159.37 + */
  159.38 +
  159.39 +package java.util.concurrent.atomic;
  159.40 +
  159.41 +/**
  159.42 + * A {@code boolean} value that may be updated atomically. See the
  159.43 + * {@link java.util.concurrent.atomic} package specification for
  159.44 + * description of the properties of atomic variables. An
  159.45 + * {@code AtomicBoolean} is used in applications such as atomically
  159.46 + * updated flags, and cannot be used as a replacement for a
  159.47 + * {@link java.lang.Boolean}.
  159.48 + *
  159.49 + * @since 1.5
  159.50 + * @author Doug Lea
  159.51 + */
  159.52 +public class AtomicBoolean implements java.io.Serializable {
  159.53 +    private static final long serialVersionUID = 4654671469794556979L;
  159.54 +
  159.55 +    private volatile int value;
  159.56 +
  159.57 +    /**
  159.58 +     * Creates a new {@code AtomicBoolean} with the given initial value.
  159.59 +     *
  159.60 +     * @param initialValue the initial value
  159.61 +     */
  159.62 +    public AtomicBoolean(boolean initialValue) {
  159.63 +        value = initialValue ? 1 : 0;
  159.64 +    }
  159.65 +
  159.66 +    /**
  159.67 +     * Creates a new {@code AtomicBoolean} with initial value {@code false}.
  159.68 +     */
  159.69 +    public AtomicBoolean() {
  159.70 +    }
  159.71 +
  159.72 +    /**
  159.73 +     * Returns the current value.
  159.74 +     *
  159.75 +     * @return the current value
  159.76 +     */
  159.77 +    public final boolean get() {
  159.78 +        return value != 0;
  159.79 +    }
  159.80 +
  159.81 +    /**
  159.82 +     * Atomically sets the value to the given updated value
  159.83 +     * if the current value {@code ==} the expected value.
  159.84 +     *
  159.85 +     * @param expect the expected value
  159.86 +     * @param update the new value
  159.87 +     * @return true if successful. False return indicates that
  159.88 +     * the actual value was not equal to the expected value.
  159.89 +     */
  159.90 +    public final boolean compareAndSet(boolean expect, boolean update) {
  159.91 +        int e = expect ? 1 : 0;
  159.92 +        int u = update ? 1 : 0;
  159.93 +        if (this.value == e) {
  159.94 +            this.value = u;
  159.95 +            return true;
  159.96 +        } else {
  159.97 +            return false;
  159.98 +        }
  159.99 +    }
 159.100 +
 159.101 +    /**
 159.102 +     * Atomically sets the value to the given updated value
 159.103 +     * if the current value {@code ==} the expected value.
 159.104 +     *
 159.105 +     * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
 159.106 +     * and does not provide ordering guarantees, so is only rarely an
 159.107 +     * appropriate alternative to {@code compareAndSet}.
 159.108 +     *
 159.109 +     * @param expect the expected value
 159.110 +     * @param update the new value
 159.111 +     * @return true if successful.
 159.112 +     */
 159.113 +    public boolean weakCompareAndSet(boolean expect, boolean update) {
 159.114 +        return compareAndSet(expect, update);
 159.115 +    }
 159.116 +
 159.117 +    /**
 159.118 +     * Unconditionally sets to the given value.
 159.119 +     *
 159.120 +     * @param newValue the new value
 159.121 +     */
 159.122 +    public final void set(boolean newValue) {
 159.123 +        value = newValue ? 1 : 0;
 159.124 +    }
 159.125 +
 159.126 +    /**
 159.127 +     * Eventually sets to the given value.
 159.128 +     *
 159.129 +     * @param newValue the new value
 159.130 +     * @since 1.6
 159.131 +     */
 159.132 +    public final void lazySet(boolean newValue) {
 159.133 +        set(newValue);
 159.134 +    }
 159.135 +
 159.136 +    /**
 159.137 +     * Atomically sets to the given value and returns the previous value.
 159.138 +     *
 159.139 +     * @param newValue the new value
 159.140 +     * @return the previous value
 159.141 +     */
 159.142 +    public final boolean getAndSet(boolean newValue) {
 159.143 +        for (;;) {
 159.144 +            boolean current = get();
 159.145 +            if (compareAndSet(current, newValue))
 159.146 +                return current;
 159.147 +        }
 159.148 +    }
 159.149 +
 159.150 +    /**
 159.151 +     * Returns the String representation of the current value.
 159.152 +     * @return the String representation of the current value.
 159.153 +     */
 159.154 +    public String toString() {
 159.155 +        return Boolean.toString(get());
 159.156 +    }
 159.157 +
 159.158 +}
   160.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   160.2 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/atomic/AtomicInteger.java	Tue Feb 11 13:31:42 2014 +0100
   160.3 @@ -0,0 +1,258 @@
   160.4 +/*
   160.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   160.6 + *
   160.7 + * This code is free software; you can redistribute it and/or modify it
   160.8 + * under the terms of the GNU General Public License version 2 only, as
   160.9 + * published by the Free Software Foundation.  Oracle designates this
  160.10 + * particular file as subject to the "Classpath" exception as provided
  160.11 + * by Oracle in the LICENSE file that accompanied this code.
  160.12 + *
  160.13 + * This code is distributed in the hope that it will be useful, but WITHOUT
  160.14 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  160.15 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  160.16 + * version 2 for more details (a copy is included in the LICENSE file that
  160.17 + * accompanied this code).
  160.18 + *
  160.19 + * You should have received a copy of the GNU General Public License version
  160.20 + * 2 along with this work; if not, write to the Free Software Foundation,
  160.21 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  160.22 + *
  160.23 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  160.24 + * or visit www.oracle.com if you need additional information or have any
  160.25 + * questions.
  160.26 + */
  160.27 +
  160.28 +/*
  160.29 + * This file is available under and governed by the GNU General Public
  160.30 + * License version 2 only, as published by the Free Software Foundation.
  160.31 + * However, the following notice accompanied the original version of this
  160.32 + * file:
  160.33 + *
  160.34 + * Written by Doug Lea with assistance from members of JCP JSR-166
  160.35 + * Expert Group and released to the public domain, as explained at
  160.36 + * http://creativecommons.org/publicdomain/zero/1.0/
  160.37 + */
  160.38 +
  160.39 +package java.util.concurrent.atomic;
  160.40 +
  160.41 +/**
  160.42 + * An {@code int} value that may be updated atomically.  See the
  160.43 + * {@link java.util.concurrent.atomic} package specification for
  160.44 + * description of the properties of atomic variables. An
  160.45 + * {@code AtomicInteger} is used in applications such as atomically
  160.46 + * incremented counters, and cannot be used as a replacement for an
  160.47 + * {@link java.lang.Integer}. However, this class does extend
  160.48 + * {@code Number} to allow uniform access by tools and utilities that
  160.49 + * deal with numerically-based classes.
  160.50 + *
  160.51 + * @since 1.5
  160.52 + * @author Doug Lea
  160.53 +*/
  160.54 +public class AtomicInteger extends Number implements java.io.Serializable {
  160.55 +    private static final long serialVersionUID = 6214790243416807050L;
  160.56 +
  160.57 +    private volatile int value;
  160.58 +
  160.59 +    /**
  160.60 +     * Creates a new AtomicInteger with the given initial value.
  160.61 +     *
  160.62 +     * @param initialValue the initial value
  160.63 +     */
  160.64 +    public AtomicInteger(int initialValue) {
  160.65 +        value = initialValue;
  160.66 +    }
  160.67 +
  160.68 +    /**
  160.69 +     * Creates a new AtomicInteger with initial value {@code 0}.
  160.70 +     */
  160.71 +    public AtomicInteger() {
  160.72 +    }
  160.73 +
  160.74 +    /**
  160.75 +     * Gets the current value.
  160.76 +     *
  160.77 +     * @return the current value
  160.78 +     */
  160.79 +    public final int get() {
  160.80 +        return value;
  160.81 +    }
  160.82 +
  160.83 +    /**
  160.84 +     * Sets to the given value.
  160.85 +     *
  160.86 +     * @param newValue the new value
  160.87 +     */
  160.88 +    public final void set(int newValue) {
  160.89 +        value = newValue;
  160.90 +    }
  160.91 +
  160.92 +    /**
  160.93 +     * Eventually sets to the given value.
  160.94 +     *
  160.95 +     * @param newValue the new value
  160.96 +     * @since 1.6
  160.97 +     */
  160.98 +    public final void lazySet(int newValue) {
  160.99 +        value = newValue;
 160.100 +    }
 160.101 +
 160.102 +    /**
 160.103 +     * Atomically sets to the given value and returns the old value.
 160.104 +     *
 160.105 +     * @param newValue the new value
 160.106 +     * @return the previous value
 160.107 +     */
 160.108 +    public final int getAndSet(int newValue) {
 160.109 +        for (;;) {
 160.110 +            int current = get();
 160.111 +            if (compareAndSet(current, newValue))
 160.112 +                return current;
 160.113 +        }
 160.114 +    }
 160.115 +
 160.116 +    /**
 160.117 +     * Atomically sets the value to the given updated value
 160.118 +     * if the current value {@code ==} the expected value.
 160.119 +     *
 160.120 +     * @param expect the expected value
 160.121 +     * @param update the new value
 160.122 +     * @return true if successful. False return indicates that
 160.123 +     * the actual value was not equal to the expected value.
 160.124 +     */
 160.125 +    public final boolean compareAndSet(int expect, int update) {
 160.126 +        if (value == expect) {
 160.127 +            value = update;
 160.128 +            return true;
 160.129 +        } else {
 160.130 +            return false;
 160.131 +        }
 160.132 +    }
 160.133 +
 160.134 +    /**
 160.135 +     * Atomically sets the value to the given updated value
 160.136 +     * if the current value {@code ==} the expected value.
 160.137 +     *
 160.138 +     * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
 160.139 +     * and does not provide ordering guarantees, so is only rarely an
 160.140 +     * appropriate alternative to {@code compareAndSet}.
 160.141 +     *
 160.142 +     * @param expect the expected value
 160.143 +     * @param update the new value
 160.144 +     * @return true if successful.
 160.145 +     */
 160.146 +    public final boolean weakCompareAndSet(int expect, int update) {
 160.147 +        return compareAndSet(expect, update);
 160.148 +    }
 160.149 +
 160.150 +    /**
 160.151 +     * Atomically increments by one the current value.
 160.152 +     *
 160.153 +     * @return the previous value
 160.154 +     */
 160.155 +    public final int getAndIncrement() {
 160.156 +        for (;;) {
 160.157 +            int current = get();
 160.158 +            int next = current + 1;
 160.159 +            if (compareAndSet(current, next))
 160.160 +                return current;
 160.161 +        }
 160.162 +    }
 160.163 +
 160.164 +    /**
 160.165 +     * Atomically decrements by one the current value.
 160.166 +     *
 160.167 +     * @return the previous value
 160.168 +     */
 160.169 +    public final int getAndDecrement() {
 160.170 +        for (;;) {
 160.171 +            int current = get();
 160.172 +            int next = current - 1;
 160.173 +            if (compareAndSet(current, next))
 160.174 +                return current;
 160.175 +        }
 160.176 +    }
 160.177 +
 160.178 +    /**
 160.179 +     * Atomically adds the given value to the current value.
 160.180 +     *
 160.181 +     * @param delta the value to add
 160.182 +     * @return the previous value
 160.183 +     */
 160.184 +    public final int getAndAdd(int delta) {
 160.185 +        for (;;) {
 160.186 +            int current = get();
 160.187 +            int next = current + delta;
 160.188 +            if (compareAndSet(current, next))
 160.189 +                return current;
 160.190 +        }
 160.191 +    }
 160.192 +
 160.193 +    /**
 160.194 +     * Atomically increments by one the current value.
 160.195 +     *
 160.196 +     * @return the updated value
 160.197 +     */
 160.198 +    public final int incrementAndGet() {
 160.199 +        for (;;) {
 160.200 +            int current = get();
 160.201 +            int next = current + 1;
 160.202 +            if (compareAndSet(current, next))
 160.203 +                return next;
 160.204 +        }
 160.205 +    }
 160.206 +
 160.207 +    /**
 160.208 +     * Atomically decrements by one the current value.
 160.209 +     *
 160.210 +     * @return the updated value
 160.211 +     */
 160.212 +    public final int decrementAndGet() {
 160.213 +        for (;;) {
 160.214 +            int current = get();
 160.215 +            int next = current - 1;
 160.216 +            if (compareAndSet(current, next))
 160.217 +                return next;
 160.218 +        }
 160.219 +    }
 160.220 +
 160.221 +    /**
 160.222 +     * Atomically adds the given value to the current value.
 160.223 +     *
 160.224 +     * @param delta the value to add
 160.225 +     * @return the updated value
 160.226 +     */
 160.227 +    public final int addAndGet(int delta) {
 160.228 +        for (;;) {
 160.229 +            int current = get();
 160.230 +            int next = current + delta;
 160.231 +            if (compareAndSet(current, next))
 160.232 +                return next;
 160.233 +        }
 160.234 +    }
 160.235 +
 160.236 +    /**
 160.237 +     * Returns the String representation of the current value.
 160.238 +     * @return the String representation of the current value.
 160.239 +     */
 160.240 +    public String toString() {
 160.241 +        return Integer.toString(get());
 160.242 +    }
 160.243 +
 160.244 +
 160.245 +    public int intValue() {
 160.246 +        return get();
 160.247 +    }
 160.248 +
 160.249 +    public long longValue() {
 160.250 +        return (long)get();
 160.251 +    }
 160.252 +
 160.253 +    public float floatValue() {
 160.254 +        return (float)get();
 160.255 +    }
 160.256 +
 160.257 +    public double doubleValue() {
 160.258 +        return (double)get();
 160.259 +    }
 160.260 +
 160.261 +}
   161.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   161.2 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/atomic/AtomicIntegerArray.java	Tue Feb 11 13:31:42 2014 +0100
   161.3 @@ -0,0 +1,247 @@
   161.4 +/*
   161.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   161.6 + *
   161.7 + * This code is free software; you can redistribute it and/or modify it
   161.8 + * under the terms of the GNU General Public License version 2 only, as
   161.9 + * published by the Free Software Foundation.  Oracle designates this
  161.10 + * particular file as subject to the "Classpath" exception as provided
  161.11 + * by Oracle in the LICENSE file that accompanied this code.
  161.12 + *
  161.13 + * This code is distributed in the hope that it will be useful, but WITHOUT
  161.14 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  161.15 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  161.16 + * version 2 for more details (a copy is included in the LICENSE file that
  161.17 + * accompanied this code).
  161.18 + *
  161.19 + * You should have received a copy of the GNU General Public License version
  161.20 + * 2 along with this work; if not, write to the Free Software Foundation,
  161.21 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  161.22 + *
  161.23 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  161.24 + * or visit www.oracle.com if you need additional information or have any
  161.25 + * questions.
  161.26 + */
  161.27 +
  161.28 +/*
  161.29 + * This file is available under and governed by the GNU General Public
  161.30 + * License version 2 only, as published by the Free Software Foundation.
  161.31 + * However, the following notice accompanied the original version of this
  161.32 + * file:
  161.33 + *
  161.34 + * Written by Doug Lea with assistance from members of JCP JSR-166
  161.35 + * Expert Group and released to the public domain, as explained at
  161.36 + * http://creativecommons.org/publicdomain/zero/1.0/
  161.37 + */
  161.38 +
  161.39 +package java.util.concurrent.atomic;
  161.40 +
  161.41 +/**
  161.42 + * An {@code int} array in which elements may be updated atomically.
  161.43 + * See the {@link java.util.concurrent.atomic} package
  161.44 + * specification for description of the properties of atomic
  161.45 + * variables.
  161.46 + * @since 1.5
  161.47 + * @author Doug Lea
  161.48 + */
  161.49 +public class AtomicIntegerArray implements java.io.Serializable {
  161.50 +    private static final long serialVersionUID = 2862133569453604235L;
  161.51 +
  161.52 +    private final int[] array;
  161.53 +
  161.54 +    /**
  161.55 +     * Creates a new AtomicIntegerArray of the given length, with all
  161.56 +     * elements initially zero.
  161.57 +     *
  161.58 +     * @param length the length of the array
  161.59 +     */
  161.60 +    public AtomicIntegerArray(int length) {
  161.61 +        array = new int[length];
  161.62 +    }
  161.63 +
  161.64 +    /**
  161.65 +     * Creates a new AtomicIntegerArray with the same length as, and
  161.66 +     * all elements copied from, the given array.
  161.67 +     *
  161.68 +     * @param array the array to copy elements from
  161.69 +     * @throws NullPointerException if array is null
  161.70 +     */
  161.71 +    public AtomicIntegerArray(int[] array) {
  161.72 +        // Visibility guaranteed by final field guarantees
  161.73 +        this.array = array.clone();
  161.74 +    }
  161.75 +
  161.76 +    /**
  161.77 +     * Returns the length of the array.
  161.78 +     *
  161.79 +     * @return the length of the array
  161.80 +     */
  161.81 +    public final int length() {
  161.82 +        return array.length;
  161.83 +    }
  161.84 +
  161.85 +    /**
  161.86 +     * Gets the current value at position {@code i}.
  161.87 +     *
  161.88 +     * @param i the index
  161.89 +     * @return the current value
  161.90 +     */
  161.91 +    public final int get(int i) {
  161.92 +        return array[i];
  161.93 +    }
  161.94 +
  161.95 +    /**
  161.96 +     * Sets the element at position {@code i} to the given value.
  161.97 +     *
  161.98 +     * @param i the index
  161.99 +     * @param newValue the new value
 161.100 +     */
 161.101 +    public final void set(int i, int newValue) {
 161.102 +        array[i] = newValue;
 161.103 +    }
 161.104 +
 161.105 +    /**
 161.106 +     * Eventually sets the element at position {@code i} to the given value.
 161.107 +     *
 161.108 +     * @param i the index
 161.109 +     * @param newValue the new value
 161.110 +     * @since 1.6
 161.111 +     */
 161.112 +    public final void lazySet(int i, int newValue) {
 161.113 +        array[i] = newValue;
 161.114 +    }
 161.115 +
 161.116 +    /**
 161.117 +     * Atomically sets the element at position {@code i} to the given
 161.118 +     * value and returns the old value.
 161.119 +     *
 161.120 +     * @param i the index
 161.121 +     * @param newValue the new value
 161.122 +     * @return the previous value
 161.123 +     */
 161.124 +    public final int getAndSet(int i, int newValue) {
 161.125 +        int current = array[i];
 161.126 +        array[i] = newValue;
 161.127 +        return current;
 161.128 +    }
 161.129 +
 161.130 +    /**
 161.131 +     * Atomically sets the element at position {@code i} to the given
 161.132 +     * updated value if the current value {@code ==} the expected value.
 161.133 +     *
 161.134 +     * @param i the index
 161.135 +     * @param expect the expected value
 161.136 +     * @param update the new value
 161.137 +     * @return true if successful. False return indicates that
 161.138 +     * the actual value was not equal to the expected value.
 161.139 +     */
 161.140 +    public final boolean compareAndSet(int i, int expect, int update) {
 161.141 +        if (array[i] == expect) {
 161.142 +            array[i] = update;
 161.143 +            return true;
 161.144 +        } else {
 161.145 +            return false;
 161.146 +        }
 161.147 +    }
 161.148 +
 161.149 +    /**
 161.150 +     * Atomically sets the element at position {@code i} to the given
 161.151 +     * updated value if the current value {@code ==} the expected value.
 161.152 +     *
 161.153 +     * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
 161.154 +     * and does not provide ordering guarantees, so is only rarely an
 161.155 +     * appropriate alternative to {@code compareAndSet}.
 161.156 +     *
 161.157 +     * @param i the index
 161.158 +     * @param expect the expected value
 161.159 +     * @param update the new value
 161.160 +     * @return true if successful.
 161.161 +     */
 161.162 +    public final boolean weakCompareAndSet(int i, int expect, int update) {
 161.163 +        return compareAndSet(i, expect, update);
 161.164 +    }
 161.165 +
 161.166 +    /**
 161.167 +     * Atomically increments by one the element at index {@code i}.
 161.168 +     *
 161.169 +     * @param i the index
 161.170 +     * @return the previous value
 161.171 +     */
 161.172 +    public final int getAndIncrement(int i) {
 161.173 +        return getAndAdd(i, 1);
 161.174 +    }
 161.175 +
 161.176 +    /**
 161.177 +     * Atomically decrements by one the element at index {@code i}.
 161.178 +     *
 161.179 +     * @param i the index
 161.180 +     * @return the previous value
 161.181 +     */
 161.182 +    public final int getAndDecrement(int i) {
 161.183 +        return getAndAdd(i, -1);
 161.184 +    }
 161.185 +
 161.186 +    /**
 161.187 +     * Atomically adds the given value to the element at index {@code i}.
 161.188 +     *
 161.189 +     * @param i the index
 161.190 +     * @param delta the value to add
 161.191 +     * @return the previous value
 161.192 +     */
 161.193 +    public final int getAndAdd(int i, int delta) {
 161.194 +        int v = array[i];
 161.195 +        array[i] += delta;
 161.196 +        return v;
 161.197 +    }
 161.198 +
 161.199 +    /**
 161.200 +     * Atomically increments by one the element at index {@code i}.
 161.201 +     *
 161.202 +     * @param i the index
 161.203 +     * @return the updated value
 161.204 +     */
 161.205 +    public final int incrementAndGet(int i) {
 161.206 +        return addAndGet(i, 1);
 161.207 +    }
 161.208 +
 161.209 +    /**
 161.210 +     * Atomically decrements by one the element at index {@code i}.
 161.211 +     *
 161.212 +     * @param i the index
 161.213 +     * @return the updated value
 161.214 +     */
 161.215 +    public final int decrementAndGet(int i) {
 161.216 +        return addAndGet(i, -1);
 161.217 +    }
 161.218 +
 161.219 +    /**
 161.220 +     * Atomically adds the given value to the element at index {@code i}.
 161.221 +     *
 161.222 +     * @param i the index
 161.223 +     * @param delta the value to add
 161.224 +     * @return the updated value
 161.225 +     */
 161.226 +    public final int addAndGet(int i, int delta) {
 161.227 +        array[i] += delta;
 161.228 +        return array[i];
 161.229 +    }
 161.230 +
 161.231 +    /**
 161.232 +     * Returns the String representation of the current values of array.
 161.233 +     * @return the String representation of the current values of array
 161.234 +     */
 161.235 +    public String toString() {
 161.236 +        int iMax = array.length - 1;
 161.237 +        if (iMax == -1)
 161.238 +            return "[]";
 161.239 +
 161.240 +        StringBuilder b = new StringBuilder();
 161.241 +        b.append('[');
 161.242 +        for (int i = 0; ; i++) {
 161.243 +            b.append(get(i));
 161.244 +            if (i == iMax)
 161.245 +                return b.append(']').toString();
 161.246 +            b.append(',').append(' ');
 161.247 +        }
 161.248 +    }
 161.249 +
 161.250 +}
   162.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   162.2 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/atomic/AtomicLong.java	Tue Feb 11 13:31:42 2014 +0100
   162.3 @@ -0,0 +1,265 @@
   162.4 +/*
   162.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   162.6 + *
   162.7 + * This code is free software; you can redistribute it and/or modify it
   162.8 + * under the terms of the GNU General Public License version 2 only, as
   162.9 + * published by the Free Software Foundation.  Oracle designates this
  162.10 + * particular file as subject to the "Classpath" exception as provided
  162.11 + * by Oracle in the LICENSE file that accompanied this code.
  162.12 + *
  162.13 + * This code is distributed in the hope that it will be useful, but WITHOUT
  162.14 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  162.15 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  162.16 + * version 2 for more details (a copy is included in the LICENSE file that
  162.17 + * accompanied this code).
  162.18 + *
  162.19 + * You should have received a copy of the GNU General Public License version
  162.20 + * 2 along with this work; if not, write to the Free Software Foundation,
  162.21 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  162.22 + *
  162.23 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  162.24 + * or visit www.oracle.com if you need additional information or have any
  162.25 + * questions.
  162.26 + */
  162.27 +
  162.28 +/*
  162.29 + * This file is available under and governed by the GNU General Public
  162.30 + * License version 2 only, as published by the Free Software Foundation.
  162.31 + * However, the following notice accompanied the original version of this
  162.32 + * file:
  162.33 + *
  162.34 + * Written by Doug Lea with assistance from members of JCP JSR-166
  162.35 + * Expert Group and released to the public domain, as explained at
  162.36 + * http://creativecommons.org/publicdomain/zero/1.0/
  162.37 + */
  162.38 +
  162.39 +package java.util.concurrent.atomic;
  162.40 +
  162.41 +/**
  162.42 + * A {@code long} value that may be updated atomically.  See the
  162.43 + * {@link java.util.concurrent.atomic} package specification for
  162.44 + * description of the properties of atomic variables. An
  162.45 + * {@code AtomicLong} is used in applications such as atomically
  162.46 + * incremented sequence numbers, and cannot be used as a replacement
  162.47 + * for a {@link java.lang.Long}. However, this class does extend
  162.48 + * {@code Number} to allow uniform access by tools and utilities that
  162.49 + * deal with numerically-based classes.
  162.50 + *
  162.51 + * @since 1.5
  162.52 + * @author Doug Lea
  162.53 + */
  162.54 +public class AtomicLong extends Number implements java.io.Serializable {
  162.55 +    private static final long serialVersionUID = 1927816293512124184L;
  162.56 +
  162.57 +
  162.58 +    /**
  162.59 +     * Returns whether underlying JVM supports lockless CompareAndSet
  162.60 +     * for longs. Called only once and cached in VM_SUPPORTS_LONG_CAS.
  162.61 +     */
  162.62 +    private static native boolean VMSupportsCS8();
  162.63 +
  162.64 +    private volatile long value;
  162.65 +
  162.66 +    /**
  162.67 +     * Creates a new AtomicLong with the given initial value.
  162.68 +     *
  162.69 +     * @param initialValue the initial value
  162.70 +     */
  162.71 +    public AtomicLong(long initialValue) {
  162.72 +        value = initialValue;
  162.73 +    }
  162.74 +
  162.75 +    /**
  162.76 +     * Creates a new AtomicLong with initial value {@code 0}.
  162.77 +     */
  162.78 +    public AtomicLong() {
  162.79 +    }
  162.80 +
  162.81 +    /**
  162.82 +     * Gets the current value.
  162.83 +     *
  162.84 +     * @return the current value
  162.85 +     */
  162.86 +    public final long get() {
  162.87 +        return value;
  162.88 +    }
  162.89 +
  162.90 +    /**
  162.91 +     * Sets to the given value.
  162.92 +     *
  162.93 +     * @param newValue the new value
  162.94 +     */
  162.95 +    public final void set(long newValue) {
  162.96 +        value = newValue;
  162.97 +    }
  162.98 +
  162.99 +    /**
 162.100 +     * Eventually sets to the given value.
 162.101 +     *
 162.102 +     * @param newValue the new value
 162.103 +     * @since 1.6
 162.104 +     */
 162.105 +    public final void lazySet(long newValue) {
 162.106 +        value = newValue;
 162.107 +    }
 162.108 +
 162.109 +    /**
 162.110 +     * Atomically sets to the given value and returns the old value.
 162.111 +     *
 162.112 +     * @param newValue the new value
 162.113 +     * @return the previous value
 162.114 +     */
 162.115 +    public final long getAndSet(long newValue) {
 162.116 +        while (true) {
 162.117 +            long current = get();
 162.118 +            if (compareAndSet(current, newValue))
 162.119 +                return current;
 162.120 +        }
 162.121 +    }
 162.122 +
 162.123 +    /**
 162.124 +     * Atomically sets the value to the given updated value
 162.125 +     * if the current value {@code ==} the expected value.
 162.126 +     *
 162.127 +     * @param expect the expected value
 162.128 +     * @param update the new value
 162.129 +     * @return true if successful. False return indicates that
 162.130 +     * the actual value was not equal to the expected value.
 162.131 +     */
 162.132 +    public final boolean compareAndSet(long expect, long update) {
 162.133 +        if (value == expect) {
 162.134 +            value = update;
 162.135 +            return true;
 162.136 +        } else {
 162.137 +            return false;
 162.138 +        }
 162.139 +    }
 162.140 +
 162.141 +    /**
 162.142 +     * Atomically sets the value to the given updated value
 162.143 +     * if the current value {@code ==} the expected value.
 162.144 +     *
 162.145 +     * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
 162.146 +     * and does not provide ordering guarantees, so is only rarely an
 162.147 +     * appropriate alternative to {@code compareAndSet}.
 162.148 +     *
 162.149 +     * @param expect the expected value
 162.150 +     * @param update the new value
 162.151 +     * @return true if successful.
 162.152 +     */
 162.153 +    public final boolean weakCompareAndSet(long expect, long update) {
 162.154 +        return compareAndSet(expect, update);
 162.155 +    }
 162.156 +
 162.157 +    /**
 162.158 +     * Atomically increments by one the current value.
 162.159 +     *
 162.160 +     * @return the previous value
 162.161 +     */
 162.162 +    public final long getAndIncrement() {
 162.163 +        while (true) {
 162.164 +            long current = get();
 162.165 +            long next = current + 1;
 162.166 +            if (compareAndSet(current, next))
 162.167 +                return current;
 162.168 +        }
 162.169 +    }
 162.170 +
 162.171 +    /**
 162.172 +     * Atomically decrements by one the current value.
 162.173 +     *
 162.174 +     * @return the previous value
 162.175 +     */
 162.176 +    public final long getAndDecrement() {
 162.177 +        while (true) {
 162.178 +            long current = get();
 162.179 +            long next = current - 1;
 162.180 +            if (compareAndSet(current, next))
 162.181 +                return current;
 162.182 +        }
 162.183 +    }
 162.184 +
 162.185 +    /**
 162.186 +     * Atomically adds the given value to the current value.
 162.187 +     *
 162.188 +     * @param delta the value to add
 162.189 +     * @return the previous value
 162.190 +     */
 162.191 +    public final long getAndAdd(long delta) {
 162.192 +        while (true) {
 162.193 +            long current = get();
 162.194 +            long next = current + delta;
 162.195 +            if (compareAndSet(current, next))
 162.196 +                return current;
 162.197 +        }
 162.198 +    }
 162.199 +
 162.200 +    /**
 162.201 +     * Atomically increments by one the current value.
 162.202 +     *
 162.203 +     * @return the updated value
 162.204 +     */
 162.205 +    public final long incrementAndGet() {
 162.206 +        for (;;) {
 162.207 +            long current = get();
 162.208 +            long next = current + 1;
 162.209 +            if (compareAndSet(current, next))
 162.210 +                return next;
 162.211 +        }
 162.212 +    }
 162.213 +
 162.214 +    /**
 162.215 +     * Atomically decrements by one the current value.
 162.216 +     *
 162.217 +     * @return the updated value
 162.218 +     */
 162.219 +    public final long decrementAndGet() {
 162.220 +        for (;;) {
 162.221 +            long current = get();
 162.222 +            long next = current - 1;
 162.223 +            if (compareAndSet(current, next))
 162.224 +                return next;
 162.225 +        }
 162.226 +    }
 162.227 +
 162.228 +    /**
 162.229 +     * Atomically adds the given value to the current value.
 162.230 +     *
 162.231 +     * @param delta the value to add
 162.232 +     * @return the updated value
 162.233 +     */
 162.234 +    public final long addAndGet(long delta) {
 162.235 +        for (;;) {
 162.236 +            long current = get();
 162.237 +            long next = current + delta;
 162.238 +            if (compareAndSet(current, next))
 162.239 +                return next;
 162.240 +        }
 162.241 +    }
 162.242 +
 162.243 +    /**
 162.244 +     * Returns the String representation of the current value.
 162.245 +     * @return the String representation of the current value.
 162.246 +     */
 162.247 +    public String toString() {
 162.248 +        return Long.toString(get());
 162.249 +    }
 162.250 +
 162.251 +
 162.252 +    public int intValue() {
 162.253 +        return (int)get();
 162.254 +    }
 162.255 +
 162.256 +    public long longValue() {
 162.257 +        return get();
 162.258 +    }
 162.259 +
 162.260 +    public float floatValue() {
 162.261 +        return (float)get();
 162.262 +    }
 162.263 +
 162.264 +    public double doubleValue() {
 162.265 +        return (double)get();
 162.266 +    }
 162.267 +
 162.268 +}
   163.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   163.2 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/atomic/AtomicLongArray.java	Tue Feb 11 13:31:42 2014 +0100
   163.3 @@ -0,0 +1,247 @@
   163.4 +/*
   163.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   163.6 + *
   163.7 + * This code is free software; you can redistribute it and/or modify it
   163.8 + * under the terms of the GNU General Public License version 2 only, as
   163.9 + * published by the Free Software Foundation.  Oracle designates this
  163.10 + * particular file as subject to the "Classpath" exception as provided
  163.11 + * by Oracle in the LICENSE file that accompanied this code.
  163.12 + *
  163.13 + * This code is distributed in the hope that it will be useful, but WITHOUT
  163.14 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  163.15 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  163.16 + * version 2 for more details (a copy is included in the LICENSE file that
  163.17 + * accompanied this code).
  163.18 + *
  163.19 + * You should have received a copy of the GNU General Public License version
  163.20 + * 2 along with this work; if not, write to the Free Software Foundation,
  163.21 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  163.22 + *
  163.23 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  163.24 + * or visit www.oracle.com if you need additional information or have any
  163.25 + * questions.
  163.26 + */
  163.27 +
  163.28 +/*
  163.29 + * This file is available under and governed by the GNU General Public
  163.30 + * License version 2 only, as published by the Free Software Foundation.
  163.31 + * However, the following notice accompanied the original version of this
  163.32 + * file:
  163.33 + *
  163.34 + * Written by Doug Lea with assistance from members of JCP JSR-166
  163.35 + * Expert Group and released to the public domain, as explained at
  163.36 + * http://creativecommons.org/publicdomain/zero/1.0/
  163.37 + */
  163.38 +
  163.39 +package java.util.concurrent.atomic;
  163.40 +
  163.41 +/**
  163.42 + * A {@code long} array in which elements may be updated atomically.
  163.43 + * See the {@link java.util.concurrent.atomic} package specification
  163.44 + * for description of the properties of atomic variables.
  163.45 + * @since 1.5
  163.46 + * @author Doug Lea
  163.47 + */
  163.48 +public class AtomicLongArray implements java.io.Serializable {
  163.49 +    private static final long serialVersionUID = -2308431214976778248L;
  163.50 +
  163.51 +    private final long[] array;
  163.52 +
  163.53 +    /**
  163.54 +     * Creates a new AtomicLongArray of the given length, with all
  163.55 +     * elements initially zero.
  163.56 +     *
  163.57 +     * @param length the length of the array
  163.58 +     */
  163.59 +    public AtomicLongArray(int length) {
  163.60 +        array = new long[length];
  163.61 +    }
  163.62 +
  163.63 +    /**
  163.64 +     * Creates a new AtomicLongArray with the same length as, and
  163.65 +     * all elements copied from, the given array.
  163.66 +     *
  163.67 +     * @param array the array to copy elements from
  163.68 +     * @throws NullPointerException if array is null
  163.69 +     */
  163.70 +    public AtomicLongArray(long[] array) {
  163.71 +        // Visibility guaranteed by final field guarantees
  163.72 +        this.array = array.clone();
  163.73 +    }
  163.74 +
  163.75 +    /**
  163.76 +     * Returns the length of the array.
  163.77 +     *
  163.78 +     * @return the length of the array
  163.79 +     */
  163.80 +    public final int length() {
  163.81 +        return array.length;
  163.82 +    }
  163.83 +
  163.84 +    /**
  163.85 +     * Gets the current value at position {@code i}.
  163.86 +     *
  163.87 +     * @param i the index
  163.88 +     * @return the current value
  163.89 +     */
  163.90 +    public final long get(int i) {
  163.91 +        return array[i];
  163.92 +    }
  163.93 +
  163.94 +    /**
  163.95 +     * Sets the element at position {@code i} to the given value.
  163.96 +     *
  163.97 +     * @param i the index
  163.98 +     * @param newValue the new value
  163.99 +     */
 163.100 +    public final void set(int i, long newValue) {
 163.101 +        array[i] = newValue;
 163.102 +    }
 163.103 +
 163.104 +    /**
 163.105 +     * Eventually sets the element at position {@code i} to the given value.
 163.106 +     *
 163.107 +     * @param i the index
 163.108 +     * @param newValue the new value
 163.109 +     * @since 1.6
 163.110 +     */
 163.111 +    public final void lazySet(int i, long newValue) {
 163.112 +        array[i] = newValue;
 163.113 +    }
 163.114 +
 163.115 +
 163.116 +    /**
 163.117 +     * Atomically sets the element at position {@code i} to the given value
 163.118 +     * and returns the old value.
 163.119 +     *
 163.120 +     * @param i the index
 163.121 +     * @param newValue the new value
 163.122 +     * @return the previous value
 163.123 +     */
 163.124 +    public final long getAndSet(int i, long newValue) {
 163.125 +        long v = array[i];
 163.126 +        array[i] = newValue;
 163.127 +        return v;
 163.128 +    }
 163.129 +
 163.130 +    /**
 163.131 +     * Atomically sets the element at position {@code i} to the given
 163.132 +     * updated value if the current value {@code ==} the expected value.
 163.133 +     *
 163.134 +     * @param i the index
 163.135 +     * @param expect the expected value
 163.136 +     * @param update the new value
 163.137 +     * @return true if successful. False return indicates that
 163.138 +     * the actual value was not equal to the expected value.
 163.139 +     */
 163.140 +    public final boolean compareAndSet(int i, long expect, long update) {
 163.141 +        if (array[i] == expect) {
 163.142 +            array[i] = update;
 163.143 +            return true;
 163.144 +        } else {
 163.145 +            return false;
 163.146 +        }
 163.147 +    }
 163.148 +
 163.149 +    /**
 163.150 +     * Atomically sets the element at position {@code i} to the given
 163.151 +     * updated value if the current value {@code ==} the expected value.
 163.152 +     *
 163.153 +     * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
 163.154 +     * and does not provide ordering guarantees, so is only rarely an
 163.155 +     * appropriate alternative to {@code compareAndSet}.
 163.156 +     *
 163.157 +     * @param i the index
 163.158 +     * @param expect the expected value
 163.159 +     * @param update the new value
 163.160 +     * @return true if successful.
 163.161 +     */
 163.162 +    public final boolean weakCompareAndSet(int i, long expect, long update) {
 163.163 +        return compareAndSet(i, expect, update);
 163.164 +    }
 163.165 +
 163.166 +    /**
 163.167 +     * Atomically increments by one the element at index {@code i}.
 163.168 +     *
 163.169 +     * @param i the index
 163.170 +     * @return the previous value
 163.171 +     */
 163.172 +    public final long getAndIncrement(int i) {
 163.173 +        return getAndAdd(i, 1);
 163.174 +    }
 163.175 +
 163.176 +    /**
 163.177 +     * Atomically decrements by one the element at index {@code i}.
 163.178 +     *
 163.179 +     * @param i the index
 163.180 +     * @return the previous value
 163.181 +     */
 163.182 +    public final long getAndDecrement(int i) {
 163.183 +        return getAndAdd(i, -1);
 163.184 +    }
 163.185 +
 163.186 +    /**
 163.187 +     * Atomically adds the given value to the element at index {@code i}.
 163.188 +     *
 163.189 +     * @param i the index
 163.190 +     * @param delta the value to add
 163.191 +     * @return the previous value
 163.192 +     */
 163.193 +    public final long getAndAdd(int i, long delta) {
 163.194 +        long v = array[i];
 163.195 +        array[i] += delta;
 163.196 +        return v;
 163.197 +    }
 163.198 +
 163.199 +    /**
 163.200 +     * Atomically increments by one the element at index {@code i}.
 163.201 +     *
 163.202 +     * @param i the index
 163.203 +     * @return the updated value
 163.204 +     */
 163.205 +    public final long incrementAndGet(int i) {
 163.206 +        return addAndGet(i, 1);
 163.207 +    }
 163.208 +
 163.209 +    /**
 163.210 +     * Atomically decrements by one the element at index {@code i}.
 163.211 +     *
 163.212 +     * @param i the index
 163.213 +     * @return the updated value
 163.214 +     */
 163.215 +    public final long decrementAndGet(int i) {
 163.216 +        return addAndGet(i, -1);
 163.217 +    }
 163.218 +
 163.219 +    /**
 163.220 +     * Atomically adds the given value to the element at index {@code i}.
 163.221 +     *
 163.222 +     * @param i the index
 163.223 +     * @param delta the value to add
 163.224 +     * @return the updated value
 163.225 +     */
 163.226 +    public long addAndGet(int i, long delta) {
 163.227 +        array[i] += delta;
 163.228 +        return array[i];
 163.229 +    }
 163.230 +
 163.231 +    /**
 163.232 +     * Returns the String representation of the current values of array.
 163.233 +     * @return the String representation of the current values of array
 163.234 +     */
 163.235 +    public String toString() {
 163.236 +        int iMax = array.length - 1;
 163.237 +        if (iMax == -1)
 163.238 +            return "[]";
 163.239 +
 163.240 +        StringBuilder b = new StringBuilder();
 163.241 +        b.append('[');
 163.242 +        for (int i = 0; ; i++) {
 163.243 +            b.append(get(i));
 163.244 +            if (i == iMax)
 163.245 +                return b.append(']').toString();
 163.246 +            b.append(',').append(' ');
 163.247 +        }
 163.248 +    }
 163.249 +
 163.250 +}
   164.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   164.2 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/atomic/AtomicReference.java	Tue Feb 11 13:31:42 2014 +0100
   164.3 @@ -0,0 +1,149 @@
   164.4 +/*
   164.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   164.6 + *
   164.7 + * This code is free software; you can redistribute it and/or modify it
   164.8 + * under the terms of the GNU General Public License version 2 only, as
   164.9 + * published by the Free Software Foundation.  Oracle designates this
  164.10 + * particular file as subject to the "Classpath" exception as provided
  164.11 + * by Oracle in the LICENSE file that accompanied this code.
  164.12 + *
  164.13 + * This code is distributed in the hope that it will be useful, but WITHOUT
  164.14 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  164.15 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  164.16 + * version 2 for more details (a copy is included in the LICENSE file that
  164.17 + * accompanied this code).
  164.18 + *
  164.19 + * You should have received a copy of the GNU General Public License version
  164.20 + * 2 along with this work; if not, write to the Free Software Foundation,
  164.21 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  164.22 + *
  164.23 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  164.24 + * or visit www.oracle.com if you need additional information or have any
  164.25 + * questions.
  164.26 + */
  164.27 +
  164.28 +/*
  164.29 + * This file is available under and governed by the GNU General Public
  164.30 + * License version 2 only, as published by the Free Software Foundation.
  164.31 + * However, the following notice accompanied the original version of this
  164.32 + * file:
  164.33 + *
  164.34 + * Written by Doug Lea with assistance from members of JCP JSR-166
  164.35 + * Expert Group and released to the public domain, as explained at
  164.36 + * http://creativecommons.org/publicdomain/zero/1.0/
  164.37 + */
  164.38 +
  164.39 +package java.util.concurrent.atomic;
  164.40 +
  164.41 +/**
  164.42 + * An object reference that may be updated atomically. See the {@link
  164.43 + * java.util.concurrent.atomic} package specification for description
  164.44 + * of the properties of atomic variables.
  164.45 + * @since 1.5
  164.46 + * @author Doug Lea
  164.47 + * @param <V> The type of object referred to by this reference
  164.48 + */
  164.49 +public class AtomicReference<V>  implements java.io.Serializable {
  164.50 +    private static final long serialVersionUID = -1848883965231344442L;
  164.51 +
  164.52 +    private volatile V value;
  164.53 +
  164.54 +    /**
  164.55 +     * Creates a new AtomicReference with the given initial value.
  164.56 +     *
  164.57 +     * @param initialValue the initial value
  164.58 +     */
  164.59 +    public AtomicReference(V initialValue) {
  164.60 +        value = initialValue;
  164.61 +    }
  164.62 +
  164.63 +    /**
  164.64 +     * Creates a new AtomicReference with null initial value.
  164.65 +     */
  164.66 +    public AtomicReference() {
  164.67 +    }
  164.68 +
  164.69 +    /**
  164.70 +     * Gets the current value.
  164.71 +     *
  164.72 +     * @return the current value
  164.73 +     */
  164.74 +    public final V get() {
  164.75 +        return value;
  164.76 +    }
  164.77 +
  164.78 +    /**
  164.79 +     * Sets to the given value.
  164.80 +     *
  164.81 +     * @param newValue the new value
  164.82 +     */
  164.83 +    public final void set(V newValue) {
  164.84 +        value = newValue;
  164.85 +    }
  164.86 +
  164.87 +    /**
  164.88 +     * Eventually sets to the given value.
  164.89 +     *
  164.90 +     * @param newValue the new value
  164.91 +     * @since 1.6
  164.92 +     */
  164.93 +    public final void lazySet(V newValue) {
  164.94 +        value = newValue;
  164.95 +    }
  164.96 +
  164.97 +    /**
  164.98 +     * Atomically sets the value to the given updated value
  164.99 +     * if the current value {@code ==} the expected value.
 164.100 +     * @param expect the expected value
 164.101 +     * @param update the new value
 164.102 +     * @return true if successful. False return indicates that
 164.103 +     * the actual value was not equal to the expected value.
 164.104 +     */
 164.105 +    public final boolean compareAndSet(V expect, V update) {
 164.106 +        if (value == expect) {
 164.107 +            value = update;
 164.108 +            return true;
 164.109 +        } else {
 164.110 +            return false;
 164.111 +        }
 164.112 +    }
 164.113 +
 164.114 +    /**
 164.115 +     * Atomically sets the value to the given updated value
 164.116 +     * if the current value {@code ==} the expected value.
 164.117 +     *
 164.118 +     * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
 164.119 +     * and does not provide ordering guarantees, so is only rarely an
 164.120 +     * appropriate alternative to {@code compareAndSet}.
 164.121 +     *
 164.122 +     * @param expect the expected value
 164.123 +     * @param update the new value
 164.124 +     * @return true if successful.
 164.125 +     */
 164.126 +    public final boolean weakCompareAndSet(V expect, V update) {
 164.127 +        return compareAndSet(expect, update);
 164.128 +    }
 164.129 +
 164.130 +    /**
 164.131 +     * Atomically sets to the given value and returns the old value.
 164.132 +     *
 164.133 +     * @param newValue the new value
 164.134 +     * @return the previous value
 164.135 +     */
 164.136 +    public final V getAndSet(V newValue) {
 164.137 +        while (true) {
 164.138 +            V x = get();
 164.139 +            if (compareAndSet(x, newValue))
 164.140 +                return x;
 164.141 +        }
 164.142 +    }
 164.143 +
 164.144 +    /**
 164.145 +     * Returns the String representation of the current value.
 164.146 +     * @return the String representation of the current value.
 164.147 +     */
 164.148 +    public String toString() {
 164.149 +        return String.valueOf(get());
 164.150 +    }
 164.151 +
 164.152 +}
   165.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   165.2 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/atomic/AtomicReferenceArray.java	Tue Feb 11 13:31:42 2014 +0100
   165.3 @@ -0,0 +1,184 @@
   165.4 +/*
   165.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   165.6 + *
   165.7 + * This code is free software; you can redistribute it and/or modify it
   165.8 + * under the terms of the GNU General Public License version 2 only, as
   165.9 + * published by the Free Software Foundation.  Oracle designates this
  165.10 + * particular file as subject to the "Classpath" exception as provided
  165.11 + * by Oracle in the LICENSE file that accompanied this code.
  165.12 + *
  165.13 + * This code is distributed in the hope that it will be useful, but WITHOUT
  165.14 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  165.15 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  165.16 + * version 2 for more details (a copy is included in the LICENSE file that
  165.17 + * accompanied this code).
  165.18 + *
  165.19 + * You should have received a copy of the GNU General Public License version
  165.20 + * 2 along with this work; if not, write to the Free Software Foundation,
  165.21 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  165.22 + *
  165.23 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  165.24 + * or visit www.oracle.com if you need additional information or have any
  165.25 + * questions.
  165.26 + */
  165.27 +
  165.28 +/*
  165.29 + * This file is available under and governed by the GNU General Public
  165.30 + * License version 2 only, as published by the Free Software Foundation.
  165.31 + * However, the following notice accompanied the original version of this
  165.32 + * file:
  165.33 + *
  165.34 + * Written by Doug Lea with assistance from members of JCP JSR-166
  165.35 + * Expert Group and released to the public domain, as explained at
  165.36 + * http://creativecommons.org/publicdomain/zero/1.0/
  165.37 + */
  165.38 +
  165.39 +package java.util.concurrent.atomic;
  165.40 +
  165.41 +/**
  165.42 + * An array of object references in which elements may be updated
  165.43 + * atomically.  See the {@link java.util.concurrent.atomic} package
  165.44 + * specification for description of the properties of atomic
  165.45 + * variables.
  165.46 + * @since 1.5
  165.47 + * @author Doug Lea
  165.48 + * @param <E> The base class of elements held in this array
  165.49 + */
  165.50 +public class AtomicReferenceArray<E> implements java.io.Serializable {
  165.51 +    private static final long serialVersionUID = -6209656149925076980L;
  165.52 +
  165.53 +    private final Object[] array;
  165.54 +
  165.55 +    /**
  165.56 +     * Creates a new AtomicReferenceArray of the given length, with all
  165.57 +     * elements initially null.
  165.58 +     *
  165.59 +     * @param length the length of the array
  165.60 +     */
  165.61 +    public AtomicReferenceArray(int length) {
  165.62 +        array = new Object[length];
  165.63 +    }
  165.64 +
  165.65 +    /**
  165.66 +     * Creates a new AtomicReferenceArray with the same length as, and
  165.67 +     * all elements copied from, the given array.
  165.68 +     *
  165.69 +     * @param array the array to copy elements from
  165.70 +     * @throws NullPointerException if array is null
  165.71 +     */
  165.72 +    public AtomicReferenceArray(E[] array) {
  165.73 +        // Visibility guaranteed by final field guarantees
  165.74 +        this.array = array.clone();
  165.75 +    }
  165.76 +
  165.77 +    /**
  165.78 +     * Returns the length of the array.
  165.79 +     *
  165.80 +     * @return the length of the array
  165.81 +     */
  165.82 +    public final int length() {
  165.83 +        return array.length;
  165.84 +    }
  165.85 +
  165.86 +    /**
  165.87 +     * Gets the current value at position {@code i}.
  165.88 +     *
  165.89 +     * @param i the index
  165.90 +     * @return the current value
  165.91 +     */
  165.92 +    public final E get(int i) {
  165.93 +        return (E)array[i];
  165.94 +    }
  165.95 +
  165.96 +    /**
  165.97 +     * Sets the element at position {@code i} to the given value.
  165.98 +     *
  165.99 +     * @param i the index
 165.100 +     * @param newValue the new value
 165.101 +     */
 165.102 +    public final void set(int i, E newValue) {
 165.103 +        array[i] = newValue;
 165.104 +    }
 165.105 +
 165.106 +    /**
 165.107 +     * Eventually sets the element at position {@code i} to the given value.
 165.108 +     *
 165.109 +     * @param i the index
 165.110 +     * @param newValue the new value
 165.111 +     * @since 1.6
 165.112 +     */
 165.113 +    public final void lazySet(int i, E newValue) {
 165.114 +        array[i] = newValue;
 165.115 +    }
 165.116 +
 165.117 +
 165.118 +    /**
 165.119 +     * Atomically sets the element at position {@code i} to the given
 165.120 +     * value and returns the old value.
 165.121 +     *
 165.122 +     * @param i the index
 165.123 +     * @param newValue the new value
 165.124 +     * @return the previous value
 165.125 +     */
 165.126 +    public final E getAndSet(int i, E newValue) {
 165.127 +        E v = (E)array[i];
 165.128 +        array[i] = newValue;
 165.129 +        return v;
 165.130 +    }
 165.131 +
 165.132 +    /**
 165.133 +     * Atomically sets the element at position {@code i} to the given
 165.134 +     * updated value if the current value {@code ==} the expected value.
 165.135 +     *
 165.136 +     * @param i the index
 165.137 +     * @param expect the expected value
 165.138 +     * @param update the new value
 165.139 +     * @return true if successful. False return indicates that
 165.140 +     * the actual value was not equal to the expected value.
 165.141 +     */
 165.142 +    public final boolean compareAndSet(int i, E expect, E update) {
 165.143 +        if (array[i] == expect) {
 165.144 +            array[i] = update;
 165.145 +            return true;
 165.146 +        } else {
 165.147 +            return false;
 165.148 +        }
 165.149 +    }
 165.150 +
 165.151 +    /**
 165.152 +     * Atomically sets the element at position {@code i} to the given
 165.153 +     * updated value if the current value {@code ==} the expected value.
 165.154 +     *
 165.155 +     * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
 165.156 +     * and does not provide ordering guarantees, so is only rarely an
 165.157 +     * appropriate alternative to {@code compareAndSet}.
 165.158 +     *
 165.159 +     * @param i the index
 165.160 +     * @param expect the expected value
 165.161 +     * @param update the new value
 165.162 +     * @return true if successful.
 165.163 +     */
 165.164 +    public final boolean weakCompareAndSet(int i, E expect, E update) {
 165.165 +        return compareAndSet(i, expect, update);
 165.166 +    }
 165.167 +
 165.168 +    /**
 165.169 +     * Returns the String representation of the current values of array.
 165.170 +     * @return the String representation of the current values of array
 165.171 +     */
 165.172 +    public String toString() {
 165.173 +           int iMax = array.length - 1;
 165.174 +        if (iMax == -1)
 165.175 +            return "[]";
 165.176 +
 165.177 +        StringBuilder b = new StringBuilder();
 165.178 +        b.append('[');
 165.179 +        for (int i = 0; ; i++) {
 165.180 +            b.append(get(i));
 165.181 +            if (i == iMax)
 165.182 +                return b.append(']').toString();
 165.183 +            b.append(',').append(' ');
 165.184 +        }
 165.185 +    }
 165.186 +
 165.187 +}
   166.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   166.2 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/atomic/package-info.java	Tue Feb 11 13:31:42 2014 +0100
   166.3 @@ -0,0 +1,199 @@
   166.4 +/*
   166.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   166.6 + *
   166.7 + * This code is free software; you can redistribute it and/or modify it
   166.8 + * under the terms of the GNU General Public License version 2 only, as
   166.9 + * published by the Free Software Foundation.  Oracle designates this
  166.10 + * particular file as subject to the "Classpath" exception as provided
  166.11 + * by Oracle in the LICENSE file that accompanied this code.
  166.12 + *
  166.13 + * This code is distributed in the hope that it will be useful, but WITHOUT
  166.14 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  166.15 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  166.16 + * version 2 for more details (a copy is included in the LICENSE file that
  166.17 + * accompanied this code).
  166.18 + *
  166.19 + * You should have received a copy of the GNU General Public License version
  166.20 + * 2 along with this work; if not, write to the Free Software Foundation,
  166.21 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  166.22 + *
  166.23 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  166.24 + * or visit www.oracle.com if you need additional information or have any
  166.25 + * questions.
  166.26 + */
  166.27 +
  166.28 +/*
  166.29 + * This file is available under and governed by the GNU General Public
  166.30 + * License version 2 only, as published by the Free Software Foundation.
  166.31 + * However, the following notice accompanied the original version of this
  166.32 + * file:
  166.33 + *
  166.34 + * Written by Doug Lea with assistance from members of JCP JSR-166
  166.35 + * Expert Group and released to the public domain, as explained at
  166.36 + * http://creativecommons.org/publicdomain/zero/1.0/
  166.37 + */
  166.38 +
  166.39 +/**
  166.40 + * A small toolkit of classes that support lock-free thread-safe
  166.41 + * programming on single variables.  In essence, the classes in this
  166.42 + * package extend the notion of {@code volatile} values, fields, and
  166.43 + * array elements to those that also provide an atomic conditional update
  166.44 + * operation of the form:
  166.45 + *
  166.46 + * <pre>
  166.47 + *   boolean compareAndSet(expectedValue, updateValue);
  166.48 + * </pre>
  166.49 + *
  166.50 + * <p>This method (which varies in argument types across different
  166.51 + * classes) atomically sets a variable to the {@code updateValue} if it
  166.52 + * currently holds the {@code expectedValue}, reporting {@code true} on
  166.53 + * success.  The classes in this package also contain methods to get and
  166.54 + * unconditionally set values, as well as a weaker conditional atomic
  166.55 + * update operation {@code weakCompareAndSet} described below.
  166.56 + *
  166.57 + * <p>The specifications of these methods enable implementations to
  166.58 + * employ efficient machine-level atomic instructions that are available
  166.59 + * on contemporary processors.  However on some platforms, support may
  166.60 + * entail some form of internal locking.  Thus the methods are not
  166.61 + * strictly guaranteed to be non-blocking --
  166.62 + * a thread may block transiently before performing the operation.
  166.63 + *
  166.64 + * <p>Instances of classes
  166.65 + * {@link java.util.concurrent.atomic.AtomicBoolean},
  166.66 + * {@link java.util.concurrent.atomic.AtomicInteger},
  166.67 + * {@link java.util.concurrent.atomic.AtomicLong}, and
  166.68 + * {@link java.util.concurrent.atomic.AtomicReference}
  166.69 + * each provide access and updates to a single variable of the
  166.70 + * corresponding type.  Each class also provides appropriate utility
  166.71 + * methods for that type.  For example, classes {@code AtomicLong} and
  166.72 + * {@code AtomicInteger} provide atomic increment methods.  One
  166.73 + * application is to generate sequence numbers, as in:
  166.74 + *
  166.75 + * <pre>
  166.76 + * class Sequencer {
  166.77 + *   private final AtomicLong sequenceNumber
  166.78 + *     = new AtomicLong(0);
  166.79 + *   public long next() {
  166.80 + *     return sequenceNumber.getAndIncrement();
  166.81 + *   }
  166.82 + * }
  166.83 + * </pre>
  166.84 + *
  166.85 + * <p>The memory effects for accesses and updates of atomics generally
  166.86 + * follow the rules for volatiles, as stated in section 17.4 of
  166.87 + * <cite>The Java&trade; Language Specification</cite>.
  166.88 + *
  166.89 + * <ul>
  166.90 + *
  166.91 + *   <li> {@code get} has the memory effects of reading a
  166.92 + * {@code volatile} variable.
  166.93 + *
  166.94 + *   <li> {@code set} has the memory effects of writing (assigning) a
  166.95 + * {@code volatile} variable.
  166.96 + *
  166.97 + *   <li> {@code lazySet} has the memory effects of writing (assigning)
  166.98 + *   a {@code volatile} variable except that it permits reorderings with
  166.99 + *   subsequent (but not previous) memory actions that do not themselves
 166.100 + *   impose reordering constraints with ordinary non-{@code volatile}
 166.101 + *   writes.  Among other usage contexts, {@code lazySet} may apply when
 166.102 + *   nulling out, for the sake of garbage collection, a reference that is
 166.103 + *   never accessed again.
 166.104 + *
 166.105 + *   <li>{@code weakCompareAndSet} atomically reads and conditionally
 166.106 + *   writes a variable but does <em>not</em>
 166.107 + *   create any happens-before orderings, so provides no guarantees
 166.108 + *   with respect to previous or subsequent reads and writes of any
 166.109 + *   variables other than the target of the {@code weakCompareAndSet}.
 166.110 + *
 166.111 + *   <li> {@code compareAndSet}
 166.112 + *   and all other read-and-update operations such as {@code getAndIncrement}
 166.113 + *   have the memory effects of both reading and
 166.114 + *   writing {@code volatile} variables.
 166.115 + * </ul>
 166.116 + *
 166.117 + * <p>In addition to classes representing single values, this package
 166.118 + * contains <em>Updater</em> classes that can be used to obtain
 166.119 + * {@code compareAndSet} operations on any selected {@code volatile}
 166.120 + * field of any selected class.
 166.121 + *
 166.122 + * {@link java.util.concurrent.atomic.AtomicReferenceFieldUpdater},
 166.123 + * {@link java.util.concurrent.atomic.AtomicIntegerFieldUpdater}, and
 166.124 + * {@link java.util.concurrent.atomic.AtomicLongFieldUpdater} are
 166.125 + * reflection-based utilities that provide access to the associated
 166.126 + * field types.  These are mainly of use in atomic data structures in
 166.127 + * which several {@code volatile} fields of the same node (for
 166.128 + * example, the links of a tree node) are independently subject to
 166.129 + * atomic updates.  These classes enable greater flexibility in how
 166.130 + * and when to use atomic updates, at the expense of more awkward
 166.131 + * reflection-based setup, less convenient usage, and weaker
 166.132 + * guarantees.
 166.133 + *
 166.134 + * <p>The
 166.135 + * {@link java.util.concurrent.atomic.AtomicIntegerArray},
 166.136 + * {@link java.util.concurrent.atomic.AtomicLongArray}, and
 166.137 + * {@link java.util.concurrent.atomic.AtomicReferenceArray} classes
 166.138 + * further extend atomic operation support to arrays of these types.
 166.139 + * These classes are also notable in providing {@code volatile} access
 166.140 + * semantics for their array elements, which is not supported for
 166.141 + * ordinary arrays.
 166.142 + *
 166.143 + * <a name="Spurious">
 166.144 + * <p>The atomic classes also support method {@code weakCompareAndSet},
 166.145 + * which has limited applicability.  On some platforms, the weak version
 166.146 + * may be more efficient than {@code compareAndSet} in the normal case,
 166.147 + * but differs in that any given invocation of the
 166.148 + * {@code weakCompareAndSet} method may return {@code false}
 166.149 + * <em>spuriously</em> (that is, for no apparent reason)</a>.  A
 166.150 + * {@code false} return means only that the operation may be retried if
 166.151 + * desired, relying on the guarantee that repeated invocation when the
 166.152 + * variable holds {@code expectedValue} and no other thread is also
 166.153 + * attempting to set the variable will eventually succeed.  (Such
 166.154 + * spurious failures may for example be due to memory contention effects
 166.155 + * that are unrelated to whether the expected and current values are
 166.156 + * equal.)  Additionally {@code weakCompareAndSet} does not provide
 166.157 + * ordering guarantees that are usually needed for synchronization
 166.158 + * control.  However, the method may be useful for updating counters and
 166.159 + * statistics when such updates are unrelated to the other
 166.160 + * happens-before orderings of a program.  When a thread sees an update
 166.161 + * to an atomic variable caused by a {@code weakCompareAndSet}, it does
 166.162 + * not necessarily see updates to any <em>other</em> variables that
 166.163 + * occurred before the {@code weakCompareAndSet}.  This may be
 166.164 + * acceptable when, for example, updating performance statistics, but
 166.165 + * rarely otherwise.
 166.166 + *
 166.167 + * <p>The {@link java.util.concurrent.atomic.AtomicMarkableReference}
 166.168 + * class associates a single boolean with a reference.  For example, this
 166.169 + * bit might be used inside a data structure to mean that the object
 166.170 + * being referenced has logically been deleted.
 166.171 + *
 166.172 + * The {@link java.util.concurrent.atomic.AtomicStampedReference}
 166.173 + * class associates an integer value with a reference.  This may be
 166.174 + * used for example, to represent version numbers corresponding to
 166.175 + * series of updates.
 166.176 + *
 166.177 + * <p>Atomic classes are designed primarily as building blocks for
 166.178 + * implementing non-blocking data structures and related infrastructure
 166.179 + * classes.  The {@code compareAndSet} method is not a general
 166.180 + * replacement for locking.  It applies only when critical updates for an
 166.181 + * object are confined to a <em>single</em> variable.
 166.182 + *
 166.183 + * <p>Atomic classes are not general purpose replacements for
 166.184 + * {@code java.lang.Integer} and related classes.  They do <em>not</em>
 166.185 + * define methods such as {@code hashCode} and
 166.186 + * {@code compareTo}.  (Because atomic variables are expected to be
 166.187 + * mutated, they are poor choices for hash table keys.)  Additionally,
 166.188 + * classes are provided only for those types that are commonly useful in
 166.189 + * intended applications.  For example, there is no atomic class for
 166.190 + * representing {@code byte}.  In those infrequent cases where you would
 166.191 + * like to do so, you can use an {@code AtomicInteger} to hold
 166.192 + * {@code byte} values, and cast appropriately.
 166.193 + *
 166.194 + * You can also hold floats using
 166.195 + * {@link java.lang.Float#floatToIntBits} and
 166.196 + * {@link java.lang.Float#intBitsToFloat} conversions, and doubles using
 166.197 + * {@link java.lang.Double#doubleToLongBits} and
 166.198 + * {@link java.lang.Double#longBitsToDouble} conversions.
 166.199 + *
 166.200 + * @since 1.5
 166.201 + */
 166.202 +package java.util.concurrent.atomic;
   167.1 --- a/rt/emul/compact/src/main/java/java/util/logging/Logger.java	Tue Feb 11 10:48:24 2014 +0100
   167.2 +++ b/rt/emul/compact/src/main/java/java/util/logging/Logger.java	Tue Feb 11 13:31:42 2014 +0100
   167.3 @@ -457,16 +457,22 @@
   167.4              case "WARNING": method = "warn"; break;
   167.5              default: method = "log"; break;
   167.6          }
   167.7 +        
   167.8 +        String msg = record.getMessage();
   167.9 +        final Object[] params = record.getParameters();
  167.10 +        if (params != null && params.length != 0) {
  167.11 +            for (int i = 0; i < params.length; i++) {
  167.12 +                msg = msg.replace("{" + i + "}", params[i] == null ? "null" : params[i].toString());
  167.13 +            }
  167.14 +        }
  167.15  
  167.16          consoleLog(
  167.17              method, 
  167.18 -            record.getLoggerName(),
  167.19 -            record.getMessage()
  167.20 -        );
  167.21 +            record.getLoggerName(), msg);
  167.22      }
  167.23      
  167.24      @JavaScriptBody(args = { "method", "logger", "msg" }, body = 
  167.25 -        "window.console[method]('[' + logger + ']: ' + msg);"
  167.26 +        "if (typeof console !== 'undefined') console[method]('[' + logger + ']: ' + msg);"
  167.27      )
  167.28      private static native void consoleLog(
  167.29          String method, String logger, String msg
   168.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   168.2 +++ b/rt/emul/compact/src/main/java/java/util/regex/ASCII.java	Tue Feb 11 13:31:42 2014 +0100
   168.3 @@ -0,0 +1,274 @@
   168.4 +/*
   168.5 + * Copyright (c) 1999, 2000, Oracle and/or its affiliates. All rights reserved.
   168.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   168.7 + *
   168.8 + * This code is free software; you can redistribute it and/or modify it
   168.9 + * under the terms of the GNU General Public License version 2 only, as
  168.10 + * published by the Free Software Foundation.  Oracle designates this
  168.11 + * particular file as subject to the "Classpath" exception as provided
  168.12 + * by Oracle in the LICENSE file that accompanied this code.
  168.13 + *
  168.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  168.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  168.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  168.17 + * version 2 for more details (a copy is included in the LICENSE file that
  168.18 + * accompanied this code).
  168.19 + *
  168.20 + * You should have received a copy of the GNU General Public License version
  168.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  168.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  168.23 + *
  168.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  168.25 + * or visit www.oracle.com if you need additional information or have any
  168.26 + * questions.
  168.27 + */
  168.28 +
  168.29 +package java.util.regex;
  168.30 +
  168.31 +
  168.32 +/**
  168.33 + * Utility class that implements the standard C ctype functionality.
  168.34 + *
  168.35 + * @author Hong Zhang
  168.36 + */
  168.37 +
  168.38 +final class ASCII {
  168.39 +
  168.40 +    static final int UPPER   = 0x00000100;
  168.41 +
  168.42 +    static final int LOWER   = 0x00000200;
  168.43 +
  168.44 +    static final int DIGIT   = 0x00000400;
  168.45 +
  168.46 +    static final int SPACE   = 0x00000800;
  168.47 +
  168.48 +    static final int PUNCT   = 0x00001000;
  168.49 +
  168.50 +    static final int CNTRL   = 0x00002000;
  168.51 +
  168.52 +    static final int BLANK   = 0x00004000;
  168.53 +
  168.54 +    static final int HEX     = 0x00008000;
  168.55 +
  168.56 +    static final int UNDER   = 0x00010000;
  168.57 +
  168.58 +    static final int ASCII   = 0x0000FF00;
  168.59 +
  168.60 +    static final int ALPHA   = (UPPER|LOWER);
  168.61 +
  168.62 +    static final int ALNUM   = (UPPER|LOWER|DIGIT);
  168.63 +
  168.64 +    static final int GRAPH   = (PUNCT|UPPER|LOWER|DIGIT);
  168.65 +
  168.66 +    static final int WORD    = (UPPER|LOWER|UNDER|DIGIT);
  168.67 +
  168.68 +    static final int XDIGIT  = (HEX);
  168.69 +
  168.70 +    private static final int[] ctype = new int[] {
  168.71 +        CNTRL,                  /* 00 (NUL) */
  168.72 +        CNTRL,                  /* 01 (SOH) */
  168.73 +        CNTRL,                  /* 02 (STX) */
  168.74 +        CNTRL,                  /* 03 (ETX) */
  168.75 +        CNTRL,                  /* 04 (EOT) */
  168.76 +        CNTRL,                  /* 05 (ENQ) */
  168.77 +        CNTRL,                  /* 06 (ACK) */
  168.78 +        CNTRL,                  /* 07 (BEL) */
  168.79 +        CNTRL,                  /* 08 (BS)  */
  168.80 +        SPACE+CNTRL+BLANK,      /* 09 (HT)  */
  168.81 +        SPACE+CNTRL,            /* 0A (LF)  */
  168.82 +        SPACE+CNTRL,            /* 0B (VT)  */
  168.83 +        SPACE+CNTRL,            /* 0C (FF)  */
  168.84 +        SPACE+CNTRL,            /* 0D (CR)  */
  168.85 +        CNTRL,                  /* 0E (SI)  */
  168.86 +        CNTRL,                  /* 0F (SO)  */
  168.87 +        CNTRL,                  /* 10 (DLE) */
  168.88 +        CNTRL,                  /* 11 (DC1) */
  168.89 +        CNTRL,                  /* 12 (DC2) */
  168.90 +        CNTRL,                  /* 13 (DC3) */
  168.91 +        CNTRL,                  /* 14 (DC4) */
  168.92 +        CNTRL,                  /* 15 (NAK) */
  168.93 +        CNTRL,                  /* 16 (SYN) */
  168.94 +        CNTRL,                  /* 17 (ETB) */
  168.95 +        CNTRL,                  /* 18 (CAN) */
  168.96 +        CNTRL,                  /* 19 (EM)  */
  168.97 +        CNTRL,                  /* 1A (SUB) */
  168.98 +        CNTRL,                  /* 1B (ESC) */
  168.99 +        CNTRL,                  /* 1C (FS)  */
 168.100 +        CNTRL,                  /* 1D (GS)  */
 168.101 +        CNTRL,                  /* 1E (RS)  */
 168.102 +        CNTRL,                  /* 1F (US)  */
 168.103 +        SPACE+BLANK,            /* 20 SPACE */
 168.104 +        PUNCT,                  /* 21 !     */
 168.105 +        PUNCT,                  /* 22 "     */
 168.106 +        PUNCT,                  /* 23 #     */
 168.107 +        PUNCT,                  /* 24 $     */
 168.108 +        PUNCT,                  /* 25 %     */
 168.109 +        PUNCT,                  /* 26 &     */
 168.110 +        PUNCT,                  /* 27 '     */
 168.111 +        PUNCT,                  /* 28 (     */
 168.112 +        PUNCT,                  /* 29 )     */
 168.113 +        PUNCT,                  /* 2A *     */
 168.114 +        PUNCT,                  /* 2B +     */
 168.115 +        PUNCT,                  /* 2C ,     */
 168.116 +        PUNCT,                  /* 2D -     */
 168.117 +        PUNCT,                  /* 2E .     */
 168.118 +        PUNCT,                  /* 2F /     */
 168.119 +        DIGIT+HEX+0,            /* 30 0     */
 168.120 +        DIGIT+HEX+1,            /* 31 1     */
 168.121 +        DIGIT+HEX+2,            /* 32 2     */
 168.122 +        DIGIT+HEX+3,            /* 33 3     */
 168.123 +        DIGIT+HEX+4,            /* 34 4     */
 168.124 +        DIGIT+HEX+5,            /* 35 5     */
 168.125 +        DIGIT+HEX+6,            /* 36 6     */
 168.126 +        DIGIT+HEX+7,            /* 37 7     */
 168.127 +        DIGIT+HEX+8,            /* 38 8     */
 168.128 +        DIGIT+HEX+9,            /* 39 9     */
 168.129 +        PUNCT,                  /* 3A :     */
 168.130 +        PUNCT,                  /* 3B ;     */
 168.131 +        PUNCT,                  /* 3C <     */
 168.132 +        PUNCT,                  /* 3D =     */
 168.133 +        PUNCT,                  /* 3E >     */
 168.134 +        PUNCT,                  /* 3F ?     */
 168.135 +        PUNCT,                  /* 40 @     */
 168.136 +        UPPER+HEX+10,           /* 41 A     */
 168.137 +        UPPER+HEX+11,           /* 42 B     */
 168.138 +        UPPER+HEX+12,           /* 43 C     */
 168.139 +        UPPER+HEX+13,           /* 44 D     */
 168.140 +        UPPER+HEX+14,           /* 45 E     */
 168.141 +        UPPER+HEX+15,           /* 46 F     */
 168.142 +        UPPER+16,               /* 47 G     */
 168.143 +        UPPER+17,               /* 48 H     */
 168.144 +        UPPER+18,               /* 49 I     */
 168.145 +        UPPER+19,               /* 4A J     */
 168.146 +        UPPER+20,               /* 4B K     */
 168.147 +        UPPER+21,               /* 4C L     */
 168.148 +        UPPER+22,               /* 4D M     */
 168.149 +        UPPER+23,               /* 4E N     */
 168.150 +        UPPER+24,               /* 4F O     */
 168.151 +        UPPER+25,               /* 50 P     */
 168.152 +        UPPER+26,               /* 51 Q     */
 168.153 +        UPPER+27,               /* 52 R     */
 168.154 +        UPPER+28,               /* 53 S     */
 168.155 +        UPPER+29,               /* 54 T     */
 168.156 +        UPPER+30,               /* 55 U     */
 168.157 +        UPPER+31,               /* 56 V     */
 168.158 +        UPPER+32,               /* 57 W     */
 168.159 +        UPPER+33,               /* 58 X     */
 168.160 +        UPPER+34,               /* 59 Y     */
 168.161 +        UPPER+35,               /* 5A Z     */
 168.162 +        PUNCT,                  /* 5B [     */
 168.163 +        PUNCT,                  /* 5C \     */
 168.164 +        PUNCT,                  /* 5D ]     */
 168.165 +        PUNCT,                  /* 5E ^     */
 168.166 +        PUNCT|UNDER,            /* 5F _     */
 168.167 +        PUNCT,                  /* 60 `     */
 168.168 +        LOWER+HEX+10,           /* 61 a     */
 168.169 +        LOWER+HEX+11,           /* 62 b     */
 168.170 +        LOWER+HEX+12,           /* 63 c     */
 168.171 +        LOWER+HEX+13,           /* 64 d     */
 168.172 +        LOWER+HEX+14,           /* 65 e     */
 168.173 +        LOWER+HEX+15,           /* 66 f     */
 168.174 +        LOWER+16,               /* 67 g     */
 168.175 +        LOWER+17,               /* 68 h     */
 168.176 +        LOWER+18,               /* 69 i     */
 168.177 +        LOWER+19,               /* 6A j     */
 168.178 +        LOWER+20,               /* 6B k     */
 168.179 +        LOWER+21,               /* 6C l     */
 168.180 +        LOWER+22,               /* 6D m     */
 168.181 +        LOWER+23,               /* 6E n     */
 168.182 +        LOWER+24,               /* 6F o     */
 168.183 +        LOWER+25,               /* 70 p     */
 168.184 +        LOWER+26,               /* 71 q     */
 168.185 +        LOWER+27,               /* 72 r     */
 168.186 +        LOWER+28,               /* 73 s     */
 168.187 +        LOWER+29,               /* 74 t     */
 168.188 +        LOWER+30,               /* 75 u     */
 168.189 +        LOWER+31,               /* 76 v     */
 168.190 +        LOWER+32,               /* 77 w     */
 168.191 +        LOWER+33,               /* 78 x     */
 168.192 +        LOWER+34,               /* 79 y     */
 168.193 +        LOWER+35,               /* 7A z     */
 168.194 +        PUNCT,                  /* 7B {     */
 168.195 +        PUNCT,                  /* 7C |     */
 168.196 +        PUNCT,                  /* 7D }     */
 168.197 +        PUNCT,                  /* 7E ~     */
 168.198 +        CNTRL,                  /* 7F (DEL) */
 168.199 +    };
 168.200 +
 168.201 +    static int getType(int ch) {
 168.202 +        return ((ch & 0xFFFFFF80) == 0 ? ctype[ch] : 0);
 168.203 +    }
 168.204 +
 168.205 +    static boolean isType(int ch, int type) {
 168.206 +        return (getType(ch) & type) != 0;
 168.207 +    }
 168.208 +
 168.209 +    static boolean isAscii(int ch) {
 168.210 +        return ((ch & 0xFFFFFF80) == 0);
 168.211 +    }
 168.212 +
 168.213 +    static boolean isAlpha(int ch) {
 168.214 +        return isType(ch, ALPHA);
 168.215 +    }
 168.216 +
 168.217 +    static boolean isDigit(int ch) {
 168.218 +        return ((ch-'0')|('9'-ch)) >= 0;
 168.219 +    }
 168.220 +
 168.221 +    static boolean isAlnum(int ch) {
 168.222 +        return isType(ch, ALNUM);
 168.223 +    }
 168.224 +
 168.225 +    static boolean isGraph(int ch) {
 168.226 +        return isType(ch, GRAPH);
 168.227 +    }
 168.228 +
 168.229 +    static boolean isPrint(int ch) {
 168.230 +        return ((ch-0x20)|(0x7E-ch)) >= 0;
 168.231 +    }
 168.232 +
 168.233 +    static boolean isPunct(int ch) {
 168.234 +        return isType(ch, PUNCT);
 168.235 +    }
 168.236 +
 168.237 +    static boolean isSpace(int ch) {
 168.238 +        return isType(ch, SPACE);
 168.239 +    }
 168.240 +
 168.241 +    static boolean isHexDigit(int ch) {
 168.242 +        return isType(ch, HEX);
 168.243 +    }
 168.244 +
 168.245 +    static boolean isOctDigit(int ch) {
 168.246 +        return ((ch-'0')|('7'-ch)) >= 0;
 168.247 +    }
 168.248 +
 168.249 +    static boolean isCntrl(int ch) {
 168.250 +        return isType(ch, CNTRL);
 168.251 +    }
 168.252 +
 168.253 +    static boolean isLower(int ch) {
 168.254 +        return ((ch-'a')|('z'-ch)) >= 0;
 168.255 +    }
 168.256 +
 168.257 +    static boolean isUpper(int ch) {
 168.258 +        return ((ch-'A')|('Z'-ch)) >= 0;
 168.259 +    }
 168.260 +
 168.261 +    static boolean isWord(int ch) {
 168.262 +        return isType(ch, WORD);
 168.263 +    }
 168.264 +
 168.265 +    static int toDigit(int ch) {
 168.266 +        return (ctype[ch & 0x7F] & 0x3F);
 168.267 +    }
 168.268 +
 168.269 +    static int toLower(int ch) {
 168.270 +        return isUpper(ch) ? (ch + 0x20) : ch;
 168.271 +    }
 168.272 +
 168.273 +    static int toUpper(int ch) {
 168.274 +        return isLower(ch) ? (ch - 0x20) : ch;
 168.275 +    }
 168.276 +
 168.277 +}
   169.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   169.2 +++ b/rt/emul/compact/src/main/java/java/util/regex/MatchResult.java	Tue Feb 11 13:31:42 2014 +0100
   169.3 @@ -0,0 +1,188 @@
   169.4 +/*
   169.5 + * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
   169.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   169.7 + *
   169.8 + * This code is free software; you can redistribute it and/or modify it
   169.9 + * under the terms of the GNU General Public License version 2 only, as
  169.10 + * published by the Free Software Foundation.  Oracle designates this
  169.11 + * particular file as subject to the "Classpath" exception as provided
  169.12 + * by Oracle in the LICENSE file that accompanied this code.
  169.13 + *
  169.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  169.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  169.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  169.17 + * version 2 for more details (a copy is included in the LICENSE file that
  169.18 + * accompanied this code).
  169.19 + *
  169.20 + * You should have received a copy of the GNU General Public License version
  169.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  169.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  169.23 + *
  169.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  169.25 + * or visit www.oracle.com if you need additional information or have any
  169.26 + * questions.
  169.27 + */
  169.28 +
  169.29 +package java.util.regex;
  169.30 +
  169.31 +/**
  169.32 + * The result of a match operation.
  169.33 + *
  169.34 + * <p>This interface contains query methods used to determine the
  169.35 + * results of a match against a regular expression. The match boundaries,
  169.36 + * groups and group boundaries can be seen but not modified through
  169.37 + * a <code>MatchResult</code>.
  169.38 + *
  169.39 + * @author  Michael McCloskey
  169.40 + * @see Matcher
  169.41 + * @since 1.5
  169.42 + */
  169.43 +public interface MatchResult {
  169.44 +
  169.45 +    /**
  169.46 +     * Returns the start index of the match.
  169.47 +     *
  169.48 +     * @return  The index of the first character matched
  169.49 +     *
  169.50 +     * @throws  IllegalStateException
  169.51 +     *          If no match has yet been attempted,
  169.52 +     *          or if the previous match operation failed
  169.53 +     */
  169.54 +    public int start();
  169.55 +
  169.56 +    /**
  169.57 +     * Returns the start index of the subsequence captured by the given group
  169.58 +     * during this match.
  169.59 +     *
  169.60 +     * <p> <a href="Pattern.html#cg">Capturing groups</a> are indexed from left
  169.61 +     * to right, starting at one.  Group zero denotes the entire pattern, so
  169.62 +     * the expression <i>m.</i><tt>start(0)</tt> is equivalent to
  169.63 +     * <i>m.</i><tt>start()</tt>.  </p>
  169.64 +     *
  169.65 +     * @param  group
  169.66 +     *         The index of a capturing group in this matcher's pattern
  169.67 +     *
  169.68 +     * @return  The index of the first character captured by the group,
  169.69 +     *          or <tt>-1</tt> if the match was successful but the group
  169.70 +     *          itself did not match anything
  169.71 +     *
  169.72 +     * @throws  IllegalStateException
  169.73 +     *          If no match has yet been attempted,
  169.74 +     *          or if the previous match operation failed
  169.75 +     *
  169.76 +     * @throws  IndexOutOfBoundsException
  169.77 +     *          If there is no capturing group in the pattern
  169.78 +     *          with the given index
  169.79 +     */
  169.80 +    public int start(int group);
  169.81 +
  169.82 +    /**
  169.83 +     * Returns the offset after the last character matched.  </p>
  169.84 +     *
  169.85 +     * @return  @return  The offset after the last character matched
  169.86 +     *
  169.87 +     * @throws  IllegalStateException
  169.88 +     *          If no match has yet been attempted,
  169.89 +     *          or if the previous match operation failed
  169.90 +     */
  169.91 +    public int end();
  169.92 +
  169.93 +    /**
  169.94 +     * Returns the offset after the last character of the subsequence
  169.95 +     * captured by the given group during this match.
  169.96 +     *
  169.97 +     * <p> <a href="Pattern.html#cg">Capturing groups</a> are indexed from left
  169.98 +     * to right, starting at one.  Group zero denotes the entire pattern, so
  169.99 +     * the expression <i>m.</i><tt>end(0)</tt> is equivalent to
 169.100 +     * <i>m.</i><tt>end()</tt>.  </p>
 169.101 +     *
 169.102 +     * @param  group
 169.103 +     *         The index of a capturing group in this matcher's pattern
 169.104 +     *
 169.105 +     * @return  The offset after the last character captured by the group,
 169.106 +     *          or <tt>-1</tt> if the match was successful
 169.107 +     *          but the group itself did not match anything
 169.108 +     *
 169.109 +     * @throws  IllegalStateException
 169.110 +     *          If no match has yet been attempted,
 169.111 +     *          or if the previous match operation failed
 169.112 +     *
 169.113 +     * @throws  IndexOutOfBoundsException
 169.114 +     *          If there is no capturing group in the pattern
 169.115 +     *          with the given index
 169.116 +     */
 169.117 +    public int end(int group);
 169.118 +
 169.119 +    /**
 169.120 +     * Returns the input subsequence matched by the previous match.
 169.121 +     *
 169.122 +     * <p> For a matcher <i>m</i> with input sequence <i>s</i>,
 169.123 +     * the expressions <i>m.</i><tt>group()</tt> and
 169.124 +     * <i>s.</i><tt>substring(</tt><i>m.</i><tt>start(),</tt>&nbsp;<i>m.</i><tt>end())</tt>
 169.125 +     * are equivalent.  </p>
 169.126 +     *
 169.127 +     * <p> Note that some patterns, for example <tt>a*</tt>, match the empty
 169.128 +     * string.  This method will return the empty string when the pattern
 169.129 +     * successfully matches the empty string in the input.  </p>
 169.130 +     *
 169.131 +     * @return The (possibly empty) subsequence matched by the previous match,
 169.132 +     *         in string form
 169.133 +     *
 169.134 +     * @throws  IllegalStateException
 169.135 +     *          If no match has yet been attempted,
 169.136 +     *          or if the previous match operation failed
 169.137 +     */
 169.138 +    public String group();
 169.139 +
 169.140 +    /**
 169.141 +     * Returns the input subsequence captured by the given group during the
 169.142 +     * previous match operation.
 169.143 +     *
 169.144 +     * <p> For a matcher <i>m</i>, input sequence <i>s</i>, and group index
 169.145 +     * <i>g</i>, the expressions <i>m.</i><tt>group(</tt><i>g</i><tt>)</tt> and
 169.146 +     * <i>s.</i><tt>substring(</tt><i>m.</i><tt>start(</tt><i>g</i><tt>),</tt>&nbsp;<i>m.</i><tt>end(</tt><i>g</i><tt>))</tt>
 169.147 +     * are equivalent.  </p>
 169.148 +     *
 169.149 +     * <p> <a href="Pattern.html#cg">Capturing groups</a> are indexed from left
 169.150 +     * to right, starting at one.  Group zero denotes the entire pattern, so
 169.151 +     * the expression <tt>m.group(0)</tt> is equivalent to <tt>m.group()</tt>.
 169.152 +     * </p>
 169.153 +     *
 169.154 +     * <p> If the match was successful but the group specified failed to match
 169.155 +     * any part of the input sequence, then <tt>null</tt> is returned. Note
 169.156 +     * that some groups, for example <tt>(a*)</tt>, match the empty string.
 169.157 +     * This method will return the empty string when such a group successfully
 169.158 +     * matches the empty string in the input.  </p>
 169.159 +     *
 169.160 +     * @param  group
 169.161 +     *         The index of a capturing group in this matcher's pattern
 169.162 +     *
 169.163 +     * @return  The (possibly empty) subsequence captured by the group
 169.164 +     *          during the previous match, or <tt>null</tt> if the group
 169.165 +     *          failed to match part of the input
 169.166 +     *
 169.167 +     * @throws  IllegalStateException
 169.168 +     *          If no match has yet been attempted,
 169.169 +     *          or if the previous match operation failed
 169.170 +     *
 169.171 +     * @throws  IndexOutOfBoundsException
 169.172 +     *          If there is no capturing group in the pattern
 169.173 +     *          with the given index
 169.174 +     */
 169.175 +    public String group(int group);
 169.176 +
 169.177 +    /**
 169.178 +     * Returns the number of capturing groups in this match result's pattern.
 169.179 +     *
 169.180 +     * <p> Group zero denotes the entire pattern by convention. It is not
 169.181 +     * included in this count.
 169.182 +     *
 169.183 +     * <p> Any non-negative integer smaller than or equal to the value
 169.184 +     * returned by this method is guaranteed to be a valid group index for
 169.185 +     * this matcher.  </p>
 169.186 +     *
 169.187 +     * @return The number of capturing groups in this matcher's pattern
 169.188 +     */
 169.189 +    public int groupCount();
 169.190 +
 169.191 +}
   170.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   170.2 +++ b/rt/emul/compact/src/main/java/java/util/regex/Matcher.java	Tue Feb 11 13:31:42 2014 +0100
   170.3 @@ -0,0 +1,1256 @@
   170.4 +/*
   170.5 + * Copyright (c) 1999, 2009, Oracle and/or its affiliates. All rights reserved.
   170.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   170.7 + *
   170.8 + * This code is free software; you can redistribute it and/or modify it
   170.9 + * under the terms of the GNU General Public License version 2 only, as
  170.10 + * published by the Free Software Foundation.  Oracle designates this
  170.11 + * particular file as subject to the "Classpath" exception as provided
  170.12 + * by Oracle in the LICENSE file that accompanied this code.
  170.13 + *
  170.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  170.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  170.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  170.17 + * version 2 for more details (a copy is included in the LICENSE file that
  170.18 + * accompanied this code).
  170.19 + *
  170.20 + * You should have received a copy of the GNU General Public License version
  170.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  170.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  170.23 + *
  170.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  170.25 + * or visit www.oracle.com if you need additional information or have any
  170.26 + * questions.
  170.27 + */
  170.28 +
  170.29 +package java.util.regex;
  170.30 +
  170.31 +
  170.32 +/**
  170.33 + * An engine that performs match operations on a {@link java.lang.CharSequence
  170.34 + * </code>character sequence<code>} by interpreting a {@link Pattern}.
  170.35 + *
  170.36 + * <p> A matcher is created from a pattern by invoking the pattern's {@link
  170.37 + * Pattern#matcher matcher} method.  Once created, a matcher can be used to
  170.38 + * perform three different kinds of match operations:
  170.39 + *
  170.40 + * <ul>
  170.41 + *
  170.42 + *   <li><p> The {@link #matches matches} method attempts to match the entire
  170.43 + *   input sequence against the pattern.  </p></li>
  170.44 + *
  170.45 + *   <li><p> The {@link #lookingAt lookingAt} method attempts to match the
  170.46 + *   input sequence, starting at the beginning, against the pattern.  </p></li>
  170.47 + *
  170.48 + *   <li><p> The {@link #find find} method scans the input sequence looking for
  170.49 + *   the next subsequence that matches the pattern.  </p></li>
  170.50 + *
  170.51 + * </ul>
  170.52 + *
  170.53 + * <p> Each of these methods returns a boolean indicating success or failure.
  170.54 + * More information about a successful match can be obtained by querying the
  170.55 + * state of the matcher.
  170.56 + *
  170.57 + * <p> A matcher finds matches in a subset of its input called the
  170.58 + * <i>region</i>. By default, the region contains all of the matcher's input.
  170.59 + * The region can be modified via the{@link #region region} method and queried
  170.60 + * via the {@link #regionStart regionStart} and {@link #regionEnd regionEnd}
  170.61 + * methods. The way that the region boundaries interact with some pattern
  170.62 + * constructs can be changed. See {@link #useAnchoringBounds
  170.63 + * useAnchoringBounds} and {@link #useTransparentBounds useTransparentBounds}
  170.64 + * for more details.
  170.65 + *
  170.66 + * <p> This class also defines methods for replacing matched subsequences with
  170.67 + * new strings whose contents can, if desired, be computed from the match
  170.68 + * result.  The {@link #appendReplacement appendReplacement} and {@link
  170.69 + * #appendTail appendTail} methods can be used in tandem in order to collect
  170.70 + * the result into an existing string buffer, or the more convenient {@link
  170.71 + * #replaceAll replaceAll} method can be used to create a string in which every
  170.72 + * matching subsequence in the input sequence is replaced.
  170.73 + *
  170.74 + * <p> The explicit state of a matcher includes the start and end indices of
  170.75 + * the most recent successful match.  It also includes the start and end
  170.76 + * indices of the input subsequence captured by each <a
  170.77 + * href="Pattern.html#cg">capturing group</a> in the pattern as well as a total
  170.78 + * count of such subsequences.  As a convenience, methods are also provided for
  170.79 + * returning these captured subsequences in string form.
  170.80 + *
  170.81 + * <p> The explicit state of a matcher is initially undefined; attempting to
  170.82 + * query any part of it before a successful match will cause an {@link
  170.83 + * IllegalStateException} to be thrown.  The explicit state of a matcher is
  170.84 + * recomputed by every match operation.
  170.85 + *
  170.86 + * <p> The implicit state of a matcher includes the input character sequence as
  170.87 + * well as the <i>append position</i>, which is initially zero and is updated
  170.88 + * by the {@link #appendReplacement appendReplacement} method.
  170.89 + *
  170.90 + * <p> A matcher may be reset explicitly by invoking its {@link #reset()}
  170.91 + * method or, if a new input sequence is desired, its {@link
  170.92 + * #reset(java.lang.CharSequence) reset(CharSequence)} method.  Resetting a
  170.93 + * matcher discards its explicit state information and sets the append position
  170.94 + * to zero.
  170.95 + *
  170.96 + * <p> Instances of this class are not safe for use by multiple concurrent
  170.97 + * threads. </p>
  170.98 + *
  170.99 + *
 170.100 + * @author      Mike McCloskey
 170.101 + * @author      Mark Reinhold
 170.102 + * @author      JSR-51 Expert Group
 170.103 + * @since       1.4
 170.104 + * @spec        JSR-51
 170.105 + */
 170.106 +
 170.107 +public final class Matcher implements MatchResult {
 170.108 +
 170.109 +    /**
 170.110 +     * The Pattern object that created this Matcher.
 170.111 +     */
 170.112 +    Pattern parentPattern;
 170.113 +
 170.114 +    /**
 170.115 +     * The storage used by groups. They may contain invalid values if
 170.116 +     * a group was skipped during the matching.
 170.117 +     */
 170.118 +    int[] groups;
 170.119 +
 170.120 +    /**
 170.121 +     * The range within the sequence that is to be matched. Anchors
 170.122 +     * will match at these "hard" boundaries. Changing the region
 170.123 +     * changes these values.
 170.124 +     */
 170.125 +    int from, to;
 170.126 +
 170.127 +    /**
 170.128 +     * Lookbehind uses this value to ensure that the subexpression
 170.129 +     * match ends at the point where the lookbehind was encountered.
 170.130 +     */
 170.131 +    int lookbehindTo;
 170.132 +
 170.133 +    /**
 170.134 +     * The original string being matched.
 170.135 +     */
 170.136 +    CharSequence text;
 170.137 +
 170.138 +    /**
 170.139 +     * Matcher state used by the last node. NOANCHOR is used when a
 170.140 +     * match does not have to consume all of the input. ENDANCHOR is
 170.141 +     * the mode used for matching all the input.
 170.142 +     */
 170.143 +    static final int ENDANCHOR = 1;
 170.144 +    static final int NOANCHOR = 0;
 170.145 +    int acceptMode = NOANCHOR;
 170.146 +
 170.147 +    /**
 170.148 +     * The range of string that last matched the pattern. If the last
 170.149 +     * match failed then first is -1; last initially holds 0 then it
 170.150 +     * holds the index of the end of the last match (which is where the
 170.151 +     * next search starts).
 170.152 +     */
 170.153 +    int first = -1, last = 0;
 170.154 +
 170.155 +    /**
 170.156 +     * The end index of what matched in the last match operation.
 170.157 +     */
 170.158 +    int oldLast = -1;
 170.159 +
 170.160 +    /**
 170.161 +     * The index of the last position appended in a substitution.
 170.162 +     */
 170.163 +    int lastAppendPosition = 0;
 170.164 +
 170.165 +    /**
 170.166 +     * Storage used by nodes to tell what repetition they are on in
 170.167 +     * a pattern, and where groups begin. The nodes themselves are stateless,
 170.168 +     * so they rely on this field to hold state during a match.
 170.169 +     */
 170.170 +    int[] locals;
 170.171 +
 170.172 +    /**
 170.173 +     * Boolean indicating whether or not more input could change
 170.174 +     * the results of the last match.
 170.175 +     *
 170.176 +     * If hitEnd is true, and a match was found, then more input
 170.177 +     * might cause a different match to be found.
 170.178 +     * If hitEnd is true and a match was not found, then more
 170.179 +     * input could cause a match to be found.
 170.180 +     * If hitEnd is false and a match was found, then more input
 170.181 +     * will not change the match.
 170.182 +     * If hitEnd is false and a match was not found, then more
 170.183 +     * input will not cause a match to be found.
 170.184 +     */
 170.185 +    boolean hitEnd;
 170.186 +
 170.187 +    /**
 170.188 +     * Boolean indicating whether or not more input could change
 170.189 +     * a positive match into a negative one.
 170.190 +     *
 170.191 +     * If requireEnd is true, and a match was found, then more
 170.192 +     * input could cause the match to be lost.
 170.193 +     * If requireEnd is false and a match was found, then more
 170.194 +     * input might change the match but the match won't be lost.
 170.195 +     * If a match was not found, then requireEnd has no meaning.
 170.196 +     */
 170.197 +    boolean requireEnd;
 170.198 +
 170.199 +    /**
 170.200 +     * If transparentBounds is true then the boundaries of this
 170.201 +     * matcher's region are transparent to lookahead, lookbehind,
 170.202 +     * and boundary matching constructs that try to see beyond them.
 170.203 +     */
 170.204 +    boolean transparentBounds = false;
 170.205 +
 170.206 +    /**
 170.207 +     * If anchoringBounds is true then the boundaries of this
 170.208 +     * matcher's region match anchors such as ^ and $.
 170.209 +     */
 170.210 +    boolean anchoringBounds = true;
 170.211 +
 170.212 +    /**
 170.213 +     * No default constructor.
 170.214 +     */
 170.215 +    Matcher() {
 170.216 +    }
 170.217 +
 170.218 +    /**
 170.219 +     * All matchers have the state used by Pattern during a match.
 170.220 +     */
 170.221 +    Matcher(Pattern parent, CharSequence text) {
 170.222 +        this.parentPattern = parent;
 170.223 +        this.text = text;
 170.224 +
 170.225 +        // Allocate state storage
 170.226 +        int parentGroupCount = Math.max(parent.capturingGroupCount, 10);
 170.227 +        groups = new int[parentGroupCount * 2];
 170.228 +        locals = new int[parent.localCount];
 170.229 +
 170.230 +        // Put fields into initial states
 170.231 +        reset();
 170.232 +    }
 170.233 +
 170.234 +    /**
 170.235 +     * Returns the pattern that is interpreted by this matcher.
 170.236 +     *
 170.237 +     * @return  The pattern for which this matcher was created
 170.238 +     */
 170.239 +    public Pattern pattern() {
 170.240 +        return parentPattern;
 170.241 +    }
 170.242 +
 170.243 +    /**
 170.244 +     * Returns the match state of this matcher as a {@link MatchResult}.
 170.245 +     * The result is unaffected by subsequent operations performed upon this
 170.246 +     * matcher.
 170.247 +     *
 170.248 +     * @return  a <code>MatchResult</code> with the state of this matcher
 170.249 +     * @since 1.5
 170.250 +     */
 170.251 +    public MatchResult toMatchResult() {
 170.252 +        Matcher result = new Matcher(this.parentPattern, text.toString());
 170.253 +        result.first = this.first;
 170.254 +        result.last = this.last;
 170.255 +        result.groups = this.groups.clone();
 170.256 +        return result;
 170.257 +    }
 170.258 +
 170.259 +    /**
 170.260 +      * Changes the <tt>Pattern</tt> that this <tt>Matcher</tt> uses to
 170.261 +      * find matches with.
 170.262 +      *
 170.263 +      * <p> This method causes this matcher to lose information
 170.264 +      * about the groups of the last match that occurred. The
 170.265 +      * matcher's position in the input is maintained and its
 170.266 +      * last append position is unaffected.</p>
 170.267 +      *
 170.268 +      * @param  newPattern
 170.269 +      *         The new pattern used by this matcher
 170.270 +      * @return  This matcher
 170.271 +      * @throws  IllegalArgumentException
 170.272 +      *          If newPattern is <tt>null</tt>
 170.273 +      * @since 1.5
 170.274 +      */
 170.275 +    public Matcher usePattern(Pattern newPattern) {
 170.276 +        if (newPattern == null)
 170.277 +            throw new IllegalArgumentException("Pattern cannot be null");
 170.278 +        parentPattern = newPattern;
 170.279 +
 170.280 +        // Reallocate state storage
 170.281 +        int parentGroupCount = Math.max(newPattern.capturingGroupCount, 10);
 170.282 +        groups = new int[parentGroupCount * 2];
 170.283 +        locals = new int[newPattern.localCount];
 170.284 +        for (int i = 0; i < groups.length; i++)
 170.285 +            groups[i] = -1;
 170.286 +        for (int i = 0; i < locals.length; i++)
 170.287 +            locals[i] = -1;
 170.288 +        return this;
 170.289 +    }
 170.290 +
 170.291 +    /**
 170.292 +     * Resets this matcher.
 170.293 +     *
 170.294 +     * <p> Resetting a matcher discards all of its explicit state information
 170.295 +     * and sets its append position to zero. The matcher's region is set to the
 170.296 +     * default region, which is its entire character sequence. The anchoring
 170.297 +     * and transparency of this matcher's region boundaries are unaffected.
 170.298 +     *
 170.299 +     * @return  This matcher
 170.300 +     */
 170.301 +    public Matcher reset() {
 170.302 +        first = -1;
 170.303 +        last = 0;
 170.304 +        oldLast = -1;
 170.305 +        for(int i=0; i<groups.length; i++)
 170.306 +            groups[i] = -1;
 170.307 +        for(int i=0; i<locals.length; i++)
 170.308 +            locals[i] = -1;
 170.309 +        lastAppendPosition = 0;
 170.310 +        from = 0;
 170.311 +        to = getTextLength();
 170.312 +        return this;
 170.313 +    }
 170.314 +
 170.315 +    /**
 170.316 +     * Resets this matcher with a new input sequence.
 170.317 +     *
 170.318 +     * <p> Resetting a matcher discards all of its explicit state information
 170.319 +     * and sets its append position to zero.  The matcher's region is set to
 170.320 +     * the default region, which is its entire character sequence.  The
 170.321 +     * anchoring and transparency of this matcher's region boundaries are
 170.322 +     * unaffected.
 170.323 +     *
 170.324 +     * @param  input
 170.325 +     *         The new input character sequence
 170.326 +     *
 170.327 +     * @return  This matcher
 170.328 +     */
 170.329 +    public Matcher reset(CharSequence input) {
 170.330 +        text = input;
 170.331 +        return reset();
 170.332 +    }
 170.333 +
 170.334 +    /**
 170.335 +     * Returns the start index of the previous match.  </p>
 170.336 +     *
 170.337 +     * @return  The index of the first character matched
 170.338 +     *
 170.339 +     * @throws  IllegalStateException
 170.340 +     *          If no match has yet been attempted,
 170.341 +     *          or if the previous match operation failed
 170.342 +     */
 170.343 +    public int start() {
 170.344 +        if (first < 0)
 170.345 +            throw new IllegalStateException("No match available");
 170.346 +        return first;
 170.347 +    }
 170.348 +
 170.349 +    /**
 170.350 +     * Returns the start index of the subsequence captured by the given group
 170.351 +     * during the previous match operation.
 170.352 +     *
 170.353 +     * <p> <a href="Pattern.html#cg">Capturing groups</a> are indexed from left
 170.354 +     * to right, starting at one.  Group zero denotes the entire pattern, so
 170.355 +     * the expression <i>m.</i><tt>start(0)</tt> is equivalent to
 170.356 +     * <i>m.</i><tt>start()</tt>.  </p>
 170.357 +     *
 170.358 +     * @param  group
 170.359 +     *         The index of a capturing group in this matcher's pattern
 170.360 +     *
 170.361 +     * @return  The index of the first character captured by the group,
 170.362 +     *          or <tt>-1</tt> if the match was successful but the group
 170.363 +     *          itself did not match anything
 170.364 +     *
 170.365 +     * @throws  IllegalStateException
 170.366 +     *          If no match has yet been attempted,
 170.367 +     *          or if the previous match operation failed
 170.368 +     *
 170.369 +     * @throws  IndexOutOfBoundsException
 170.370 +     *          If there is no capturing group in the pattern
 170.371 +     *          with the given index
 170.372 +     */
 170.373 +    public int start(int group) {
 170.374 +        if (first < 0)
 170.375 +            throw new IllegalStateException("No match available");
 170.376 +        if (group > groupCount())
 170.377 +            throw new IndexOutOfBoundsException("No group " + group);
 170.378 +        return groups[group * 2];
 170.379 +    }
 170.380 +
 170.381 +    /**
 170.382 +     * Returns the offset after the last character matched.  </p>
 170.383 +     *
 170.384 +     * @return  The offset after the last character matched
 170.385 +     *
 170.386 +     * @throws  IllegalStateException
 170.387 +     *          If no match has yet been attempted,
 170.388 +     *          or if the previous match operation failed
 170.389 +     */
 170.390 +    public int end() {
 170.391 +        if (first < 0)
 170.392 +            throw new IllegalStateException("No match available");
 170.393 +        return last;
 170.394 +    }
 170.395 +
 170.396 +    /**
 170.397 +     * Returns the offset after the last character of the subsequence
 170.398 +     * captured by the given group during the previous match operation.
 170.399 +     *
 170.400 +     * <p> <a href="Pattern.html#cg">Capturing groups</a> are indexed from left
 170.401 +     * to right, starting at one.  Group zero denotes the entire pattern, so
 170.402 +     * the expression <i>m.</i><tt>end(0)</tt> is equivalent to
 170.403 +     * <i>m.</i><tt>end()</tt>.  </p>
 170.404 +     *
 170.405 +     * @param  group
 170.406 +     *         The index of a capturing group in this matcher's pattern
 170.407 +     *
 170.408 +     * @return  The offset after the last character captured by the group,
 170.409 +     *          or <tt>-1</tt> if the match was successful
 170.410 +     *          but the group itself did not match anything
 170.411 +     *
 170.412 +     * @throws  IllegalStateException
 170.413 +     *          If no match has yet been attempted,
 170.414 +     *          or if the previous match operation failed
 170.415 +     *
 170.416 +     * @throws  IndexOutOfBoundsException
 170.417 +     *          If there is no capturing group in the pattern
 170.418 +     *          with the given index
 170.419 +     */
 170.420 +    public int end(int group) {
 170.421 +        if (first < 0)
 170.422 +            throw new IllegalStateException("No match available");
 170.423 +        if (group > groupCount())
 170.424 +            throw new IndexOutOfBoundsException("No group " + group);
 170.425 +        return groups[group * 2 + 1];
 170.426 +    }
 170.427 +
 170.428 +    /**
 170.429 +     * Returns the input subsequence matched by the previous match.
 170.430 +     *
 170.431 +     * <p> For a matcher <i>m</i> with input sequence <i>s</i>,
 170.432 +     * the expressions <i>m.</i><tt>group()</tt> and
 170.433 +     * <i>s.</i><tt>substring(</tt><i>m.</i><tt>start(),</tt>&nbsp;<i>m.</i><tt>end())</tt>
 170.434 +     * are equivalent.  </p>
 170.435 +     *
 170.436 +     * <p> Note that some patterns, for example <tt>a*</tt>, match the empty
 170.437 +     * string.  This method will return the empty string when the pattern
 170.438 +     * successfully matches the empty string in the input.  </p>
 170.439 +     *
 170.440 +     * @return The (possibly empty) subsequence matched by the previous match,
 170.441 +     *         in string form
 170.442 +     *
 170.443 +     * @throws  IllegalStateException
 170.444 +     *          If no match has yet been attempted,
 170.445 +     *          or if the previous match operation failed
 170.446 +     */
 170.447 +    public String group() {
 170.448 +        return group(0);
 170.449 +    }
 170.450 +
 170.451 +    /**
 170.452 +     * Returns the input subsequence captured by the given group during the
 170.453 +     * previous match operation.
 170.454 +     *
 170.455 +     * <p> For a matcher <i>m</i>, input sequence <i>s</i>, and group index
 170.456 +     * <i>g</i>, the expressions <i>m.</i><tt>group(</tt><i>g</i><tt>)</tt> and
 170.457 +     * <i>s.</i><tt>substring(</tt><i>m.</i><tt>start(</tt><i>g</i><tt>),</tt>&nbsp;<i>m.</i><tt>end(</tt><i>g</i><tt>))</tt>
 170.458 +     * are equivalent.  </p>
 170.459 +     *
 170.460 +     * <p> <a href="Pattern.html#cg">Capturing groups</a> are indexed from left
 170.461 +     * to right, starting at one.  Group zero denotes the entire pattern, so
 170.462 +     * the expression <tt>m.group(0)</tt> is equivalent to <tt>m.group()</tt>.
 170.463 +     * </p>
 170.464 +     *
 170.465 +     * <p> If the match was successful but the group specified failed to match
 170.466 +     * any part of the input sequence, then <tt>null</tt> is returned. Note
 170.467 +     * that some groups, for example <tt>(a*)</tt>, match the empty string.
 170.468 +     * This method will return the empty string when such a group successfully
 170.469 +     * matches the empty string in the input.  </p>
 170.470 +     *
 170.471 +     * @param  group
 170.472 +     *         The index of a capturing group in this matcher's pattern
 170.473 +     *
 170.474 +     * @return  The (possibly empty) subsequence captured by the group
 170.475 +     *          during the previous match, or <tt>null</tt> if the group
 170.476 +     *          failed to match part of the input
 170.477 +     *
 170.478 +     * @throws  IllegalStateException
 170.479 +     *          If no match has yet been attempted,
 170.480 +     *          or if the previous match operation failed
 170.481 +     *
 170.482 +     * @throws  IndexOutOfBoundsException
 170.483 +     *          If there is no capturing group in the pattern
 170.484 +     *          with the given index
 170.485 +     */
 170.486 +    public String group(int group) {
 170.487 +        if (first < 0)
 170.488 +            throw new IllegalStateException("No match found");
 170.489 +        if (group < 0 || group > groupCount())
 170.490 +            throw new IndexOutOfBoundsException("No group " + group);
 170.491 +        if ((groups[group*2] == -1) || (groups[group*2+1] == -1))
 170.492 +            return null;
 170.493 +        return getSubSequence(groups[group * 2], groups[group * 2 + 1]).toString();
 170.494 +    }
 170.495 +
 170.496 +    /**
 170.497 +     * Returns the input subsequence captured by the given
 170.498 +     * <a href="Pattern.html#groupname">named-capturing group</a> during the previous
 170.499 +     * match operation.
 170.500 +     *
 170.501 +     * <p> If the match was successful but the group specified failed to match
 170.502 +     * any part of the input sequence, then <tt>null</tt> is returned. Note
 170.503 +     * that some groups, for example <tt>(a*)</tt>, match the empty string.
 170.504 +     * This method will return the empty string when such a group successfully
 170.505 +     * matches the empty string in the input.  </p>
 170.506 +     *
 170.507 +     * @param  name
 170.508 +     *         The name of a named-capturing group in this matcher's pattern
 170.509 +     *
 170.510 +     * @return  The (possibly empty) subsequence captured by the named group
 170.511 +     *          during the previous match, or <tt>null</tt> if the group
 170.512 +     *          failed to match part of the input
 170.513 +     *
 170.514 +     * @throws  IllegalStateException
 170.515 +     *          If no match has yet been attempted,
 170.516 +     *          or if the previous match operation failed
 170.517 +     *
 170.518 +     * @throws  IllegalArgumentException
 170.519 +     *          If there is no capturing group in the pattern
 170.520 +     *          with the given name
 170.521 +     */
 170.522 +    public String group(String name) {
 170.523 +        if (name == null)
 170.524 +            throw new NullPointerException("Null group name");
 170.525 +        if (first < 0)
 170.526 +            throw new IllegalStateException("No match found");
 170.527 +        if (!parentPattern.namedGroups().containsKey(name))
 170.528 +            throw new IllegalArgumentException("No group with name <" + name + ">");
 170.529 +        int group = parentPattern.namedGroups().get(name);
 170.530 +        if ((groups[group*2] == -1) || (groups[group*2+1] == -1))
 170.531 +            return null;
 170.532 +        return getSubSequence(groups[group * 2], groups[group * 2 + 1]).toString();
 170.533 +    }
 170.534 +
 170.535 +    /**
 170.536 +     * Returns the number of capturing groups in this matcher's pattern.
 170.537 +     *
 170.538 +     * <p> Group zero denotes the entire pattern by convention. It is not
 170.539 +     * included in this count.
 170.540 +     *
 170.541 +     * <p> Any non-negative integer smaller than or equal to the value
 170.542 +     * returned by this method is guaranteed to be a valid group index for
 170.543 +     * this matcher.  </p>
 170.544 +     *
 170.545 +     * @return The number of capturing groups in this matcher's pattern
 170.546 +     */
 170.547 +    public int groupCount() {
 170.548 +        return parentPattern.capturingGroupCount - 1;
 170.549 +    }
 170.550 +
 170.551 +    /**
 170.552 +     * Attempts to match the entire region against the pattern.
 170.553 +     *
 170.554 +     * <p> If the match succeeds then more information can be obtained via the
 170.555 +     * <tt>start</tt>, <tt>end</tt>, and <tt>group</tt> methods.  </p>
 170.556 +     *
 170.557 +     * @return  <tt>true</tt> if, and only if, the entire region sequence
 170.558 +     *          matches this matcher's pattern
 170.559 +     */
 170.560 +    public boolean matches() {
 170.561 +        return match(from, ENDANCHOR);
 170.562 +    }
 170.563 +
 170.564 +    /**
 170.565 +     * Attempts to find the next subsequence of the input sequence that matches
 170.566 +     * the pattern.
 170.567 +     *
 170.568 +     * <p> This method starts at the beginning of this matcher's region, or, if
 170.569 +     * a previous invocation of the method was successful and the matcher has
 170.570 +     * not since been reset, at the first character not matched by the previous
 170.571 +     * match.
 170.572 +     *
 170.573 +     * <p> If the match succeeds then more information can be obtained via the
 170.574 +     * <tt>start</tt>, <tt>end</tt>, and <tt>group</tt> methods.  </p>
 170.575 +     *
 170.576 +     * @return  <tt>true</tt> if, and only if, a subsequence of the input
 170.577 +     *          sequence matches this matcher's pattern
 170.578 +     */
 170.579 +    public boolean find() {
 170.580 +        int nextSearchIndex = last;
 170.581 +        if (nextSearchIndex == first)
 170.582 +            nextSearchIndex++;
 170.583 +
 170.584 +        // If next search starts before region, start it at region
 170.585 +        if (nextSearchIndex < from)
 170.586 +            nextSearchIndex = from;
 170.587 +
 170.588 +        // If next search starts beyond region then it fails
 170.589 +        if (nextSearchIndex > to) {
 170.590 +            for (int i = 0; i < groups.length; i++)
 170.591 +                groups[i] = -1;
 170.592 +            return false;
 170.593 +        }
 170.594 +        return search(nextSearchIndex);
 170.595 +    }
 170.596 +
 170.597 +    /**
 170.598 +     * Resets this matcher and then attempts to find the next subsequence of
 170.599 +     * the input sequence that matches the pattern, starting at the specified
 170.600 +     * index.
 170.601 +     *
 170.602 +     * <p> If the match succeeds then more information can be obtained via the
 170.603 +     * <tt>start</tt>, <tt>end</tt>, and <tt>group</tt> methods, and subsequent
 170.604 +     * invocations of the {@link #find()} method will start at the first
 170.605 +     * character not matched by this match.  </p>
 170.606 +     *
 170.607 +     * @throws  IndexOutOfBoundsException
 170.608 +     *          If start is less than zero or if start is greater than the
 170.609 +     *          length of the input sequence.
 170.610 +     *
 170.611 +     * @return  <tt>true</tt> if, and only if, a subsequence of the input
 170.612 +     *          sequence starting at the given index matches this matcher's
 170.613 +     *          pattern
 170.614 +     */
 170.615 +    public boolean find(int start) {
 170.616 +        int limit = getTextLength();
 170.617 +        if ((start < 0) || (start > limit))
 170.618 +            throw new IndexOutOfBoundsException("Illegal start index");
 170.619 +        reset();
 170.620 +        return search(start);
 170.621 +    }
 170.622 +
 170.623 +    /**
 170.624 +     * Attempts to match the input sequence, starting at the beginning of the
 170.625 +     * region, against the pattern.
 170.626 +     *
 170.627 +     * <p> Like the {@link #matches matches} method, this method always starts
 170.628 +     * at the beginning of the region; unlike that method, it does not
 170.629 +     * require that the entire region be matched.
 170.630 +     *
 170.631 +     * <p> If the match succeeds then more information can be obtained via the
 170.632 +     * <tt>start</tt>, <tt>end</tt>, and <tt>group</tt> methods.  </p>
 170.633 +     *
 170.634 +     * @return  <tt>true</tt> if, and only if, a prefix of the input
 170.635 +     *          sequence matches this matcher's pattern
 170.636 +     */
 170.637 +    public boolean lookingAt() {
 170.638 +        return match(from, NOANCHOR);
 170.639 +    }
 170.640 +
 170.641 +    /**
 170.642 +     * Returns a literal replacement <code>String</code> for the specified
 170.643 +     * <code>String</code>.
 170.644 +     *
 170.645 +     * This method produces a <code>String</code> that will work
 170.646 +     * as a literal replacement <code>s</code> in the
 170.647 +     * <code>appendReplacement</code> method of the {@link Matcher} class.
 170.648 +     * The <code>String</code> produced will match the sequence of characters
 170.649 +     * in <code>s</code> treated as a literal sequence. Slashes ('\') and
 170.650 +     * dollar signs ('$') will be given no special meaning.
 170.651 +     *
 170.652 +     * @param  s The string to be literalized
 170.653 +     * @return  A literal string replacement
 170.654 +     * @since 1.5
 170.655 +     */
 170.656 +    public static String quoteReplacement(String s) {
 170.657 +        if ((s.indexOf('\\') == -1) && (s.indexOf('$') == -1))
 170.658 +            return s;
 170.659 +        StringBuilder sb = new StringBuilder();
 170.660 +        for (int i=0; i<s.length(); i++) {
 170.661 +            char c = s.charAt(i);
 170.662 +            if (c == '\\' || c == '$') {
 170.663 +                sb.append('\\');
 170.664 +            }
 170.665 +            sb.append(c);
 170.666 +        }
 170.667 +        return sb.toString();
 170.668 +    }
 170.669 +
 170.670 +    /**
 170.671 +     * Implements a non-terminal append-and-replace step.
 170.672 +     *
 170.673 +     * <p> This method performs the following actions: </p>
 170.674 +     *
 170.675 +     * <ol>
 170.676 +     *
 170.677 +     *   <li><p> It reads characters from the input sequence, starting at the
 170.678 +     *   append position, and appends them to the given string buffer.  It
 170.679 +     *   stops after reading the last character preceding the previous match,
 170.680 +     *   that is, the character at index {@link
 170.681 +     *   #start()}&nbsp;<tt>-</tt>&nbsp;<tt>1</tt>.  </p></li>
 170.682 +     *
 170.683 +     *   <li><p> It appends the given replacement string to the string buffer.
 170.684 +     *   </p></li>
 170.685 +     *
 170.686 +     *   <li><p> It sets the append position of this matcher to the index of
 170.687 +     *   the last character matched, plus one, that is, to {@link #end()}.
 170.688 +     *   </p></li>
 170.689 +     *
 170.690 +     * </ol>
 170.691 +     *
 170.692 +     * <p> The replacement string may contain references to subsequences
 170.693 +     * captured during the previous match: Each occurrence of
 170.694 +     * <tt>${</tt><i>name</i><tt>}</tt> or <tt>$</tt><i>g</i>
 170.695 +     * will be replaced by the result of evaluating the corresponding
 170.696 +     * {@link #group(String) group(name)} or {@link #group(int) group(g)</tt>}
 170.697 +     * respectively. For  <tt>$</tt><i>g</i><tt></tt>,
 170.698 +     * the first number after the <tt>$</tt> is always treated as part of
 170.699 +     * the group reference. Subsequent numbers are incorporated into g if
 170.700 +     * they would form a legal group reference. Only the numerals '0'
 170.701 +     * through '9' are considered as potential components of the group
 170.702 +     * reference. If the second group matched the string <tt>"foo"</tt>, for
 170.703 +     * example, then passing the replacement string <tt>"$2bar"</tt> would
 170.704 +     * cause <tt>"foobar"</tt> to be appended to the string buffer. A dollar
 170.705 +     * sign (<tt>$</tt>) may be included as a literal in the replacement
 170.706 +     * string by preceding it with a backslash (<tt>\$</tt>).
 170.707 +     *
 170.708 +     * <p> Note that backslashes (<tt>\</tt>) and dollar signs (<tt>$</tt>) in
 170.709 +     * the replacement string may cause the results to be different than if it
 170.710 +     * were being treated as a literal replacement string. Dollar signs may be
 170.711 +     * treated as references to captured subsequences as described above, and
 170.712 +     * backslashes are used to escape literal characters in the replacement
 170.713 +     * string.
 170.714 +     *
 170.715 +     * <p> This method is intended to be used in a loop together with the
 170.716 +     * {@link #appendTail appendTail} and {@link #find find} methods.  The
 170.717 +     * following code, for example, writes <tt>one dog two dogs in the
 170.718 +     * yard</tt> to the standard-output stream: </p>
 170.719 +     *
 170.720 +     * <blockquote><pre>
 170.721 +     * Pattern p = Pattern.compile("cat");
 170.722 +     * Matcher m = p.matcher("one cat two cats in the yard");
 170.723 +     * StringBuffer sb = new StringBuffer();
 170.724 +     * while (m.find()) {
 170.725 +     *     m.appendReplacement(sb, "dog");
 170.726 +     * }
 170.727 +     * m.appendTail(sb);
 170.728 +     * System.out.println(sb.toString());</pre></blockquote>
 170.729 +     *
 170.730 +     * @param  sb
 170.731 +     *         The target string buffer
 170.732 +     *
 170.733 +     * @param  replacement
 170.734 +     *         The replacement string
 170.735 +     *
 170.736 +     * @return  This matcher
 170.737 +     *
 170.738 +     * @throws  IllegalStateException
 170.739 +     *          If no match has yet been attempted,
 170.740 +     *          or if the previous match operation failed
 170.741 +     *
 170.742 +     * @throws  IllegalArgumentException
 170.743 +     *          If the replacement string refers to a named-capturing
 170.744 +     *          group that does not exist in the pattern
 170.745 +     *
 170.746 +     * @throws  IndexOutOfBoundsException
 170.747 +     *          If the replacement string refers to a capturing group
 170.748 +     *          that does not exist in the pattern
 170.749 +     */
 170.750 +    public Matcher appendReplacement(StringBuffer sb, String replacement) {
 170.751 +
 170.752 +        // If no match, return error
 170.753 +        if (first < 0)
 170.754 +            throw new IllegalStateException("No match available");
 170.755 +
 170.756 +        // Process substitution string to replace group references with groups
 170.757 +        int cursor = 0;
 170.758 +        StringBuilder result = new StringBuilder();
 170.759 +
 170.760 +        while (cursor < replacement.length()) {
 170.761 +            char nextChar = replacement.charAt(cursor);
 170.762 +            if (nextChar == '\\') {
 170.763 +                cursor++;
 170.764 +                nextChar = replacement.charAt(cursor);
 170.765 +                result.append(nextChar);
 170.766 +                cursor++;
 170.767 +            } else if (nextChar == '$') {
 170.768 +                // Skip past $
 170.769 +                cursor++;
 170.770 +                // A StringIndexOutOfBoundsException is thrown if
 170.771 +                // this "$" is the last character in replacement
 170.772 +                // string in current implementation, a IAE might be
 170.773 +                // more appropriate.
 170.774 +                nextChar = replacement.charAt(cursor);
 170.775 +                int refNum = -1;
 170.776 +                if (nextChar == '{') {
 170.777 +                    cursor++;
 170.778 +                    StringBuilder gsb = new StringBuilder();
 170.779 +                    while (cursor < replacement.length()) {
 170.780 +                        nextChar = replacement.charAt(cursor);
 170.781 +                        if (ASCII.isLower(nextChar) ||
 170.782 +                            ASCII.isUpper(nextChar) ||
 170.783 +                            ASCII.isDigit(nextChar)) {
 170.784 +                            gsb.append(nextChar);
 170.785 +                            cursor++;
 170.786 +                        } else {
 170.787 +                            break;
 170.788 +                        }
 170.789 +                    }
 170.790 +                    if (gsb.length() == 0)
 170.791 +                        throw new IllegalArgumentException(
 170.792 +                            "named capturing group has 0 length name");
 170.793 +                    if (nextChar != '}')
 170.794 +                        throw new IllegalArgumentException(
 170.795 +                            "named capturing group is missing trailing '}'");
 170.796 +                    String gname = gsb.toString();
 170.797 +                    if (ASCII.isDigit(gname.charAt(0)))
 170.798 +                        throw new IllegalArgumentException(
 170.799 +                            "capturing group name {" + gname +
 170.800 +                            "} starts with digit character");
 170.801 +                    if (!parentPattern.namedGroups().containsKey(gname))
 170.802 +                        throw new IllegalArgumentException(
 170.803 +                            "No group with name {" + gname + "}");
 170.804 +                    refNum = parentPattern.namedGroups().get(gname);
 170.805 +                    cursor++;
 170.806 +                } else {
 170.807 +                    // The first number is always a group
 170.808 +                    refNum = (int)nextChar - '0';
 170.809 +                    if ((refNum < 0)||(refNum > 9))
 170.810 +                        throw new IllegalArgumentException(
 170.811 +                            "Illegal group reference");
 170.812 +                    cursor++;
 170.813 +                    // Capture the largest legal group string
 170.814 +                    boolean done = false;
 170.815 +                    while (!done) {
 170.816 +                        if (cursor >= replacement.length()) {
 170.817 +                            break;
 170.818 +                        }
 170.819 +                        int nextDigit = replacement.charAt(cursor) - '0';
 170.820 +                        if ((nextDigit < 0)||(nextDigit > 9)) { // not a number
 170.821 +                            break;
 170.822 +                        }
 170.823 +                        int newRefNum = (refNum * 10) + nextDigit;
 170.824 +                        if (groupCount() < newRefNum) {
 170.825 +                            done = true;
 170.826 +                        } else {
 170.827 +                            refNum = newRefNum;
 170.828 +                            cursor++;
 170.829 +                        }
 170.830 +                    }
 170.831 +                }
 170.832 +                // Append group
 170.833 +                if (start(refNum) != -1 && end(refNum) != -1)
 170.834 +                    result.append(text, start(refNum), end(refNum));
 170.835 +            } else {
 170.836 +                result.append(nextChar);
 170.837 +                cursor++;
 170.838 +            }
 170.839 +        }
 170.840 +        // Append the intervening text
 170.841 +        sb.append(text, lastAppendPosition, first);
 170.842 +        // Append the match substitution
 170.843 +        sb.append(result);
 170.844 +
 170.845 +        lastAppendPosition = last;
 170.846 +        return this;
 170.847 +    }
 170.848 +
 170.849 +    /**
 170.850 +     * Implements a terminal append-and-replace step.
 170.851 +     *
 170.852 +     * <p> This method reads characters from the input sequence, starting at
 170.853 +     * the append position, and appends them to the given string buffer.  It is
 170.854 +     * intended to be invoked after one or more invocations of the {@link
 170.855 +     * #appendReplacement appendReplacement} method in order to copy the
 170.856 +     * remainder of the input sequence.  </p>
 170.857 +     *
 170.858 +     * @param  sb
 170.859 +     *         The target string buffer
 170.860 +     *
 170.861 +     * @return  The target string buffer
 170.862 +     */
 170.863 +    public StringBuffer appendTail(StringBuffer sb) {
 170.864 +        sb.append(text, lastAppendPosition, getTextLength());
 170.865 +        return sb;
 170.866 +    }
 170.867 +
 170.868 +    /**
 170.869 +     * Replaces every subsequence of the input sequence that matches the
 170.870 +     * pattern with the given replacement string.
 170.871 +     *
 170.872 +     * <p> This method first resets this matcher.  It then scans the input
 170.873 +     * sequence looking for matches of the pattern.  Characters that are not
 170.874 +     * part of any match are appended directly to the result string; each match
 170.875 +     * is replaced in the result by the replacement string.  The replacement
 170.876 +     * string may contain references to captured subsequences as in the {@link
 170.877 +     * #appendReplacement appendReplacement} method.
 170.878 +     *
 170.879 +     * <p> Note that backslashes (<tt>\</tt>) and dollar signs (<tt>$</tt>) in
 170.880 +     * the replacement string may cause the results to be different than if it
 170.881 +     * were being treated as a literal replacement string. Dollar signs may be
 170.882 +     * treated as references to captured subsequences as described above, and
 170.883 +     * backslashes are used to escape literal characters in the replacement
 170.884 +     * string.
 170.885 +     *
 170.886 +     * <p> Given the regular expression <tt>a*b</tt>, the input
 170.887 +     * <tt>"aabfooaabfooabfoob"</tt>, and the replacement string
 170.888 +     * <tt>"-"</tt>, an invocation of this method on a matcher for that
 170.889 +     * expression would yield the string <tt>"-foo-foo-foo-"</tt>.
 170.890 +     *
 170.891 +     * <p> Invoking this method changes this matcher's state.  If the matcher
 170.892 +     * is to be used in further matching operations then it should first be
 170.893 +     * reset.  </p>
 170.894 +     *
 170.895 +     * @param  replacement
 170.896 +     *         The replacement string
 170.897 +     *
 170.898 +     * @return  The string constructed by replacing each matching subsequence
 170.899 +     *          by the replacement string, substituting captured subsequences
 170.900 +     *          as needed
 170.901 +     */
 170.902 +    public String replaceAll(String replacement) {
 170.903 +        reset();
 170.904 +        boolean result = find();
 170.905 +        if (result) {
 170.906 +            StringBuffer sb = new StringBuffer();
 170.907 +            do {
 170.908 +                appendReplacement(sb, replacement);
 170.909 +                result = find();
 170.910 +            } while (result);
 170.911 +            appendTail(sb);
 170.912 +            return sb.toString();
 170.913 +        }
 170.914 +        return text.toString();
 170.915 +    }
 170.916 +
 170.917 +    /**
 170.918 +     * Replaces the first subsequence of the input sequence that matches the
 170.919 +     * pattern with the given replacement string.
 170.920 +     *
 170.921 +     * <p> This method first resets this matcher.  It then scans the input
 170.922 +     * sequence looking for a match of the pattern.  Characters that are not
 170.923 +     * part of the match are appended directly to the result string; the match
 170.924 +     * is replaced in the result by the replacement string.  The replacement
 170.925 +     * string may contain references to captured subsequences as in the {@link
 170.926 +     * #appendReplacement appendReplacement} method.
 170.927 +     *
 170.928 +     * <p>Note that backslashes (<tt>\</tt>) and dollar signs (<tt>$</tt>) in
 170.929 +     * the replacement string may cause the results to be different than if it
 170.930 +     * were being treated as a literal replacement string. Dollar signs may be
 170.931 +     * treated as references to captured subsequences as described above, and
 170.932 +     * backslashes are used to escape literal characters in the replacement
 170.933 +     * string.
 170.934 +     *
 170.935 +     * <p> Given the regular expression <tt>dog</tt>, the input
 170.936 +     * <tt>"zzzdogzzzdogzzz"</tt>, and the replacement string
 170.937 +     * <tt>"cat"</tt>, an invocation of this method on a matcher for that
 170.938 +     * expression would yield the string <tt>"zzzcatzzzdogzzz"</tt>.  </p>
 170.939 +     *
 170.940 +     * <p> Invoking this method changes this matcher's state.  If the matcher
 170.941 +     * is to be used in further matching operations then it should first be
 170.942 +     * reset.  </p>
 170.943 +     *
 170.944 +     * @param  replacement
 170.945 +     *         The replacement string
 170.946 +     * @return  The string constructed by replacing the first matching
 170.947 +     *          subsequence by the replacement string, substituting captured
 170.948 +     *          subsequences as needed
 170.949 +     */
 170.950 +    public String replaceFirst(String replacement) {
 170.951 +        if (replacement == null)
 170.952 +            throw new NullPointerException("replacement");
 170.953 +        reset();
 170.954 +        if (!find())
 170.955 +            return text.toString();
 170.956 +        StringBuffer sb = new StringBuffer();
 170.957 +        appendReplacement(sb, replacement);
 170.958 +        appendTail(sb);
 170.959 +        return sb.toString();
 170.960 +    }
 170.961 +
 170.962 +    /**
 170.963 +     * Sets the limits of this matcher's region. The region is the part of the
 170.964 +     * input sequence that will be searched to find a match. Invoking this
 170.965 +     * method resets the matcher, and then sets the region to start at the
 170.966 +     * index specified by the <code>start</code> parameter and end at the
 170.967 +     * index specified by the <code>end</code> parameter.
 170.968 +     *
 170.969 +     * <p>Depending on the transparency and anchoring being used (see
 170.970 +     * {@link #useTransparentBounds useTransparentBounds} and
 170.971 +     * {@link #useAnchoringBounds useAnchoringBounds}), certain constructs such
 170.972 +     * as anchors may behave differently at or around the boundaries of the
 170.973 +     * region.
 170.974 +     *
 170.975 +     * @param  start
 170.976 +     *         The index to start searching at (inclusive)
 170.977 +     * @param  end
 170.978 +     *         The index to end searching at (exclusive)
 170.979 +     * @throws  IndexOutOfBoundsException
 170.980 +     *          If start or end is less than zero, if
 170.981 +     *          start is greater than the length of the input sequence, if
 170.982 +     *          end is greater than the length of the input sequence, or if
 170.983 +     *          start is greater than end.
 170.984 +     * @return  this matcher
 170.985 +     * @since 1.5
 170.986 +     */
 170.987 +    public Matcher region(int start, int end) {
 170.988 +        if ((start < 0) || (start > getTextLength()))
 170.989 +            throw new IndexOutOfBoundsException("start");
 170.990 +        if ((end < 0) || (end > getTextLength()))
 170.991 +            throw new IndexOutOfBoundsException("end");
 170.992 +        if (start > end)
 170.993 +            throw new IndexOutOfBoundsException("start > end");
 170.994 +        reset();
 170.995 +        from = start;
 170.996 +        to = end;
 170.997 +        return this;
 170.998 +    }
 170.999 +
170.1000 +    /**
170.1001 +     * Reports the start index of this matcher's region. The
170.1002 +     * searches this matcher conducts are limited to finding matches
170.1003 +     * within {@link #regionStart regionStart} (inclusive) and
170.1004 +     * {@link #regionEnd regionEnd} (exclusive).
170.1005 +     *
170.1006 +     * @return  The starting point of this matcher's region
170.1007 +     * @since 1.5
170.1008 +     */
170.1009 +    public int regionStart() {
170.1010 +        return from;
170.1011 +    }
170.1012 +
170.1013 +    /**
170.1014 +     * Reports the end index (exclusive) of this matcher's region.
170.1015 +     * The searches this matcher conducts are limited to finding matches
170.1016 +     * within {@link #regionStart regionStart} (inclusive) and
170.1017 +     * {@link #regionEnd regionEnd} (exclusive).
170.1018 +     *
170.1019 +     * @return  the ending point of this matcher's region
170.1020 +     * @since 1.5
170.1021 +     */
170.1022 +    public int regionEnd() {
170.1023 +        return to;
170.1024 +    }
170.1025 +
170.1026 +    /**
170.1027 +     * Queries the transparency of region bounds for this matcher.
170.1028 +     *
170.1029 +     * <p> This method returns <tt>true</tt> if this matcher uses
170.1030 +     * <i>transparent</i> bounds, <tt>false</tt> if it uses <i>opaque</i>
170.1031 +     * bounds.
170.1032 +     *
170.1033 +     * <p> See {@link #useTransparentBounds useTransparentBounds} for a
170.1034 +     * description of transparent and opaque bounds.
170.1035 +     *
170.1036 +     * <p> By default, a matcher uses opaque region boundaries.
170.1037 +     *
170.1038 +     * @return <tt>true</tt> iff this matcher is using transparent bounds,
170.1039 +     *         <tt>false</tt> otherwise.
170.1040 +     * @see java.util.regex.Matcher#useTransparentBounds(boolean)
170.1041 +     * @since 1.5
170.1042 +     */
170.1043 +    public boolean hasTransparentBounds() {
170.1044 +        return transparentBounds;
170.1045 +    }
170.1046 +
170.1047 +    /**
170.1048 +     * Sets the transparency of region bounds for this matcher.
170.1049 +     *
170.1050 +     * <p> Invoking this method with an argument of <tt>true</tt> will set this
170.1051 +     * matcher to use <i>transparent</i> bounds. If the boolean
170.1052 +     * argument is <tt>false</tt>, then <i>opaque</i> bounds will be used.
170.1053 +     *
170.1054 +     * <p> Using transparent bounds, the boundaries of this
170.1055 +     * matcher's region are transparent to lookahead, lookbehind,
170.1056 +     * and boundary matching constructs. Those constructs can see beyond the
170.1057 +     * boundaries of the region to see if a match is appropriate.
170.1058 +     *
170.1059 +     * <p> Using opaque bounds, the boundaries of this matcher's
170.1060 +     * region are opaque to lookahead, lookbehind, and boundary matching
170.1061 +     * constructs that may try to see beyond them. Those constructs cannot
170.1062 +     * look past the boundaries so they will fail to match anything outside
170.1063 +     * of the region.
170.1064 +     *
170.1065 +     * <p> By default, a matcher uses opaque bounds.
170.1066 +     *
170.1067 +     * @param  b a boolean indicating whether to use opaque or transparent
170.1068 +     *         regions
170.1069 +     * @return this matcher
170.1070 +     * @see java.util.regex.Matcher#hasTransparentBounds
170.1071 +     * @since 1.5
170.1072 +     */
170.1073 +    public Matcher useTransparentBounds(boolean b) {
170.1074 +        transparentBounds = b;
170.1075 +        return this;
170.1076 +    }
170.1077 +
170.1078 +    /**
170.1079 +     * Queries the anchoring of region bounds for this matcher.
170.1080 +     *
170.1081 +     * <p> This method returns <tt>true</tt> if this matcher uses
170.1082 +     * <i>anchoring</i> bounds, <tt>false</tt> otherwise.
170.1083 +     *
170.1084 +     * <p> See {@link #useAnchoringBounds useAnchoringBounds} for a
170.1085 +     * description of anchoring bounds.
170.1086 +     *
170.1087 +     * <p> By default, a matcher uses anchoring region boundaries.
170.1088 +     *
170.1089 +     * @return <tt>true</tt> iff this matcher is using anchoring bounds,
170.1090 +     *         <tt>false</tt> otherwise.
170.1091 +     * @see java.util.regex.Matcher#useAnchoringBounds(boolean)
170.1092 +     * @since 1.5
170.1093 +     */
170.1094 +    public boolean hasAnchoringBounds() {
170.1095 +        return anchoringBounds;
170.1096 +    }
170.1097 +
170.1098 +    /**
170.1099 +     * Sets the anchoring of region bounds for this matcher.
170.1100 +     *
170.1101 +     * <p> Invoking this method with an argument of <tt>true</tt> will set this
170.1102 +     * matcher to use <i>anchoring</i> bounds. If the boolean
170.1103 +     * argument is <tt>false</tt>, then <i>non-anchoring</i> bounds will be
170.1104 +     * used.
170.1105 +     *
170.1106 +     * <p> Using anchoring bounds, the boundaries of this
170.1107 +     * matcher's region match anchors such as ^ and $.
170.1108 +     *
170.1109 +     * <p> Without anchoring bounds, the boundaries of this
170.1110 +     * matcher's region will not match anchors such as ^ and $.
170.1111 +     *
170.1112 +     * <p> By default, a matcher uses anchoring region boundaries.
170.1113 +     *
170.1114 +     * @param  b a boolean indicating whether or not to use anchoring bounds.
170.1115 +     * @return this matcher
170.1116 +     * @see java.util.regex.Matcher#hasAnchoringBounds
170.1117 +     * @since 1.5
170.1118 +     */
170.1119 +    public Matcher useAnchoringBounds(boolean b) {
170.1120 +        anchoringBounds = b;
170.1121 +        return this;
170.1122 +    }
170.1123 +
170.1124 +    /**
170.1125 +     * <p>Returns the string representation of this matcher. The
170.1126 +     * string representation of a <code>Matcher</code> contains information
170.1127 +     * that may be useful for debugging. The exact format is unspecified.
170.1128 +     *
170.1129 +     * @return  The string representation of this matcher
170.1130 +     * @since 1.5
170.1131 +     */
170.1132 +    public String toString() {
170.1133 +        StringBuilder sb = new StringBuilder();
170.1134 +        sb.append("java.util.regex.Matcher");
170.1135 +        sb.append("[pattern=" + pattern());
170.1136 +        sb.append(" region=");
170.1137 +        sb.append(regionStart() + "," + regionEnd());
170.1138 +        sb.append(" lastmatch=");
170.1139 +        if ((first >= 0) && (group() != null)) {
170.1140 +            sb.append(group());
170.1141 +        }
170.1142 +        sb.append("]");
170.1143 +        return sb.toString();
170.1144 +    }
170.1145 +
170.1146 +    /**
170.1147 +     * <p>Returns true if the end of input was hit by the search engine in
170.1148 +     * the last match operation performed by this matcher.
170.1149 +     *
170.1150 +     * <p>When this method returns true, then it is possible that more input
170.1151 +     * would have changed the result of the last search.
170.1152 +     *
170.1153 +     * @return  true iff the end of input was hit in the last match; false
170.1154 +     *          otherwise
170.1155 +     * @since 1.5
170.1156 +     */
170.1157 +    public boolean hitEnd() {
170.1158 +        return hitEnd;
170.1159 +    }
170.1160 +
170.1161 +    /**
170.1162 +     * <p>Returns true if more input could change a positive match into a
170.1163 +     * negative one.
170.1164 +     *
170.1165 +     * <p>If this method returns true, and a match was found, then more
170.1166 +     * input could cause the match to be lost. If this method returns false
170.1167 +     * and a match was found, then more input might change the match but the
170.1168 +     * match won't be lost. If a match was not found, then requireEnd has no
170.1169 +     * meaning.
170.1170 +     *
170.1171 +     * @return  true iff more input could change a positive match into a
170.1172 +     *          negative one.
170.1173 +     * @since 1.5
170.1174 +     */
170.1175 +    public boolean requireEnd() {
170.1176 +        return requireEnd;
170.1177 +    }
170.1178 +
170.1179 +    /**
170.1180 +     * Initiates a search to find a Pattern within the given bounds.
170.1181 +     * The groups are filled with default values and the match of the root
170.1182 +     * of the state machine is called. The state machine will hold the state
170.1183 +     * of the match as it proceeds in this matcher.
170.1184 +     *
170.1185 +     * Matcher.from is not set here, because it is the "hard" boundary
170.1186 +     * of the start of the search which anchors will set to. The from param
170.1187 +     * is the "soft" boundary of the start of the search, meaning that the
170.1188 +     * regex tries to match at that index but ^ won't match there. Subsequent
170.1189 +     * calls to the search methods start at a new "soft" boundary which is
170.1190 +     * the end of the previous match.
170.1191 +     */
170.1192 +    boolean search(int from) {
170.1193 +        this.hitEnd = false;
170.1194 +        this.requireEnd = false;
170.1195 +        from        = from < 0 ? 0 : from;
170.1196 +        this.first  = from;
170.1197 +        this.oldLast = oldLast < 0 ? from : oldLast;
170.1198 +        for (int i = 0; i < groups.length; i++)
170.1199 +            groups[i] = -1;
170.1200 +        acceptMode = NOANCHOR;
170.1201 +        boolean result = parentPattern.root.match(this, from, text);
170.1202 +        if (!result)
170.1203 +            this.first = -1;
170.1204 +        this.oldLast = this.last;
170.1205 +        return result;
170.1206 +    }
170.1207 +
170.1208 +    /**
170.1209 +     * Initiates a search for an anchored match to a Pattern within the given
170.1210 +     * bounds. The groups are filled with default values and the match of the
170.1211 +     * root of the state machine is called. The state machine will hold the
170.1212 +     * state of the match as it proceeds in this matcher.
170.1213 +     */
170.1214 +    boolean match(int from, int anchor) {
170.1215 +        this.hitEnd = false;
170.1216 +        this.requireEnd = false;
170.1217 +        from        = from < 0 ? 0 : from;
170.1218 +        this.first  = from;
170.1219 +        this.oldLast = oldLast < 0 ? from : oldLast;
170.1220 +        for (int i = 0; i < groups.length; i++)
170.1221 +            groups[i] = -1;
170.1222 +        acceptMode = anchor;
170.1223 +        boolean result = parentPattern.matchRoot.match(this, from, text);
170.1224 +        if (!result)
170.1225 +            this.first = -1;
170.1226 +        this.oldLast = this.last;
170.1227 +        return result;
170.1228 +    }
170.1229 +
170.1230 +    /**
170.1231 +     * Returns the end index of the text.
170.1232 +     *
170.1233 +     * @return the index after the last character in the text
170.1234 +     */
170.1235 +    int getTextLength() {
170.1236 +        return text.length();
170.1237 +    }
170.1238 +
170.1239 +    /**
170.1240 +     * Generates a String from this Matcher's input in the specified range.
170.1241 +     *
170.1242 +     * @param  beginIndex   the beginning index, inclusive
170.1243 +     * @param  endIndex     the ending index, exclusive
170.1244 +     * @return A String generated from this Matcher's input
170.1245 +     */
170.1246 +    CharSequence getSubSequence(int beginIndex, int endIndex) {
170.1247 +        return text.subSequence(beginIndex, endIndex);
170.1248 +    }
170.1249 +
170.1250 +    /**
170.1251 +     * Returns this Matcher's input character at index i.
170.1252 +     *
170.1253 +     * @return A char from the specified index
170.1254 +     */
170.1255 +    char charAt(int i) {
170.1256 +        return text.charAt(i);
170.1257 +    }
170.1258 +
170.1259 +}
   171.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   171.2 +++ b/rt/emul/compact/src/main/java/java/util/regex/Pattern.java	Tue Feb 11 13:31:42 2014 +0100
   171.3 @@ -0,0 +1,5657 @@
   171.4 +/*
   171.5 + * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
   171.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   171.7 + *
   171.8 + * This code is free software; you can redistribute it and/or modify it
   171.9 + * under the terms of the GNU General Public License version 2 only, as
  171.10 + * published by the Free Software Foundation.  Oracle designates this
  171.11 + * particular file as subject to the "Classpath" exception as provided
  171.12 + * by Oracle in the LICENSE file that accompanied this code.
  171.13 + *
  171.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  171.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  171.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  171.17 + * version 2 for more details (a copy is included in the LICENSE file that
  171.18 + * accompanied this code).
  171.19 + *
  171.20 + * You should have received a copy of the GNU General Public License version
  171.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  171.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  171.23 + *
  171.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  171.25 + * or visit www.oracle.com if you need additional information or have any
  171.26 + * questions.
  171.27 + */
  171.28 +
  171.29 +package java.util.regex;
  171.30 +
  171.31 +import java.util.Locale;
  171.32 +import java.util.Map;
  171.33 +import java.util.ArrayList;
  171.34 +import java.util.HashMap;
  171.35 +import java.util.Arrays;
  171.36 +
  171.37 +
  171.38 +/**
  171.39 + * A compiled representation of a regular expression.
  171.40 + *
  171.41 + * <p> A regular expression, specified as a string, must first be compiled into
  171.42 + * an instance of this class.  The resulting pattern can then be used to create
  171.43 + * a {@link Matcher} object that can match arbitrary {@link
  171.44 + * java.lang.CharSequence </code>character sequences<code>} against the regular
  171.45 + * expression.  All of the state involved in performing a match resides in the
  171.46 + * matcher, so many matchers can share the same pattern.
  171.47 + *
  171.48 + * <p> A typical invocation sequence is thus
  171.49 + *
  171.50 + * <blockquote><pre>
  171.51 + * Pattern p = Pattern.{@link #compile compile}("a*b");
  171.52 + * Matcher m = p.{@link #matcher matcher}("aaaaab");
  171.53 + * boolean b = m.{@link Matcher#matches matches}();</pre></blockquote>
  171.54 + *
  171.55 + * <p> A {@link #matches matches} method is defined by this class as a
  171.56 + * convenience for when a regular expression is used just once.  This method
  171.57 + * compiles an expression and matches an input sequence against it in a single
  171.58 + * invocation.  The statement
  171.59 + *
  171.60 + * <blockquote><pre>
  171.61 + * boolean b = Pattern.matches("a*b", "aaaaab");</pre></blockquote>
  171.62 + *
  171.63 + * is equivalent to the three statements above, though for repeated matches it
  171.64 + * is less efficient since it does not allow the compiled pattern to be reused.
  171.65 + *
  171.66 + * <p> Instances of this class are immutable and are safe for use by multiple
  171.67 + * concurrent threads.  Instances of the {@link Matcher} class are not safe for
  171.68 + * such use.
  171.69 + *
  171.70 + *
  171.71 + * <a name="sum">
  171.72 + * <h4> Summary of regular-expression constructs </h4>
  171.73 + *
  171.74 + * <table border="0" cellpadding="1" cellspacing="0"
  171.75 + *  summary="Regular expression constructs, and what they match">
  171.76 + *
  171.77 + * <tr align="left">
  171.78 + * <th bgcolor="#CCCCFF" align="left" id="construct">Construct</th>
  171.79 + * <th bgcolor="#CCCCFF" align="left" id="matches">Matches</th>
  171.80 + * </tr>
  171.81 + *
  171.82 + * <tr><th>&nbsp;</th></tr>
  171.83 + * <tr align="left"><th colspan="2" id="characters">Characters</th></tr>
  171.84 + *
  171.85 + * <tr><td valign="top" headers="construct characters"><i>x</i></td>
  171.86 + *     <td headers="matches">The character <i>x</i></td></tr>
  171.87 + * <tr><td valign="top" headers="construct characters"><tt>\\</tt></td>
  171.88 + *     <td headers="matches">The backslash character</td></tr>
  171.89 + * <tr><td valign="top" headers="construct characters"><tt>\0</tt><i>n</i></td>
  171.90 + *     <td headers="matches">The character with octal value <tt>0</tt><i>n</i>
  171.91 + *         (0&nbsp;<tt>&lt;=</tt>&nbsp;<i>n</i>&nbsp;<tt>&lt;=</tt>&nbsp;7)</td></tr>
  171.92 + * <tr><td valign="top" headers="construct characters"><tt>\0</tt><i>nn</i></td>
  171.93 + *     <td headers="matches">The character with octal value <tt>0</tt><i>nn</i>
  171.94 + *         (0&nbsp;<tt>&lt;=</tt>&nbsp;<i>n</i>&nbsp;<tt>&lt;=</tt>&nbsp;7)</td></tr>
  171.95 + * <tr><td valign="top" headers="construct characters"><tt>\0</tt><i>mnn</i></td>
  171.96 + *     <td headers="matches">The character with octal value <tt>0</tt><i>mnn</i>
  171.97 + *         (0&nbsp;<tt>&lt;=</tt>&nbsp;<i>m</i>&nbsp;<tt>&lt;=</tt>&nbsp;3,
  171.98 + *         0&nbsp;<tt>&lt;=</tt>&nbsp;<i>n</i>&nbsp;<tt>&lt;=</tt>&nbsp;7)</td></tr>
  171.99 + * <tr><td valign="top" headers="construct characters"><tt>\x</tt><i>hh</i></td>
 171.100 + *     <td headers="matches">The character with hexadecimal&nbsp;value&nbsp;<tt>0x</tt><i>hh</i></td></tr>
 171.101 + * <tr><td valign="top" headers="construct characters"><tt>&#92;u</tt><i>hhhh</i></td>
 171.102 + *     <td headers="matches">The character with hexadecimal&nbsp;value&nbsp;<tt>0x</tt><i>hhhh</i></td></tr>
 171.103 + * <tr><td valign="top" headers="construct characters"><tt>&#92;x</tt><i>{h...h}</i></td>
 171.104 + *     <td headers="matches">The character with hexadecimal&nbsp;value&nbsp;<tt>0x</tt><i>h...h</i>
 171.105 + *         ({@link java.lang.Character#MIN_CODE_POINT Character.MIN_CODE_POINT}
 171.106 + *         &nbsp;&lt;=&nbsp;<tt>0x</tt><i>h...h</i>&nbsp;&lt;=&nbsp
 171.107 + *          {@link java.lang.Character#MAX_CODE_POINT Character.MAX_CODE_POINT})</td></tr>
 171.108 + * <tr><td valign="top" headers="matches"><tt>\t</tt></td>
 171.109 + *     <td headers="matches">The tab character (<tt>'&#92;u0009'</tt>)</td></tr>
 171.110 + * <tr><td valign="top" headers="construct characters"><tt>\n</tt></td>
 171.111 + *     <td headers="matches">The newline (line feed) character (<tt>'&#92;u000A'</tt>)</td></tr>
 171.112 + * <tr><td valign="top" headers="construct characters"><tt>\r</tt></td>
 171.113 + *     <td headers="matches">The carriage-return character (<tt>'&#92;u000D'</tt>)</td></tr>
 171.114 + * <tr><td valign="top" headers="construct characters"><tt>\f</tt></td>
 171.115 + *     <td headers="matches">The form-feed character (<tt>'&#92;u000C'</tt>)</td></tr>
 171.116 + * <tr><td valign="top" headers="construct characters"><tt>\a</tt></td>
 171.117 + *     <td headers="matches">The alert (bell) character (<tt>'&#92;u0007'</tt>)</td></tr>
 171.118 + * <tr><td valign="top" headers="construct characters"><tt>\e</tt></td>
 171.119 + *     <td headers="matches">The escape character (<tt>'&#92;u001B'</tt>)</td></tr>
 171.120 + * <tr><td valign="top" headers="construct characters"><tt>\c</tt><i>x</i></td>
 171.121 + *     <td headers="matches">The control character corresponding to <i>x</i></td></tr>
 171.122 + *
 171.123 + * <tr><th>&nbsp;</th></tr>
 171.124 + * <tr align="left"><th colspan="2" id="classes">Character classes</th></tr>
 171.125 + *
 171.126 + * <tr><td valign="top" headers="construct classes"><tt>[abc]</tt></td>
 171.127 + *     <td headers="matches"><tt>a</tt>, <tt>b</tt>, or <tt>c</tt> (simple class)</td></tr>
 171.128 + * <tr><td valign="top" headers="construct classes"><tt>[^abc]</tt></td>
 171.129 + *     <td headers="matches">Any character except <tt>a</tt>, <tt>b</tt>, or <tt>c</tt> (negation)</td></tr>
 171.130 + * <tr><td valign="top" headers="construct classes"><tt>[a-zA-Z]</tt></td>
 171.131 + *     <td headers="matches"><tt>a</tt> through <tt>z</tt>
 171.132 + *         or <tt>A</tt> through <tt>Z</tt>, inclusive (range)</td></tr>
 171.133 + * <tr><td valign="top" headers="construct classes"><tt>[a-d[m-p]]</tt></td>
 171.134 + *     <td headers="matches"><tt>a</tt> through <tt>d</tt>,
 171.135 + *      or <tt>m</tt> through <tt>p</tt>: <tt>[a-dm-p]</tt> (union)</td></tr>
 171.136 + * <tr><td valign="top" headers="construct classes"><tt>[a-z&&[def]]</tt></td>
 171.137 + *     <td headers="matches"><tt>d</tt>, <tt>e</tt>, or <tt>f</tt> (intersection)</tr>
 171.138 + * <tr><td valign="top" headers="construct classes"><tt>[a-z&&[^bc]]</tt></td>
 171.139 + *     <td headers="matches"><tt>a</tt> through <tt>z</tt>,
 171.140 + *         except for <tt>b</tt> and <tt>c</tt>: <tt>[ad-z]</tt> (subtraction)</td></tr>
 171.141 + * <tr><td valign="top" headers="construct classes"><tt>[a-z&&[^m-p]]</tt></td>
 171.142 + *     <td headers="matches"><tt>a</tt> through <tt>z</tt>,
 171.143 + *          and not <tt>m</tt> through <tt>p</tt>: <tt>[a-lq-z]</tt>(subtraction)</td></tr>
 171.144 + * <tr><th>&nbsp;</th></tr>
 171.145 + *
 171.146 + * <tr align="left"><th colspan="2" id="predef">Predefined character classes</th></tr>
 171.147 + *
 171.148 + * <tr><td valign="top" headers="construct predef"><tt>.</tt></td>
 171.149 + *     <td headers="matches">Any character (may or may not match <a href="#lt">line terminators</a>)</td></tr>
 171.150 + * <tr><td valign="top" headers="construct predef"><tt>\d</tt></td>
 171.151 + *     <td headers="matches">A digit: <tt>[0-9]</tt></td></tr>
 171.152 + * <tr><td valign="top" headers="construct predef"><tt>\D</tt></td>
 171.153 + *     <td headers="matches">A non-digit: <tt>[^0-9]</tt></td></tr>
 171.154 + * <tr><td valign="top" headers="construct predef"><tt>\s</tt></td>
 171.155 + *     <td headers="matches">A whitespace character: <tt>[ \t\n\x0B\f\r]</tt></td></tr>
 171.156 + * <tr><td valign="top" headers="construct predef"><tt>\S</tt></td>
 171.157 + *     <td headers="matches">A non-whitespace character: <tt>[^\s]</tt></td></tr>
 171.158 + * <tr><td valign="top" headers="construct predef"><tt>\w</tt></td>
 171.159 + *     <td headers="matches">A word character: <tt>[a-zA-Z_0-9]</tt></td></tr>
 171.160 + * <tr><td valign="top" headers="construct predef"><tt>\W</tt></td>
 171.161 + *     <td headers="matches">A non-word character: <tt>[^\w]</tt></td></tr>
 171.162 + *
 171.163 + * <tr><th>&nbsp;</th></tr>
 171.164 + * <tr align="left"><th colspan="2" id="posix">POSIX character classes</b> (US-ASCII only)<b></th></tr>
 171.165 + *
 171.166 + * <tr><td valign="top" headers="construct posix"><tt>\p{Lower}</tt></td>
 171.167 + *     <td headers="matches">A lower-case alphabetic character: <tt>[a-z]</tt></td></tr>
 171.168 + * <tr><td valign="top" headers="construct posix"><tt>\p{Upper}</tt></td>
 171.169 + *     <td headers="matches">An upper-case alphabetic character:<tt>[A-Z]</tt></td></tr>
 171.170 + * <tr><td valign="top" headers="construct posix"><tt>\p{ASCII}</tt></td>
 171.171 + *     <td headers="matches">All ASCII:<tt>[\x00-\x7F]</tt></td></tr>
 171.172 + * <tr><td valign="top" headers="construct posix"><tt>\p{Alpha}</tt></td>
 171.173 + *     <td headers="matches">An alphabetic character:<tt>[\p{Lower}\p{Upper}]</tt></td></tr>
 171.174 + * <tr><td valign="top" headers="construct posix"><tt>\p{Digit}</tt></td>
 171.175 + *     <td headers="matches">A decimal digit: <tt>[0-9]</tt></td></tr>
 171.176 + * <tr><td valign="top" headers="construct posix"><tt>\p{Alnum}</tt></td>
 171.177 + *     <td headers="matches">An alphanumeric character:<tt>[\p{Alpha}\p{Digit}]</tt></td></tr>
 171.178 + * <tr><td valign="top" headers="construct posix"><tt>\p{Punct}</tt></td>
 171.179 + *     <td headers="matches">Punctuation: One of <tt>!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~</tt></td></tr>
 171.180 + *     <!-- <tt>[\!"#\$%&'\(\)\*\+,\-\./:;\<=\>\?@\[\\\]\^_`\{\|\}~]</tt>
 171.181 + *          <tt>[\X21-\X2F\X31-\X40\X5B-\X60\X7B-\X7E]</tt> -->
 171.182 + * <tr><td valign="top" headers="construct posix"><tt>\p{Graph}</tt></td>
 171.183 + *     <td headers="matches">A visible character: <tt>[\p{Alnum}\p{Punct}]</tt></td></tr>
 171.184 + * <tr><td valign="top" headers="construct posix"><tt>\p{Print}</tt></td>
 171.185 + *     <td headers="matches">A printable character: <tt>[\p{Graph}\x20]</tt></td></tr>
 171.186 + * <tr><td valign="top" headers="construct posix"><tt>\p{Blank}</tt></td>
 171.187 + *     <td headers="matches">A space or a tab: <tt>[ \t]</tt></td></tr>
 171.188 + * <tr><td valign="top" headers="construct posix"><tt>\p{Cntrl}</tt></td>
 171.189 + *     <td headers="matches">A control character: <tt>[\x00-\x1F\x7F]</tt></td></tr>
 171.190 + * <tr><td valign="top" headers="construct posix"><tt>\p{XDigit}</tt></td>
 171.191 + *     <td headers="matches">A hexadecimal digit: <tt>[0-9a-fA-F]</tt></td></tr>
 171.192 + * <tr><td valign="top" headers="construct posix"><tt>\p{Space}</tt></td>
 171.193 + *     <td headers="matches">A whitespace character: <tt>[ \t\n\x0B\f\r]</tt></td></tr>
 171.194 + *
 171.195 + * <tr><th>&nbsp;</th></tr>
 171.196 + * <tr align="left"><th colspan="2">java.lang.Character classes (simple <a href="#jcc">java character type</a>)</th></tr>
 171.197 + *
 171.198 + * <tr><td valign="top"><tt>\p{javaLowerCase}</tt></td>
 171.199 + *     <td>Equivalent to java.lang.Character.isLowerCase()</td></tr>
 171.200 + * <tr><td valign="top"><tt>\p{javaUpperCase}</tt></td>
 171.201 + *     <td>Equivalent to java.lang.Character.isUpperCase()</td></tr>
 171.202 + * <tr><td valign="top"><tt>\p{javaWhitespace}</tt></td>
 171.203 + *     <td>Equivalent to java.lang.Character.isWhitespace()</td></tr>
 171.204 + * <tr><td valign="top"><tt>\p{javaMirrored}</tt></td>
 171.205 + *     <td>Equivalent to java.lang.Character.isMirrored()</td></tr>
 171.206 + *
 171.207 + * <tr><th>&nbsp;</th></tr>
 171.208 + * <tr align="left"><th colspan="2" id="unicode">Classes for Unicode scripts, blocks, categories and binary properties</th></tr>
 171.209 + * * <tr><td valign="top" headers="construct unicode"><tt>\p{IsLatin}</tt></td>
 171.210 + *     <td headers="matches">A Latin&nbsp;script character (<a href="#usc">script</a>)</td></tr>
 171.211 + * <tr><td valign="top" headers="construct unicode"><tt>\p{InGreek}</tt></td>
 171.212 + *     <td headers="matches">A character in the Greek&nbsp;block (<a href="#ubc">block</a>)</td></tr>
 171.213 + * <tr><td valign="top" headers="construct unicode"><tt>\p{Lu}</tt></td>
 171.214 + *     <td headers="matches">An uppercase letter (<a href="#ucc">category</a>)</td></tr>
 171.215 + * <tr><td valign="top" headers="construct unicode"><tt>\p{IsAlphabetic}</tt></td>
 171.216 + *     <td headers="matches">An alphabetic character (<a href="#ubpc">binary property</a>)</td></tr>
 171.217 + * <tr><td valign="top" headers="construct unicode"><tt>\p{Sc}</tt></td>
 171.218 + *     <td headers="matches">A currency symbol</td></tr>
 171.219 + * <tr><td valign="top" headers="construct unicode"><tt>\P{InGreek}</tt></td>
 171.220 + *     <td headers="matches">Any character except one in the Greek block (negation)</td></tr>
 171.221 + * <tr><td valign="top" headers="construct unicode"><tt>[\p{L}&&[^\p{Lu}]]&nbsp;</tt></td>
 171.222 + *     <td headers="matches">Any letter except an uppercase letter (subtraction)</td></tr>
 171.223 + *
 171.224 + * <tr><th>&nbsp;</th></tr>
 171.225 + * <tr align="left"><th colspan="2" id="bounds">Boundary matchers</th></tr>
 171.226 + *
 171.227 + * <tr><td valign="top" headers="construct bounds"><tt>^</tt></td>
 171.228 + *     <td headers="matches">The beginning of a line</td></tr>
 171.229 + * <tr><td valign="top" headers="construct bounds"><tt>$</tt></td>
 171.230 + *     <td headers="matches">The end of a line</td></tr>
 171.231 + * <tr><td valign="top" headers="construct bounds"><tt>\b</tt></td>
 171.232 + *     <td headers="matches">A word boundary</td></tr>
 171.233 + * <tr><td valign="top" headers="construct bounds"><tt>\B</tt></td>
 171.234 + *     <td headers="matches">A non-word boundary</td></tr>
 171.235 + * <tr><td valign="top" headers="construct bounds"><tt>\A</tt></td>
 171.236 + *     <td headers="matches">The beginning of the input</td></tr>
 171.237 + * <tr><td valign="top" headers="construct bounds"><tt>\G</tt></td>
 171.238 + *     <td headers="matches">The end of the previous match</td></tr>
 171.239 + * <tr><td valign="top" headers="construct bounds"><tt>\Z</tt></td>
 171.240 + *     <td headers="matches">The end of the input but for the final
 171.241 + *         <a href="#lt">terminator</a>, if&nbsp;any</td></tr>
 171.242 + * <tr><td valign="top" headers="construct bounds"><tt>\z</tt></td>
 171.243 + *     <td headers="matches">The end of the input</td></tr>
 171.244 + *
 171.245 + * <tr><th>&nbsp;</th></tr>
 171.246 + * <tr align="left"><th colspan="2" id="greedy">Greedy quantifiers</th></tr>
 171.247 + *
 171.248 + * <tr><td valign="top" headers="construct greedy"><i>X</i><tt>?</tt></td>
 171.249 + *     <td headers="matches"><i>X</i>, once or not at all</td></tr>
 171.250 + * <tr><td valign="top" headers="construct greedy"><i>X</i><tt>*</tt></td>
 171.251 + *     <td headers="matches"><i>X</i>, zero or more times</td></tr>
 171.252 + * <tr><td valign="top" headers="construct greedy"><i>X</i><tt>+</tt></td>
 171.253 + *     <td headers="matches"><i>X</i>, one or more times</td></tr>
 171.254 + * <tr><td valign="top" headers="construct greedy"><i>X</i><tt>{</tt><i>n</i><tt>}</tt></td>
 171.255 + *     <td headers="matches"><i>X</i>, exactly <i>n</i> times</td></tr>
 171.256 + * <tr><td valign="top" headers="construct greedy"><i>X</i><tt>{</tt><i>n</i><tt>,}</tt></td>
 171.257 + *     <td headers="matches"><i>X</i>, at least <i>n</i> times</td></tr>
 171.258 + * <tr><td valign="top" headers="construct greedy"><i>X</i><tt>{</tt><i>n</i><tt>,</tt><i>m</i><tt>}</tt></td>
 171.259 + *     <td headers="matches"><i>X</i>, at least <i>n</i> but not more than <i>m</i> times</td></tr>
 171.260 + *
 171.261 + * <tr><th>&nbsp;</th></tr>
 171.262 + * <tr align="left"><th colspan="2" id="reluc">Reluctant quantifiers</th></tr>
 171.263 + *
 171.264 + * <tr><td valign="top" headers="construct reluc"><i>X</i><tt>??</tt></td>
 171.265 + *     <td headers="matches"><i>X</i>, once or not at all</td></tr>
 171.266 + * <tr><td valign="top" headers="construct reluc"><i>X</i><tt>*?</tt></td>
 171.267 + *     <td headers="matches"><i>X</i>, zero or more times</td></tr>
 171.268 + * <tr><td valign="top" headers="construct reluc"><i>X</i><tt>+?</tt></td>
 171.269 + *     <td headers="matches"><i>X</i>, one or more times</td></tr>
 171.270 + * <tr><td valign="top" headers="construct reluc"><i>X</i><tt>{</tt><i>n</i><tt>}?</tt></td>
 171.271 + *     <td headers="matches"><i>X</i>, exactly <i>n</i> times</td></tr>
 171.272 + * <tr><td valign="top" headers="construct reluc"><i>X</i><tt>{</tt><i>n</i><tt>,}?</tt></td>
 171.273 + *     <td headers="matches"><i>X</i>, at least <i>n</i> times</td></tr>
 171.274 + * <tr><td valign="top" headers="construct reluc"><i>X</i><tt>{</tt><i>n</i><tt>,</tt><i>m</i><tt>}?</tt></td>
 171.275 + *     <td headers="matches"><i>X</i>, at least <i>n</i> but not more than <i>m</i> times</td></tr>
 171.276 + *
 171.277 + * <tr><th>&nbsp;</th></tr>
 171.278 + * <tr align="left"><th colspan="2" id="poss">Possessive quantifiers</th></tr>
 171.279 + *
 171.280 + * <tr><td valign="top" headers="construct poss"><i>X</i><tt>?+</tt></td>
 171.281 + *     <td headers="matches"><i>X</i>, once or not at all</td></tr>
 171.282 + * <tr><td valign="top" headers="construct poss"><i>X</i><tt>*+</tt></td>
 171.283 + *     <td headers="matches"><i>X</i>, zero or more times</td></tr>
 171.284 + * <tr><td valign="top" headers="construct poss"><i>X</i><tt>++</tt></td>
 171.285 + *     <td headers="matches"><i>X</i>, one or more times</td></tr>
 171.286 + * <tr><td valign="top" headers="construct poss"><i>X</i><tt>{</tt><i>n</i><tt>}+</tt></td>
 171.287 + *     <td headers="matches"><i>X</i>, exactly <i>n</i> times</td></tr>
 171.288 + * <tr><td valign="top" headers="construct poss"><i>X</i><tt>{</tt><i>n</i><tt>,}+</tt></td>
 171.289 + *     <td headers="matches"><i>X</i>, at least <i>n</i> times</td></tr>
 171.290 + * <tr><td valign="top" headers="construct poss"><i>X</i><tt>{</tt><i>n</i><tt>,</tt><i>m</i><tt>}+</tt></td>
 171.291 + *     <td headers="matches"><i>X</i>, at least <i>n</i> but not more than <i>m</i> times</td></tr>
 171.292 + *
 171.293 + * <tr><th>&nbsp;</th></tr>
 171.294 + * <tr align="left"><th colspan="2" id="logical">Logical operators</th></tr>
 171.295 + *
 171.296 + * <tr><td valign="top" headers="construct logical"><i>XY</i></td>
 171.297 + *     <td headers="matches"><i>X</i> followed by <i>Y</i></td></tr>
 171.298 + * <tr><td valign="top" headers="construct logical"><i>X</i><tt>|</tt><i>Y</i></td>
 171.299 + *     <td headers="matches">Either <i>X</i> or <i>Y</i></td></tr>
 171.300 + * <tr><td valign="top" headers="construct logical"><tt>(</tt><i>X</i><tt>)</tt></td>
 171.301 + *     <td headers="matches">X, as a <a href="#cg">capturing group</a></td></tr>
 171.302 + *
 171.303 + * <tr><th>&nbsp;</th></tr>
 171.304 + * <tr align="left"><th colspan="2" id="backref">Back references</th></tr>
 171.305 + *
 171.306 + * <tr><td valign="bottom" headers="construct backref"><tt>\</tt><i>n</i></td>
 171.307 + *     <td valign="bottom" headers="matches">Whatever the <i>n</i><sup>th</sup>
 171.308 + *     <a href="#cg">capturing group</a> matched</td></tr>
 171.309 + *
 171.310 + * <tr><td valign="bottom" headers="construct backref"><tt>\</tt><i>k</i>&lt;<i>name</i>&gt;</td>
 171.311 + *     <td valign="bottom" headers="matches">Whatever the
 171.312 + *     <a href="#groupname">named-capturing group</a> "name" matched</td></tr>
 171.313 + *
 171.314 + * <tr><th>&nbsp;</th></tr>
 171.315 + * <tr align="left"><th colspan="2" id="quot">Quotation</th></tr>
 171.316 + *
 171.317 + * <tr><td valign="top" headers="construct quot"><tt>\</tt></td>
 171.318 + *     <td headers="matches">Nothing, but quotes the following character</td></tr>
 171.319 + * <tr><td valign="top" headers="construct quot"><tt>\Q</tt></td>
 171.320 + *     <td headers="matches">Nothing, but quotes all characters until <tt>\E</tt></td></tr>
 171.321 + * <tr><td valign="top" headers="construct quot"><tt>\E</tt></td>
 171.322 + *     <td headers="matches">Nothing, but ends quoting started by <tt>\Q</tt></td></tr>
 171.323 + *     <!-- Metachars: !$()*+.<>?[\]^{|} -->
 171.324 + *
 171.325 + * <tr><th>&nbsp;</th></tr>
 171.326 + * <tr align="left"><th colspan="2" id="special">Special constructs (named-capturing and non-capturing)</th></tr>
 171.327 + *
 171.328 + * <tr><td valign="top" headers="construct special"><tt>(?&lt;<a href="#groupname">name</a>&gt;</tt><i>X</i><tt>)</tt></td>
 171.329 + *     <td headers="matches"><i>X</i>, as a named-capturing group</td></tr>
 171.330 + * <tr><td valign="top" headers="construct special"><tt>(?:</tt><i>X</i><tt>)</tt></td>
 171.331 + *     <td headers="matches"><i>X</i>, as a non-capturing group</td></tr>
 171.332 + * <tr><td valign="top" headers="construct special"><tt>(?idmsuxU-idmsuxU)&nbsp;</tt></td>
 171.333 + *     <td headers="matches">Nothing, but turns match flags <a href="#CASE_INSENSITIVE">i</a>
 171.334 + * <a href="#UNIX_LINES">d</a> <a href="#MULTILINE">m</a> <a href="#DOTALL">s</a>
 171.335 + * <a href="#UNICODE_CASE">u</a> <a href="#COMMENTS">x</a> <a href="#UNICODE_CHARACTER_CLASS">U</a>
 171.336 + * on - off</td></tr>
 171.337 + * <tr><td valign="top" headers="construct special"><tt>(?idmsux-idmsux:</tt><i>X</i><tt>)</tt>&nbsp;&nbsp;</td>
 171.338 + *     <td headers="matches"><i>X</i>, as a <a href="#cg">non-capturing group</a> with the
 171.339 + *         given flags <a href="#CASE_INSENSITIVE">i</a> <a href="#UNIX_LINES">d</a>
 171.340 + * <a href="#MULTILINE">m</a> <a href="#DOTALL">s</a> <a href="#UNICODE_CASE">u</a >
 171.341 + * <a href="#COMMENTS">x</a> on - off</td></tr>
 171.342 + * <tr><td valign="top" headers="construct special"><tt>(?=</tt><i>X</i><tt>)</tt></td>
 171.343 + *     <td headers="matches"><i>X</i>, via zero-width positive lookahead</td></tr>
 171.344 + * <tr><td valign="top" headers="construct special"><tt>(?!</tt><i>X</i><tt>)</tt></td>
 171.345 + *     <td headers="matches"><i>X</i>, via zero-width negative lookahead</td></tr>
 171.346 + * <tr><td valign="top" headers="construct special"><tt>(?&lt;=</tt><i>X</i><tt>)</tt></td>
 171.347 + *     <td headers="matches"><i>X</i>, via zero-width positive lookbehind</td></tr>
 171.348 + * <tr><td valign="top" headers="construct special"><tt>(?&lt;!</tt><i>X</i><tt>)</tt></td>
 171.349 + *     <td headers="matches"><i>X</i>, via zero-width negative lookbehind</td></tr>
 171.350 + * <tr><td valign="top" headers="construct special"><tt>(?&gt;</tt><i>X</i><tt>)</tt></td>
 171.351 + *     <td headers="matches"><i>X</i>, as an independent, non-capturing group</td></tr>
 171.352 + *
 171.353 + * </table>
 171.354 + *
 171.355 + * <hr>
 171.356 + *
 171.357 + *
 171.358 + * <a name="bs">
 171.359 + * <h4> Backslashes, escapes, and quoting </h4>
 171.360 + *
 171.361 + * <p> The backslash character (<tt>'\'</tt>) serves to introduce escaped
 171.362 + * constructs, as defined in the table above, as well as to quote characters
 171.363 + * that otherwise would be interpreted as unescaped constructs.  Thus the
 171.364 + * expression <tt>\\</tt> matches a single backslash and <tt>\{</tt> matches a
 171.365 + * left brace.
 171.366 + *
 171.367 + * <p> It is an error to use a backslash prior to any alphabetic character that
 171.368 + * does not denote an escaped construct; these are reserved for future
 171.369 + * extensions to the regular-expression language.  A backslash may be used
 171.370 + * prior to a non-alphabetic character regardless of whether that character is
 171.371 + * part of an unescaped construct.
 171.372 + *
 171.373 + * <p> Backslashes within string literals in Java source code are interpreted
 171.374 + * as required by
 171.375 + * <cite>The Java&trade; Language Specification</cite>
 171.376 + * as either Unicode escapes (section 3.3) or other character escapes (section 3.10.6)
 171.377 + * It is therefore necessary to double backslashes in string
 171.378 + * literals that represent regular expressions to protect them from
 171.379 + * interpretation by the Java bytecode compiler.  The string literal
 171.380 + * <tt>"&#92;b"</tt>, for example, matches a single backspace character when
 171.381 + * interpreted as a regular expression, while <tt>"&#92;&#92;b"</tt> matches a
 171.382 + * word boundary.  The string literal <tt>"&#92;(hello&#92;)"</tt> is illegal
 171.383 + * and leads to a compile-time error; in order to match the string
 171.384 + * <tt>(hello)</tt> the string literal <tt>"&#92;&#92;(hello&#92;&#92;)"</tt>
 171.385 + * must be used.
 171.386 + *
 171.387 + * <a name="cc">
 171.388 + * <h4> Character Classes </h4>
 171.389 + *
 171.390 + *    <p> Character classes may appear within other character classes, and
 171.391 + *    may be composed by the union operator (implicit) and the intersection
 171.392 + *    operator (<tt>&amp;&amp;</tt>).
 171.393 + *    The union operator denotes a class that contains every character that is
 171.394 + *    in at least one of its operand classes.  The intersection operator
 171.395 + *    denotes a class that contains every character that is in both of its
 171.396 + *    operand classes.
 171.397 + *
 171.398 + *    <p> The precedence of character-class operators is as follows, from
 171.399 + *    highest to lowest:
 171.400 + *
 171.401 + *    <blockquote><table border="0" cellpadding="1" cellspacing="0"
 171.402 + *                 summary="Precedence of character class operators.">
 171.403 + *      <tr><th>1&nbsp;&nbsp;&nbsp;&nbsp;</th>
 171.404 + *        <td>Literal escape&nbsp;&nbsp;&nbsp;&nbsp;</td>
 171.405 + *        <td><tt>\x</tt></td></tr>
 171.406 + *     <tr><th>2&nbsp;&nbsp;&nbsp;&nbsp;</th>
 171.407 + *        <td>Grouping</td>
 171.408 + *        <td><tt>[...]</tt></td></tr>
 171.409 + *     <tr><th>3&nbsp;&nbsp;&nbsp;&nbsp;</th>
 171.410 + *        <td>Range</td>
 171.411 + *        <td><tt>a-z</tt></td></tr>
 171.412 + *      <tr><th>4&nbsp;&nbsp;&nbsp;&nbsp;</th>
 171.413 + *        <td>Union</td>
 171.414 + *        <td><tt>[a-e][i-u]</tt></td></tr>
 171.415 + *      <tr><th>5&nbsp;&nbsp;&nbsp;&nbsp;</th>
 171.416 + *        <td>Intersection</td>
 171.417 + *        <td><tt>[a-z&&[aeiou]]</tt></td></tr>
 171.418 + *    </table></blockquote>
 171.419 + *
 171.420 + *    <p> Note that a different set of metacharacters are in effect inside
 171.421 + *    a character class than outside a character class. For instance, the
 171.422 + *    regular expression <tt>.</tt> loses its special meaning inside a
 171.423 + *    character class, while the expression <tt>-</tt> becomes a range
 171.424 + *    forming metacharacter.
 171.425 + *
 171.426 + * <a name="lt">
 171.427 + * <h4> Line terminators </h4>
 171.428 + *
 171.429 + * <p> A <i>line terminator</i> is a one- or two-character sequence that marks
 171.430 + * the end of a line of the input character sequence.  The following are
 171.431 + * recognized as line terminators:
 171.432 + *
 171.433 + * <ul>
 171.434 + *
 171.435 + *   <li> A newline (line feed) character&nbsp;(<tt>'\n'</tt>),
 171.436 + *
 171.437 + *   <li> A carriage-return character followed immediately by a newline
 171.438 + *   character&nbsp;(<tt>"\r\n"</tt>),
 171.439 + *
 171.440 + *   <li> A standalone carriage-return character&nbsp;(<tt>'\r'</tt>),
 171.441 + *
 171.442 + *   <li> A next-line character&nbsp;(<tt>'&#92;u0085'</tt>),
 171.443 + *
 171.444 + *   <li> A line-separator character&nbsp;(<tt>'&#92;u2028'</tt>), or
 171.445 + *
 171.446 + *   <li> A paragraph-separator character&nbsp;(<tt>'&#92;u2029</tt>).
 171.447 + *
 171.448 + * </ul>
 171.449 + * <p>If {@link #UNIX_LINES} mode is activated, then the only line terminators
 171.450 + * recognized are newline characters.
 171.451 + *
 171.452 + * <p> The regular expression <tt>.</tt> matches any character except a line
 171.453 + * terminator unless the {@link #DOTALL} flag is specified.
 171.454 + *
 171.455 + * <p> By default, the regular expressions <tt>^</tt> and <tt>$</tt> ignore
 171.456 + * line terminators and only match at the beginning and the end, respectively,
 171.457 + * of the entire input sequence. If {@link #MULTILINE} mode is activated then
 171.458 + * <tt>^</tt> matches at the beginning of input and after any line terminator
 171.459 + * except at the end of input. When in {@link #MULTILINE} mode <tt>$</tt>
 171.460 + * matches just before a line terminator or the end of the input sequence.
 171.461 + *
 171.462 + * <a name="cg">
 171.463 + * <h4> Groups and capturing </h4>
 171.464 + *
 171.465 + * <a name="gnumber">
 171.466 + * <h5> Group number </h5>
 171.467 + * <p> Capturing groups are numbered by counting their opening parentheses from
 171.468 + * left to right.  In the expression <tt>((A)(B(C)))</tt>, for example, there
 171.469 + * are four such groups: </p>
 171.470 + *
 171.471 + * <blockquote><table cellpadding=1 cellspacing=0 summary="Capturing group numberings">
 171.472 + * <tr><th>1&nbsp;&nbsp;&nbsp;&nbsp;</th>
 171.473 + *     <td><tt>((A)(B(C)))</tt></td></tr>
 171.474 + * <tr><th>2&nbsp;&nbsp;&nbsp;&nbsp;</th>
 171.475 + *     <td><tt>(A)</tt></td></tr>
 171.476 + * <tr><th>3&nbsp;&nbsp;&nbsp;&nbsp;</th>
 171.477 + *     <td><tt>(B(C))</tt></td></tr>
 171.478 + * <tr><th>4&nbsp;&nbsp;&nbsp;&nbsp;</th>
 171.479 + *     <td><tt>(C)</tt></td></tr>
 171.480 + * </table></blockquote>
 171.481 + *
 171.482 + * <p> Group zero always stands for the entire expression.
 171.483 + *
 171.484 + * <p> Capturing groups are so named because, during a match, each subsequence
 171.485 + * of the input sequence that matches such a group is saved.  The captured
 171.486 + * subsequence may be used later in the expression, via a back reference, and
 171.487 + * may also be retrieved from the matcher once the match operation is complete.
 171.488 + *
 171.489 + * <a name="groupname">
 171.490 + * <h5> Group name </h5>
 171.491 + * <p>A capturing group can also be assigned a "name", a <tt>named-capturing group</tt>,
 171.492 + * and then be back-referenced later by the "name". Group names are composed of
 171.493 + * the following characters. The first character must be a <tt>letter</tt>.
 171.494 + *
 171.495 + * <ul>
 171.496 + *   <li> The uppercase letters <tt>'A'</tt> through <tt>'Z'</tt>
 171.497 + *        (<tt>'&#92;u0041'</tt>&nbsp;through&nbsp;<tt>'&#92;u005a'</tt>),
 171.498 + *   <li> The lowercase letters <tt>'a'</tt> through <tt>'z'</tt>
 171.499 + *        (<tt>'&#92;u0061'</tt>&nbsp;through&nbsp;<tt>'&#92;u007a'</tt>),
 171.500 + *   <li> The digits <tt>'0'</tt> through <tt>'9'</tt>
 171.501 + *        (<tt>'&#92;u0030'</tt>&nbsp;through&nbsp;<tt>'&#92;u0039'</tt>),
 171.502 + * </ul>
 171.503 + *
 171.504 + * <p> A <tt>named-capturing group</tt> is still numbered as described in
 171.505 + * <a href="#gnumber">Group number</a>.
 171.506 + *
 171.507 + * <p> The captured input associated with a group is always the subsequence
 171.508 + * that the group most recently matched.  If a group is evaluated a second time
 171.509 + * because of quantification then its previously-captured value, if any, will
 171.510 + * be retained if the second evaluation fails.  Matching the string
 171.511 + * <tt>"aba"</tt> against the expression <tt>(a(b)?)+</tt>, for example, leaves
 171.512 + * group two set to <tt>"b"</tt>.  All captured input is discarded at the
 171.513 + * beginning of each match.
 171.514 + *
 171.515 + * <p> Groups beginning with <tt>(?</tt> are either pure, <i>non-capturing</i> groups
 171.516 + * that do not capture text and do not count towards the group total, or
 171.517 + * <i>named-capturing</i> group.
 171.518 + *
 171.519 + * <h4> Unicode support </h4>
 171.520 + *
 171.521 + * <p> This class is in conformance with Level 1 of <a
 171.522 + * href="http://www.unicode.org/reports/tr18/"><i>Unicode Technical
 171.523 + * Standard #18: Unicode Regular Expression</i></a>, plus RL2.1
 171.524 + * Canonical Equivalents.
 171.525 + * <p>
 171.526 + * <b>Unicode escape sequences</b> such as <tt>&#92;u2014</tt> in Java source code
 171.527 + * are processed as described in section 3.3 of
 171.528 + * <cite>The Java&trade; Language Specification</cite>.
 171.529 + * Such escape sequences are also implemented directly by the regular-expression
 171.530 + * parser so that Unicode escapes can be used in expressions that are read from
 171.531 + * files or from the keyboard.  Thus the strings <tt>"&#92;u2014"</tt> and
 171.532 + * <tt>"\\u2014"</tt>, while not equal, compile into the same pattern, which
 171.533 + * matches the character with hexadecimal value <tt>0x2014</tt>.
 171.534 + * <p>
 171.535 + * A Unicode character can also be represented in a regular-expression by
 171.536 + * using its <b>Hex notation</b>(hexadecimal code point value) directly as described in construct
 171.537 + * <tt>&#92;x{...}</tt>, for example a supplementary character U+2011F
 171.538 + * can be specified as <tt>&#92;x{2011F}</tt>, instead of two consecutive
 171.539 + * Unicode escape sequences of the surrogate pair
 171.540 + * <tt>&#92;uD840</tt><tt>&#92;uDD1F</tt>.
 171.541 + * <p>
 171.542 + * Unicode scripts, blocks, categories and binary properties are written with
 171.543 + * the <tt>\p</tt> and <tt>\P</tt> constructs as in Perl.
 171.544 + * <tt>\p{</tt><i>prop</i><tt>}</tt> matches if
 171.545 + * the input has the property <i>prop</i>, while <tt>\P{</tt><i>prop</i><tt>}</tt>
 171.546 + * does not match if the input has that property.
 171.547 + * <p>
 171.548 + * Scripts, blocks, categories and binary properties can be used both inside
 171.549 + * and outside of a character class.
 171.550 + * <a name="usc">
 171.551 + * <p>
 171.552 + * <b>Scripts</b> are specified either with the prefix {@code Is}, as in
 171.553 + * {@code IsHiragana}, or by using  the {@code script} keyword (or its short
 171.554 + * form {@code sc})as in {@code script=Hiragana} or {@code sc=Hiragana}.
 171.555 + * <p>
 171.556 + * The script names supported by <code>Pattern</code> are the valid script names
 171.557 + * accepted and defined by
 171.558 + * {@link java.lang.Character.UnicodeScript#forName(String) UnicodeScript.forName}.
 171.559 + * <a name="ubc">
 171.560 + * <p>
 171.561 + * <b>Blocks</b> are specified with the prefix {@code In}, as in
 171.562 + * {@code InMongolian}, or by using the keyword {@code block} (or its short
 171.563 + * form {@code blk}) as in {@code block=Mongolian} or {@code blk=Mongolian}.
 171.564 + * <p>
 171.565 + * The block names supported by <code>Pattern</code> are the valid block names
 171.566 + * accepted and defined by
 171.567 + * {@link java.lang.Character.UnicodeBlock#forName(String) UnicodeBlock.forName}.
 171.568 + * <p>
 171.569 + * <a name="ucc">
 171.570 + * <b>Categories</b> may be specified with the optional prefix {@code Is}:
 171.571 + * Both {@code \p{L}} and {@code \p{IsL}} denote the category of Unicode
 171.572 + * letters. Same as scripts and blocks, categories can also be specified
 171.573 + * by using the keyword {@code general_category} (or its short form
 171.574 + * {@code gc}) as in {@code general_category=Lu} or {@code gc=Lu}.
 171.575 + * <p>
 171.576 + * The supported categories are those of
 171.577 + * <a href="http://www.unicode.org/unicode/standard/standard.html">
 171.578 + * <i>The Unicode Standard</i></a> in the version specified by the
 171.579 + * {@link java.lang.Character Character} class. The category names are those
 171.580 + * defined in the Standard, both normative and informative.
 171.581 + * <p>
 171.582 + * <a name="ubpc">
 171.583 + * <b>Binary properties</b> are specified with the prefix {@code Is}, as in
 171.584 + * {@code IsAlphabetic}. The supported binary properties by <code>Pattern</code>
 171.585 + * are
 171.586 + * <ul>
 171.587 + *   <li> Alphabetic
 171.588 + *   <li> Ideographic
 171.589 + *   <li> Letter
 171.590 + *   <li> Lowercase
 171.591 + *   <li> Uppercase
 171.592 + *   <li> Titlecase
 171.593 + *   <li> Punctuation
 171.594 + *   <Li> Control
 171.595 + *   <li> White_Space
 171.596 + *   <li> Digit
 171.597 + *   <li> Hex_Digit
 171.598 + *   <li> Noncharacter_Code_Point
 171.599 + *   <li> Assigned
 171.600 + * </ul>
 171.601 +
 171.602 +
 171.603 + * <p>
 171.604 + * <b>Predefined Character classes</b> and <b>POSIX character classes</b> are in
 171.605 + * conformance with the recommendation of <i>Annex C: Compatibility Properties</i>
 171.606 + * of <a href="http://www.unicode.org/reports/tr18/"><i>Unicode Regular Expression
 171.607 + * </i></a>, when {@link #UNICODE_CHARACTER_CLASS} flag is specified.
 171.608 + * <p>
 171.609 + * <table border="0" cellpadding="1" cellspacing="0"
 171.610 + *  summary="predefined and posix character classes in Unicode mode">
 171.611 + * <tr align="left">
 171.612 + * <th bgcolor="#CCCCFF" align="left" id="classes">Classes</th>
 171.613 + * <th bgcolor="#CCCCFF" align="left" id="matches">Matches</th>
 171.614 + *</tr>
 171.615 + * <tr><td><tt>\p{Lower}</tt></td>
 171.616 + *     <td>A lowercase character:<tt>\p{IsLowercase}</tt></td></tr>
 171.617 + * <tr><td><tt>\p{Upper}</tt></td>
 171.618 + *     <td>An uppercase character:<tt>\p{IsUppercase}</tt></td></tr>
 171.619 + * <tr><td><tt>\p{ASCII}</tt></td>
 171.620 + *     <td>All ASCII:<tt>[\x00-\x7F]</tt></td></tr>
 171.621 + * <tr><td><tt>\p{Alpha}</tt></td>
 171.622 + *     <td>An alphabetic character:<tt>\p{IsAlphabetic}</tt></td></tr>
 171.623 + * <tr><td><tt>\p{Digit}</tt></td>
 171.624 + *     <td>A decimal digit character:<tt>p{IsDigit}</tt></td></tr>
 171.625 + * <tr><td><tt>\p{Alnum}</tt></td>
 171.626 + *     <td>An alphanumeric character:<tt>[\p{IsAlphabetic}\p{IsDigit}]</tt></td></tr>
 171.627 + * <tr><td><tt>\p{Punct}</tt></td>
 171.628 + *     <td>A punctuation character:<tt>p{IsPunctuation}</tt></td></tr>
 171.629 + * <tr><td><tt>\p{Graph}</tt></td>
 171.630 + *     <td>A visible character: <tt>[^\p{IsWhite_Space}\p{gc=Cc}\p{gc=Cs}\p{gc=Cn}]</tt></td></tr>
 171.631 + * <tr><td><tt>\p{Print}</tt></td>
 171.632 + *     <td>A printable character: <tt>[\p{Graph}\p{Blank}&&[^\p{Cntrl}]]</tt></td></tr>
 171.633 + * <tr><td><tt>\p{Blank}</tt></td>
 171.634 + *     <td>A space or a tab: <tt>[\p{IsWhite_Space}&&[^\p{gc=Zl}\p{gc=Zp}\x0a\x0b\x0c\x0d\x85]]</tt></td></tr>
 171.635 + * <tr><td><tt>\p{Cntrl}</tt></td>
 171.636 + *     <td>A control character: <tt>\p{gc=Cc}</tt></td></tr>
 171.637 + * <tr><td><tt>\p{XDigit}</tt></td>
 171.638 + *     <td>A hexadecimal digit: <tt>[\p{gc=Nd}\p{IsHex_Digit}]</tt></td></tr>
 171.639 + * <tr><td><tt>\p{Space}</tt></td>
 171.640 + *     <td>A whitespace character:<tt>\p{IsWhite_Space}</tt></td></tr>
 171.641 + * <tr><td><tt>\d</tt></td>
 171.642 + *     <td>A digit: <tt>\p{IsDigit}</tt></td></tr>
 171.643 + * <tr><td><tt>\D</tt></td>
 171.644 + *     <td>A non-digit: <tt>[^\d]</tt></td></tr>
 171.645 + * <tr><td><tt>\s</tt></td>
 171.646 + *     <td>A whitespace character: <tt>\p{IsWhite_Space}</tt></td></tr>
 171.647 + * <tr><td><tt>\S</tt></td>
 171.648 + *     <td>A non-whitespace character: <tt>[^\s]</tt></td></tr>
 171.649 + * <tr><td><tt>\w</tt></td>
 171.650 + *     <td>A word character: <tt>[\p{Alpha}\p{gc=Mn}\p{gc=Me}\p{gc=Mc}\p{Digit}\p{gc=Pc}]</tt></td></tr>
 171.651 + * <tr><td><tt>\W</tt></td>
 171.652 + *     <td>A non-word character: <tt>[^\w]</tt></td></tr>
 171.653 + * </table>
 171.654 + * <p>
 171.655 + * <a name="jcc">
 171.656 + * Categories that behave like the java.lang.Character
 171.657 + * boolean is<i>methodname</i> methods (except for the deprecated ones) are
 171.658 + * available through the same <tt>\p{</tt><i>prop</i><tt>}</tt> syntax where
 171.659 + * the specified property has the name <tt>java<i>methodname</i></tt>.
 171.660 + *
 171.661 + * <h4> Comparison to Perl 5 </h4>
 171.662 + *
 171.663 + * <p>The <code>Pattern</code> engine performs traditional NFA-based matching
 171.664 + * with ordered alternation as occurs in Perl 5.
 171.665 + *
 171.666 + * <p> Perl constructs not supported by this class: </p>
 171.667 + *
 171.668 + * <ul>
 171.669 + *    <li><p> Predefined character classes (Unicode character)
 171.670 + *    <p><tt>\h&nbsp;&nbsp;&nbsp;&nbsp;</tt>A horizontal whitespace
 171.671 + *    <p><tt>\H&nbsp;&nbsp;&nbsp;&nbsp;</tt>A non horizontal whitespace
 171.672 + *    <p><tt>\v&nbsp;&nbsp;&nbsp;&nbsp;</tt>A vertical whitespace
 171.673 + *    <p><tt>\V&nbsp;&nbsp;&nbsp;&nbsp;</tt>A non vertical whitespace
 171.674 + *    <p><tt>\R&nbsp;&nbsp;&nbsp;&nbsp;</tt>Any Unicode linebreak sequence
 171.675 + *    <tt>\u005cu000D\u005cu000A|[\u005cu000A\u005cu000B\u005cu000C\u005cu000D\u005cu0085\u005cu2028\u005cu2029]</tt>
 171.676 + *    <p><tt>\X&nbsp;&nbsp;&nbsp;&nbsp;</tt>Match Unicode
 171.677 + *    <a href="http://www.unicode.org/reports/tr18/#Default_Grapheme_Clusters">
 171.678 + *    <i>extended grapheme cluster</i></a>
 171.679 + *    </p></li>
 171.680 + *
 171.681 + *    <li><p> The backreference constructs, <tt>\g{</tt><i>n</i><tt>}</tt> for
 171.682 + *    the <i>n</i><sup>th</sup><a href="#cg">capturing group</a> and
 171.683 + *    <tt>\g{</tt><i>name</i><tt>}</tt> for
 171.684 + *    <a href="#groupname">named-capturing group</a>.
 171.685 + *    </p></li>
 171.686 + *
 171.687 + *    <li><p> The named character construct, <tt>\N{</tt><i>name</i><tt>}</tt>
 171.688 + *    for a Unicode character by its name.
 171.689 + *    </p></li>
 171.690 + *
 171.691 + *    <li><p> The conditional constructs
 171.692 + *    <tt>(?(</tt><i>condition</i><tt>)</tt><i>X</i><tt>)</tt> and
 171.693 + *    <tt>(?(</tt><i>condition</i><tt>)</tt><i>X</i><tt>|</tt><i>Y</i><tt>)</tt>,
 171.694 + *    </p></li>
 171.695 + *
 171.696 + *    <li><p> The embedded code constructs <tt>(?{</tt><i>code</i><tt>})</tt>
 171.697 + *    and <tt>(??{</tt><i>code</i><tt>})</tt>,</p></li>
 171.698 + *
 171.699 + *    <li><p> The embedded comment syntax <tt>(?#comment)</tt>, and </p></li>
 171.700 + *
 171.701 + *    <li><p> The preprocessing operations <tt>\l</tt> <tt>&#92;u</tt>,
 171.702 + *    <tt>\L</tt>, and <tt>\U</tt>.  </p></li>
 171.703 + *
 171.704 + * </ul>
 171.705 + *
 171.706 + * <p> Constructs supported by this class but not by Perl: </p>
 171.707 + *
 171.708 + * <ul>
 171.709 + *
 171.710 + *    <li><p> Character-class union and intersection as described
 171.711 + *    <a href="#cc">above</a>.</p></li>
 171.712 + *
 171.713 + * </ul>
 171.714 + *
 171.715 + * <p> Notable differences from Perl: </p>
 171.716 + *
 171.717 + * <ul>
 171.718 + *
 171.719 + *    <li><p> In Perl, <tt>\1</tt> through <tt>\9</tt> are always interpreted
 171.720 + *    as back references; a backslash-escaped number greater than <tt>9</tt> is
 171.721 + *    treated as a back reference if at least that many subexpressions exist,
 171.722 + *    otherwise it is interpreted, if possible, as an octal escape.  In this
 171.723 + *    class octal escapes must always begin with a zero. In this class,
 171.724 + *    <tt>\1</tt> through <tt>\9</tt> are always interpreted as back
 171.725 + *    references, and a larger number is accepted as a back reference if at
 171.726 + *    least that many subexpressions exist at that point in the regular
 171.727 + *    expression, otherwise the parser will drop digits until the number is
 171.728 + *    smaller or equal to the existing number of groups or it is one digit.
 171.729 + *    </p></li>
 171.730 + *
 171.731 + *    <li><p> Perl uses the <tt>g</tt> flag to request a match that resumes
 171.732 + *    where the last match left off.  This functionality is provided implicitly
 171.733 + *    by the {@link Matcher} class: Repeated invocations of the {@link
 171.734 + *    Matcher#find find} method will resume where the last match left off,
 171.735 + *    unless the matcher is reset.  </p></li>
 171.736 + *
 171.737 + *    <li><p> In Perl, embedded flags at the top level of an expression affect
 171.738 + *    the whole expression.  In this class, embedded flags always take effect
 171.739 + *    at the point at which they appear, whether they are at the top level or
 171.740 + *    within a group; in the latter case, flags are restored at the end of the
 171.741 + *    group just as in Perl.  </p></li>
 171.742 + *
 171.743 + * </ul>
 171.744 + *
 171.745 + *
 171.746 + * <p> For a more precise description of the behavior of regular expression
 171.747 + * constructs, please see <a href="http://www.oreilly.com/catalog/regex3/">
 171.748 + * <i>Mastering Regular Expressions, 3nd Edition</i>, Jeffrey E. F. Friedl,
 171.749 + * O'Reilly and Associates, 2006.</a>
 171.750 + * </p>
 171.751 + *
 171.752 + * @see java.lang.String#split(String, int)
 171.753 + * @see java.lang.String#split(String)
 171.754 + *
 171.755 + * @author      Mike McCloskey
 171.756 + * @author      Mark Reinhold
 171.757 + * @author      JSR-51 Expert Group
 171.758 + * @since       1.4
 171.759 + * @spec        JSR-51
 171.760 + */
 171.761 +
 171.762 +public final class Pattern
 171.763 +    implements java.io.Serializable
 171.764 +{
 171.765 +
 171.766 +    /**
 171.767 +     * Regular expression modifier values.  Instead of being passed as
 171.768 +     * arguments, they can also be passed as inline modifiers.
 171.769 +     * For example, the following statements have the same effect.
 171.770 +     * <pre>
 171.771 +     * RegExp r1 = RegExp.compile("abc", Pattern.I|Pattern.M);
 171.772 +     * RegExp r2 = RegExp.compile("(?im)abc", 0);
 171.773 +     * </pre>
 171.774 +     *
 171.775 +     * The flags are duplicated so that the familiar Perl match flag
 171.776 +     * names are available.
 171.777 +     */
 171.778 +
 171.779 +    /**
 171.780 +     * Enables Unix lines mode.
 171.781 +     *
 171.782 +     * <p> In this mode, only the <tt>'\n'</tt> line terminator is recognized
 171.783 +     * in the behavior of <tt>.</tt>, <tt>^</tt>, and <tt>$</tt>.
 171.784 +     *
 171.785 +     * <p> Unix lines mode can also be enabled via the embedded flag
 171.786 +     * expression&nbsp;<tt>(?d)</tt>.
 171.787 +     */
 171.788 +    public static final int UNIX_LINES = 0x01;
 171.789 +
 171.790 +    /**
 171.791 +     * Enables case-insensitive matching.
 171.792 +     *
 171.793 +     * <p> By default, case-insensitive matching assumes that only characters
 171.794 +     * in the US-ASCII charset are being matched.  Unicode-aware
 171.795 +     * case-insensitive matching can be enabled by specifying the {@link
 171.796 +     * #UNICODE_CASE} flag in conjunction with this flag.
 171.797 +     *
 171.798 +     * <p> Case-insensitive matching can also be enabled via the embedded flag
 171.799 +     * expression&nbsp;<tt>(?i)</tt>.
 171.800 +     *
 171.801 +     * <p> Specifying this flag may impose a slight performance penalty.  </p>
 171.802 +     */
 171.803 +    public static final int CASE_INSENSITIVE = 0x02;
 171.804 +
 171.805 +    /**
 171.806 +     * Permits whitespace and comments in pattern.
 171.807 +     *
 171.808 +     * <p> In this mode, whitespace is ignored, and embedded comments starting
 171.809 +     * with <tt>#</tt> are ignored until the end of a line.
 171.810 +     *
 171.811 +     * <p> Comments mode can also be enabled via the embedded flag
 171.812 +     * expression&nbsp;<tt>(?x)</tt>.
 171.813 +     */
 171.814 +    public static final int COMMENTS = 0x04;
 171.815 +
 171.816 +    /**
 171.817 +     * Enables multiline mode.
 171.818 +     *
 171.819 +     * <p> In multiline mode the expressions <tt>^</tt> and <tt>$</tt> match
 171.820 +     * just after or just before, respectively, a line terminator or the end of
 171.821 +     * the input sequence.  By default these expressions only match at the
 171.822 +     * beginning and the end of the entire input sequence.
 171.823 +     *
 171.824 +     * <p> Multiline mode can also be enabled via the embedded flag
 171.825 +     * expression&nbsp;<tt>(?m)</tt>.  </p>
 171.826 +     */
 171.827 +    public static final int MULTILINE = 0x08;
 171.828 +
 171.829 +    /**
 171.830 +     * Enables literal parsing of the pattern.
 171.831 +     *
 171.832 +     * <p> When this flag is specified then the input string that specifies
 171.833 +     * the pattern is treated as a sequence of literal characters.
 171.834 +     * Metacharacters or escape sequences in the input sequence will be
 171.835 +     * given no special meaning.
 171.836 +     *
 171.837 +     * <p>The flags CASE_INSENSITIVE and UNICODE_CASE retain their impact on
 171.838 +     * matching when used in conjunction with this flag. The other flags
 171.839 +     * become superfluous.
 171.840 +     *
 171.841 +     * <p> There is no embedded flag character for enabling literal parsing.
 171.842 +     * @since 1.5
 171.843 +     */
 171.844 +    public static final int LITERAL = 0x10;
 171.845 +
 171.846 +    /**
 171.847 +     * Enables dotall mode.
 171.848 +     *
 171.849 +     * <p> In dotall mode, the expression <tt>.</tt> matches any character,
 171.850 +     * including a line terminator.  By default this expression does not match
 171.851 +     * line terminators.
 171.852 +     *
 171.853 +     * <p> Dotall mode can also be enabled via the embedded flag
 171.854 +     * expression&nbsp;<tt>(?s)</tt>.  (The <tt>s</tt> is a mnemonic for
 171.855 +     * "single-line" mode, which is what this is called in Perl.)  </p>
 171.856 +     */
 171.857 +    public static final int DOTALL = 0x20;
 171.858 +
 171.859 +    /**
 171.860 +     * Enables Unicode-aware case folding.
 171.861 +     *
 171.862 +     * <p> When this flag is specified then case-insensitive matching, when
 171.863 +     * enabled by the {@link #CASE_INSENSITIVE} flag, is done in a manner
 171.864 +     * consistent with the Unicode Standard.  By default, case-insensitive
 171.865 +     * matching assumes that only characters in the US-ASCII charset are being
 171.866 +     * matched.
 171.867 +     *
 171.868 +     * <p> Unicode-aware case folding can also be enabled via the embedded flag
 171.869 +     * expression&nbsp;<tt>(?u)</tt>.
 171.870 +     *
 171.871 +     * <p> Specifying this flag may impose a performance penalty.  </p>
 171.872 +     */
 171.873 +    public static final int UNICODE_CASE = 0x40;
 171.874 +
 171.875 +    /**
 171.876 +     * Enables canonical equivalence.
 171.877 +     *
 171.878 +     * <p> When this flag is specified then two characters will be considered
 171.879 +     * to match if, and only if, their full canonical decompositions match.
 171.880 +     * The expression <tt>"a&#92;u030A"</tt>, for example, will match the
 171.881 +     * string <tt>"&#92;u00E5"</tt> when this flag is specified.  By default,
 171.882 +     * matching does not take canonical equivalence into account.
 171.883 +     *
 171.884 +     * <p> There is no embedded flag character for enabling canonical
 171.885 +     * equivalence.
 171.886 +     *
 171.887 +     * <p> Specifying this flag may impose a performance penalty.  </p>
 171.888 +     */
 171.889 +    public static final int CANON_EQ = 0x80;
 171.890 +
 171.891 +    /**
 171.892 +     * Enables the Unicode version of <i>Predefined character classes</i> and
 171.893 +     * <i>POSIX character classes</i>.
 171.894 +     *
 171.895 +     * <p> When this flag is specified then the (US-ASCII only)
 171.896 +     * <i>Predefined character classes</i> and <i>POSIX character classes</i>
 171.897 +     * are in conformance with
 171.898 +     * <a href="http://www.unicode.org/reports/tr18/"><i>Unicode Technical
 171.899 +     * Standard #18: Unicode Regular Expression</i></a>
 171.900 +     * <i>Annex C: Compatibility Properties</i>.
 171.901 +     * <p>
 171.902 +     * The UNICODE_CHARACTER_CLASS mode can also be enabled via the embedded
 171.903 +     * flag expression&nbsp;<tt>(?U)</tt>.
 171.904 +     * <p>
 171.905 +     * The flag implies UNICODE_CASE, that is, it enables Unicode-aware case
 171.906 +     * folding.
 171.907 +     * <p>
 171.908 +     * Specifying this flag may impose a performance penalty.  </p>
 171.909 +     * @since 1.7
 171.910 +     */
 171.911 +    public static final int UNICODE_CHARACTER_CLASS = 0x100;
 171.912 +
 171.913 +    /* Pattern has only two serialized components: The pattern string
 171.914 +     * and the flags, which are all that is needed to recompile the pattern
 171.915 +     * when it is deserialized.
 171.916 +     */
 171.917 +
 171.918 +    /** use serialVersionUID from Merlin b59 for interoperability */
 171.919 +    private static final long serialVersionUID = 5073258162644648461L;
 171.920 +
 171.921 +    /**
 171.922 +     * The original regular-expression pattern string.
 171.923 +     *
 171.924 +     * @serial
 171.925 +     */
 171.926 +    private String pattern;
 171.927 +
 171.928 +    /**
 171.929 +     * The original pattern flags.
 171.930 +     *
 171.931 +     * @serial
 171.932 +     */
 171.933 +    private int flags;
 171.934 +
 171.935 +    /**
 171.936 +     * Boolean indicating this Pattern is compiled; this is necessary in order
 171.937 +     * to lazily compile deserialized Patterns.
 171.938 +     */
 171.939 +    private transient volatile boolean compiled = false;
 171.940 +
 171.941 +    /**
 171.942 +     * The normalized pattern string.
 171.943 +     */
 171.944 +    private transient String normalizedPattern;
 171.945 +
 171.946 +    /**
 171.947 +     * The starting point of state machine for the find operation.  This allows
 171.948 +     * a match to start anywhere in the input.
 171.949 +     */
 171.950 +    transient Node root;
 171.951 +
 171.952 +    /**
 171.953 +     * The root of object tree for a match operation.  The pattern is matched
 171.954 +     * at the beginning.  This may include a find that uses BnM or a First
 171.955 +     * node.
 171.956 +     */
 171.957 +    transient Node matchRoot;
 171.958 +
 171.959 +    /**
 171.960 +     * Temporary storage used by parsing pattern slice.
 171.961 +     */
 171.962 +    transient int[] buffer;
 171.963 +
 171.964 +    /**
 171.965 +     * Map the "name" of the "named capturing group" to its group id
 171.966 +     * node.
 171.967 +     */
 171.968 +    transient volatile Map<String, Integer> namedGroups;
 171.969 +
 171.970 +    /**
 171.971 +     * Temporary storage used while parsing group references.
 171.972 +     */
 171.973 +    transient GroupHead[] groupNodes;
 171.974 +
 171.975 +    /**
 171.976 +     * Temporary null terminated code point array used by pattern compiling.
 171.977 +     */
 171.978 +    private transient int[] temp;
 171.979 +
 171.980 +    /**
 171.981 +     * The number of capturing groups in this Pattern. Used by matchers to
 171.982 +     * allocate storage needed to perform a match.
 171.983 +     */
 171.984 +    transient int capturingGroupCount;
 171.985 +
 171.986 +    /**
 171.987 +     * The local variable count used by parsing tree. Used by matchers to
 171.988 +     * allocate storage needed to perform a match.
 171.989 +     */
 171.990 +    transient int localCount;
 171.991 +
 171.992 +    /**
 171.993 +     * Index into the pattern string that keeps track of how much has been
 171.994 +     * parsed.
 171.995 +     */
 171.996 +    private transient int cursor;
 171.997 +
 171.998 +    /**
 171.999 +     * Holds the length of the pattern string.
171.1000 +     */
171.1001 +    private transient int patternLength;
171.1002 +
171.1003 +    /**
171.1004 +     * If the Start node might possibly match supplementary characters.
171.1005 +     * It is set to true during compiling if
171.1006 +     * (1) There is supplementary char in pattern, or
171.1007 +     * (2) There is complement node of Category or Block
171.1008 +     */
171.1009 +    private transient boolean hasSupplementary;
171.1010 +
171.1011 +    /**
171.1012 +     * Compiles the given regular expression into a pattern.  </p>
171.1013 +     *
171.1014 +     * @param  regex
171.1015 +     *         The expression to be compiled
171.1016 +     *
171.1017 +     * @throws  PatternSyntaxException
171.1018 +     *          If the expression's syntax is invalid
171.1019 +     */
171.1020 +    public static Pattern compile(String regex) {
171.1021 +        return new Pattern(regex, 0);
171.1022 +    }
171.1023 +
171.1024 +    /**
171.1025 +     * Compiles the given regular expression into a pattern with the given
171.1026 +     * flags.  </p>
171.1027 +     *
171.1028 +     * @param  regex
171.1029 +     *         The expression to be compiled
171.1030 +     *
171.1031 +     * @param  flags
171.1032 +     *         Match flags, a bit mask that may include
171.1033 +     *         {@link #CASE_INSENSITIVE}, {@link #MULTILINE}, {@link #DOTALL},
171.1034 +     *         {@link #UNICODE_CASE}, {@link #CANON_EQ}, {@link #UNIX_LINES},
171.1035 +     *         {@link #LITERAL}, {@link #UNICODE_CHARACTER_CLASS}
171.1036 +     *         and {@link #COMMENTS}
171.1037 +     *
171.1038 +     * @throws  IllegalArgumentException
171.1039 +     *          If bit values other than those corresponding to the defined
171.1040 +     *          match flags are set in <tt>flags</tt>
171.1041 +     *
171.1042 +     * @throws  PatternSyntaxException
171.1043 +     *          If the expression's syntax is invalid
171.1044 +     */
171.1045 +    public static Pattern compile(String regex, int flags) {
171.1046 +        return new Pattern(regex, flags);
171.1047 +    }
171.1048 +
171.1049 +    /**
171.1050 +     * Returns the regular expression from which this pattern was compiled.
171.1051 +     * </p>
171.1052 +     *
171.1053 +     * @return  The source of this pattern
171.1054 +     */
171.1055 +    public String pattern() {
171.1056 +        return pattern;
171.1057 +    }
171.1058 +
171.1059 +    /**
171.1060 +     * <p>Returns the string representation of this pattern. This
171.1061 +     * is the regular expression from which this pattern was
171.1062 +     * compiled.</p>
171.1063 +     *
171.1064 +     * @return  The string representation of this pattern
171.1065 +     * @since 1.5
171.1066 +     */
171.1067 +    public String toString() {
171.1068 +        return pattern;
171.1069 +    }
171.1070 +
171.1071 +    /**
171.1072 +     * Creates a matcher that will match the given input against this pattern.
171.1073 +     * </p>
171.1074 +     *
171.1075 +     * @param  input
171.1076 +     *         The character sequence to be matched
171.1077 +     *
171.1078 +     * @return  A new matcher for this pattern
171.1079 +     */
171.1080 +    public Matcher matcher(CharSequence input) {
171.1081 +        if (!compiled) {
171.1082 +            synchronized(this) {
171.1083 +                if (!compiled)
171.1084 +                    compile();
171.1085 +            }
171.1086 +        }
171.1087 +        Matcher m = new Matcher(this, input);
171.1088 +        return m;
171.1089 +    }
171.1090 +
171.1091 +    /**
171.1092 +     * Returns this pattern's match flags.  </p>
171.1093 +     *
171.1094 +     * @return  The match flags specified when this pattern was compiled
171.1095 +     */
171.1096 +    public int flags() {
171.1097 +        return flags;
171.1098 +    }
171.1099 +
171.1100 +    /**
171.1101 +     * Compiles the given regular expression and attempts to match the given
171.1102 +     * input against it.
171.1103 +     *
171.1104 +     * <p> An invocation of this convenience method of the form
171.1105 +     *
171.1106 +     * <blockquote><pre>
171.1107 +     * Pattern.matches(regex, input);</pre></blockquote>
171.1108 +     *
171.1109 +     * behaves in exactly the same way as the expression
171.1110 +     *
171.1111 +     * <blockquote><pre>
171.1112 +     * Pattern.compile(regex).matcher(input).matches()</pre></blockquote>
171.1113 +     *
171.1114 +     * <p> If a pattern is to be used multiple times, compiling it once and reusing
171.1115 +     * it will be more efficient than invoking this method each time.  </p>
171.1116 +     *
171.1117 +     * @param  regex
171.1118 +     *         The expression to be compiled
171.1119 +     *
171.1120 +     * @param  input
171.1121 +     *         The character sequence to be matched
171.1122 +     *
171.1123 +     * @throws  PatternSyntaxException
171.1124 +     *          If the expression's syntax is invalid
171.1125 +     */
171.1126 +    public static boolean matches(String regex, CharSequence input) {
171.1127 +        Pattern p = Pattern.compile(regex);
171.1128 +        Matcher m = p.matcher(input);
171.1129 +        return m.matches();
171.1130 +    }
171.1131 +
171.1132 +    /**
171.1133 +     * Splits the given input sequence around matches of this pattern.
171.1134 +     *
171.1135 +     * <p> The array returned by this method contains each substring of the
171.1136 +     * input sequence that is terminated by another subsequence that matches
171.1137 +     * this pattern or is terminated by the end of the input sequence.  The
171.1138 +     * substrings in the array are in the order in which they occur in the
171.1139 +     * input.  If this pattern does not match any subsequence of the input then
171.1140 +     * the resulting array has just one element, namely the input sequence in
171.1141 +     * string form.
171.1142 +     *
171.1143 +     * <p> The <tt>limit</tt> parameter controls the number of times the
171.1144 +     * pattern is applied and therefore affects the length of the resulting
171.1145 +     * array.  If the limit <i>n</i> is greater than zero then the pattern
171.1146 +     * will be applied at most <i>n</i>&nbsp;-&nbsp;1 times, the array's
171.1147 +     * length will be no greater than <i>n</i>, and the array's last entry
171.1148 +     * will contain all input beyond the last matched delimiter.  If <i>n</i>
171.1149 +     * is non-positive then the pattern will be applied as many times as
171.1150 +     * possible and the array can have any length.  If <i>n</i> is zero then
171.1151 +     * the pattern will be applied as many times as possible, the array can
171.1152 +     * have any length, and trailing empty strings will be discarded.
171.1153 +     *
171.1154 +     * <p> The input <tt>"boo:and:foo"</tt>, for example, yields the following
171.1155 +     * results with these parameters:
171.1156 +     *
171.1157 +     * <blockquote><table cellpadding=1 cellspacing=0
171.1158 +     *              summary="Split examples showing regex, limit, and result">
171.1159 +     * <tr><th><P align="left"><i>Regex&nbsp;&nbsp;&nbsp;&nbsp;</i></th>
171.1160 +     *     <th><P align="left"><i>Limit&nbsp;&nbsp;&nbsp;&nbsp;</i></th>
171.1161 +     *     <th><P align="left"><i>Result&nbsp;&nbsp;&nbsp;&nbsp;</i></th></tr>
171.1162 +     * <tr><td align=center>:</td>
171.1163 +     *     <td align=center>2</td>
171.1164 +     *     <td><tt>{ "boo", "and:foo" }</tt></td></tr>
171.1165 +     * <tr><td align=center>:</td>
171.1166 +     *     <td align=center>5</td>
171.1167 +     *     <td><tt>{ "boo", "and", "foo" }</tt></td></tr>
171.1168 +     * <tr><td align=center>:</td>
171.1169 +     *     <td align=center>-2</td>
171.1170 +     *     <td><tt>{ "boo", "and", "foo" }</tt></td></tr>
171.1171 +     * <tr><td align=center>o</td>
171.1172 +     *     <td align=center>5</td>
171.1173 +     *     <td><tt>{ "b", "", ":and:f", "", "" }</tt></td></tr>
171.1174 +     * <tr><td align=center>o</td>
171.1175 +     *     <td align=center>-2</td>
171.1176 +     *     <td><tt>{ "b", "", ":and:f", "", "" }</tt></td></tr>
171.1177 +     * <tr><td align=center>o</td>
171.1178 +     *     <td align=center>0</td>
171.1179 +     *     <td><tt>{ "b", "", ":and:f" }</tt></td></tr>
171.1180 +     * </table></blockquote>
171.1181 +     *
171.1182 +     *
171.1183 +     * @param  input
171.1184 +     *         The character sequence to be split
171.1185 +     *
171.1186 +     * @param  limit
171.1187 +     *         The result threshold, as described above
171.1188 +     *
171.1189 +     * @return  The array of strings computed by splitting the input
171.1190 +     *          around matches of this pattern
171.1191 +     */
171.1192 +    public String[] split(CharSequence input, int limit) {
171.1193 +        int index = 0;
171.1194 +        boolean matchLimited = limit > 0;
171.1195 +        ArrayList<String> matchList = new ArrayList<>();
171.1196 +        Matcher m = matcher(input);
171.1197 +
171.1198 +        // Add segments before each match found
171.1199 +        while(m.find()) {
171.1200 +            if (!matchLimited || matchList.size() < limit - 1) {
171.1201 +                String match = input.subSequence(index, m.start()).toString();
171.1202 +                matchList.add(match);
171.1203 +                index = m.end();
171.1204 +            } else if (matchList.size() == limit - 1) { // last one
171.1205 +                String match = input.subSequence(index,
171.1206 +                                                 input.length()).toString();
171.1207 +                matchList.add(match);
171.1208 +                index = m.end();
171.1209 +            }
171.1210 +        }
171.1211 +
171.1212 +        // If no match was found, return this
171.1213 +        if (index == 0)
171.1214 +            return new String[] {input.toString()};
171.1215 +
171.1216 +        // Add remaining segment
171.1217 +        if (!matchLimited || matchList.size() < limit)
171.1218 +            matchList.add(input.subSequence(index, input.length()).toString());
171.1219 +
171.1220 +        // Construct result
171.1221 +        int resultSize = matchList.size();
171.1222 +        if (limit == 0)
171.1223 +            while (resultSize > 0 && matchList.get(resultSize-1).equals(""))
171.1224 +                resultSize--;
171.1225 +        String[] result = new String[resultSize];
171.1226 +        return matchList.subList(0, resultSize).toArray(result);
171.1227 +    }
171.1228 +
171.1229 +    /**
171.1230 +     * Splits the given input sequence around matches of this pattern.
171.1231 +     *
171.1232 +     * <p> This method works as if by invoking the two-argument {@link
171.1233 +     * #split(java.lang.CharSequence, int) split} method with the given input
171.1234 +     * sequence and a limit argument of zero.  Trailing empty strings are
171.1235 +     * therefore not included in the resulting array. </p>
171.1236 +     *
171.1237 +     * <p> The input <tt>"boo:and:foo"</tt>, for example, yields the following
171.1238 +     * results with these expressions:
171.1239 +     *
171.1240 +     * <blockquote><table cellpadding=1 cellspacing=0
171.1241 +     *              summary="Split examples showing regex and result">
171.1242 +     * <tr><th><P align="left"><i>Regex&nbsp;&nbsp;&nbsp;&nbsp;</i></th>
171.1243 +     *     <th><P align="left"><i>Result</i></th></tr>
171.1244 +     * <tr><td align=center>:</td>
171.1245 +     *     <td><tt>{ "boo", "and", "foo" }</tt></td></tr>
171.1246 +     * <tr><td align=center>o</td>
171.1247 +     *     <td><tt>{ "b", "", ":and:f" }</tt></td></tr>
171.1248 +     * </table></blockquote>
171.1249 +     *
171.1250 +     *
171.1251 +     * @param  input
171.1252 +     *         The character sequence to be split
171.1253 +     *
171.1254 +     * @return  The array of strings computed by splitting the input
171.1255 +     *          around matches of this pattern
171.1256 +     */
171.1257 +    public String[] split(CharSequence input) {
171.1258 +        return split(input, 0);
171.1259 +    }
171.1260 +
171.1261 +    /**
171.1262 +     * Returns a literal pattern <code>String</code> for the specified
171.1263 +     * <code>String</code>.
171.1264 +     *
171.1265 +     * <p>This method produces a <code>String</code> that can be used to
171.1266 +     * create a <code>Pattern</code> that would match the string
171.1267 +     * <code>s</code> as if it were a literal pattern.</p> Metacharacters
171.1268 +     * or escape sequences in the input sequence will be given no special
171.1269 +     * meaning.
171.1270 +     *
171.1271 +     * @param  s The string to be literalized
171.1272 +     * @return  A literal string replacement
171.1273 +     * @since 1.5
171.1274 +     */
171.1275 +    public static String quote(String s) {
171.1276 +        int slashEIndex = s.indexOf("\\E");
171.1277 +        if (slashEIndex == -1)
171.1278 +            return "\\Q" + s + "\\E";
171.1279 +
171.1280 +        StringBuilder sb = new StringBuilder(s.length() * 2);
171.1281 +        sb.append("\\Q");
171.1282 +        slashEIndex = 0;
171.1283 +        int current = 0;
171.1284 +        while ((slashEIndex = s.indexOf("\\E", current)) != -1) {
171.1285 +            sb.append(s.substring(current, slashEIndex));
171.1286 +            current = slashEIndex + 2;
171.1287 +            sb.append("\\E\\\\E\\Q");
171.1288 +        }
171.1289 +        sb.append(s.substring(current, s.length()));
171.1290 +        sb.append("\\E");
171.1291 +        return sb.toString();
171.1292 +    }
171.1293 +
171.1294 +    /**
171.1295 +     * Recompile the Pattern instance from a stream.  The original pattern
171.1296 +     * string is read in and the object tree is recompiled from it.
171.1297 +     */
171.1298 +    private void readObject(java.io.ObjectInputStream s)
171.1299 +        throws java.io.IOException, ClassNotFoundException {
171.1300 +
171.1301 +        // Read in all fields
171.1302 +        s.defaultReadObject();
171.1303 +
171.1304 +        // Initialize counts
171.1305 +        capturingGroupCount = 1;
171.1306 +        localCount = 0;
171.1307 +
171.1308 +        // if length > 0, the Pattern is lazily compiled
171.1309 +        compiled = false;
171.1310 +        if (pattern.length() == 0) {
171.1311 +            root = new Start(lastAccept);
171.1312 +            matchRoot = lastAccept;
171.1313 +            compiled = true;
171.1314 +        }
171.1315 +    }
171.1316 +
171.1317 +    /**
171.1318 +     * This private constructor is used to create all Patterns. The pattern
171.1319 +     * string and match flags are all that is needed to completely describe
171.1320 +     * a Pattern. An empty pattern string results in an object tree with
171.1321 +     * only a Start node and a LastNode node.
171.1322 +     */
171.1323 +    private Pattern(String p, int f) {
171.1324 +        pattern = p;
171.1325 +        flags = f;
171.1326 +
171.1327 +        // to use UNICODE_CASE if UNICODE_CHARACTER_CLASS present
171.1328 +        if ((flags & UNICODE_CHARACTER_CLASS) != 0)
171.1329 +            flags |= UNICODE_CASE;
171.1330 +
171.1331 +        // Reset group index count
171.1332 +        capturingGroupCount = 1;
171.1333 +        localCount = 0;
171.1334 +
171.1335 +        if (pattern.length() > 0) {
171.1336 +            compile();
171.1337 +        } else {
171.1338 +            root = new Start(lastAccept);
171.1339 +            matchRoot = lastAccept;
171.1340 +        }
171.1341 +    }
171.1342 +
171.1343 +    /**
171.1344 +     * The pattern is converted to normalizedD form and then a pure group
171.1345 +     * is constructed to match canonical equivalences of the characters.
171.1346 +     */
171.1347 +    private void normalize() {
171.1348 +        boolean inCharClass = false;
171.1349 +        int lastCodePoint = -1;
171.1350 +
171.1351 +        // Convert pattern into normalizedD form
171.1352 +        normalizedPattern = Normalizer.normalize(pattern, Normalizer.NFD);
171.1353 +        patternLength = normalizedPattern.length();
171.1354 +
171.1355 +        // Modify pattern to match canonical equivalences
171.1356 +        StringBuilder newPattern = new StringBuilder(patternLength);
171.1357 +        for(int i=0; i<patternLength; ) {
171.1358 +            int c = normalizedPattern.codePointAt(i);
171.1359 +            StringBuilder sequenceBuffer;
171.1360 +            if ((Character.getType(c) == Character.NON_SPACING_MARK)
171.1361 +                && (lastCodePoint != -1)) {
171.1362 +                sequenceBuffer = new StringBuilder();
171.1363 +                sequenceBuffer.appendCodePoint(lastCodePoint);
171.1364 +                sequenceBuffer.appendCodePoint(c);
171.1365 +                while(Character.getType(c) == Character.NON_SPACING_MARK) {
171.1366 +                    i += Character.charCount(c);
171.1367 +                    if (i >= patternLength)
171.1368 +                        break;
171.1369 +                    c = normalizedPattern.codePointAt(i);
171.1370 +                    sequenceBuffer.appendCodePoint(c);
171.1371 +                }
171.1372 +                String ea = produceEquivalentAlternation(
171.1373 +                                               sequenceBuffer.toString());
171.1374 +                newPattern.setLength(newPattern.length()-Character.charCount(lastCodePoint));
171.1375 +                newPattern.append("(?:").append(ea).append(")");
171.1376 +            } else if (c == '[' && lastCodePoint != '\\') {
171.1377 +                i = normalizeCharClass(newPattern, i);
171.1378 +            } else {
171.1379 +                newPattern.appendCodePoint(c);
171.1380 +            }
171.1381 +            lastCodePoint = c;
171.1382 +            i += Character.charCount(c);
171.1383 +        }
171.1384 +        normalizedPattern = newPattern.toString();
171.1385 +    }
171.1386 +
171.1387 +    /**
171.1388 +     * Complete the character class being parsed and add a set
171.1389 +     * of alternations to it that will match the canonical equivalences
171.1390 +     * of the characters within the class.
171.1391 +     */
171.1392 +    private int normalizeCharClass(StringBuilder newPattern, int i) {
171.1393 +        StringBuilder charClass = new StringBuilder();
171.1394 +        StringBuilder eq = null;
171.1395 +        int lastCodePoint = -1;
171.1396 +        String result;
171.1397 +
171.1398 +        i++;
171.1399 +        charClass.append("[");
171.1400 +        while(true) {
171.1401 +            int c = normalizedPattern.codePointAt(i);
171.1402 +            StringBuilder sequenceBuffer;
171.1403 +
171.1404 +            if (c == ']' && lastCodePoint != '\\') {
171.1405 +                charClass.append((char)c);
171.1406 +                break;
171.1407 +            } else if (Character.getType(c) == Character.NON_SPACING_MARK) {
171.1408 +                sequenceBuffer = new StringBuilder();
171.1409 +                sequenceBuffer.appendCodePoint(lastCodePoint);
171.1410 +                while(Character.getType(c) == Character.NON_SPACING_MARK) {
171.1411 +                    sequenceBuffer.appendCodePoint(c);
171.1412 +                    i += Character.charCount(c);
171.1413 +                    if (i >= normalizedPattern.length())
171.1414 +                        break;
171.1415 +                    c = normalizedPattern.codePointAt(i);
171.1416 +                }
171.1417 +                String ea = produceEquivalentAlternation(
171.1418 +                                                  sequenceBuffer.toString());
171.1419 +
171.1420 +                charClass.setLength(charClass.length()-Character.charCount(lastCodePoint));
171.1421 +                if (eq == null)
171.1422 +                    eq = new StringBuilder();
171.1423 +                eq.append('|');
171.1424 +                eq.append(ea);
171.1425 +            } else {
171.1426 +                charClass.appendCodePoint(c);
171.1427 +                i++;
171.1428 +            }
171.1429 +            if (i == normalizedPattern.length())
171.1430 +                throw error("Unclosed character class");
171.1431 +            lastCodePoint = c;
171.1432 +        }
171.1433 +
171.1434 +        if (eq != null) {
171.1435 +            result = "(?:"+charClass.toString()+eq.toString()+")";
171.1436 +        } else {
171.1437 +            result = charClass.toString();
171.1438 +        }
171.1439 +
171.1440 +        newPattern.append(result);
171.1441 +        return i;
171.1442 +    }
171.1443 +
171.1444 +    /**
171.1445 +     * Given a specific sequence composed of a regular character and
171.1446 +     * combining marks that follow it, produce the alternation that will
171.1447 +     * match all canonical equivalences of that sequence.
171.1448 +     */
171.1449 +    private String produceEquivalentAlternation(String source) {
171.1450 +        int len = countChars(source, 0, 1);
171.1451 +        if (source.length() == len)
171.1452 +            // source has one character.
171.1453 +            return source;
171.1454 +
171.1455 +        String base = source.substring(0,len);
171.1456 +        String combiningMarks = source.substring(len);
171.1457 +
171.1458 +        String[] perms = producePermutations(combiningMarks);
171.1459 +        StringBuilder result = new StringBuilder(source);
171.1460 +
171.1461 +        // Add combined permutations
171.1462 +        for(int x=0; x<perms.length; x++) {
171.1463 +            String next = base + perms[x];
171.1464 +            if (x>0)
171.1465 +                result.append("|"+next);
171.1466 +            next = composeOneStep(next);
171.1467 +            if (next != null)
171.1468 +                result.append("|"+produceEquivalentAlternation(next));
171.1469 +        }
171.1470 +        return result.toString();
171.1471 +    }
171.1472 +
171.1473 +    /**
171.1474 +     * Returns an array of strings that have all the possible
171.1475 +     * permutations of the characters in the input string.
171.1476 +     * This is used to get a list of all possible orderings
171.1477 +     * of a set of combining marks. Note that some of the permutations
171.1478 +     * are invalid because of combining class collisions, and these
171.1479 +     * possibilities must be removed because they are not canonically
171.1480 +     * equivalent.
171.1481 +     */
171.1482 +    private String[] producePermutations(String input) {
171.1483 +        if (input.length() == countChars(input, 0, 1))
171.1484 +            return new String[] {input};
171.1485 +
171.1486 +        if (input.length() == countChars(input, 0, 2)) {
171.1487 +            int c0 = Character.codePointAt(input, 0);
171.1488 +            int c1 = Character.codePointAt(input, Character.charCount(c0));
171.1489 +            if (getClass(c1) == getClass(c0)) {
171.1490 +                return new String[] {input};
171.1491 +            }
171.1492 +            String[] result = new String[2];
171.1493 +            result[0] = input;
171.1494 +            StringBuilder sb = new StringBuilder(2);
171.1495 +            sb.appendCodePoint(c1);
171.1496 +            sb.appendCodePoint(c0);
171.1497 +            result[1] = sb.toString();
171.1498 +            return result;
171.1499 +        }
171.1500 +
171.1501 +        int length = 1;
171.1502 +        int nCodePoints = countCodePoints(input);
171.1503 +        for(int x=1; x<nCodePoints; x++)
171.1504 +            length = length * (x+1);
171.1505 +
171.1506 +        String[] temp = new String[length];
171.1507 +
171.1508 +        int combClass[] = new int[nCodePoints];
171.1509 +        for(int x=0, i=0; x<nCodePoints; x++) {
171.1510 +            int c = Character.codePointAt(input, i);
171.1511 +            combClass[x] = getClass(c);
171.1512 +            i +=  Character.charCount(c);
171.1513 +        }
171.1514 +
171.1515 +        // For each char, take it out and add the permutations
171.1516 +        // of the remaining chars
171.1517 +        int index = 0;
171.1518 +        int len;
171.1519 +        // offset maintains the index in code units.
171.1520 +loop:   for(int x=0, offset=0; x<nCodePoints; x++, offset+=len) {
171.1521 +            len = countChars(input, offset, 1);
171.1522 +            boolean skip = false;
171.1523 +            for(int y=x-1; y>=0; y--) {
171.1524 +                if (combClass[y] == combClass[x]) {
171.1525 +                    continue loop;
171.1526 +                }
171.1527 +            }
171.1528 +            StringBuilder sb = new StringBuilder(input);
171.1529 +            String otherChars = sb.delete(offset, offset+len).toString();
171.1530 +            String[] subResult = producePermutations(otherChars);
171.1531 +
171.1532 +            String prefix = input.substring(offset, offset+len);
171.1533 +            for(int y=0; y<subResult.length; y++)
171.1534 +                temp[index++] =  prefix + subResult[y];
171.1535 +        }
171.1536 +        String[] result = new String[index];
171.1537 +        for (int x=0; x<index; x++)
171.1538 +            result[x] = temp[x];
171.1539 +        return result;
171.1540 +    }
171.1541 +
171.1542 +    private int getClass(int c) {
171.1543 +        return Normalizer.getCombiningClass(c);
171.1544 +    }
171.1545 +
171.1546 +    /**
171.1547 +     * Attempts to compose input by combining the first character
171.1548 +     * with the first combining mark following it. Returns a String
171.1549 +     * that is the composition of the leading character with its first
171.1550 +     * combining mark followed by the remaining combining marks. Returns
171.1551 +     * null if the first two characters cannot be further composed.
171.1552 +     */
171.1553 +    private String composeOneStep(String input) {
171.1554 +        int len = countChars(input, 0, 2);
171.1555 +        String firstTwoCharacters = input.substring(0, len);
171.1556 +        String result = Normalizer.normalize(firstTwoCharacters, Normalizer.NFC);
171.1557 +
171.1558 +        if (result.equals(firstTwoCharacters))
171.1559 +            return null;
171.1560 +        else {
171.1561 +            String remainder = input.substring(len);
171.1562 +            return result + remainder;
171.1563 +        }
171.1564 +    }
171.1565 +
171.1566 +    /**
171.1567 +     * Preprocess any \Q...\E sequences in `temp', meta-quoting them.
171.1568 +     * See the description of `quotemeta' in perlfunc(1).
171.1569 +     */
171.1570 +    private void RemoveQEQuoting() {
171.1571 +        final int pLen = patternLength;
171.1572 +        int i = 0;
171.1573 +        while (i < pLen-1) {
171.1574 +            if (temp[i] != '\\')
171.1575 +                i += 1;
171.1576 +            else if (temp[i + 1] != 'Q')
171.1577 +                i += 2;
171.1578 +            else
171.1579 +                break;
171.1580 +        }
171.1581 +        if (i >= pLen - 1)    // No \Q sequence found
171.1582 +            return;
171.1583 +        int j = i;
171.1584 +        i += 2;
171.1585 +        int[] newtemp = new int[j + 2*(pLen-i) + 2];
171.1586 +        System.arraycopy(temp, 0, newtemp, 0, j);
171.1587 +
171.1588 +        boolean inQuote = true;
171.1589 +        while (i < pLen) {
171.1590 +            int c = temp[i++];
171.1591 +            if (! ASCII.isAscii(c) || ASCII.isAlnum(c)) {
171.1592 +                newtemp[j++] = c;
171.1593 +            } else if (c != '\\') {
171.1594 +                if (inQuote) newtemp[j++] = '\\';
171.1595 +                newtemp[j++] = c;
171.1596 +            } else if (inQuote) {
171.1597 +                if (temp[i] == 'E') {
171.1598 +                    i++;
171.1599 +                    inQuote = false;
171.1600 +                } else {
171.1601 +                    newtemp[j++] = '\\';
171.1602 +                    newtemp[j++] = '\\';
171.1603 +                }
171.1604 +            } else {
171.1605 +                if (temp[i] == 'Q') {
171.1606 +                    i++;
171.1607 +                    inQuote = true;
171.1608 +                } else {
171.1609 +                    newtemp[j++] = c;
171.1610 +                    if (i != pLen)
171.1611 +                        newtemp[j++] = temp[i++];
171.1612 +                }
171.1613 +            }
171.1614 +        }
171.1615 +
171.1616 +        patternLength = j;
171.1617 +        temp = Arrays.copyOf(newtemp, j + 2); // double zero termination
171.1618 +    }
171.1619 +
171.1620 +    /**
171.1621 +     * Copies regular expression to an int array and invokes the parsing
171.1622 +     * of the expression which will create the object tree.
171.1623 +     */
171.1624 +    private void compile() {
171.1625 +        // Handle canonical equivalences
171.1626 +        if (has(CANON_EQ) && !has(LITERAL)) {
171.1627 +            normalize();
171.1628 +        } else {
171.1629 +            normalizedPattern = pattern;
171.1630 +        }
171.1631 +        patternLength = normalizedPattern.length();
171.1632 +
171.1633 +        // Copy pattern to int array for convenience
171.1634 +        // Use double zero to terminate pattern
171.1635 +        temp = new int[patternLength + 2];
171.1636 +
171.1637 +        hasSupplementary = false;
171.1638 +        int c, count = 0;
171.1639 +        // Convert all chars into code points
171.1640 +        for (int x = 0; x < patternLength; x += Character.charCount(c)) {
171.1641 +            c = normalizedPattern.codePointAt(x);
171.1642 +            if (isSupplementary(c)) {
171.1643 +                hasSupplementary = true;
171.1644 +            }
171.1645 +            temp[count++] = c;
171.1646 +        }
171.1647 +
171.1648 +        patternLength = count;   // patternLength now in code points
171.1649 +
171.1650 +        if (! has(LITERAL))
171.1651 +            RemoveQEQuoting();
171.1652 +
171.1653 +        // Allocate all temporary objects here.
171.1654 +        buffer = new int[32];
171.1655 +        groupNodes = new GroupHead[10];
171.1656 +        namedGroups = null;
171.1657 +
171.1658 +        if (has(LITERAL)) {
171.1659 +            // Literal pattern handling
171.1660 +            matchRoot = newSlice(temp, patternLength, hasSupplementary);
171.1661 +            matchRoot.next = lastAccept;
171.1662 +        } else {
171.1663 +            // Start recursive descent parsing
171.1664 +            matchRoot = expr(lastAccept);
171.1665 +            // Check extra pattern characters
171.1666 +            if (patternLength != cursor) {
171.1667 +                if (peek() == ')') {
171.1668 +                    throw error("Unmatched closing ')'");
171.1669 +                } else {
171.1670 +                    throw error("Unexpected internal error");
171.1671 +                }
171.1672 +            }
171.1673 +        }
171.1674 +
171.1675 +        // Peephole optimization
171.1676 +        if (matchRoot instanceof Slice) {
171.1677 +            root = BnM.optimize(matchRoot);
171.1678 +            if (root == matchRoot) {
171.1679 +                root = hasSupplementary ? new StartS(matchRoot) : new Start(matchRoot);
171.1680 +            }
171.1681 +        } else if (matchRoot instanceof Begin || matchRoot instanceof First) {
171.1682 +            root = matchRoot;
171.1683 +        } else {
171.1684 +            root = hasSupplementary ? new StartS(matchRoot) : new Start(matchRoot);
171.1685 +        }
171.1686 +
171.1687 +        // Release temporary storage
171.1688 +        temp = null;
171.1689 +        buffer = null;
171.1690 +        groupNodes = null;
171.1691 +        patternLength = 0;
171.1692 +        compiled = true;
171.1693 +    }
171.1694 +
171.1695 +    Map<String, Integer> namedGroups() {
171.1696 +        if (namedGroups == null)
171.1697 +            namedGroups = new HashMap<>(2);
171.1698 +        return namedGroups;
171.1699 +    }
171.1700 +
171.1701 +    /**
171.1702 +     * Used to print out a subtree of the Pattern to help with debugging.
171.1703 +     */
171.1704 +    private static void printObjectTree(Node node) {
171.1705 +        while(node != null) {
171.1706 +            if (node instanceof Prolog) {
171.1707 +                System.out.println(node);
171.1708 +                printObjectTree(((Prolog)node).loop);
171.1709 +                System.out.println("**** end contents prolog loop");
171.1710 +            } else if (node instanceof Loop) {
171.1711 +                System.out.println(node);
171.1712 +                printObjectTree(((Loop)node).body);
171.1713 +                System.out.println("**** end contents Loop body");
171.1714 +            } else if (node instanceof Curly) {
171.1715 +                System.out.println(node);
171.1716 +                printObjectTree(((Curly)node).atom);
171.1717 +                System.out.println("**** end contents Curly body");
171.1718 +            } else if (node instanceof GroupCurly) {
171.1719 +                System.out.println(node);
171.1720 +                printObjectTree(((GroupCurly)node).atom);
171.1721 +                System.out.println("**** end contents GroupCurly body");
171.1722 +            } else if (node instanceof GroupTail) {
171.1723 +                System.out.println(node);
171.1724 +                System.out.println("Tail next is "+node.next);
171.1725 +                return;
171.1726 +            } else {
171.1727 +                System.out.println(node);
171.1728 +            }
171.1729 +            node = node.next;
171.1730 +            if (node != null)
171.1731 +                System.out.println("->next:");
171.1732 +            if (node == Pattern.accept) {
171.1733 +                System.out.println("Accept Node");
171.1734 +                node = null;
171.1735 +            }
171.1736 +       }
171.1737 +    }
171.1738 +
171.1739 +    /**
171.1740 +     * Used to accumulate information about a subtree of the object graph
171.1741 +     * so that optimizations can be applied to the subtree.
171.1742 +     */
171.1743 +    static final class TreeInfo {
171.1744 +        int minLength;
171.1745 +        int maxLength;
171.1746 +        boolean maxValid;
171.1747 +        boolean deterministic;
171.1748 +
171.1749 +        TreeInfo() {
171.1750 +            reset();
171.1751 +        }
171.1752 +        void reset() {
171.1753 +            minLength = 0;
171.1754 +            maxLength = 0;
171.1755 +            maxValid = true;
171.1756 +            deterministic = true;
171.1757 +        }
171.1758 +    }
171.1759 +
171.1760 +    /*
171.1761 +     * The following private methods are mainly used to improve the
171.1762 +     * readability of the code. In order to let the Java compiler easily
171.1763 +     * inline them, we should not put many assertions or error checks in them.
171.1764 +     */
171.1765 +
171.1766 +    /**
171.1767 +     * Indicates whether a particular flag is set or not.
171.1768 +     */
171.1769 +    private boolean has(int f) {
171.1770 +        return (flags & f) != 0;
171.1771 +    }
171.1772 +
171.1773 +    /**
171.1774 +     * Match next character, signal error if failed.
171.1775 +     */
171.1776 +    private void accept(int ch, String s) {
171.1777 +        int testChar = temp[cursor++];
171.1778 +        if (has(COMMENTS))
171.1779 +            testChar = parsePastWhitespace(testChar);
171.1780 +        if (ch != testChar) {
171.1781 +            throw error(s);
171.1782 +        }
171.1783 +    }
171.1784 +
171.1785 +    /**
171.1786 +     * Mark the end of pattern with a specific character.
171.1787 +     */
171.1788 +    private void mark(int c) {
171.1789 +        temp[patternLength] = c;
171.1790 +    }
171.1791 +
171.1792 +    /**
171.1793 +     * Peek the next character, and do not advance the cursor.
171.1794 +     */
171.1795 +    private int peek() {
171.1796 +        int ch = temp[cursor];
171.1797 +        if (has(COMMENTS))
171.1798 +            ch = peekPastWhitespace(ch);
171.1799 +        return ch;
171.1800 +    }
171.1801 +
171.1802 +    /**
171.1803 +     * Read the next character, and advance the cursor by one.
171.1804 +     */
171.1805 +    private int read() {
171.1806 +        int ch = temp[cursor++];
171.1807 +        if (has(COMMENTS))
171.1808 +            ch = parsePastWhitespace(ch);
171.1809 +        return ch;
171.1810 +    }
171.1811 +
171.1812 +    /**
171.1813 +     * Read the next character, and advance the cursor by one,
171.1814 +     * ignoring the COMMENTS setting
171.1815 +     */
171.1816 +    private int readEscaped() {
171.1817 +        int ch = temp[cursor++];
171.1818 +        return ch;
171.1819 +    }
171.1820 +
171.1821 +    /**
171.1822 +     * Advance the cursor by one, and peek the next character.
171.1823 +     */
171.1824 +    private int next() {
171.1825 +        int ch = temp[++cursor];
171.1826 +        if (has(COMMENTS))
171.1827 +            ch = peekPastWhitespace(ch);
171.1828 +        return ch;
171.1829 +    }
171.1830 +
171.1831 +    /**
171.1832 +     * Advance the cursor by one, and peek the next character,
171.1833 +     * ignoring the COMMENTS setting
171.1834 +     */
171.1835 +    private int nextEscaped() {
171.1836 +        int ch = temp[++cursor];
171.1837 +        return ch;
171.1838 +    }
171.1839 +
171.1840 +    /**
171.1841 +     * If in xmode peek past whitespace and comments.
171.1842 +     */
171.1843 +    private int peekPastWhitespace(int ch) {
171.1844 +        while (ASCII.isSpace(ch) || ch == '#') {
171.1845 +            while (ASCII.isSpace(ch))
171.1846 +                ch = temp[++cursor];
171.1847 +            if (ch == '#') {
171.1848 +                ch = peekPastLine();
171.1849 +            }
171.1850 +        }
171.1851 +        return ch;
171.1852 +    }
171.1853 +
171.1854 +    /**
171.1855 +     * If in xmode parse past whitespace and comments.
171.1856 +     */
171.1857 +    private int parsePastWhitespace(int ch) {
171.1858 +        while (ASCII.isSpace(ch) || ch == '#') {
171.1859 +            while (ASCII.isSpace(ch))
171.1860 +                ch = temp[cursor++];
171.1861 +            if (ch == '#')
171.1862 +                ch = parsePastLine();
171.1863 +        }
171.1864 +        return ch;
171.1865 +    }
171.1866 +
171.1867 +    /**
171.1868 +     * xmode parse past comment to end of line.
171.1869 +     */
171.1870 +    private int parsePastLine() {
171.1871 +        int ch = temp[cursor++];
171.1872 +        while (ch != 0 && !isLineSeparator(ch))
171.1873 +            ch = temp[cursor++];
171.1874 +        return ch;
171.1875 +    }
171.1876 +
171.1877 +    /**
171.1878 +     * xmode peek past comment to end of line.
171.1879 +     */
171.1880 +    private int peekPastLine() {
171.1881 +        int ch = temp[++cursor];
171.1882 +        while (ch != 0 && !isLineSeparator(ch))
171.1883 +            ch = temp[++cursor];
171.1884 +        return ch;
171.1885 +    }
171.1886 +
171.1887 +    /**
171.1888 +     * Determines if character is a line separator in the current mode
171.1889 +     */
171.1890 +    private boolean isLineSeparator(int ch) {
171.1891 +        if (has(UNIX_LINES)) {
171.1892 +            return ch == '\n';
171.1893 +        } else {
171.1894 +            return (ch == '\n' ||
171.1895 +                    ch == '\r' ||
171.1896 +                    (ch|1) == '\u2029' ||
171.1897 +                    ch == '\u0085');
171.1898 +        }
171.1899 +    }
171.1900 +
171.1901 +    /**
171.1902 +     * Read the character after the next one, and advance the cursor by two.
171.1903 +     */
171.1904 +    private int skip() {
171.1905 +        int i = cursor;
171.1906 +        int ch = temp[i+1];
171.1907 +        cursor = i + 2;
171.1908 +        return ch;
171.1909 +    }
171.1910 +
171.1911 +    /**
171.1912 +     * Unread one next character, and retreat cursor by one.
171.1913 +     */
171.1914 +    private void unread() {
171.1915 +        cursor--;
171.1916 +    }
171.1917 +
171.1918 +    /**
171.1919 +     * Internal method used for handling all syntax errors. The pattern is
171.1920 +     * displayed with a pointer to aid in locating the syntax error.
171.1921 +     */
171.1922 +    private PatternSyntaxException error(String s) {
171.1923 +        return new PatternSyntaxException(s, normalizedPattern,  cursor - 1);
171.1924 +    }
171.1925 +
171.1926 +    /**
171.1927 +     * Determines if there is any supplementary character or unpaired
171.1928 +     * surrogate in the specified range.
171.1929 +     */
171.1930 +    private boolean findSupplementary(int start, int end) {
171.1931 +        for (int i = start; i < end; i++) {
171.1932 +            if (isSupplementary(temp[i]))
171.1933 +                return true;
171.1934 +        }
171.1935 +        return false;
171.1936 +    }
171.1937 +
171.1938 +    /**
171.1939 +     * Determines if the specified code point is a supplementary
171.1940 +     * character or unpaired surrogate.
171.1941 +     */
171.1942 +    private static final boolean isSupplementary(int ch) {
171.1943 +        return ch >= Character.MIN_SUPPLEMENTARY_CODE_POINT ||
171.1944 +               Character.isSurrogate((char)ch);
171.1945 +    }
171.1946 +
171.1947 +    /**
171.1948 +     *  The following methods handle the main parsing. They are sorted
171.1949 +     *  according to their precedence order, the lowest one first.
171.1950 +     */
171.1951 +
171.1952 +    /**
171.1953 +     * The expression is parsed with branch nodes added for alternations.
171.1954 +     * This may be called recursively to parse sub expressions that may
171.1955 +     * contain alternations.
171.1956 +     */
171.1957 +    private Node expr(Node end) {
171.1958 +        Node prev = null;
171.1959 +        Node firstTail = null;
171.1960 +        Node branchConn = null;
171.1961 +
171.1962 +        for (;;) {
171.1963 +            Node node = sequence(end);
171.1964 +            Node nodeTail = root;      //double return
171.1965 +            if (prev == null) {
171.1966 +                prev = node;
171.1967 +                firstTail = nodeTail;
171.1968 +            } else {
171.1969 +                // Branch
171.1970 +                if (branchConn == null) {
171.1971 +                    branchConn = new BranchConn();
171.1972 +                    branchConn.next = end;
171.1973 +                }
171.1974 +                if (node == end) {
171.1975 +                    // if the node returned from sequence() is "end"
171.1976 +                    // we have an empty expr, set a null atom into
171.1977 +                    // the branch to indicate to go "next" directly.
171.1978 +                    node = null;
171.1979 +                } else {
171.1980 +                    // the "tail.next" of each atom goes to branchConn
171.1981 +                    nodeTail.next = branchConn;
171.1982 +                }
171.1983 +                if (prev instanceof Branch) {
171.1984 +                    ((Branch)prev).add(node);
171.1985 +                } else {
171.1986 +                    if (prev == end) {
171.1987 +                        prev = null;
171.1988 +                    } else {
171.1989 +                        // replace the "end" with "branchConn" at its tail.next
171.1990 +                        // when put the "prev" into the branch as the first atom.
171.1991 +                        firstTail.next = branchConn;
171.1992 +                    }
171.1993 +                    prev = new Branch(prev, node, branchConn);
171.1994 +                }
171.1995 +            }
171.1996 +            if (peek() != '|') {
171.1997 +                return prev;
171.1998 +            }
171.1999 +            next();
171.2000 +        }
171.2001 +    }
171.2002 +
171.2003 +    /**
171.2004 +     * Parsing of sequences between alternations.
171.2005 +     */
171.2006 +    private Node sequence(Node end) {
171.2007 +        Node head = null;
171.2008 +        Node tail = null;
171.2009 +        Node node = null;
171.2010 +    LOOP:
171.2011 +        for (;;) {
171.2012 +            int ch = peek();
171.2013 +            switch (ch) {
171.2014 +            case '(':
171.2015 +                // Because group handles its own closure,
171.2016 +                // we need to treat it differently
171.2017 +                node = group0();
171.2018 +                // Check for comment or flag group
171.2019 +                if (node == null)
171.2020 +                    continue;
171.2021 +                if (head == null)
171.2022 +                    head = node;
171.2023 +                else
171.2024 +                    tail.next = node;
171.2025 +                // Double return: Tail was returned in root
171.2026 +                tail = root;
171.2027 +                continue;
171.2028 +            case '[':
171.2029 +                node = clazz(true);
171.2030 +                break;
171.2031 +            case '\\':
171.2032 +                ch = nextEscaped();
171.2033 +                if (ch == 'p' || ch == 'P') {
171.2034 +                    boolean oneLetter = true;
171.2035 +                    boolean comp = (ch == 'P');
171.2036 +                    ch = next(); // Consume { if present
171.2037 +                    if (ch != '{') {
171.2038 +                        unread();
171.2039 +                    } else {
171.2040 +                        oneLetter = false;
171.2041 +                    }
171.2042 +                    node = family(oneLetter, comp);
171.2043 +                } else {
171.2044 +                    unread();
171.2045 +                    node = atom();
171.2046 +                }
171.2047 +                break;
171.2048 +            case '^':
171.2049 +                next();
171.2050 +                if (has(MULTILINE)) {
171.2051 +                    if (has(UNIX_LINES))
171.2052 +                        node = new UnixCaret();
171.2053 +                    else
171.2054 +                        node = new Caret();
171.2055 +                } else {
171.2056 +                    node = new Begin();
171.2057 +                }
171.2058 +                break;
171.2059 +            case '$':
171.2060 +                next();
171.2061 +                if (has(UNIX_LINES))
171.2062 +                    node = new UnixDollar(has(MULTILINE));
171.2063 +                else
171.2064 +                    node = new Dollar(has(MULTILINE));
171.2065 +                break;
171.2066 +            case '.':
171.2067 +                next();
171.2068 +                if (has(DOTALL)) {
171.2069 +                    node = new All();
171.2070 +                } else {
171.2071 +                    if (has(UNIX_LINES))
171.2072 +                        node = new UnixDot();
171.2073 +                    else {
171.2074 +                        node = new Dot();
171.2075 +                    }
171.2076 +                }
171.2077 +                break;
171.2078 +            case '|':
171.2079 +            case ')':
171.2080 +                break LOOP;
171.2081 +            case ']': // Now interpreting dangling ] and } as literals
171.2082 +            case '}':
171.2083 +                node = atom();
171.2084 +                break;
171.2085 +            case '?':
171.2086 +            case '*':
171.2087 +            case '+':
171.2088 +                next();
171.2089 +                throw error("Dangling meta character '" + ((char)ch) + "'");
171.2090 +            case 0:
171.2091 +                if (cursor >= patternLength) {
171.2092 +                    break LOOP;
171.2093 +                }
171.2094 +                // Fall through
171.2095 +            default:
171.2096 +                node = atom();
171.2097 +                break;
171.2098 +            }
171.2099 +
171.2100 +            node = closure(node);
171.2101 +
171.2102 +            if (head == null) {
171.2103 +                head = tail = node;
171.2104 +            } else {
171.2105 +                tail.next = node;
171.2106 +                tail = node;
171.2107 +            }
171.2108 +        }
171.2109 +        if (head == null) {
171.2110 +            return end;
171.2111 +        }
171.2112 +        tail.next = end;
171.2113 +        root = tail;      //double return
171.2114 +        return head;
171.2115 +    }
171.2116 +
171.2117 +    /**
171.2118 +     * Parse and add a new Single or Slice.
171.2119 +     */
171.2120 +    private Node atom() {
171.2121 +        int first = 0;
171.2122 +        int prev = -1;
171.2123 +        boolean hasSupplementary = false;
171.2124 +        int ch = peek();
171.2125 +        for (;;) {
171.2126 +            switch (ch) {
171.2127 +            case '*':
171.2128 +            case '+':
171.2129 +            case '?':
171.2130 +            case '{':
171.2131 +                if (first > 1) {
171.2132 +                    cursor = prev;    // Unwind one character
171.2133 +                    first--;
171.2134 +                }
171.2135 +                break;
171.2136 +            case '$':
171.2137 +            case '.':
171.2138 +            case '^':
171.2139 +            case '(':
171.2140 +            case '[':
171.2141 +            case '|':
171.2142 +            case ')':
171.2143 +                break;
171.2144 +            case '\\':
171.2145 +                ch = nextEscaped();
171.2146 +                if (ch == 'p' || ch == 'P') { // Property
171.2147 +                    if (first > 0) { // Slice is waiting; handle it first
171.2148 +                        unread();
171.2149 +                        break;
171.2150 +                    } else { // No slice; just return the family node
171.2151 +                        boolean comp = (ch == 'P');
171.2152 +                        boolean oneLetter = true;
171.2153 +                        ch = next(); // Consume { if present
171.2154 +                        if (ch != '{')
171.2155 +                            unread();
171.2156 +                        else
171.2157 +                            oneLetter = false;
171.2158 +                        return family(oneLetter, comp);
171.2159 +                    }
171.2160 +                }
171.2161 +                unread();
171.2162 +                prev = cursor;
171.2163 +                ch = escape(false, first == 0);
171.2164 +                if (ch >= 0) {
171.2165 +                    append(ch, first);
171.2166 +                    first++;
171.2167 +                    if (isSupplementary(ch)) {
171.2168 +                        hasSupplementary = true;
171.2169 +                    }
171.2170 +                    ch = peek();
171.2171 +                    continue;
171.2172 +                } else if (first == 0) {
171.2173 +                    return root;
171.2174 +                }
171.2175 +                // Unwind meta escape sequence
171.2176 +                cursor = prev;
171.2177 +                break;
171.2178 +            case 0:
171.2179 +                if (cursor >= patternLength) {
171.2180 +                    break;
171.2181 +                }
171.2182 +                // Fall through
171.2183 +            default:
171.2184 +                prev = cursor;
171.2185 +                append(ch, first);
171.2186 +                first++;
171.2187 +                if (isSupplementary(ch)) {
171.2188 +                    hasSupplementary = true;
171.2189 +                }
171.2190 +                ch = next();
171.2191 +                continue;
171.2192 +            }
171.2193 +            break;
171.2194 +        }
171.2195 +        if (first == 1) {
171.2196 +            return newSingle(buffer[0]);
171.2197 +        } else {
171.2198 +            return newSlice(buffer, first, hasSupplementary);
171.2199 +        }
171.2200 +    }
171.2201 +
171.2202 +    private void append(int ch, int len) {
171.2203 +        if (len >= buffer.length) {
171.2204 +            int[] tmp = new int[len+len];
171.2205 +            System.arraycopy(buffer, 0, tmp, 0, len);
171.2206 +            buffer = tmp;
171.2207 +        }
171.2208 +        buffer[len] = ch;
171.2209 +    }
171.2210 +
171.2211 +    /**
171.2212 +     * Parses a backref greedily, taking as many numbers as it
171.2213 +     * can. The first digit is always treated as a backref, but
171.2214 +     * multi digit numbers are only treated as a backref if at
171.2215 +     * least that many backrefs exist at this point in the regex.
171.2216 +     */
171.2217 +    private Node ref(int refNum) {
171.2218 +        boolean done = false;
171.2219 +        while(!done) {
171.2220 +            int ch = peek();
171.2221 +            switch(ch) {
171.2222 +            case '0':
171.2223 +            case '1':
171.2224 +            case '2':
171.2225 +            case '3':
171.2226 +            case '4':
171.2227 +            case '5':
171.2228 +            case '6':
171.2229 +            case '7':
171.2230 +            case '8':
171.2231 +            case '9':
171.2232 +                int newRefNum = (refNum * 10) + (ch - '0');
171.2233 +                // Add another number if it doesn't make a group
171.2234 +                // that doesn't exist
171.2235 +                if (capturingGroupCount - 1 < newRefNum) {
171.2236 +                    done = true;
171.2237 +                    break;
171.2238 +                }
171.2239 +                refNum = newRefNum;
171.2240 +                read();
171.2241 +                break;
171.2242 +            default:
171.2243 +                done = true;
171.2244 +                break;
171.2245 +            }
171.2246 +        }
171.2247 +        if (has(CASE_INSENSITIVE))
171.2248 +            return new CIBackRef(refNum, has(UNICODE_CASE));
171.2249 +        else
171.2250 +            return new BackRef(refNum);
171.2251 +    }
171.2252 +
171.2253 +    /**
171.2254 +     * Parses an escape sequence to determine the actual value that needs
171.2255 +     * to be matched.
171.2256 +     * If -1 is returned and create was true a new object was added to the tree
171.2257 +     * to handle the escape sequence.
171.2258 +     * If the returned value is greater than zero, it is the value that
171.2259 +     * matches the escape sequence.
171.2260 +     */
171.2261 +    private int escape(boolean inclass, boolean create) {
171.2262 +        int ch = skip();
171.2263 +        switch (ch) {
171.2264 +        case '0':
171.2265 +            return o();
171.2266 +        case '1':
171.2267 +        case '2':
171.2268 +        case '3':
171.2269 +        case '4':
171.2270 +        case '5':
171.2271 +        case '6':
171.2272 +        case '7':
171.2273 +        case '8':
171.2274 +        case '9':
171.2275 +            if (inclass) break;
171.2276 +            if (create) {
171.2277 +                root = ref((ch - '0'));
171.2278 +            }
171.2279 +            return -1;
171.2280 +        case 'A':
171.2281 +            if (inclass) break;
171.2282 +            if (create) root = new Begin();
171.2283 +            return -1;
171.2284 +        case 'B':
171.2285 +            if (inclass) break;
171.2286 +            if (create) root = new Bound(Bound.NONE, has(UNICODE_CHARACTER_CLASS));
171.2287 +            return -1;
171.2288 +        case 'C':
171.2289 +            break;
171.2290 +        case 'D':
171.2291 +            if (create) root = has(UNICODE_CHARACTER_CLASS)
171.2292 +                               ? new Utype(UnicodeProp.DIGIT).complement()
171.2293 +                               : new Ctype(ASCII.DIGIT).complement();
171.2294 +            return -1;
171.2295 +        case 'E':
171.2296 +        case 'F':
171.2297 +            break;
171.2298 +        case 'G':
171.2299 +            if (inclass) break;
171.2300 +            if (create) root = new LastMatch();
171.2301 +            return -1;
171.2302 +        case 'H':
171.2303 +        case 'I':
171.2304 +        case 'J':
171.2305 +        case 'K':
171.2306 +        case 'L':
171.2307 +        case 'M':
171.2308 +        case 'N':
171.2309 +        case 'O':
171.2310 +        case 'P':
171.2311 +        case 'Q':
171.2312 +        case 'R':
171.2313 +            break;
171.2314 +        case 'S':
171.2315 +            if (create) root = has(UNICODE_CHARACTER_CLASS)
171.2316 +                               ? new Utype(UnicodeProp.WHITE_SPACE).complement()
171.2317 +                               : new Ctype(ASCII.SPACE).complement();
171.2318 +            return -1;
171.2319 +        case 'T':
171.2320 +        case 'U':
171.2321 +        case 'V':
171.2322 +            break;
171.2323 +        case 'W':
171.2324 +            if (create) root = has(UNICODE_CHARACTER_CLASS)
171.2325 +                               ? new Utype(UnicodeProp.WORD).complement()
171.2326 +                               : new Ctype(ASCII.WORD).complement();
171.2327 +            return -1;
171.2328 +        case 'X':
171.2329 +        case 'Y':
171.2330 +            break;
171.2331 +        case 'Z':
171.2332 +            if (inclass) break;
171.2333 +            if (create) {
171.2334 +                if (has(UNIX_LINES))
171.2335 +                    root = new UnixDollar(false);
171.2336 +                else
171.2337 +                    root = new Dollar(false);
171.2338 +            }
171.2339 +            return -1;
171.2340 +        case 'a':
171.2341 +            return '\007';
171.2342 +        case 'b':
171.2343 +            if (inclass) break;
171.2344 +            if (create) root = new Bound(Bound.BOTH, has(UNICODE_CHARACTER_CLASS));
171.2345 +            return -1;
171.2346 +        case 'c':
171.2347 +            return c();
171.2348 +        case 'd':
171.2349 +            if (create) root = has(UNICODE_CHARACTER_CLASS)
171.2350 +                               ? new Utype(UnicodeProp.DIGIT)
171.2351 +                               : new Ctype(ASCII.DIGIT);
171.2352 +            return -1;
171.2353 +        case 'e':
171.2354 +            return '\033';
171.2355 +        case 'f':
171.2356 +            return '\f';
171.2357 +        case 'g':
171.2358 +        case 'h':
171.2359 +        case 'i':
171.2360 +        case 'j':
171.2361 +            break;
171.2362 +        case 'k':
171.2363 +            if (inclass)
171.2364 +                break;
171.2365 +            if (read() != '<')
171.2366 +                throw error("\\k is not followed by '<' for named capturing group");
171.2367 +            String name = groupname(read());
171.2368 +            if (!namedGroups().containsKey(name))
171.2369 +                throw error("(named capturing group <"+ name+"> does not exit");
171.2370 +            if (create) {
171.2371 +                if (has(CASE_INSENSITIVE))
171.2372 +                    root = new CIBackRef(namedGroups().get(name), has(UNICODE_CASE));
171.2373 +                else
171.2374 +                    root = new BackRef(namedGroups().get(name));
171.2375 +            }
171.2376 +            return -1;
171.2377 +        case 'l':
171.2378 +        case 'm':
171.2379 +            break;
171.2380 +        case 'n':
171.2381 +            return '\n';
171.2382 +        case 'o':
171.2383 +        case 'p':
171.2384 +        case 'q':
171.2385 +            break;
171.2386 +        case 'r':
171.2387 +            return '\r';
171.2388 +        case 's':
171.2389 +            if (create) root = has(UNICODE_CHARACTER_CLASS)
171.2390 +                               ? new Utype(UnicodeProp.WHITE_SPACE)
171.2391 +                               : new Ctype(ASCII.SPACE);
171.2392 +            return -1;
171.2393 +        case 't':
171.2394 +            return '\t';
171.2395 +        case 'u':
171.2396 +            return u();
171.2397 +        case 'v':
171.2398 +            return '\013';
171.2399 +        case 'w':
171.2400 +            if (create) root = has(UNICODE_CHARACTER_CLASS)
171.2401 +                               ? new Utype(UnicodeProp.WORD)
171.2402 +                               : new Ctype(ASCII.WORD);
171.2403 +            return -1;
171.2404 +        case 'x':
171.2405 +            return x();
171.2406 +        case 'y':
171.2407 +            break;
171.2408 +        case 'z':
171.2409 +            if (inclass) break;
171.2410 +            if (create) root = new End();
171.2411 +            return -1;
171.2412 +        default:
171.2413 +            return ch;
171.2414 +        }
171.2415 +        throw error("Illegal/unsupported escape sequence");
171.2416 +    }
171.2417 +
171.2418 +    /**
171.2419 +     * Parse a character class, and return the node that matches it.
171.2420 +     *
171.2421 +     * Consumes a ] on the way out if consume is true. Usually consume
171.2422 +     * is true except for the case of [abc&&def] where def is a separate
171.2423 +     * right hand node with "understood" brackets.
171.2424 +     */
171.2425 +    private CharProperty clazz(boolean consume) {
171.2426 +        CharProperty prev = null;
171.2427 +        CharProperty node = null;
171.2428 +        BitClass bits = new BitClass();
171.2429 +        boolean include = true;
171.2430 +        boolean firstInClass = true;
171.2431 +        int ch = next();
171.2432 +        for (;;) {
171.2433 +            switch (ch) {
171.2434 +                case '^':
171.2435 +                    // Negates if first char in a class, otherwise literal
171.2436 +                    if (firstInClass) {
171.2437 +                        if (temp[cursor-1] != '[')
171.2438 +                            break;
171.2439 +                        ch = next();
171.2440 +                        include = !include;
171.2441 +                        continue;
171.2442 +                    } else {
171.2443 +                        // ^ not first in class, treat as literal
171.2444 +                        break;
171.2445 +                    }
171.2446 +                case '[':
171.2447 +                    firstInClass = false;
171.2448 +                    node = clazz(true);
171.2449 +                    if (prev == null)
171.2450 +                        prev = node;
171.2451 +                    else
171.2452 +                        prev = union(prev, node);
171.2453 +                    ch = peek();
171.2454 +                    continue;
171.2455 +                case '&':
171.2456 +                    firstInClass = false;
171.2457 +                    ch = next();
171.2458 +                    if (ch == '&') {
171.2459 +                        ch = next();
171.2460 +                        CharProperty rightNode = null;
171.2461 +                        while (ch != ']' && ch != '&') {
171.2462 +                            if (ch == '[') {
171.2463 +                                if (rightNode == null)
171.2464 +                                    rightNode = clazz(true);
171.2465 +                                else
171.2466 +                                    rightNode = union(rightNode, clazz(true));
171.2467 +                            } else { // abc&&def
171.2468 +                                unread();
171.2469 +                                rightNode = clazz(false);
171.2470 +                            }
171.2471 +                            ch = peek();
171.2472 +                        }
171.2473 +                        if (rightNode != null)
171.2474 +                            node = rightNode;
171.2475 +                        if (prev == null) {
171.2476 +                            if (rightNode == null)
171.2477 +                                throw error("Bad class syntax");
171.2478 +                            else
171.2479 +                                prev = rightNode;
171.2480 +                        } else {
171.2481 +                            prev = intersection(prev, node);
171.2482 +                        }
171.2483 +                    } else {
171.2484 +                        // treat as a literal &
171.2485 +                        unread();
171.2486 +                        break;
171.2487 +                    }
171.2488 +                    continue;
171.2489 +                case 0:
171.2490 +                    firstInClass = false;
171.2491 +                    if (cursor >= patternLength)
171.2492 +                        throw error("Unclosed character class");
171.2493 +                    break;
171.2494 +                case ']':
171.2495 +                    firstInClass = false;
171.2496 +                    if (prev != null) {
171.2497 +                        if (consume)
171.2498 +                            next();
171.2499 +                        return prev;
171.2500 +                    }
171.2501 +                    break;
171.2502 +                default:
171.2503 +                    firstInClass = false;
171.2504 +                    break;
171.2505 +            }
171.2506 +            node = range(bits);
171.2507 +            if (include) {
171.2508 +                if (prev == null) {
171.2509 +                    prev = node;
171.2510 +                } else {
171.2511 +                    if (prev != node)
171.2512 +                        prev = union(prev, node);
171.2513 +                }
171.2514 +            } else {
171.2515 +                if (prev == null) {
171.2516 +                    prev = node.complement();
171.2517 +                } else {
171.2518 +                    if (prev != node)
171.2519 +                        prev = setDifference(prev, node);
171.2520 +                }
171.2521 +            }
171.2522 +            ch = peek();
171.2523 +        }
171.2524 +    }
171.2525 +
171.2526 +    private CharProperty bitsOrSingle(BitClass bits, int ch) {
171.2527 +        /* Bits can only handle codepoints in [u+0000-u+00ff] range.
171.2528 +           Use "single" node instead of bits when dealing with unicode
171.2529 +           case folding for codepoints listed below.
171.2530 +           (1)Uppercase out of range: u+00ff, u+00b5
171.2531 +              toUpperCase(u+00ff) -> u+0178
171.2532 +              toUpperCase(u+00b5) -> u+039c
171.2533 +           (2)LatinSmallLetterLongS u+17f
171.2534 +              toUpperCase(u+017f) -> u+0053
171.2535 +           (3)LatinSmallLetterDotlessI u+131
171.2536 +              toUpperCase(u+0131) -> u+0049
171.2537 +           (4)LatinCapitalLetterIWithDotAbove u+0130
171.2538 +              toLowerCase(u+0130) -> u+0069
171.2539 +           (5)KelvinSign u+212a
171.2540 +              toLowerCase(u+212a) ==> u+006B
171.2541 +           (6)AngstromSign u+212b
171.2542 +              toLowerCase(u+212b) ==> u+00e5
171.2543 +        */
171.2544 +        int d;
171.2545 +        if (ch < 256 &&
171.2546 +            !(has(CASE_INSENSITIVE) && has(UNICODE_CASE) &&
171.2547 +              (ch == 0xff || ch == 0xb5 ||
171.2548 +               ch == 0x49 || ch == 0x69 ||  //I and i
171.2549 +               ch == 0x53 || ch == 0x73 ||  //S and s
171.2550 +               ch == 0x4b || ch == 0x6b ||  //K and k
171.2551 +               ch == 0xc5 || ch == 0xe5)))  //A+ring
171.2552 +            return bits.add(ch, flags());
171.2553 +        return newSingle(ch);
171.2554 +    }
171.2555 +
171.2556 +    /**
171.2557 +     * Parse a single character or a character range in a character class
171.2558 +     * and return its representative node.
171.2559 +     */
171.2560 +    private CharProperty range(BitClass bits) {
171.2561 +        int ch = peek();
171.2562 +        if (ch == '\\') {
171.2563 +            ch = nextEscaped();
171.2564 +            if (ch == 'p' || ch == 'P') { // A property
171.2565 +                boolean comp = (ch == 'P');
171.2566 +                boolean oneLetter = true;
171.2567 +                // Consume { if present
171.2568 +                ch = next();
171.2569 +                if (ch != '{')
171.2570 +                    unread();
171.2571 +                else
171.2572 +                    oneLetter = false;
171.2573 +                return family(oneLetter, comp);
171.2574 +            } else { // ordinary escape
171.2575 +                unread();
171.2576 +                ch = escape(true, true);
171.2577 +                if (ch == -1)
171.2578 +                    return (CharProperty) root;
171.2579 +            }
171.2580 +        } else {
171.2581 +            ch = single();
171.2582 +        }
171.2583 +        if (ch >= 0) {
171.2584 +            if (peek() == '-') {
171.2585 +                int endRange = temp[cursor+1];
171.2586 +                if (endRange == '[') {
171.2587 +                    return bitsOrSingle(bits, ch);
171.2588 +                }
171.2589 +                if (endRange != ']') {
171.2590 +                    next();
171.2591 +                    int m = single();
171.2592 +                    if (m < ch)
171.2593 +                        throw error("Illegal character range");
171.2594 +                    if (has(CASE_INSENSITIVE))
171.2595 +                        return caseInsensitiveRangeFor(ch, m);
171.2596 +                    else
171.2597 +                        return rangeFor(ch, m);
171.2598 +                }
171.2599 +            }
171.2600 +            return bitsOrSingle(bits, ch);
171.2601 +        }
171.2602 +        throw error("Unexpected character '"+((char)ch)+"'");
171.2603 +    }
171.2604 +
171.2605 +    private int single() {
171.2606 +        int ch = peek();
171.2607 +        switch (ch) {
171.2608 +        case '\\':
171.2609 +            return escape(true, false);
171.2610 +        default:
171.2611 +            next();
171.2612 +            return ch;
171.2613 +        }
171.2614 +    }
171.2615 +
171.2616 +    /**
171.2617 +     * Parses a Unicode character family and returns its representative node.
171.2618 +     */
171.2619 +    private CharProperty family(boolean singleLetter,
171.2620 +                                boolean maybeComplement)
171.2621 +    {
171.2622 +        next();
171.2623 +        String name;
171.2624 +        CharProperty node = null;
171.2625 +
171.2626 +        if (singleLetter) {
171.2627 +            int c = temp[cursor];
171.2628 +            if (!Character.isSupplementaryCodePoint(c)) {
171.2629 +                name = String.valueOf((char)c);
171.2630 +            } else {
171.2631 +                name = new String(temp, cursor, 1);
171.2632 +            }
171.2633 +            read();
171.2634 +        } else {
171.2635 +            int i = cursor;
171.2636 +            mark('}');
171.2637 +            while(read() != '}') {
171.2638 +            }
171.2639 +            mark('\000');
171.2640 +            int j = cursor;
171.2641 +            if (j > patternLength)
171.2642 +                throw error("Unclosed character family");
171.2643 +            if (i + 1 >= j)
171.2644 +                throw error("Empty character family");
171.2645 +            name = new String(temp, i, j-i-1);
171.2646 +        }
171.2647 +
171.2648 +        int i = name.indexOf('=');
171.2649 +        if (i != -1) {
171.2650 +            // property construct \p{name=value}
171.2651 +            String value = name.substring(i + 1);
171.2652 +            name = name.substring(0, i).toLowerCase(Locale.ENGLISH);
171.2653 +    /*        if ("sc".equals(name) || "script".equals(name)) {
171.2654 +                node = unicodeScriptPropertyFor(value);
171.2655 +            } else if ("blk".equals(name) || "block".equals(name)) {
171.2656 +                node = unicodeBlockPropertyFor(value);
171.2657 +            } else*/ if ("gc".equals(name) || "general_category".equals(name)) {
171.2658 +                node = charPropertyNodeFor(value);
171.2659 +            } else {
171.2660 +                throw error("Unknown Unicode property {name=<" + name + ">, "
171.2661 +                             + "value=<" + value + ">}");
171.2662 +            }
171.2663 +        } else {
171.2664 +            /*if (name.startsWith("In")) {
171.2665 +                // \p{inBlockName}
171.2666 +                node = unicodeBlockPropertyFor(name.substring(2));
171.2667 +            } else if (name.startsWith("Is")) {
171.2668 +                // \p{isGeneralCategory} and \p{isScriptName}
171.2669 +                name = name.substring(2);
171.2670 +                UnicodeProp uprop = UnicodeProp.forName(name);
171.2671 +                if (uprop != null)
171.2672 +                    node = new Utype(uprop);
171.2673 +                if (node == null)
171.2674 +                    node = CharPropertyNames.charPropertyFor(name);
171.2675 +                if (node == null)
171.2676 +                    node = unicodeScriptPropertyFor(name);
171.2677 +            } else*/ {
171.2678 +                if (has(UNICODE_CHARACTER_CLASS)) {
171.2679 +                    UnicodeProp uprop = UnicodeProp.forPOSIXName(name);
171.2680 +                    if (uprop != null)
171.2681 +                        node = new Utype(uprop);
171.2682 +                }
171.2683 +                if (node == null)
171.2684 +                    node = charPropertyNodeFor(name);
171.2685 +            }
171.2686 +        }
171.2687 +        if (maybeComplement) {
171.2688 +            if (node instanceof Category /*|| node instanceof Block*/)
171.2689 +                hasSupplementary = true;
171.2690 +            node = node.complement();
171.2691 +        }
171.2692 +        return node;
171.2693 +    }
171.2694 +
171.2695 +
171.2696 +    /**
171.2697 +     * Returns a CharProperty matching all characters belong to
171.2698 +     * a UnicodeScript.
171.2699 +     *
171.2700 +    private CharProperty unicodeScriptPropertyFor(String name) {
171.2701 +        final Character.UnicodeScript script;
171.2702 +        try {
171.2703 +            script = Character.UnicodeScript.forName(name);
171.2704 +        } catch (IllegalArgumentException iae) {
171.2705 +            throw error("Unknown character script name {" + name + "}");
171.2706 +        }
171.2707 +        return new Script(script);
171.2708 +    }
171.2709 +
171.2710 +    /**
171.2711 +     * Returns a CharProperty matching all characters in a UnicodeBlock.
171.2712 +     *
171.2713 +    private CharProperty unicodeBlockPropertyFor(String name) {
171.2714 +        final Character.UnicodeBlock block;
171.2715 +        try {
171.2716 +            block = Character.UnicodeBlock.forName(name);
171.2717 +        } catch (IllegalArgumentException iae) {
171.2718 +            throw error("Unknown character block name {" + name + "}");
171.2719 +        }
171.2720 +        return new Block(block);
171.2721 +    }
171.2722 +
171.2723 +    /**
171.2724 +     * Returns a CharProperty matching all characters in a named property.
171.2725 +     */
171.2726 +    private CharProperty charPropertyNodeFor(String name) {
171.2727 +        CharProperty p = CharPropertyNames.charPropertyFor(name);
171.2728 +        if (p == null)
171.2729 +            throw error("Unknown character property name {" + name + "}");
171.2730 +        return p;
171.2731 +    }
171.2732 +
171.2733 +    /**
171.2734 +     * Parses and returns the name of a "named capturing group", the trailing
171.2735 +     * ">" is consumed after parsing.
171.2736 +     */
171.2737 +    private String groupname(int ch) {
171.2738 +        StringBuilder sb = new StringBuilder();
171.2739 +        sb.append(Character.toChars(ch));
171.2740 +        while (ASCII.isLower(ch=read()) || ASCII.isUpper(ch) ||
171.2741 +               ASCII.isDigit(ch)) {
171.2742 +            sb.append(Character.toChars(ch));
171.2743 +        }
171.2744 +        if (sb.length() == 0)
171.2745 +            throw error("named capturing group has 0 length name");
171.2746 +        if (ch != '>')
171.2747 +            throw error("named capturing group is missing trailing '>'");
171.2748 +        return sb.toString();
171.2749 +    }
171.2750 +
171.2751 +    /**
171.2752 +     * Parses a group and returns the head node of a set of nodes that process
171.2753 +     * the group. Sometimes a double return system is used where the tail is
171.2754 +     * returned in root.
171.2755 +     */
171.2756 +    private Node group0() {
171.2757 +        boolean capturingGroup = false;
171.2758 +        Node head = null;
171.2759 +        Node tail = null;
171.2760 +        int save = flags;
171.2761 +        root = null;
171.2762 +        int ch = next();
171.2763 +        if (ch == '?') {
171.2764 +            ch = skip();
171.2765 +            switch (ch) {
171.2766 +            case ':':   //  (?:xxx) pure group
171.2767 +                head = createGroup(true);
171.2768 +                tail = root;
171.2769 +                head.next = expr(tail);
171.2770 +                break;
171.2771 +            case '=':   // (?=xxx) and (?!xxx) lookahead
171.2772 +            case '!':
171.2773 +                head = createGroup(true);
171.2774 +                tail = root;
171.2775 +                head.next = expr(tail);
171.2776 +                if (ch == '=') {
171.2777 +                    head = tail = new Pos(head);
171.2778 +                } else {
171.2779 +                    head = tail = new Neg(head);
171.2780 +                }
171.2781 +                break;
171.2782 +            case '>':   // (?>xxx)  independent group
171.2783 +                head = createGroup(true);
171.2784 +                tail = root;
171.2785 +                head.next = expr(tail);
171.2786 +                head = tail = new Ques(head, INDEPENDENT);
171.2787 +                break;
171.2788 +            case '<':   // (?<xxx)  look behind
171.2789 +                ch = read();
171.2790 +                if (ASCII.isLower(ch) || ASCII.isUpper(ch)) {
171.2791 +                    // named captured group
171.2792 +                    String name = groupname(ch);
171.2793 +                    if (namedGroups().containsKey(name))
171.2794 +                        throw error("Named capturing group <" + name
171.2795 +                                    + "> is already defined");
171.2796 +                    capturingGroup = true;
171.2797 +                    head = createGroup(false);
171.2798 +                    tail = root;
171.2799 +                    namedGroups().put(name, capturingGroupCount-1);
171.2800 +                    head.next = expr(tail);
171.2801 +                    break;
171.2802 +                }
171.2803 +                int start = cursor;
171.2804 +                head = createGroup(true);
171.2805 +                tail = root;
171.2806 +                head.next = expr(tail);
171.2807 +                tail.next = lookbehindEnd;
171.2808 +                TreeInfo info = new TreeInfo();
171.2809 +                head.study(info);
171.2810 +                if (info.maxValid == false) {
171.2811 +                    throw error("Look-behind group does not have "
171.2812 +                                + "an obvious maximum length");
171.2813 +                }
171.2814 +                boolean hasSupplementary = findSupplementary(start, patternLength);
171.2815 +                if (ch == '=') {
171.2816 +                    head = tail = (hasSupplementary ?
171.2817 +                                   new BehindS(head, info.maxLength,
171.2818 +                                               info.minLength) :
171.2819 +                                   new Behind(head, info.maxLength,
171.2820 +                                              info.minLength));
171.2821 +                } else if (ch == '!') {
171.2822 +                    head = tail = (hasSupplementary ?
171.2823 +                                   new NotBehindS(head, info.maxLength,
171.2824 +                                                  info.minLength) :
171.2825 +                                   new NotBehind(head, info.maxLength,
171.2826 +                                                 info.minLength));
171.2827 +                } else {
171.2828 +                    throw error("Unknown look-behind group");
171.2829 +                }
171.2830 +                break;
171.2831 +            case '$':
171.2832 +            case '@':
171.2833 +                throw error("Unknown group type");
171.2834 +            default:    // (?xxx:) inlined match flags
171.2835 +                unread();
171.2836 +                addFlag();
171.2837 +                ch = read();
171.2838 +                if (ch == ')') {
171.2839 +                    return null;    // Inline modifier only
171.2840 +                }
171.2841 +                if (ch != ':') {
171.2842 +                    throw error("Unknown inline modifier");
171.2843 +                }
171.2844 +                head = createGroup(true);
171.2845 +                tail = root;
171.2846 +                head.next = expr(tail);
171.2847 +                break;
171.2848 +            }
171.2849 +        } else { // (xxx) a regular group
171.2850 +            capturingGroup = true;
171.2851 +            head = createGroup(false);
171.2852 +            tail = root;
171.2853 +            head.next = expr(tail);
171.2854 +        }
171.2855 +
171.2856 +        accept(')', "Unclosed group");
171.2857 +        flags = save;
171.2858 +
171.2859 +        // Check for quantifiers
171.2860 +        Node node = closure(head);
171.2861 +        if (node == head) { // No closure
171.2862 +            root = tail;
171.2863 +            return node;    // Dual return
171.2864 +        }
171.2865 +        if (head == tail) { // Zero length assertion
171.2866 +            root = node;
171.2867 +            return node;    // Dual return
171.2868 +        }
171.2869 +
171.2870 +        if (node instanceof Ques) {
171.2871 +            Ques ques = (Ques) node;
171.2872 +            if (ques.type == POSSESSIVE) {
171.2873 +                root = node;
171.2874 +                return node;
171.2875 +            }
171.2876 +            tail.next = new BranchConn();
171.2877 +            tail = tail.next;
171.2878 +            if (ques.type == GREEDY) {
171.2879 +                head = new Branch(head, null, tail);
171.2880 +            } else { // Reluctant quantifier
171.2881 +                head = new Branch(null, head, tail);
171.2882 +            }
171.2883 +            root = tail;
171.2884 +            return head;
171.2885 +        } else if (node instanceof Curly) {
171.2886 +            Curly curly = (Curly) node;
171.2887 +            if (curly.type == POSSESSIVE) {
171.2888 +                root = node;
171.2889 +                return node;
171.2890 +            }
171.2891 +            // Discover if the group is deterministic
171.2892 +            TreeInfo info = new TreeInfo();
171.2893 +            if (head.study(info)) { // Deterministic
171.2894 +                GroupTail temp = (GroupTail) tail;
171.2895 +                head = root = new GroupCurly(head.next, curly.cmin,
171.2896 +                                   curly.cmax, curly.type,
171.2897 +                                   ((GroupTail)tail).localIndex,
171.2898 +                                   ((GroupTail)tail).groupIndex,
171.2899 +                                             capturingGroup);
171.2900 +                return head;
171.2901 +            } else { // Non-deterministic
171.2902 +                int temp = ((GroupHead) head).localIndex;
171.2903 +                Loop loop;
171.2904 +                if (curly.type == GREEDY)
171.2905 +                    loop = new Loop(this.localCount, temp);
171.2906 +                else  // Reluctant Curly
171.2907 +                    loop = new LazyLoop(this.localCount, temp);
171.2908 +                Prolog prolog = new Prolog(loop);
171.2909 +                this.localCount += 1;
171.2910 +                loop.cmin = curly.cmin;
171.2911 +                loop.cmax = curly.cmax;
171.2912 +                loop.body = head;
171.2913 +                tail.next = loop;
171.2914 +                root = loop;
171.2915 +                return prolog; // Dual return
171.2916 +            }
171.2917 +        }
171.2918 +        throw error("Internal logic error");
171.2919 +    }
171.2920 +
171.2921 +    /**
171.2922 +     * Create group head and tail nodes using double return. If the group is
171.2923 +     * created with anonymous true then it is a pure group and should not
171.2924 +     * affect group counting.
171.2925 +     */
171.2926 +    private Node createGroup(boolean anonymous) {
171.2927 +        int localIndex = localCount++;
171.2928 +        int groupIndex = 0;
171.2929 +        if (!anonymous)
171.2930 +            groupIndex = capturingGroupCount++;
171.2931 +        GroupHead head = new GroupHead(localIndex);
171.2932 +        root = new GroupTail(localIndex, groupIndex);
171.2933 +        if (!anonymous && groupIndex < 10)
171.2934 +            groupNodes[groupIndex] = head;
171.2935 +        return head;
171.2936 +    }
171.2937 +
171.2938 +    /**
171.2939 +     * Parses inlined match flags and set them appropriately.
171.2940 +     */
171.2941 +    private void addFlag() {
171.2942 +        int ch = peek();
171.2943 +        for (;;) {
171.2944 +            switch (ch) {
171.2945 +            case 'i':
171.2946 +                flags |= CASE_INSENSITIVE;
171.2947 +                break;
171.2948 +            case 'm':
171.2949 +                flags |= MULTILINE;
171.2950 +                break;
171.2951 +            case 's':
171.2952 +                flags |= DOTALL;
171.2953 +                break;
171.2954 +            case 'd':
171.2955 +                flags |= UNIX_LINES;
171.2956 +                break;
171.2957 +            case 'u':
171.2958 +                flags |= UNICODE_CASE;
171.2959 +                break;
171.2960 +            case 'c':
171.2961 +                flags |= CANON_EQ;
171.2962 +                break;
171.2963 +            case 'x':
171.2964 +                flags |= COMMENTS;
171.2965 +                break;
171.2966 +            case 'U':
171.2967 +                flags |= (UNICODE_CHARACTER_CLASS | UNICODE_CASE);
171.2968 +                break;
171.2969 +            case '-': // subFlag then fall through
171.2970 +                ch = next();
171.2971 +                subFlag();
171.2972 +            default:
171.2973 +                return;
171.2974 +            }
171.2975 +            ch = next();
171.2976 +        }
171.2977 +    }
171.2978 +
171.2979 +    /**
171.2980 +     * Parses the second part of inlined match flags and turns off
171.2981 +     * flags appropriately.
171.2982 +     */
171.2983 +    private void subFlag() {
171.2984 +        int ch = peek();
171.2985 +        for (;;) {
171.2986 +            switch (ch) {
171.2987 +            case 'i':
171.2988 +                flags &= ~CASE_INSENSITIVE;
171.2989 +                break;
171.2990 +            case 'm':
171.2991 +                flags &= ~MULTILINE;
171.2992 +                break;
171.2993 +            case 's':
171.2994 +                flags &= ~DOTALL;
171.2995 +                break;
171.2996 +            case 'd':
171.2997 +                flags &= ~UNIX_LINES;
171.2998 +                break;
171.2999 +            case 'u':
171.3000 +                flags &= ~UNICODE_CASE;
171.3001 +                break;
171.3002 +            case 'c':
171.3003 +                flags &= ~CANON_EQ;
171.3004 +                break;
171.3005 +            case 'x':
171.3006 +                flags &= ~COMMENTS;
171.3007 +                break;
171.3008 +            case 'U':
171.3009 +                flags &= ~(UNICODE_CHARACTER_CLASS | UNICODE_CASE);
171.3010 +            default:
171.3011 +                return;
171.3012 +            }
171.3013 +            ch = next();
171.3014 +        }
171.3015 +    }
171.3016 +
171.3017 +    static final int MAX_REPS   = 0x7FFFFFFF;
171.3018 +
171.3019 +    static final int GREEDY     = 0;
171.3020 +
171.3021 +    static final int LAZY       = 1;
171.3022 +
171.3023 +    static final int POSSESSIVE = 2;
171.3024 +
171.3025 +    static final int INDEPENDENT = 3;
171.3026 +
171.3027 +    /**
171.3028 +     * Processes repetition. If the next character peeked is a quantifier
171.3029 +     * then new nodes must be appended to handle the repetition.
171.3030 +     * Prev could be a single or a group, so it could be a chain of nodes.
171.3031 +     */
171.3032 +    private Node closure(Node prev) {
171.3033 +        Node atom;
171.3034 +        int ch = peek();
171.3035 +        switch (ch) {
171.3036 +        case '?':
171.3037 +            ch = next();
171.3038 +            if (ch == '?') {
171.3039 +                next();
171.3040 +                return new Ques(prev, LAZY);
171.3041 +            } else if (ch == '+') {
171.3042 +                next();
171.3043 +                return new Ques(prev, POSSESSIVE);
171.3044 +            }
171.3045 +            return new Ques(prev, GREEDY);
171.3046 +        case '*':
171.3047 +            ch = next();
171.3048 +            if (ch == '?') {
171.3049 +                next();
171.3050 +                return new Curly(prev, 0, MAX_REPS, LAZY);
171.3051 +            } else if (ch == '+') {
171.3052 +                next();
171.3053 +                return new Curly(prev, 0, MAX_REPS, POSSESSIVE);
171.3054 +            }
171.3055 +            return new Curly(prev, 0, MAX_REPS, GREEDY);
171.3056 +        case '+':
171.3057 +            ch = next();
171.3058 +            if (ch == '?') {
171.3059 +                next();
171.3060 +                return new Curly(prev, 1, MAX_REPS, LAZY);
171.3061 +            } else if (ch == '+') {
171.3062 +                next();
171.3063 +                return new Curly(prev, 1, MAX_REPS, POSSESSIVE);
171.3064 +            }
171.3065 +            return new Curly(prev, 1, MAX_REPS, GREEDY);
171.3066 +        case '{':
171.3067 +            ch = temp[cursor+1];
171.3068 +            if (ASCII.isDigit(ch)) {
171.3069 +                skip();
171.3070 +                int cmin = 0;
171.3071 +                do {
171.3072 +                    cmin = cmin * 10 + (ch - '0');
171.3073 +                } while (ASCII.isDigit(ch = read()));
171.3074 +                int cmax = cmin;
171.3075 +                if (ch == ',') {
171.3076 +                    ch = read();
171.3077 +                    cmax = MAX_REPS;
171.3078 +                    if (ch != '}') {
171.3079 +                        cmax = 0;
171.3080 +                        while (ASCII.isDigit(ch)) {
171.3081 +                            cmax = cmax * 10 + (ch - '0');
171.3082 +                            ch = read();
171.3083 +                        }
171.3084 +                    }
171.3085 +                }
171.3086 +                if (ch != '}')
171.3087 +                    throw error("Unclosed counted closure");
171.3088 +                if (((cmin) | (cmax) | (cmax - cmin)) < 0)
171.3089 +                    throw error("Illegal repetition range");
171.3090 +                Curly curly;
171.3091 +                ch = peek();
171.3092 +                if (ch == '?') {
171.3093 +                    next();
171.3094 +                    curly = new Curly(prev, cmin, cmax, LAZY);
171.3095 +                } else if (ch == '+') {
171.3096 +                    next();
171.3097 +                    curly = new Curly(prev, cmin, cmax, POSSESSIVE);
171.3098 +                } else {
171.3099 +                    curly = new Curly(prev, cmin, cmax, GREEDY);
171.3100 +                }
171.3101 +                return curly;
171.3102 +            } else {
171.3103 +                throw error("Illegal repetition");
171.3104 +            }
171.3105 +        default:
171.3106 +            return prev;
171.3107 +        }
171.3108 +    }
171.3109 +
171.3110 +    /**
171.3111 +     *  Utility method for parsing control escape sequences.
171.3112 +     */
171.3113 +    private int c() {
171.3114 +        if (cursor < patternLength) {
171.3115 +            return read() ^ 64;
171.3116 +        }
171.3117 +        throw error("Illegal control escape sequence");
171.3118 +    }
171.3119 +
171.3120 +    /**
171.3121 +     *  Utility method for parsing octal escape sequences.
171.3122 +     */
171.3123 +    private int o() {
171.3124 +        int n = read();
171.3125 +        if (((n-'0')|('7'-n)) >= 0) {
171.3126 +            int m = read();
171.3127 +            if (((m-'0')|('7'-m)) >= 0) {
171.3128 +                int o = read();
171.3129 +                if ((((o-'0')|('7'-o)) >= 0) && (((n-'0')|('3'-n)) >= 0)) {
171.3130 +                    return (n - '0') * 64 + (m - '0') * 8 + (o - '0');
171.3131 +                }
171.3132 +                unread();
171.3133 +                return (n - '0') * 8 + (m - '0');
171.3134 +            }
171.3135 +            unread();
171.3136 +            return (n - '0');
171.3137 +        }
171.3138 +        throw error("Illegal octal escape sequence");
171.3139 +    }
171.3140 +
171.3141 +    /**
171.3142 +     *  Utility method for parsing hexadecimal escape sequences.
171.3143 +     */
171.3144 +    private int x() {
171.3145 +        int n = read();
171.3146 +        if (ASCII.isHexDigit(n)) {
171.3147 +            int m = read();
171.3148 +            if (ASCII.isHexDigit(m)) {
171.3149 +                return ASCII.toDigit(n) * 16 + ASCII.toDigit(m);
171.3150 +            }
171.3151 +        } else if (n == '{' && ASCII.isHexDigit(peek())) {
171.3152 +            int ch = 0;
171.3153 +            while (ASCII.isHexDigit(n = read())) {
171.3154 +                ch = (ch << 4) + ASCII.toDigit(n);
171.3155 +                if (ch > Character.MAX_CODE_POINT)
171.3156 +                    throw error("Hexadecimal codepoint is too big");
171.3157 +            }
171.3158 +            if (n != '}')
171.3159 +                throw error("Unclosed hexadecimal escape sequence");
171.3160 +            return ch;
171.3161 +        }
171.3162 +        throw error("Illegal hexadecimal escape sequence");
171.3163 +    }
171.3164 +
171.3165 +    /**
171.3166 +     *  Utility method for parsing unicode escape sequences.
171.3167 +     */
171.3168 +    private int cursor() {
171.3169 +        return cursor;
171.3170 +    }
171.3171 +
171.3172 +    private void setcursor(int pos) {
171.3173 +        cursor = pos;
171.3174 +    }
171.3175 +
171.3176 +    private int uxxxx() {
171.3177 +        int n = 0;
171.3178 +        for (int i = 0; i < 4; i++) {
171.3179 +            int ch = read();
171.3180 +            if (!ASCII.isHexDigit(ch)) {
171.3181 +                throw error("Illegal Unicode escape sequence");
171.3182 +            }
171.3183 +            n = n * 16 + ASCII.toDigit(ch);
171.3184 +        }
171.3185 +        return n;
171.3186 +    }
171.3187 +
171.3188 +    private int u() {
171.3189 +        int n = uxxxx();
171.3190 +        if (Character.isHighSurrogate((char)n)) {
171.3191 +            int cur = cursor();
171.3192 +            if (read() == '\\' && read() == 'u') {
171.3193 +                int n2 = uxxxx();
171.3194 +                if (Character.isLowSurrogate((char)n2))
171.3195 +                    return Character.toCodePoint((char)n, (char)n2);
171.3196 +            }
171.3197 +            setcursor(cur);
171.3198 +        }
171.3199 +        return n;
171.3200 +    }
171.3201 +
171.3202 +    //
171.3203 +    // Utility methods for code point support
171.3204 +    //
171.3205 +
171.3206 +    private static final int countChars(CharSequence seq, int index,
171.3207 +                                        int lengthInCodePoints) {
171.3208 +        // optimization
171.3209 +        if (lengthInCodePoints == 1 && !Character.isHighSurrogate(seq.charAt(index))) {
171.3210 +            assert (index >= 0 && index < seq.length());
171.3211 +            return 1;
171.3212 +        }
171.3213 +        int length = seq.length();
171.3214 +        int x = index;
171.3215 +        if (lengthInCodePoints >= 0) {
171.3216 +            assert (index >= 0 && index < length);
171.3217 +            for (int i = 0; x < length && i < lengthInCodePoints; i++) {
171.3218 +                if (Character.isHighSurrogate(seq.charAt(x++))) {
171.3219 +                    if (x < length && Character.isLowSurrogate(seq.charAt(x))) {
171.3220 +                        x++;
171.3221 +                    }
171.3222 +                }
171.3223 +            }
171.3224 +            return x - index;
171.3225 +        }
171.3226 +
171.3227 +        assert (index >= 0 && index <= length);
171.3228 +        if (index == 0) {
171.3229 +            return 0;
171.3230 +        }
171.3231 +        int len = -lengthInCodePoints;
171.3232 +        for (int i = 0; x > 0 && i < len; i++) {
171.3233 +            if (Character.isLowSurrogate(seq.charAt(--x))) {
171.3234 +                if (x > 0 && Character.isHighSurrogate(seq.charAt(x-1))) {
171.3235 +                    x--;
171.3236 +                }
171.3237 +            }
171.3238 +        }
171.3239 +        return index - x;
171.3240 +    }
171.3241 +
171.3242 +    private static final int countCodePoints(CharSequence seq) {
171.3243 +        int length = seq.length();
171.3244 +        int n = 0;
171.3245 +        for (int i = 0; i < length; ) {
171.3246 +            n++;
171.3247 +            if (Character.isHighSurrogate(seq.charAt(i++))) {
171.3248 +                if (i < length && Character.isLowSurrogate(seq.charAt(i))) {
171.3249 +                    i++;
171.3250 +                }
171.3251 +            }
171.3252 +        }
171.3253 +        return n;
171.3254 +    }
171.3255 +
171.3256 +    /**
171.3257 +     *  Creates a bit vector for matching Latin-1 values. A normal BitClass
171.3258 +     *  never matches values above Latin-1, and a complemented BitClass always
171.3259 +     *  matches values above Latin-1.
171.3260 +     */
171.3261 +    private static final class BitClass extends BmpCharProperty {
171.3262 +        final boolean[] bits;
171.3263 +        BitClass() { bits = new boolean[256]; }
171.3264 +        private BitClass(boolean[] bits) { this.bits = bits; }
171.3265 +        BitClass add(int c, int flags) {
171.3266 +            assert c >= 0 && c <= 255;
171.3267 +            if ((flags & CASE_INSENSITIVE) != 0) {
171.3268 +                if (ASCII.isAscii(c)) {
171.3269 +                    bits[ASCII.toUpper(c)] = true;
171.3270 +                    bits[ASCII.toLower(c)] = true;
171.3271 +                } else if ((flags & UNICODE_CASE) != 0) {
171.3272 +                    bits[Character.toLowerCase(c)] = true;
171.3273 +                    bits[Character.toUpperCase(c)] = true;
171.3274 +                }
171.3275 +            }
171.3276 +            bits[c] = true;
171.3277 +            return this;
171.3278 +        }
171.3279 +        boolean isSatisfiedBy(int ch) {
171.3280 +            return ch < 256 && bits[ch];
171.3281 +        }
171.3282 +    }
171.3283 +
171.3284 +    /**
171.3285 +     *  Returns a suitably optimized, single character matcher.
171.3286 +     */
171.3287 +    private CharProperty newSingle(final int ch) {
171.3288 +        if (has(CASE_INSENSITIVE)) {
171.3289 +            int lower, upper;
171.3290 +            if (has(UNICODE_CASE)) {
171.3291 +                upper = Character.toUpperCase(ch);
171.3292 +                lower = Character.toLowerCase(upper);
171.3293 +                if (upper != lower)
171.3294 +                    return new SingleU(lower);
171.3295 +            } else if (ASCII.isAscii(ch)) {
171.3296 +                lower = ASCII.toLower(ch);
171.3297 +                upper = ASCII.toUpper(ch);
171.3298 +                if (lower != upper)
171.3299 +                    return new SingleI(lower, upper);
171.3300 +            }
171.3301 +        }
171.3302 +        if (isSupplementary(ch))
171.3303 +            return new SingleS(ch);    // Match a given Unicode character
171.3304 +        return new Single(ch);         // Match a given BMP character
171.3305 +    }
171.3306 +
171.3307 +    /**
171.3308 +     *  Utility method for creating a string slice matcher.
171.3309 +     */
171.3310 +    private Node newSlice(int[] buf, int count, boolean hasSupplementary) {
171.3311 +        int[] tmp = new int[count];
171.3312 +        if (has(CASE_INSENSITIVE)) {
171.3313 +            if (has(UNICODE_CASE)) {
171.3314 +                for (int i = 0; i < count; i++) {
171.3315 +                    tmp[i] = Character.toLowerCase(
171.3316 +                                 Character.toUpperCase(buf[i]));
171.3317 +                }
171.3318 +                return hasSupplementary? new SliceUS(tmp) : new SliceU(tmp);
171.3319 +            }
171.3320 +            for (int i = 0; i < count; i++) {
171.3321 +                tmp[i] = ASCII.toLower(buf[i]);
171.3322 +            }
171.3323 +            return hasSupplementary? new SliceIS(tmp) : new SliceI(tmp);
171.3324 +        }
171.3325 +        for (int i = 0; i < count; i++) {
171.3326 +            tmp[i] = buf[i];
171.3327 +        }
171.3328 +        return hasSupplementary ? new SliceS(tmp) : new Slice(tmp);
171.3329 +    }
171.3330 +
171.3331 +    /**
171.3332 +     * The following classes are the building components of the object
171.3333 +     * tree that represents a compiled regular expression. The object tree
171.3334 +     * is made of individual elements that handle constructs in the Pattern.
171.3335 +     * Each type of object knows how to match its equivalent construct with
171.3336 +     * the match() method.
171.3337 +     */
171.3338 +
171.3339 +    /**
171.3340 +     * Base class for all node classes. Subclasses should override the match()
171.3341 +     * method as appropriate. This class is an accepting node, so its match()
171.3342 +     * always returns true.
171.3343 +     */
171.3344 +    static class Node extends Object {
171.3345 +        Node next;
171.3346 +        Node() {
171.3347 +            next = Pattern.accept;
171.3348 +        }
171.3349 +        /**
171.3350 +         * This method implements the classic accept node.
171.3351 +         */
171.3352 +        boolean match(Matcher matcher, int i, CharSequence seq) {
171.3353 +            matcher.last = i;
171.3354 +            matcher.groups[0] = matcher.first;
171.3355 +            matcher.groups[1] = matcher.last;
171.3356 +            return true;
171.3357 +        }
171.3358 +        /**
171.3359 +         * This method is good for all zero length assertions.
171.3360 +         */
171.3361 +        boolean study(TreeInfo info) {
171.3362 +            if (next != null) {
171.3363 +                return next.study(info);
171.3364 +            } else {
171.3365 +                return info.deterministic;
171.3366 +            }
171.3367 +        }
171.3368 +    }
171.3369 +
171.3370 +    static class LastNode extends Node {
171.3371 +        /**
171.3372 +         * This method implements the classic accept node with
171.3373 +         * the addition of a check to see if the match occurred
171.3374 +         * using all of the input.
171.3375 +         */
171.3376 +        boolean match(Matcher matcher, int i, CharSequence seq) {
171.3377 +            if (matcher.acceptMode == Matcher.ENDANCHOR && i != matcher.to)
171.3378 +                return false;
171.3379 +            matcher.last = i;
171.3380 +            matcher.groups[0] = matcher.first;
171.3381 +            matcher.groups[1] = matcher.last;
171.3382 +            return true;
171.3383 +        }
171.3384 +    }
171.3385 +
171.3386 +    /**
171.3387 +     * Used for REs that can start anywhere within the input string.
171.3388 +     * This basically tries to match repeatedly at each spot in the
171.3389 +     * input string, moving forward after each try. An anchored search
171.3390 +     * or a BnM will bypass this node completely.
171.3391 +     */
171.3392 +    static class Start extends Node {
171.3393 +        int minLength;
171.3394 +        Start(Node node) {
171.3395 +            this.next = node;
171.3396 +            TreeInfo info = new TreeInfo();
171.3397 +            next.study(info);
171.3398 +            minLength = info.minLength;
171.3399 +        }
171.3400 +        boolean match(Matcher matcher, int i, CharSequence seq) {
171.3401 +            if (i > matcher.to - minLength) {
171.3402 +                matcher.hitEnd = true;
171.3403 +                return false;
171.3404 +            }
171.3405 +            int guard = matcher.to - minLength;
171.3406 +            for (; i <= guard; i++) {
171.3407 +                if (next.match(matcher, i, seq)) {
171.3408 +                    matcher.first = i;
171.3409 +                    matcher.groups[0] = matcher.first;
171.3410 +                    matcher.groups[1] = matcher.last;
171.3411 +                    return true;
171.3412 +                }
171.3413 +            }
171.3414 +            matcher.hitEnd = true;
171.3415 +            return false;
171.3416 +        }
171.3417 +        boolean study(TreeInfo info) {
171.3418 +            next.study(info);
171.3419 +            info.maxValid = false;
171.3420 +            info.deterministic = false;
171.3421 +            return false;
171.3422 +        }
171.3423 +    }
171.3424 +
171.3425 +    /*
171.3426 +     * StartS supports supplementary characters, including unpaired surrogates.
171.3427 +     */
171.3428 +    static final class StartS extends Start {
171.3429 +        StartS(Node node) {
171.3430 +            super(node);
171.3431 +        }
171.3432 +        boolean match(Matcher matcher, int i, CharSequence seq) {
171.3433 +            if (i > matcher.to - minLength) {
171.3434 +                matcher.hitEnd = true;
171.3435 +                return false;
171.3436 +            }
171.3437 +            int guard = matcher.to - minLength;
171.3438 +            while (i <= guard) {
171.3439 +                //if ((ret = next.match(matcher, i, seq)) || i == guard)
171.3440 +                if (next.match(matcher, i, seq)) {
171.3441 +                    matcher.first = i;
171.3442 +                    matcher.groups[0] = matcher.first;
171.3443 +                    matcher.groups[1] = matcher.last;
171.3444 +                    return true;
171.3445 +                }
171.3446 +                if (i == guard)
171.3447 +                    break;
171.3448 +                // Optimization to move to the next character. This is
171.3449 +                // faster than countChars(seq, i, 1).
171.3450 +                if (Character.isHighSurrogate(seq.charAt(i++))) {
171.3451 +                    if (i < seq.length() &&
171.3452 +                        Character.isLowSurrogate(seq.charAt(i))) {
171.3453 +                        i++;
171.3454 +                    }
171.3455 +                }
171.3456 +            }
171.3457 +            matcher.hitEnd = true;
171.3458 +            return false;
171.3459 +        }
171.3460 +    }
171.3461 +
171.3462 +    /**
171.3463 +     * Node to anchor at the beginning of input. This object implements the
171.3464 +     * match for a \A sequence, and the caret anchor will use this if not in
171.3465 +     * multiline mode.
171.3466 +     */
171.3467 +    static final class Begin extends Node {
171.3468 +        boolean match(Matcher matcher, int i, CharSequence seq) {
171.3469 +            int fromIndex = (matcher.anchoringBounds) ?
171.3470 +                matcher.from : 0;
171.3471 +            if (i == fromIndex && next.match(matcher, i, seq)) {
171.3472 +                matcher.first = i;
171.3473 +                matcher.groups[0] = i;
171.3474 +                matcher.groups[1] = matcher.last;
171.3475 +                return true;
171.3476 +            } else {
171.3477 +                return false;
171.3478 +            }
171.3479 +        }
171.3480 +    }
171.3481 +
171.3482 +    /**
171.3483 +     * Node to anchor at the end of input. This is the absolute end, so this
171.3484 +     * should not match at the last newline before the end as $ will.
171.3485 +     */
171.3486 +    static final class End extends Node {
171.3487 +        boolean match(Matcher matcher, int i, CharSequence seq) {
171.3488 +            int endIndex = (matcher.anchoringBounds) ?
171.3489 +                matcher.to : matcher.getTextLength();
171.3490 +            if (i == endIndex) {
171.3491 +                matcher.hitEnd = true;
171.3492 +                return next.match(matcher, i, seq);
171.3493 +            }
171.3494 +            return false;
171.3495 +        }
171.3496 +    }
171.3497 +
171.3498 +    /**
171.3499 +     * Node to anchor at the beginning of a line. This is essentially the
171.3500 +     * object to match for the multiline ^.
171.3501 +     */
171.3502 +    static final class Caret extends Node {
171.3503 +        boolean match(Matcher matcher, int i, CharSequence seq) {
171.3504 +            int startIndex = matcher.from;
171.3505 +            int endIndex = matcher.to;
171.3506 +            if (!matcher.anchoringBounds) {
171.3507 +                startIndex = 0;
171.3508 +                endIndex = matcher.getTextLength();
171.3509 +            }
171.3510 +            // Perl does not match ^ at end of input even after newline
171.3511 +            if (i == endIndex) {
171.3512 +                matcher.hitEnd = true;
171.3513 +                return false;
171.3514 +            }
171.3515 +            if (i > startIndex) {
171.3516 +                char ch = seq.charAt(i-1);
171.3517 +                if (ch != '\n' && ch != '\r'
171.3518 +                    && (ch|1) != '\u2029'
171.3519 +                    && ch != '\u0085' ) {
171.3520 +                    return false;
171.3521 +                }
171.3522 +                // Should treat /r/n as one newline
171.3523 +                if (ch == '\r' && seq.charAt(i) == '\n')
171.3524 +                    return false;
171.3525 +            }
171.3526 +            return next.match(matcher, i, seq);
171.3527 +        }
171.3528 +    }
171.3529 +
171.3530 +    /**
171.3531 +     * Node to anchor at the beginning of a line when in unixdot mode.
171.3532 +     */
171.3533 +    static final class UnixCaret extends Node {
171.3534 +        boolean match(Matcher matcher, int i, CharSequence seq) {
171.3535 +            int startIndex = matcher.from;
171.3536 +            int endIndex = matcher.to;
171.3537 +            if (!matcher.anchoringBounds) {
171.3538 +                startIndex = 0;
171.3539 +                endIndex = matcher.getTextLength();
171.3540 +            }
171.3541 +            // Perl does not match ^ at end of input even after newline
171.3542 +            if (i == endIndex) {
171.3543 +                matcher.hitEnd = true;
171.3544 +                return false;
171.3545 +            }
171.3546 +            if (i > startIndex) {
171.3547 +                char ch = seq.charAt(i-1);
171.3548 +                if (ch != '\n') {
171.3549 +                    return false;
171.3550 +                }
171.3551 +            }
171.3552 +            return next.match(matcher, i, seq);
171.3553 +        }
171.3554 +    }
171.3555 +
171.3556 +    /**
171.3557 +     * Node to match the location where the last match ended.
171.3558 +     * This is used for the \G construct.
171.3559 +     */
171.3560 +    static final class LastMatch extends Node {
171.3561 +        boolean match(Matcher matcher, int i, CharSequence seq) {
171.3562 +            if (i != matcher.oldLast)
171.3563 +                return false;
171.3564 +            return next.match(matcher, i, seq);
171.3565 +        }
171.3566 +    }
171.3567 +
171.3568 +    /**
171.3569 +     * Node to anchor at the end of a line or the end of input based on the
171.3570 +     * multiline mode.
171.3571 +     *
171.3572 +     * When not in multiline mode, the $ can only match at the very end
171.3573 +     * of the input, unless the input ends in a line terminator in which
171.3574 +     * it matches right before the last line terminator.
171.3575 +     *
171.3576 +     * Note that \r\n is considered an atomic line terminator.
171.3577 +     *
171.3578 +     * Like ^ the $ operator matches at a position, it does not match the
171.3579 +     * line terminators themselves.
171.3580 +     */
171.3581 +    static final class Dollar extends Node {
171.3582 +        boolean multiline;
171.3583 +        Dollar(boolean mul) {
171.3584 +            multiline = mul;
171.3585 +        }
171.3586 +        boolean match(Matcher matcher, int i, CharSequence seq) {
171.3587 +            int endIndex = (matcher.anchoringBounds) ?
171.3588 +                matcher.to : matcher.getTextLength();
171.3589 +            if (!multiline) {
171.3590 +                if (i < endIndex - 2)
171.3591 +                    return false;
171.3592 +                if (i == endIndex - 2) {
171.3593 +                    char ch = seq.charAt(i);
171.3594 +                    if (ch != '\r')
171.3595 +                        return false;
171.3596 +                    ch = seq.charAt(i + 1);
171.3597 +                    if (ch != '\n')
171.3598 +                        return false;
171.3599 +                }
171.3600 +            }
171.3601 +            // Matches before any line terminator; also matches at the
171.3602 +            // end of input
171.3603 +            // Before line terminator:
171.3604 +            // If multiline, we match here no matter what
171.3605 +            // If not multiline, fall through so that the end
171.3606 +            // is marked as hit; this must be a /r/n or a /n
171.3607 +            // at the very end so the end was hit; more input
171.3608 +            // could make this not match here
171.3609 +            if (i < endIndex) {
171.3610 +                char ch = seq.charAt(i);
171.3611 +                 if (ch == '\n') {
171.3612 +                     // No match between \r\n
171.3613 +                     if (i > 0 && seq.charAt(i-1) == '\r')
171.3614 +                         return false;
171.3615 +                     if (multiline)
171.3616 +                         return next.match(matcher, i, seq);
171.3617 +                 } else if (ch == '\r' || ch == '\u0085' ||
171.3618 +                            (ch|1) == '\u2029') {
171.3619 +                     if (multiline)
171.3620 +                         return next.match(matcher, i, seq);
171.3621 +                 } else { // No line terminator, no match
171.3622 +                     return false;
171.3623 +                 }
171.3624 +            }
171.3625 +            // Matched at current end so hit end
171.3626 +            matcher.hitEnd = true;
171.3627 +            // If a $ matches because of end of input, then more input
171.3628 +            // could cause it to fail!
171.3629 +            matcher.requireEnd = true;
171.3630 +            return next.match(matcher, i, seq);
171.3631 +        }
171.3632 +        boolean study(TreeInfo info) {
171.3633 +            next.study(info);
171.3634 +            return info.deterministic;
171.3635 +        }
171.3636 +    }
171.3637 +
171.3638 +    /**
171.3639 +     * Node to anchor at the end of a line or the end of input based on the
171.3640 +     * multiline mode when in unix lines mode.
171.3641 +     */
171.3642 +    static final class UnixDollar extends Node {
171.3643 +        boolean multiline;
171.3644 +        UnixDollar(boolean mul) {
171.3645 +            multiline = mul;
171.3646 +        }
171.3647 +        boolean match(Matcher matcher, int i, CharSequence seq) {
171.3648 +            int endIndex = (matcher.anchoringBounds) ?
171.3649 +                matcher.to : matcher.getTextLength();
171.3650 +            if (i < endIndex) {
171.3651 +                char ch = seq.charAt(i);
171.3652 +                if (ch == '\n') {
171.3653 +                    // If not multiline, then only possible to
171.3654 +                    // match at very end or one before end
171.3655 +                    if (multiline == false && i != endIndex - 1)
171.3656 +                        return false;
171.3657 +                    // If multiline return next.match without setting
171.3658 +                    // matcher.hitEnd
171.3659 +                    if (multiline)
171.3660 +                        return next.match(matcher, i, seq);
171.3661 +                } else {
171.3662 +                    return false;
171.3663 +                }
171.3664 +            }
171.3665 +            // Matching because at the end or 1 before the end;
171.3666 +            // more input could change this so set hitEnd
171.3667 +            matcher.hitEnd = true;
171.3668 +            // If a $ matches because of end of input, then more input
171.3669 +            // could cause it to fail!
171.3670 +            matcher.requireEnd = true;
171.3671 +            return next.match(matcher, i, seq);
171.3672 +        }
171.3673 +        boolean study(TreeInfo info) {
171.3674 +            next.study(info);
171.3675 +            return info.deterministic;
171.3676 +        }
171.3677 +    }
171.3678 +
171.3679 +    /**
171.3680 +     * Abstract node class to match one character satisfying some
171.3681 +     * boolean property.
171.3682 +     */
171.3683 +    private static abstract class CharProperty extends Node {
171.3684 +        abstract boolean isSatisfiedBy(int ch);
171.3685 +        CharProperty complement() {
171.3686 +            return new CharProperty() {
171.3687 +                    boolean isSatisfiedBy(int ch) {
171.3688 +                        return ! CharProperty.this.isSatisfiedBy(ch);}};
171.3689 +        }
171.3690 +        boolean match(Matcher matcher, int i, CharSequence seq) {
171.3691 +            if (i < matcher.to) {
171.3692 +                int ch = Character.codePointAt(seq, i);
171.3693 +                return isSatisfiedBy(ch)
171.3694 +                    && next.match(matcher, i+Character.charCount(ch), seq);
171.3695 +            } else {
171.3696 +                matcher.hitEnd = true;
171.3697 +                return false;
171.3698 +            }
171.3699 +        }
171.3700 +        boolean study(TreeInfo info) {
171.3701 +            info.minLength++;
171.3702 +            info.maxLength++;
171.3703 +            return next.study(info);
171.3704 +        }
171.3705 +    }
171.3706 +
171.3707 +    /**
171.3708 +     * Optimized version of CharProperty that works only for
171.3709 +     * properties never satisfied by Supplementary characters.
171.3710 +     */
171.3711 +    private static abstract class BmpCharProperty extends CharProperty {
171.3712 +        boolean match(Matcher matcher, int i, CharSequence seq) {
171.3713 +            if (i < matcher.to) {
171.3714 +                return isSatisfiedBy(seq.charAt(i))
171.3715 +                    && next.match(matcher, i+1, seq);
171.3716 +            } else {
171.3717 +                matcher.hitEnd = true;
171.3718 +                return false;
171.3719 +            }
171.3720 +        }
171.3721 +    }
171.3722 +
171.3723 +    /**
171.3724 +     * Node class that matches a Supplementary Unicode character
171.3725 +     */
171.3726 +    static final class SingleS extends CharProperty {
171.3727 +        final int c;
171.3728 +        SingleS(int c) { this.c = c; }
171.3729 +        boolean isSatisfiedBy(int ch) {
171.3730 +            return ch == c;
171.3731 +        }
171.3732 +    }
171.3733 +
171.3734 +    /**
171.3735 +     * Optimization -- matches a given BMP character
171.3736 +     */
171.3737 +    static final class Single extends BmpCharProperty {
171.3738 +        final int c;
171.3739 +        Single(int c) { this.c = c; }
171.3740 +        boolean isSatisfiedBy(int ch) {
171.3741 +            return ch == c;
171.3742 +        }
171.3743 +    }
171.3744 +
171.3745 +    /**
171.3746 +     * Case insensitive matches a given BMP character
171.3747 +     */
171.3748 +    static final class SingleI extends BmpCharProperty {
171.3749 +        final int lower;
171.3750 +        final int upper;
171.3751 +        SingleI(int lower, int upper) {
171.3752 +            this.lower = lower;
171.3753 +            this.upper = upper;
171.3754 +        }
171.3755 +        boolean isSatisfiedBy(int ch) {
171.3756 +            return ch == lower || ch == upper;
171.3757 +        }
171.3758 +    }
171.3759 +
171.3760 +    /**
171.3761 +     * Unicode case insensitive matches a given Unicode character
171.3762 +     */
171.3763 +    static final class SingleU extends CharProperty {
171.3764 +        final int lower;
171.3765 +        SingleU(int lower) {
171.3766 +            this.lower = lower;
171.3767 +        }
171.3768 +        boolean isSatisfiedBy(int ch) {
171.3769 +            return lower == ch ||
171.3770 +                lower == Character.toLowerCase(Character.toUpperCase(ch));
171.3771 +        }
171.3772 +    }
171.3773 +
171.3774 +
171.3775 +    /**
171.3776 +     * Node class that matches a Unicode block.
171.3777 +     *
171.3778 +    static final class Block extends CharProperty {
171.3779 +        final Character.UnicodeBlock block;
171.3780 +        Block(Character.UnicodeBlock block) {
171.3781 +            this.block = block;
171.3782 +        }
171.3783 +        boolean isSatisfiedBy(int ch) {
171.3784 +            return block == Character.UnicodeBlock.of(ch);
171.3785 +        }
171.3786 +    }
171.3787 +
171.3788 +    /**
171.3789 +     * Node class that matches a Unicode script
171.3790 +     *
171.3791 +    static final class Script extends CharProperty {
171.3792 +        final Character.UnicodeScript script;
171.3793 +        Script(Character.UnicodeScript script) {
171.3794 +            this.script = script;
171.3795 +        }
171.3796 +        boolean isSatisfiedBy(int ch) {
171.3797 +            return script == Character.UnicodeScript.of(ch);
171.3798 +        }
171.3799 +    }
171.3800 +
171.3801 +    /**
171.3802 +     * Node class that matches a Unicode category.
171.3803 +     */
171.3804 +    static final class Category extends CharProperty {
171.3805 +        final int typeMask;
171.3806 +        Category(int typeMask) { this.typeMask = typeMask; }
171.3807 +        boolean isSatisfiedBy(int ch) {
171.3808 +            return (typeMask & (1 << Character.getType(ch))) != 0;
171.3809 +        }
171.3810 +    }
171.3811 +
171.3812 +    /**
171.3813 +     * Node class that matches a Unicode "type"
171.3814 +     */
171.3815 +    static final class Utype extends CharProperty {
171.3816 +        final UnicodeProp uprop;
171.3817 +        Utype(UnicodeProp uprop) { this.uprop = uprop; }
171.3818 +        boolean isSatisfiedBy(int ch) {
171.3819 +            return uprop.is(ch);
171.3820 +        }
171.3821 +    }
171.3822 +
171.3823 +
171.3824 +    /**
171.3825 +     * Node class that matches a POSIX type.
171.3826 +     */
171.3827 +    static final class Ctype extends BmpCharProperty {
171.3828 +        final int ctype;
171.3829 +        Ctype(int ctype) { this.ctype = ctype; }
171.3830 +        boolean isSatisfiedBy(int ch) {
171.3831 +            return ch < 128 && ASCII.isType(ch, ctype);
171.3832 +        }
171.3833 +    }
171.3834 +
171.3835 +    /**
171.3836 +     * Base class for all Slice nodes
171.3837 +     */
171.3838 +    static class SliceNode extends Node {
171.3839 +        int[] buffer;
171.3840 +        SliceNode(int[] buf) {
171.3841 +            buffer = buf;
171.3842 +        }
171.3843 +        boolean study(TreeInfo info) {
171.3844 +            info.minLength += buffer.length;
171.3845 +            info.maxLength += buffer.length;
171.3846 +            return next.study(info);
171.3847 +        }
171.3848 +    }
171.3849 +
171.3850 +    /**
171.3851 +     * Node class for a case sensitive/BMP-only sequence of literal
171.3852 +     * characters.
171.3853 +     */
171.3854 +    static final class Slice extends SliceNode {
171.3855 +        Slice(int[] buf) {
171.3856 +            super(buf);
171.3857 +        }
171.3858 +        boolean match(Matcher matcher, int i, CharSequence seq) {
171.3859 +            int[] buf = buffer;
171.3860 +            int len = buf.length;
171.3861 +            for (int j=0; j<len; j++) {
171.3862 +                if ((i+j) >= matcher.to) {
171.3863 +                    matcher.hitEnd = true;
171.3864 +                    return false;
171.3865 +                }
171.3866 +                if (buf[j] != seq.charAt(i+j))
171.3867 +                    return false;
171.3868 +            }
171.3869 +            return next.match(matcher, i+len, seq);
171.3870 +        }
171.3871 +    }
171.3872 +
171.3873 +    /**
171.3874 +     * Node class for a case_insensitive/BMP-only sequence of literal
171.3875 +     * characters.
171.3876 +     */
171.3877 +    static class SliceI extends SliceNode {
171.3878 +        SliceI(int[] buf) {
171.3879 +            super(buf);
171.3880 +        }
171.3881 +        boolean match(Matcher matcher, int i, CharSequence seq) {
171.3882 +            int[] buf = buffer;
171.3883 +            int len = buf.length;
171.3884 +            for (int j=0; j<len; j++) {
171.3885 +                if ((i+j) >= matcher.to) {
171.3886 +                    matcher.hitEnd = true;
171.3887 +                    return false;
171.3888 +                }
171.3889 +                int c = seq.charAt(i+j);
171.3890 +                if (buf[j] != c &&
171.3891 +                    buf[j] != ASCII.toLower(c))
171.3892 +                    return false;
171.3893 +            }
171.3894 +            return next.match(matcher, i+len, seq);
171.3895 +        }
171.3896 +    }
171.3897 +
171.3898 +    /**
171.3899 +     * Node class for a unicode_case_insensitive/BMP-only sequence of
171.3900 +     * literal characters. Uses unicode case folding.
171.3901 +     */
171.3902 +    static final class SliceU extends SliceNode {
171.3903 +        SliceU(int[] buf) {
171.3904 +            super(buf);
171.3905 +        }
171.3906 +        boolean match(Matcher matcher, int i, CharSequence seq) {
171.3907 +            int[] buf = buffer;
171.3908 +            int len = buf.length;
171.3909 +            for (int j=0; j<len; j++) {
171.3910 +                if ((i+j) >= matcher.to) {
171.3911 +                    matcher.hitEnd = true;
171.3912 +                    return false;
171.3913 +                }
171.3914 +                int c = seq.charAt(i+j);
171.3915 +                if (buf[j] != c &&
171.3916 +                    buf[j] != Character.toLowerCase(Character.toUpperCase(c)))
171.3917 +                    return false;
171.3918 +            }
171.3919 +            return next.match(matcher, i+len, seq);
171.3920 +        }
171.3921 +    }
171.3922 +
171.3923 +    /**
171.3924 +     * Node class for a case sensitive sequence of literal characters
171.3925 +     * including supplementary characters.
171.3926 +     */
171.3927 +    static final class SliceS extends SliceNode {
171.3928 +        SliceS(int[] buf) {
171.3929 +            super(buf);
171.3930 +        }
171.3931 +        boolean match(Matcher matcher, int i, CharSequence seq) {
171.3932 +            int[] buf = buffer;
171.3933 +            int x = i;
171.3934 +            for (int j = 0; j < buf.length; j++) {
171.3935 +                if (x >= matcher.to) {
171.3936 +                    matcher.hitEnd = true;
171.3937 +                    return false;
171.3938 +                }
171.3939 +                int c = Character.codePointAt(seq, x);
171.3940 +                if (buf[j] != c)
171.3941 +                    return false;
171.3942 +                x += Character.charCount(c);
171.3943 +                if (x > matcher.to) {
171.3944 +                    matcher.hitEnd = true;
171.3945 +                    return false;
171.3946 +                }
171.3947 +            }
171.3948 +            return next.match(matcher, x, seq);
171.3949 +        }
171.3950 +    }
171.3951 +
171.3952 +    /**
171.3953 +     * Node class for a case insensitive sequence of literal characters
171.3954 +     * including supplementary characters.
171.3955 +     */
171.3956 +    static class SliceIS extends SliceNode {
171.3957 +        SliceIS(int[] buf) {
171.3958 +            super(buf);
171.3959 +        }
171.3960 +        int toLower(int c) {
171.3961 +            return ASCII.toLower(c);
171.3962 +        }
171.3963 +        boolean match(Matcher matcher, int i, CharSequence seq) {
171.3964 +            int[] buf = buffer;
171.3965 +            int x = i;
171.3966 +            for (int j = 0; j < buf.length; j++) {
171.3967 +                if (x >= matcher.to) {
171.3968 +                    matcher.hitEnd = true;
171.3969 +                    return false;
171.3970 +                }
171.3971 +                int c = Character.codePointAt(seq, x);
171.3972 +                if (buf[j] != c && buf[j] != toLower(c))
171.3973 +                    return false;
171.3974 +                x += Character.charCount(c);
171.3975 +                if (x > matcher.to) {
171.3976 +                    matcher.hitEnd = true;
171.3977 +                    return false;
171.3978 +                }
171.3979 +            }
171.3980 +            return next.match(matcher, x, seq);
171.3981 +        }
171.3982 +    }
171.3983 +
171.3984 +    /**
171.3985 +     * Node class for a case insensitive sequence of literal characters.
171.3986 +     * Uses unicode case folding.
171.3987 +     */
171.3988 +    static final class SliceUS extends SliceIS {
171.3989 +        SliceUS(int[] buf) {
171.3990 +            super(buf);
171.3991 +        }
171.3992 +        int toLower(int c) {
171.3993 +            return Character.toLowerCase(Character.toUpperCase(c));
171.3994 +        }
171.3995 +    }
171.3996 +
171.3997 +    private static boolean inRange(int lower, int ch, int upper) {
171.3998 +        return lower <= ch && ch <= upper;
171.3999 +    }
171.4000 +
171.4001 +    /**
171.4002 +     * Returns node for matching characters within an explicit value range.
171.4003 +     */
171.4004 +    private static CharProperty rangeFor(final int lower,
171.4005 +                                         final int upper) {
171.4006 +        return new CharProperty() {
171.4007 +                boolean isSatisfiedBy(int ch) {
171.4008 +                    return inRange(lower, ch, upper);}};
171.4009 +    }
171.4010 +
171.4011 +    /**
171.4012 +     * Returns node for matching characters within an explicit value
171.4013 +     * range in a case insensitive manner.
171.4014 +     */
171.4015 +    private CharProperty caseInsensitiveRangeFor(final int lower,
171.4016 +                                                 final int upper) {
171.4017 +        if (has(UNICODE_CASE))
171.4018 +            return new CharProperty() {
171.4019 +                boolean isSatisfiedBy(int ch) {
171.4020 +                    if (inRange(lower, ch, upper))
171.4021 +                        return true;
171.4022 +                    int up = Character.toUpperCase(ch);
171.4023 +                    return inRange(lower, up, upper) ||
171.4024 +                           inRange(lower, Character.toLowerCase(up), upper);}};
171.4025 +        return new CharProperty() {
171.4026 +            boolean isSatisfiedBy(int ch) {
171.4027 +                return inRange(lower, ch, upper) ||
171.4028 +                    ASCII.isAscii(ch) &&
171.4029 +                        (inRange(lower, ASCII.toUpper(ch), upper) ||
171.4030 +                         inRange(lower, ASCII.toLower(ch), upper));
171.4031 +            }};
171.4032 +    }
171.4033 +
171.4034 +    /**
171.4035 +     * Implements the Unicode category ALL and the dot metacharacter when
171.4036 +     * in dotall mode.
171.4037 +     */
171.4038 +    static final class All extends CharProperty {
171.4039 +        boolean isSatisfiedBy(int ch) {
171.4040 +            return true;
171.4041 +        }
171.4042 +    }
171.4043 +
171.4044 +    /**
171.4045 +     * Node class for the dot metacharacter when dotall is not enabled.
171.4046 +     */
171.4047 +    static final class Dot extends CharProperty {
171.4048 +        boolean isSatisfiedBy(int ch) {
171.4049 +            return (ch != '\n' && ch != '\r'
171.4050 +                    && (ch|1) != '\u2029'
171.4051 +                    && ch != '\u0085');
171.4052 +        }
171.4053 +    }
171.4054 +
171.4055 +    /**
171.4056 +     * Node class for the dot metacharacter when dotall is not enabled
171.4057 +     * but UNIX_LINES is enabled.
171.4058 +     */
171.4059 +    static final class UnixDot extends CharProperty {
171.4060 +        boolean isSatisfiedBy(int ch) {
171.4061 +            return ch != '\n';
171.4062 +        }
171.4063 +    }
171.4064 +
171.4065 +    /**
171.4066 +     * The 0 or 1 quantifier. This one class implements all three types.
171.4067 +     */
171.4068 +    static final class Ques extends Node {
171.4069 +        Node atom;
171.4070 +        int type;
171.4071 +        Ques(Node node, int type) {
171.4072 +            this.atom = node;
171.4073 +            this.type = type;
171.4074 +        }
171.4075 +        boolean match(Matcher matcher, int i, CharSequence seq) {
171.4076 +            switch (type) {
171.4077 +            case GREEDY:
171.4078 +                return (atom.match(matcher, i, seq) && next.match(matcher, matcher.last, seq))
171.4079 +                    || next.match(matcher, i, seq);
171.4080 +            case LAZY:
171.4081 +                return next.match(matcher, i, seq)
171.4082 +                    || (atom.match(matcher, i, seq) && next.match(matcher, matcher.last, seq));
171.4083 +            case POSSESSIVE:
171.4084 +                if (atom.match(matcher, i, seq)) i = matcher.last;
171.4085 +                return next.match(matcher, i, seq);
171.4086 +            default:
171.4087 +                return atom.match(matcher, i, seq) && next.match(matcher, matcher.last, seq);
171.4088 +            }
171.4089 +        }
171.4090 +        boolean study(TreeInfo info) {
171.4091 +            if (type != INDEPENDENT) {
171.4092 +                int minL = info.minLength;
171.4093 +                atom.study(info);
171.4094 +                info.minLength = minL;
171.4095 +                info.deterministic = false;
171.4096 +                return next.study(info);
171.4097 +            } else {
171.4098 +                atom.study(info);
171.4099 +                return next.study(info);
171.4100 +            }
171.4101 +        }
171.4102 +    }
171.4103 +
171.4104 +    /**
171.4105 +     * Handles the curly-brace style repetition with a specified minimum and
171.4106 +     * maximum occurrences. The * quantifier is handled as a special case.
171.4107 +     * This class handles the three types.
171.4108 +     */
171.4109 +    static final class Curly extends Node {
171.4110 +        Node atom;
171.4111 +        int type;
171.4112 +        int cmin;
171.4113 +        int cmax;
171.4114 +
171.4115 +        Curly(Node node, int cmin, int cmax, int type) {
171.4116 +            this.atom = node;
171.4117 +            this.type = type;
171.4118 +            this.cmin = cmin;
171.4119 +            this.cmax = cmax;
171.4120 +        }
171.4121 +        boolean match(Matcher matcher, int i, CharSequence seq) {
171.4122 +            int j;
171.4123 +            for (j = 0; j < cmin; j++) {
171.4124 +                if (atom.match(matcher, i, seq)) {
171.4125 +                    i = matcher.last;
171.4126 +                    continue;
171.4127 +                }
171.4128 +                return false;
171.4129 +            }
171.4130 +            if (type == GREEDY)
171.4131 +                return match0(matcher, i, j, seq);
171.4132 +            else if (type == LAZY)
171.4133 +                return match1(matcher, i, j, seq);
171.4134 +            else
171.4135 +                return match2(matcher, i, j, seq);
171.4136 +        }
171.4137 +        // Greedy match.
171.4138 +        // i is the index to start matching at
171.4139 +        // j is the number of atoms that have matched
171.4140 +        boolean match0(Matcher matcher, int i, int j, CharSequence seq) {
171.4141 +            if (j >= cmax) {
171.4142 +                // We have matched the maximum... continue with the rest of
171.4143 +                // the regular expression
171.4144 +                return next.match(matcher, i, seq);
171.4145 +            }
171.4146 +            int backLimit = j;
171.4147 +            while (atom.match(matcher, i, seq)) {
171.4148 +                // k is the length of this match
171.4149 +                int k = matcher.last - i;
171.4150 +                if (k == 0) // Zero length match
171.4151 +                    break;
171.4152 +                // Move up index and number matched
171.4153 +                i = matcher.last;
171.4154 +                j++;
171.4155 +                // We are greedy so match as many as we can
171.4156 +                while (j < cmax) {
171.4157 +                    if (!atom.match(matcher, i, seq))
171.4158 +                        break;
171.4159 +                    if (i + k != matcher.last) {
171.4160 +                        if (match0(matcher, matcher.last, j+1, seq))
171.4161 +                            return true;
171.4162 +                        break;
171.4163 +                    }
171.4164 +                    i += k;
171.4165 +                    j++;
171.4166 +                }
171.4167 +                // Handle backing off if match fails
171.4168 +                while (j >= backLimit) {
171.4169 +                   if (next.match(matcher, i, seq))
171.4170 +                        return true;
171.4171 +                    i -= k;
171.4172 +                    j--;
171.4173 +                }
171.4174 +                return false;
171.4175 +            }
171.4176 +            return next.match(matcher, i, seq);
171.4177 +        }
171.4178 +        // Reluctant match. At this point, the minimum has been satisfied.
171.4179 +        // i is the index to start matching at
171.4180 +        // j is the number of atoms that have matched
171.4181 +        boolean match1(Matcher matcher, int i, int j, CharSequence seq) {
171.4182 +            for (;;) {
171.4183 +                // Try finishing match without consuming any more
171.4184 +                if (next.match(matcher, i, seq))
171.4185 +                    return true;
171.4186 +                // At the maximum, no match found
171.4187 +                if (j >= cmax)
171.4188 +                    return false;
171.4189 +                // Okay, must try one more atom
171.4190 +                if (!atom.match(matcher, i, seq))
171.4191 +                    return false;
171.4192 +                // If we haven't moved forward then must break out
171.4193 +                if (i == matcher.last)
171.4194 +                    return false;
171.4195 +                // Move up index and number matched
171.4196 +                i = matcher.last;
171.4197 +                j++;
171.4198 +            }
171.4199 +        }
171.4200 +        boolean match2(Matcher matcher, int i, int j, CharSequence seq) {
171.4201 +            for (; j < cmax; j++) {
171.4202 +                if (!atom.match(matcher, i, seq))
171.4203 +                    break;
171.4204 +                if (i == matcher.last)
171.4205 +                    break;
171.4206 +                i = matcher.last;
171.4207 +            }
171.4208 +            return next.match(matcher, i, seq);
171.4209 +        }
171.4210 +        boolean study(TreeInfo info) {
171.4211 +            // Save original info
171.4212 +            int minL = info.minLength;
171.4213 +            int maxL = info.maxLength;
171.4214 +            boolean maxV = info.maxValid;
171.4215 +            boolean detm = info.deterministic;
171.4216 +            info.reset();
171.4217 +
171.4218 +            atom.study(info);
171.4219 +
171.4220 +            int temp = info.minLength * cmin + minL;
171.4221 +            if (temp < minL) {
171.4222 +                temp = 0xFFFFFFF; // arbitrary large number
171.4223 +            }
171.4224 +            info.minLength = temp;
171.4225 +
171.4226 +            if (maxV & info.maxValid) {
171.4227 +                temp = info.maxLength * cmax + maxL;
171.4228 +                info.maxLength = temp;
171.4229 +                if (temp < maxL) {
171.4230 +                    info.maxValid = false;
171.4231 +                }
171.4232 +            } else {
171.4233 +                info.maxValid = false;
171.4234 +            }
171.4235 +
171.4236 +            if (info.deterministic && cmin == cmax)
171.4237 +                info.deterministic = detm;
171.4238 +            else
171.4239 +                info.deterministic = false;
171.4240 +
171.4241 +            return next.study(info);
171.4242 +        }
171.4243 +    }
171.4244 +
171.4245 +    /**
171.4246 +     * Handles the curly-brace style repetition with a specified minimum and
171.4247 +     * maximum occurrences in deterministic cases. This is an iterative
171.4248 +     * optimization over the Prolog and Loop system which would handle this
171.4249 +     * in a recursive way. The * quantifier is handled as a special case.
171.4250 +     * If capture is true then this class saves group settings and ensures
171.4251 +     * that groups are unset when backing off of a group match.
171.4252 +     */
171.4253 +    static final class GroupCurly extends Node {
171.4254 +        Node atom;
171.4255 +        int type;
171.4256 +        int cmin;
171.4257 +        int cmax;
171.4258 +        int localIndex;
171.4259 +        int groupIndex;
171.4260 +        boolean capture;
171.4261 +
171.4262 +        GroupCurly(Node node, int cmin, int cmax, int type, int local,
171.4263 +                   int group, boolean capture) {
171.4264 +            this.atom = node;
171.4265 +            this.type = type;
171.4266 +            this.cmin = cmin;
171.4267 +            this.cmax = cmax;
171.4268 +            this.localIndex = local;
171.4269 +            this.groupIndex = group;
171.4270 +            this.capture = capture;
171.4271 +        }
171.4272 +        boolean match(Matcher matcher, int i, CharSequence seq) {
171.4273 +            int[] groups = matcher.groups;
171.4274 +            int[] locals = matcher.locals;
171.4275 +            int save0 = locals[localIndex];
171.4276 +            int save1 = 0;
171.4277 +            int save2 = 0;
171.4278 +
171.4279 +            if (capture) {
171.4280 +                save1 = groups[groupIndex];
171.4281 +                save2 = groups[groupIndex+1];
171.4282 +            }
171.4283 +
171.4284 +            // Notify GroupTail there is no need to setup group info
171.4285 +            // because it will be set here
171.4286 +            locals[localIndex] = -1;
171.4287 +
171.4288 +            boolean ret = true;
171.4289 +            for (int j = 0; j < cmin; j++) {
171.4290 +                if (atom.match(matcher, i, seq)) {
171.4291 +                    if (capture) {
171.4292 +                        groups[groupIndex] = i;
171.4293 +                        groups[groupIndex+1] = matcher.last;
171.4294 +                    }
171.4295 +                    i = matcher.last;
171.4296 +                } else {
171.4297 +                    ret = false;
171.4298 +                    break;
171.4299 +                }
171.4300 +            }
171.4301 +            if (ret) {
171.4302 +                if (type == GREEDY) {
171.4303 +                    ret = match0(matcher, i, cmin, seq);
171.4304 +                } else if (type == LAZY) {
171.4305 +                    ret = match1(matcher, i, cmin, seq);
171.4306 +                } else {
171.4307 +                    ret = match2(matcher, i, cmin, seq);
171.4308 +                }
171.4309 +            }
171.4310 +            if (!ret) {
171.4311 +                locals[localIndex] = save0;
171.4312 +                if (capture) {
171.4313 +                    groups[groupIndex] = save1;
171.4314 +                    groups[groupIndex+1] = save2;
171.4315 +                }
171.4316 +            }
171.4317 +            return ret;
171.4318 +        }
171.4319 +        // Aggressive group match
171.4320 +        boolean match0(Matcher matcher, int i, int j, CharSequence seq) {
171.4321 +            int[] groups = matcher.groups;
171.4322 +            int save0 = 0;
171.4323 +            int save1 = 0;
171.4324 +            if (capture) {
171.4325 +                save0 = groups[groupIndex];
171.4326 +                save1 = groups[groupIndex+1];
171.4327 +            }
171.4328 +            for (;;) {
171.4329 +                if (j >= cmax)
171.4330 +                    break;
171.4331 +                if (!atom.match(matcher, i, seq))
171.4332 +                    break;
171.4333 +                int k = matcher.last - i;
171.4334 +                if (k <= 0) {
171.4335 +                    if (capture) {
171.4336 +                        groups[groupIndex] = i;
171.4337 +                        groups[groupIndex+1] = i + k;
171.4338 +                    }
171.4339 +                    i = i + k;
171.4340 +                    break;
171.4341 +                }
171.4342 +                for (;;) {
171.4343 +                    if (capture) {
171.4344 +                        groups[groupIndex] = i;
171.4345 +                        groups[groupIndex+1] = i + k;
171.4346 +                    }
171.4347 +                    i = i + k;
171.4348 +                    if (++j >= cmax)
171.4349 +                        break;
171.4350 +                    if (!atom.match(matcher, i, seq))
171.4351 +                        break;
171.4352 +                    if (i + k != matcher.last) {
171.4353 +                        if (match0(matcher, i, j, seq))
171.4354 +                            return true;
171.4355 +                        break;
171.4356 +                    }
171.4357 +                }
171.4358 +                while (j > cmin) {
171.4359 +                    if (next.match(matcher, i, seq)) {
171.4360 +                        if (capture) {
171.4361 +                            groups[groupIndex+1] = i;
171.4362 +                            groups[groupIndex] = i - k;
171.4363 +                        }
171.4364 +                        i = i - k;
171.4365 +                        return true;
171.4366 +                    }
171.4367 +                    // backing off
171.4368 +                    if (capture) {
171.4369 +                        groups[groupIndex+1] = i;
171.4370 +                        groups[groupIndex] = i - k;
171.4371 +                    }
171.4372 +                    i = i - k;
171.4373 +                    j--;
171.4374 +                }
171.4375 +                break;
171.4376 +            }
171.4377 +            if (capture) {
171.4378 +                groups[groupIndex] = save0;
171.4379 +                groups[groupIndex+1] = save1;
171.4380 +            }
171.4381 +            return next.match(matcher, i, seq);
171.4382 +        }
171.4383 +        // Reluctant matching
171.4384 +        boolean match1(Matcher matcher, int i, int j, CharSequence seq) {
171.4385 +            for (;;) {
171.4386 +                if (next.match(matcher, i, seq))
171.4387 +                    return true;
171.4388 +                if (j >= cmax)
171.4389 +                    return false;
171.4390 +                if (!atom.match(matcher, i, seq))
171.4391 +                    return false;
171.4392 +                if (i == matcher.last)
171.4393 +                    return false;
171.4394 +                if (capture) {
171.4395 +                    matcher.groups[groupIndex] = i;
171.4396 +                    matcher.groups[groupIndex+1] = matcher.last;
171.4397 +                }
171.4398 +                i = matcher.last;
171.4399 +                j++;
171.4400 +            }
171.4401 +        }
171.4402 +        // Possessive matching
171.4403 +        boolean match2(Matcher matcher, int i, int j, CharSequence seq) {
171.4404 +            for (; j < cmax; j++) {
171.4405 +                if (!atom.match(matcher, i, seq)) {
171.4406 +                    break;
171.4407 +                }
171.4408 +                if (capture) {
171.4409 +                    matcher.groups[groupIndex] = i;
171.4410 +                    matcher.groups[groupIndex+1] = matcher.last;
171.4411 +                }
171.4412 +                if (i == matcher.last) {
171.4413 +                    break;
171.4414 +                }
171.4415 +                i = matcher.last;
171.4416 +            }
171.4417 +            return next.match(matcher, i, seq);
171.4418 +        }
171.4419 +        boolean study(TreeInfo info) {
171.4420 +            // Save original info
171.4421 +            int minL = info.minLength;
171.4422 +            int maxL = info.maxLength;
171.4423 +            boolean maxV = info.maxValid;
171.4424 +            boolean detm = info.deterministic;
171.4425 +            info.reset();
171.4426 +
171.4427 +            atom.study(info);
171.4428 +
171.4429 +            int temp = info.minLength * cmin + minL;
171.4430 +            if (temp < minL) {
171.4431 +                temp = 0xFFFFFFF; // Arbitrary large number
171.4432 +            }
171.4433 +            info.minLength = temp;
171.4434 +
171.4435 +            if (maxV & info.maxValid) {
171.4436 +                temp = info.maxLength * cmax + maxL;
171.4437 +                info.maxLength = temp;
171.4438 +                if (temp < maxL) {
171.4439 +                    info.maxValid = false;
171.4440 +                }
171.4441 +            } else {
171.4442 +                info.maxValid = false;
171.4443 +            }
171.4444 +
171.4445 +            if (info.deterministic && cmin == cmax) {
171.4446 +                info.deterministic = detm;
171.4447 +            } else {
171.4448 +                info.deterministic = false;
171.4449 +            }
171.4450 +
171.4451 +            return next.study(info);
171.4452 +        }
171.4453 +    }
171.4454 +
171.4455 +    /**
171.4456 +     * A Guard node at the end of each atom node in a Branch. It
171.4457 +     * serves the purpose of chaining the "match" operation to
171.4458 +     * "next" but not the "study", so we can collect the TreeInfo
171.4459 +     * of each atom node without including the TreeInfo of the
171.4460 +     * "next".
171.4461 +     */
171.4462 +    static final class BranchConn extends Node {
171.4463 +        BranchConn() {};
171.4464 +        boolean match(Matcher matcher, int i, CharSequence seq) {
171.4465 +            return next.match(matcher, i, seq);
171.4466 +        }
171.4467 +        boolean study(TreeInfo info) {
171.4468 +            return info.deterministic;
171.4469 +        }
171.4470 +    }
171.4471 +
171.4472 +    /**
171.4473 +     * Handles the branching of alternations. Note this is also used for
171.4474 +     * the ? quantifier to branch between the case where it matches once
171.4475 +     * and where it does not occur.
171.4476 +     */
171.4477 +    static final class Branch extends Node {
171.4478 +        Node[] atoms = new Node[2];
171.4479 +        int size = 2;
171.4480 +        Node conn;
171.4481 +        Branch(Node first, Node second, Node branchConn) {
171.4482 +            conn = branchConn;
171.4483 +            atoms[0] = first;
171.4484 +            atoms[1] = second;
171.4485 +        }
171.4486 +
171.4487 +        void add(Node node) {
171.4488 +            if (size >= atoms.length) {
171.4489 +                Node[] tmp = new Node[atoms.length*2];
171.4490 +                System.arraycopy(atoms, 0, tmp, 0, atoms.length);
171.4491 +                atoms = tmp;
171.4492 +            }
171.4493 +            atoms[size++] = node;
171.4494 +        }
171.4495 +
171.4496 +        boolean match(Matcher matcher, int i, CharSequence seq) {
171.4497 +            for (int n = 0; n < size; n++) {
171.4498 +                if (atoms[n] == null) {
171.4499 +                    if (conn.next.match(matcher, i, seq))
171.4500 +                        return true;
171.4501 +                } else if (atoms[n].match(matcher, i, seq)) {
171.4502 +                    return true;
171.4503 +                }
171.4504 +            }
171.4505 +            return false;
171.4506 +        }
171.4507 +
171.4508 +        boolean study(TreeInfo info) {
171.4509 +            int minL = info.minLength;
171.4510 +            int maxL = info.maxLength;
171.4511 +            boolean maxV = info.maxValid;
171.4512 +
171.4513 +            int minL2 = Integer.MAX_VALUE; //arbitrary large enough num
171.4514 +            int maxL2 = -1;
171.4515 +            for (int n = 0; n < size; n++) {
171.4516 +                info.reset();
171.4517 +                if (atoms[n] != null)
171.4518 +                    atoms[n].study(info);
171.4519 +                minL2 = Math.min(minL2, info.minLength);
171.4520 +                maxL2 = Math.max(maxL2, info.maxLength);
171.4521 +                maxV = (maxV & info.maxValid);
171.4522 +            }
171.4523 +
171.4524 +            minL += minL2;
171.4525 +            maxL += maxL2;
171.4526 +
171.4527 +            info.reset();
171.4528 +            conn.next.study(info);
171.4529 +
171.4530 +            info.minLength += minL;
171.4531 +            info.maxLength += maxL;
171.4532 +            info.maxValid &= maxV;
171.4533 +            info.deterministic = false;
171.4534 +            return false;
171.4535 +        }
171.4536 +    }
171.4537 +
171.4538 +    /**
171.4539 +     * The GroupHead saves the location where the group begins in the locals
171.4540 +     * and restores them when the match is done.
171.4541 +     *
171.4542 +     * The matchRef is used when a reference to this group is accessed later
171.4543 +     * in the expression. The locals will have a negative value in them to
171.4544 +     * indicate that we do not want to unset the group if the reference
171.4545 +     * doesn't match.
171.4546 +     */
171.4547 +    static final class GroupHead extends Node {
171.4548 +        int localIndex;
171.4549 +        GroupHead(int localCount) {
171.4550 +            localIndex = localCount;
171.4551 +        }
171.4552 +        boolean match(Matcher matcher, int i, CharSequence seq) {
171.4553 +            int save = matcher.locals[localIndex];
171.4554 +            matcher.locals[localIndex] = i;
171.4555 +            boolean ret = next.match(matcher, i, seq);
171.4556 +            matcher.locals[localIndex] = save;
171.4557 +            return ret;
171.4558 +        }
171.4559 +        boolean matchRef(Matcher matcher, int i, CharSequence seq) {
171.4560 +            int save = matcher.locals[localIndex];
171.4561 +            matcher.locals[localIndex] = ~i; // HACK
171.4562 +            boolean ret = next.match(matcher, i, seq);
171.4563 +            matcher.locals[localIndex] = save;
171.4564 +            return ret;
171.4565 +        }
171.4566 +    }
171.4567 +
171.4568 +    /**
171.4569 +     * Recursive reference to a group in the regular expression. It calls
171.4570 +     * matchRef because if the reference fails to match we would not unset
171.4571 +     * the group.
171.4572 +     */
171.4573 +    static final class GroupRef extends Node {
171.4574 +        GroupHead head;
171.4575 +        GroupRef(GroupHead head) {
171.4576 +            this.head = head;
171.4577 +        }
171.4578 +        boolean match(Matcher matcher, int i, CharSequence seq) {
171.4579 +            return head.matchRef(matcher, i, seq)
171.4580 +                && next.match(matcher, matcher.last, seq);
171.4581 +        }
171.4582 +        boolean study(TreeInfo info) {
171.4583 +            info.maxValid = false;
171.4584 +            info.deterministic = false;
171.4585 +            return next.study(info);
171.4586 +        }
171.4587 +    }
171.4588 +
171.4589 +    /**
171.4590 +     * The GroupTail handles the setting of group beginning and ending
171.4591 +     * locations when groups are successfully matched. It must also be able to
171.4592 +     * unset groups that have to be backed off of.
171.4593 +     *
171.4594 +     * The GroupTail node is also used when a previous group is referenced,
171.4595 +     * and in that case no group information needs to be set.
171.4596 +     */
171.4597 +    static final class GroupTail extends Node {
171.4598 +        int localIndex;
171.4599 +        int groupIndex;
171.4600 +        GroupTail(int localCount, int groupCount) {
171.4601 +            localIndex = localCount;
171.4602 +            groupIndex = groupCount + groupCount;
171.4603 +        }
171.4604 +        boolean match(Matcher matcher, int i, CharSequence seq) {
171.4605 +            int tmp = matcher.locals[localIndex];
171.4606 +            if (tmp >= 0) { // This is the normal group case.
171.4607 +                // Save the group so we can unset it if it
171.4608 +                // backs off of a match.
171.4609 +                int groupStart = matcher.groups[groupIndex];
171.4610 +                int groupEnd = matcher.groups[groupIndex+1];
171.4611 +
171.4612 +                matcher.groups[groupIndex] = tmp;
171.4613 +                matcher.groups[groupIndex+1] = i;
171.4614 +                if (next.match(matcher, i, seq)) {
171.4615 +                    return true;
171.4616 +                }
171.4617 +                matcher.groups[groupIndex] = groupStart;
171.4618 +                matcher.groups[groupIndex+1] = groupEnd;
171.4619 +                return false;
171.4620 +            } else {
171.4621 +                // This is a group reference case. We don't need to save any
171.4622 +                // group info because it isn't really a group.
171.4623 +                matcher.last = i;
171.4624 +                return true;
171.4625 +            }
171.4626 +        }
171.4627 +    }
171.4628 +
171.4629 +    /**
171.4630 +     * This sets up a loop to handle a recursive quantifier structure.
171.4631 +     */
171.4632 +    static final class Prolog extends Node {
171.4633 +        Loop loop;
171.4634 +        Prolog(Loop loop) {
171.4635 +            this.loop = loop;
171.4636 +        }
171.4637 +        boolean match(Matcher matcher, int i, CharSequence seq) {
171.4638 +            return loop.matchInit(matcher, i, seq);
171.4639 +        }
171.4640 +        boolean study(TreeInfo info) {
171.4641 +            return loop.study(info);
171.4642 +        }
171.4643 +    }
171.4644 +
171.4645 +    /**
171.4646 +     * Handles the repetition count for a greedy Curly. The matchInit
171.4647 +     * is called from the Prolog to save the index of where the group
171.4648 +     * beginning is stored. A zero length group check occurs in the
171.4649 +     * normal match but is skipped in the matchInit.
171.4650 +     */
171.4651 +    static class Loop extends Node {
171.4652 +        Node body;
171.4653 +        int countIndex; // local count index in matcher locals
171.4654 +        int beginIndex; // group beginning index
171.4655 +        int cmin, cmax;
171.4656 +        Loop(int countIndex, int beginIndex) {
171.4657 +            this.countIndex = countIndex;
171.4658 +            this.beginIndex = beginIndex;
171.4659 +        }
171.4660 +        boolean match(Matcher matcher, int i, CharSequence seq) {
171.4661 +            // Avoid infinite loop in zero-length case.
171.4662 +            if (i > matcher.locals[beginIndex]) {
171.4663 +                int count = matcher.locals[countIndex];
171.4664 +
171.4665 +                // This block is for before we reach the minimum
171.4666 +                // iterations required for the loop to match
171.4667 +                if (count < cmin) {
171.4668 +                    matcher.locals[countIndex] = count + 1;
171.4669 +                    boolean b = body.match(matcher, i, seq);
171.4670 +                    // If match failed we must backtrack, so
171.4671 +                    // the loop count should NOT be incremented
171.4672 +                    if (!b)
171.4673 +                        matcher.locals[countIndex] = count;
171.4674 +                    // Return success or failure since we are under
171.4675 +                    // minimum
171.4676 +                    return b;
171.4677 +                }
171.4678 +                // This block is for after we have the minimum
171.4679 +                // iterations required for the loop to match
171.4680 +                if (count < cmax) {
171.4681 +                    matcher.locals[countIndex] = count + 1;
171.4682 +                    boolean b = body.match(matcher, i, seq);
171.4683 +                    // If match failed we must backtrack, so
171.4684 +                    // the loop count should NOT be incremented
171.4685 +                    if (!b)
171.4686 +                        matcher.locals[countIndex] = count;
171.4687 +                    else
171.4688 +                        return true;
171.4689 +                }
171.4690 +            }
171.4691 +            return next.match(matcher, i, seq);
171.4692 +        }
171.4693 +        boolean matchInit(Matcher matcher, int i, CharSequence seq) {
171.4694 +            int save = matcher.locals[countIndex];
171.4695 +            boolean ret = false;
171.4696 +            if (0 < cmin) {
171.4697 +                matcher.locals[countIndex] = 1;
171.4698 +                ret = body.match(matcher, i, seq);
171.4699 +            } else if (0 < cmax) {
171.4700 +                matcher.locals[countIndex] = 1;
171.4701 +                ret = body.match(matcher, i, seq);
171.4702 +                if (ret == false)
171.4703 +                    ret = next.match(matcher, i, seq);
171.4704 +            } else {
171.4705 +                ret = next.match(matcher, i, seq);
171.4706 +            }
171.4707 +            matcher.locals[countIndex] = save;
171.4708 +            return ret;
171.4709 +        }
171.4710 +        boolean study(TreeInfo info) {
171.4711 +            info.maxValid = false;
171.4712 +            info.deterministic = false;
171.4713 +            return false;
171.4714 +        }
171.4715 +    }
171.4716 +
171.4717 +    /**
171.4718 +     * Handles the repetition count for a reluctant Curly. The matchInit
171.4719 +     * is called from the Prolog to save the index of where the group
171.4720 +     * beginning is stored. A zero length group check occurs in the
171.4721 +     * normal match but is skipped in the matchInit.
171.4722 +     */
171.4723 +    static final class LazyLoop extends Loop {
171.4724 +        LazyLoop(int countIndex, int beginIndex) {
171.4725 +            super(countIndex, beginIndex);
171.4726 +        }
171.4727 +        boolean match(Matcher matcher, int i, CharSequence seq) {
171.4728 +            // Check for zero length group
171.4729 +            if (i > matcher.locals[beginIndex]) {
171.4730 +                int count = matcher.locals[countIndex];
171.4731 +                if (count < cmin) {
171.4732 +                    matcher.locals[countIndex] = count + 1;
171.4733 +                    boolean result = body.match(matcher, i, seq);
171.4734 +                    // If match failed we must backtrack, so
171.4735 +                    // the loop count should NOT be incremented
171.4736 +                    if (!result)
171.4737 +                        matcher.locals[countIndex] = count;
171.4738 +                    return result;
171.4739 +                }
171.4740 +                if (next.match(matcher, i, seq))
171.4741 +                    return true;
171.4742 +                if (count < cmax) {
171.4743 +                    matcher.locals[countIndex] = count + 1;
171.4744 +                    boolean result = body.match(matcher, i, seq);
171.4745 +                    // If match failed we must backtrack, so
171.4746 +                    // the loop count should NOT be incremented
171.4747 +                    if (!result)
171.4748 +                        matcher.locals[countIndex] = count;
171.4749 +                    return result;
171.4750 +                }
171.4751 +                return false;
171.4752 +            }
171.4753 +            return next.match(matcher, i, seq);
171.4754 +        }
171.4755 +        boolean matchInit(Matcher matcher, int i, CharSequence seq) {
171.4756 +            int save = matcher.locals[countIndex];
171.4757 +            boolean ret = false;
171.4758 +            if (0 < cmin) {
171.4759 +                matcher.locals[countIndex] = 1;
171.4760 +                ret = body.match(matcher, i, seq);
171.4761 +            } else if (next.match(matcher, i, seq)) {
171.4762 +                ret = true;
171.4763 +            } else if (0 < cmax) {
171.4764 +                matcher.locals[countIndex] = 1;
171.4765 +                ret = body.match(matcher, i, seq);
171.4766 +            }
171.4767 +            matcher.locals[countIndex] = save;
171.4768 +            return ret;
171.4769 +        }
171.4770 +        boolean study(TreeInfo info) {
171.4771 +            info.maxValid = false;
171.4772 +            info.deterministic = false;
171.4773 +            return false;
171.4774 +        }
171.4775 +    }
171.4776 +
171.4777 +    /**
171.4778 +     * Refers to a group in the regular expression. Attempts to match
171.4779 +     * whatever the group referred to last matched.
171.4780 +     */
171.4781 +    static class BackRef extends Node {
171.4782 +        int groupIndex;
171.4783 +        BackRef(int groupCount) {
171.4784 +            super();
171.4785 +            groupIndex = groupCount + groupCount;
171.4786 +        }
171.4787 +        boolean match(Matcher matcher, int i, CharSequence seq) {
171.4788 +            int j = matcher.groups[groupIndex];
171.4789 +            int k = matcher.groups[groupIndex+1];
171.4790 +
171.4791 +            int groupSize = k - j;
171.4792 +
171.4793 +            // If the referenced group didn't match, neither can this
171.4794 +            if (j < 0)
171.4795 +                return false;
171.4796 +
171.4797 +            // If there isn't enough input left no match
171.4798 +            if (i + groupSize > matcher.to) {
171.4799 +                matcher.hitEnd = true;
171.4800 +                return false;
171.4801 +            }
171.4802 +
171.4803 +            // Check each new char to make sure it matches what the group
171.4804 +            // referenced matched last time around
171.4805 +            for (int index=0; index<groupSize; index++)
171.4806 +                if (seq.charAt(i+index) != seq.charAt(j+index))
171.4807 +                    return false;
171.4808 +
171.4809 +            return next.match(matcher, i+groupSize, seq);
171.4810 +        }
171.4811 +        boolean study(TreeInfo info) {
171.4812 +            info.maxValid = false;
171.4813 +            return next.study(info);
171.4814 +        }
171.4815 +    }
171.4816 +
171.4817 +    static class CIBackRef extends Node {
171.4818 +        int groupIndex;
171.4819 +        boolean doUnicodeCase;
171.4820 +        CIBackRef(int groupCount, boolean doUnicodeCase) {
171.4821 +            super();
171.4822 +            groupIndex = groupCount + groupCount;
171.4823 +            this.doUnicodeCase = doUnicodeCase;
171.4824 +        }
171.4825 +        boolean match(Matcher matcher, int i, CharSequence seq) {
171.4826 +            int j = matcher.groups[groupIndex];
171.4827 +            int k = matcher.groups[groupIndex+1];
171.4828 +
171.4829 +            int groupSize = k - j;
171.4830 +
171.4831 +            // If the referenced group didn't match, neither can this
171.4832 +            if (j < 0)
171.4833 +                return false;
171.4834 +
171.4835 +            // If there isn't enough input left no match
171.4836 +            if (i + groupSize > matcher.to) {
171.4837 +                matcher.hitEnd = true;
171.4838 +                return false;
171.4839 +            }
171.4840 +
171.4841 +            // Check each new char to make sure it matches what the group
171.4842 +            // referenced matched last time around
171.4843 +            int x = i;
171.4844 +            for (int index=0; index<groupSize; index++) {
171.4845 +                int c1 = Character.codePointAt(seq, x);
171.4846 +                int c2 = Character.codePointAt(seq, j);
171.4847 +                if (c1 != c2) {
171.4848 +                    if (doUnicodeCase) {
171.4849 +                        int cc1 = Character.toUpperCase(c1);
171.4850 +                        int cc2 = Character.toUpperCase(c2);
171.4851 +                        if (cc1 != cc2 &&
171.4852 +                            Character.toLowerCase(cc1) !=
171.4853 +                            Character.toLowerCase(cc2))
171.4854 +                            return false;
171.4855 +                    } else {
171.4856 +                        if (ASCII.toLower(c1) != ASCII.toLower(c2))
171.4857 +                            return false;
171.4858 +                    }
171.4859 +                }
171.4860 +                x += Character.charCount(c1);
171.4861 +                j += Character.charCount(c2);
171.4862 +            }
171.4863 +
171.4864 +            return next.match(matcher, i+groupSize, seq);
171.4865 +        }
171.4866 +        boolean study(TreeInfo info) {
171.4867 +            info.maxValid = false;
171.4868 +            return next.study(info);
171.4869 +        }
171.4870 +    }
171.4871 +
171.4872 +    /**
171.4873 +     * Searches until the next instance of its atom. This is useful for
171.4874 +     * finding the atom efficiently without passing an instance of it
171.4875 +     * (greedy problem) and without a lot of wasted search time (reluctant
171.4876 +     * problem).
171.4877 +     */
171.4878 +    static final class First extends Node {
171.4879 +        Node atom;
171.4880 +        First(Node node) {
171.4881 +            this.atom = BnM.optimize(node);
171.4882 +        }
171.4883 +        boolean match(Matcher matcher, int i, CharSequence seq) {
171.4884 +            if (atom instanceof BnM) {
171.4885 +                return atom.match(matcher, i, seq)
171.4886 +                    && next.match(matcher, matcher.last, seq);
171.4887 +            }
171.4888 +            for (;;) {
171.4889 +                if (i > matcher.to) {
171.4890 +                    matcher.hitEnd = true;
171.4891 +                    return false;
171.4892 +                }
171.4893 +                if (atom.match(matcher, i, seq)) {
171.4894 +                    return next.match(matcher, matcher.last, seq);
171.4895 +                }
171.4896 +                i += countChars(seq, i, 1);
171.4897 +                matcher.first++;
171.4898 +            }
171.4899 +        }
171.4900 +        boolean study(TreeInfo info) {
171.4901 +            atom.study(info);
171.4902 +            info.maxValid = false;
171.4903 +            info.deterministic = false;
171.4904 +            return next.study(info);
171.4905 +        }
171.4906 +    }
171.4907 +
171.4908 +    static final class Conditional extends Node {
171.4909 +        Node cond, yes, not;
171.4910 +        Conditional(Node cond, Node yes, Node not) {
171.4911 +            this.cond = cond;
171.4912 +            this.yes = yes;
171.4913 +            this.not = not;
171.4914 +        }
171.4915 +        boolean match(Matcher matcher, int i, CharSequence seq) {
171.4916 +            if (cond.match(matcher, i, seq)) {
171.4917 +                return yes.match(matcher, i, seq);
171.4918 +            } else {
171.4919 +                return not.match(matcher, i, seq);
171.4920 +            }
171.4921 +        }
171.4922 +        boolean study(TreeInfo info) {
171.4923 +            int minL = info.minLength;
171.4924 +            int maxL = info.maxLength;
171.4925 +            boolean maxV = info.maxValid;
171.4926 +            info.reset();
171.4927 +            yes.study(info);
171.4928 +
171.4929 +            int minL2 = info.minLength;
171.4930 +            int maxL2 = info.maxLength;
171.4931 +            boolean maxV2 = info.maxValid;
171.4932 +            info.reset();
171.4933 +            not.study(info);
171.4934 +
171.4935 +            info.minLength = minL + Math.min(minL2, info.minLength);
171.4936 +            info.maxLength = maxL + Math.max(maxL2, info.maxLength);
171.4937 +            info.maxValid = (maxV & maxV2 & info.maxValid);
171.4938 +            info.deterministic = false;
171.4939 +            return next.study(info);
171.4940 +        }
171.4941 +    }
171.4942 +
171.4943 +    /**
171.4944 +     * Zero width positive lookahead.
171.4945 +     */
171.4946 +    static final class Pos extends Node {
171.4947 +        Node cond;
171.4948 +        Pos(Node cond) {
171.4949 +            this.cond = cond;
171.4950 +        }
171.4951 +        boolean match(Matcher matcher, int i, CharSequence seq) {
171.4952 +            int savedTo = matcher.to;
171.4953 +            boolean conditionMatched = false;
171.4954 +
171.4955 +            // Relax transparent region boundaries for lookahead
171.4956 +            if (matcher.transparentBounds)
171.4957 +                matcher.to = matcher.getTextLength();
171.4958 +            try {
171.4959 +                conditionMatched = cond.match(matcher, i, seq);
171.4960 +            } finally {
171.4961 +                // Reinstate region boundaries
171.4962 +                matcher.to = savedTo;
171.4963 +            }
171.4964 +            return conditionMatched && next.match(matcher, i, seq);
171.4965 +        }
171.4966 +    }
171.4967 +
171.4968 +    /**
171.4969 +     * Zero width negative lookahead.
171.4970 +     */
171.4971 +    static final class Neg extends Node {
171.4972 +        Node cond;
171.4973 +        Neg(Node cond) {
171.4974 +            this.cond = cond;
171.4975 +        }
171.4976 +        boolean match(Matcher matcher, int i, CharSequence seq) {
171.4977 +            int savedTo = matcher.to;
171.4978 +            boolean conditionMatched = false;
171.4979 +
171.4980 +            // Relax transparent region boundaries for lookahead
171.4981 +            if (matcher.transparentBounds)
171.4982 +                matcher.to = matcher.getTextLength();
171.4983 +            try {
171.4984 +                if (i < matcher.to) {
171.4985 +                    conditionMatched = !cond.match(matcher, i, seq);
171.4986 +                } else {
171.4987 +                    // If a negative lookahead succeeds then more input
171.4988 +                    // could cause it to fail!
171.4989 +                    matcher.requireEnd = true;
171.4990 +                    conditionMatched = !cond.match(matcher, i, seq);
171.4991 +                }
171.4992 +            } finally {
171.4993 +                // Reinstate region boundaries
171.4994 +                matcher.to = savedTo;
171.4995 +            }
171.4996 +            return conditionMatched && next.match(matcher, i, seq);
171.4997 +        }
171.4998 +    }
171.4999 +
171.5000 +    /**
171.5001 +     * For use with lookbehinds; matches the position where the lookbehind
171.5002 +     * was encountered.
171.5003 +     */
171.5004 +    static Node lookbehindEnd = new Node() {
171.5005 +        boolean match(Matcher matcher, int i, CharSequence seq) {
171.5006 +            return i == matcher.lookbehindTo;
171.5007 +        }
171.5008 +    };
171.5009 +
171.5010 +    /**
171.5011 +     * Zero width positive lookbehind.
171.5012 +     */
171.5013 +    static class Behind extends Node {
171.5014 +        Node cond;
171.5015 +        int rmax, rmin;
171.5016 +        Behind(Node cond, int rmax, int rmin) {
171.5017 +            this.cond = cond;
171.5018 +            this.rmax = rmax;
171.5019 +            this.rmin = rmin;
171.5020 +        }
171.5021 +
171.5022 +        boolean match(Matcher matcher, int i, CharSequence seq) {
171.5023 +            int savedFrom = matcher.from;
171.5024 +            boolean conditionMatched = false;
171.5025 +            int startIndex = (!matcher.transparentBounds) ?
171.5026 +                             matcher.from : 0;
171.5027 +            int from = Math.max(i - rmax, startIndex);
171.5028 +            // Set end boundary
171.5029 +            int savedLBT = matcher.lookbehindTo;
171.5030 +            matcher.lookbehindTo = i;
171.5031 +            // Relax transparent region boundaries for lookbehind
171.5032 +            if (matcher.transparentBounds)
171.5033 +                matcher.from = 0;
171.5034 +            for (int j = i - rmin; !conditionMatched && j >= from; j--) {
171.5035 +                conditionMatched = cond.match(matcher, j, seq);
171.5036 +            }
171.5037 +            matcher.from = savedFrom;
171.5038 +            matcher.lookbehindTo = savedLBT;
171.5039 +            return conditionMatched && next.match(matcher, i, seq);
171.5040 +        }
171.5041 +    }
171.5042 +
171.5043 +    /**
171.5044 +     * Zero width positive lookbehind, including supplementary
171.5045 +     * characters or unpaired surrogates.
171.5046 +     */
171.5047 +    static final class BehindS extends Behind {
171.5048 +        BehindS(Node cond, int rmax, int rmin) {
171.5049 +            super(cond, rmax, rmin);
171.5050 +        }
171.5051 +        boolean match(Matcher matcher, int i, CharSequence seq) {
171.5052 +            int rmaxChars = countChars(seq, i, -rmax);
171.5053 +            int rminChars = countChars(seq, i, -rmin);
171.5054 +            int savedFrom = matcher.from;
171.5055 +            int startIndex = (!matcher.transparentBounds) ?
171.5056 +                             matcher.from : 0;
171.5057 +            boolean conditionMatched = false;
171.5058 +            int from = Math.max(i - rmaxChars, startIndex);
171.5059 +            // Set end boundary
171.5060 +            int savedLBT = matcher.lookbehindTo;
171.5061 +            matcher.lookbehindTo = i;
171.5062 +            // Relax transparent region boundaries for lookbehind
171.5063 +            if (matcher.transparentBounds)
171.5064 +                matcher.from = 0;
171.5065 +
171.5066 +            for (int j = i - rminChars;
171.5067 +                 !conditionMatched && j >= from;
171.5068 +                 j -= j>from ? countChars(seq, j, -1) : 1) {
171.5069 +                conditionMatched = cond.match(matcher, j, seq);
171.5070 +            }
171.5071 +            matcher.from = savedFrom;
171.5072 +            matcher.lookbehindTo = savedLBT;
171.5073 +            return conditionMatched && next.match(matcher, i, seq);
171.5074 +        }
171.5075 +    }
171.5076 +
171.5077 +    /**
171.5078 +     * Zero width negative lookbehind.
171.5079 +     */
171.5080 +    static class NotBehind extends Node {
171.5081 +        Node cond;
171.5082 +        int rmax, rmin;
171.5083 +        NotBehind(Node cond, int rmax, int rmin) {
171.5084 +            this.cond = cond;
171.5085 +            this.rmax = rmax;
171.5086 +            this.rmin = rmin;
171.5087 +        }
171.5088 +
171.5089 +        boolean match(Matcher matcher, int i, CharSequence seq) {
171.5090 +            int savedLBT = matcher.lookbehindTo;
171.5091 +            int savedFrom = matcher.from;
171.5092 +            boolean conditionMatched = false;
171.5093 +            int startIndex = (!matcher.transparentBounds) ?
171.5094 +                             matcher.from : 0;
171.5095 +            int from = Math.max(i - rmax, startIndex);
171.5096 +            matcher.lookbehindTo = i;
171.5097 +            // Relax transparent region boundaries for lookbehind
171.5098 +            if (matcher.transparentBounds)
171.5099 +                matcher.from = 0;
171.5100 +            for (int j = i - rmin; !conditionMatched && j >= from; j--) {
171.5101 +                conditionMatched = cond.match(matcher, j, seq);
171.5102 +            }
171.5103 +            // Reinstate region boundaries
171.5104 +            matcher.from = savedFrom;
171.5105 +            matcher.lookbehindTo = savedLBT;
171.5106 +            return !conditionMatched && next.match(matcher, i, seq);
171.5107 +        }
171.5108 +    }
171.5109 +
171.5110 +    /**
171.5111 +     * Zero width negative lookbehind, including supplementary
171.5112 +     * characters or unpaired surrogates.
171.5113 +     */
171.5114 +    static final class NotBehindS extends NotBehind {
171.5115 +        NotBehindS(Node cond, int rmax, int rmin) {
171.5116 +            super(cond, rmax, rmin);
171.5117 +        }
171.5118 +        boolean match(Matcher matcher, int i, CharSequence seq) {
171.5119 +            int rmaxChars = countChars(seq, i, -rmax);
171.5120 +            int rminChars = countChars(seq, i, -rmin);
171.5121 +            int savedFrom = matcher.from;
171.5122 +            int savedLBT = matcher.lookbehindTo;
171.5123 +            boolean conditionMatched = false;
171.5124 +            int startIndex = (!matcher.transparentBounds) ?
171.5125 +                             matcher.from : 0;
171.5126 +            int from = Math.max(i - rmaxChars, startIndex);
171.5127 +            matcher.lookbehindTo = i;
171.5128 +            // Relax transparent region boundaries for lookbehind
171.5129 +            if (matcher.transparentBounds)
171.5130 +                matcher.from = 0;
171.5131 +            for (int j = i - rminChars;
171.5132 +                 !conditionMatched && j >= from;
171.5133 +                 j -= j>from ? countChars(seq, j, -1) : 1) {
171.5134 +                conditionMatched = cond.match(matcher, j, seq);
171.5135 +            }
171.5136 +            //Reinstate region boundaries
171.5137 +            matcher.from = savedFrom;
171.5138 +            matcher.lookbehindTo = savedLBT;
171.5139 +            return !conditionMatched && next.match(matcher, i, seq);
171.5140 +        }
171.5141 +    }
171.5142 +
171.5143 +    /**
171.5144 +     * Returns the set union of two CharProperty nodes.
171.5145 +     */
171.5146 +    private static CharProperty union(final CharProperty lhs,
171.5147 +                                      final CharProperty rhs) {
171.5148 +        return new CharProperty() {
171.5149 +                boolean isSatisfiedBy(int ch) {
171.5150 +                    return lhs.isSatisfiedBy(ch) || rhs.isSatisfiedBy(ch);}};
171.5151 +    }
171.5152 +
171.5153 +    /**
171.5154 +     * Returns the set intersection of two CharProperty nodes.
171.5155 +     */
171.5156 +    private static CharProperty intersection(final CharProperty lhs,
171.5157 +                                             final CharProperty rhs) {
171.5158 +        return new CharProperty() {
171.5159 +                boolean isSatisfiedBy(int ch) {
171.5160 +                    return lhs.isSatisfiedBy(ch) && rhs.isSatisfiedBy(ch);}};
171.5161 +    }
171.5162 +
171.5163 +    /**
171.5164 +     * Returns the set difference of two CharProperty nodes.
171.5165 +     */
171.5166 +    private static CharProperty setDifference(final CharProperty lhs,
171.5167 +                                              final CharProperty rhs) {
171.5168 +        return new CharProperty() {
171.5169 +                boolean isSatisfiedBy(int ch) {
171.5170 +                    return ! rhs.isSatisfiedBy(ch) && lhs.isSatisfiedBy(ch);}};
171.5171 +    }
171.5172 +
171.5173 +    /**
171.5174 +     * Handles word boundaries. Includes a field to allow this one class to
171.5175 +     * deal with the different types of word boundaries we can match. The word
171.5176 +     * characters include underscores, letters, and digits. Non spacing marks
171.5177 +     * can are also part of a word if they have a base character, otherwise
171.5178 +     * they are ignored for purposes of finding word boundaries.
171.5179 +     */
171.5180 +    static final class Bound extends Node {
171.5181 +        static int LEFT = 0x1;
171.5182 +        static int RIGHT= 0x2;
171.5183 +        static int BOTH = 0x3;
171.5184 +        static int NONE = 0x4;
171.5185 +        int type;
171.5186 +        boolean useUWORD;
171.5187 +        Bound(int n, boolean useUWORD) {
171.5188 +            type = n;
171.5189 +            this.useUWORD = useUWORD;
171.5190 +        }
171.5191 +
171.5192 +        boolean isWord(int ch) {
171.5193 +            return useUWORD ? UnicodeProp.WORD.is(ch)
171.5194 +                            : (ch == '_' || Character.isLetterOrDigit(ch));
171.5195 +        }
171.5196 +
171.5197 +        int check(Matcher matcher, int i, CharSequence seq) {
171.5198 +            int ch;
171.5199 +            boolean left = false;
171.5200 +            int startIndex = matcher.from;
171.5201 +            int endIndex = matcher.to;
171.5202 +            if (matcher.transparentBounds) {
171.5203 +                startIndex = 0;
171.5204 +                endIndex = matcher.getTextLength();
171.5205 +            }
171.5206 +            if (i > startIndex) {
171.5207 +                ch = Character.codePointBefore(seq, i);
171.5208 +                left = (isWord(ch) ||
171.5209 +                    ((Character.getType(ch) == Character.NON_SPACING_MARK)
171.5210 +                     && hasBaseCharacter(matcher, i-1, seq)));
171.5211 +            }
171.5212 +            boolean right = false;
171.5213 +            if (i < endIndex) {
171.5214 +                ch = Character.codePointAt(seq, i);
171.5215 +                right = (isWord(ch) ||
171.5216 +                    ((Character.getType(ch) == Character.NON_SPACING_MARK)
171.5217 +                     && hasBaseCharacter(matcher, i, seq)));
171.5218 +            } else {
171.5219 +                // Tried to access char past the end
171.5220 +                matcher.hitEnd = true;
171.5221 +                // The addition of another char could wreck a boundary
171.5222 +                matcher.requireEnd = true;
171.5223 +            }
171.5224 +            return ((left ^ right) ? (right ? LEFT : RIGHT) : NONE);
171.5225 +        }
171.5226 +        boolean match(Matcher matcher, int i, CharSequence seq) {
171.5227 +            return (check(matcher, i, seq) & type) > 0
171.5228 +                && next.match(matcher, i, seq);
171.5229 +        }
171.5230 +    }
171.5231 +
171.5232 +    /**
171.5233 +     * Non spacing marks only count as word characters in bounds calculations
171.5234 +     * if they have a base character.
171.5235 +     */
171.5236 +    private static boolean hasBaseCharacter(Matcher matcher, int i,
171.5237 +                                            CharSequence seq)
171.5238 +    {
171.5239 +        int start = (!matcher.transparentBounds) ?
171.5240 +            matcher.from : 0;
171.5241 +        for (int x=i; x >= start; x--) {
171.5242 +            int ch = Character.codePointAt(seq, x);
171.5243 +            if (Character.isLetterOrDigit(ch))
171.5244 +                return true;
171.5245 +            if (Character.getType(ch) == Character.NON_SPACING_MARK)
171.5246 +                continue;
171.5247 +            return false;
171.5248 +        }
171.5249 +        return false;
171.5250 +    }
171.5251 +
171.5252 +    /**
171.5253 +     * Attempts to match a slice in the input using the Boyer-Moore string
171.5254 +     * matching algorithm. The algorithm is based on the idea that the
171.5255 +     * pattern can be shifted farther ahead in the search text if it is
171.5256 +     * matched right to left.
171.5257 +     * <p>
171.5258 +     * The pattern is compared to the input one character at a time, from
171.5259 +     * the rightmost character in the pattern to the left. If the characters
171.5260 +     * all match the pattern has been found. If a character does not match,
171.5261 +     * the pattern is shifted right a distance that is the maximum of two
171.5262 +     * functions, the bad character shift and the good suffix shift. This
171.5263 +     * shift moves the attempted match position through the input more
171.5264 +     * quickly than a naive one position at a time check.
171.5265 +     * <p>
171.5266 +     * The bad character shift is based on the character from the text that
171.5267 +     * did not match. If the character does not appear in the pattern, the
171.5268 +     * pattern can be shifted completely beyond the bad character. If the
171.5269 +     * character does occur in the pattern, the pattern can be shifted to
171.5270 +     * line the pattern up with the next occurrence of that character.
171.5271 +     * <p>
171.5272 +     * The good suffix shift is based on the idea that some subset on the right
171.5273 +     * side of the pattern has matched. When a bad character is found, the
171.5274 +     * pattern can be shifted right by the pattern length if the subset does
171.5275 +     * not occur again in pattern, or by the amount of distance to the
171.5276 +     * next occurrence of the subset in the pattern.
171.5277 +     *
171.5278 +     * Boyer-Moore search methods adapted from code by Amy Yu.
171.5279 +     */
171.5280 +    static class BnM extends Node {
171.5281 +        int[] buffer;
171.5282 +        int[] lastOcc;
171.5283 +        int[] optoSft;
171.5284 +
171.5285 +        /**
171.5286 +         * Pre calculates arrays needed to generate the bad character
171.5287 +         * shift and the good suffix shift. Only the last seven bits
171.5288 +         * are used to see if chars match; This keeps the tables small
171.5289 +         * and covers the heavily used ASCII range, but occasionally
171.5290 +         * results in an aliased match for the bad character shift.
171.5291 +         */
171.5292 +        static Node optimize(Node node) {
171.5293 +            if (!(node instanceof Slice)) {
171.5294 +                return node;
171.5295 +            }
171.5296 +
171.5297 +            int[] src = ((Slice) node).buffer;
171.5298 +            int patternLength = src.length;
171.5299 +            // The BM algorithm requires a bit of overhead;
171.5300 +            // If the pattern is short don't use it, since
171.5301 +            // a shift larger than the pattern length cannot
171.5302 +            // be used anyway.
171.5303 +            if (patternLength < 4) {
171.5304 +                return node;
171.5305 +            }
171.5306 +            int i, j, k;
171.5307 +            int[] lastOcc = new int[128];
171.5308 +            int[] optoSft = new int[patternLength];
171.5309 +            // Precalculate part of the bad character shift
171.5310 +            // It is a table for where in the pattern each
171.5311 +            // lower 7-bit value occurs
171.5312 +            for (i = 0; i < patternLength; i++) {
171.5313 +                lastOcc[src[i]&0x7F] = i + 1;
171.5314 +            }
171.5315 +            // Precalculate the good suffix shift
171.5316 +            // i is the shift amount being considered
171.5317 +NEXT:       for (i = patternLength; i > 0; i--) {
171.5318 +                // j is the beginning index of suffix being considered
171.5319 +                for (j = patternLength - 1; j >= i; j--) {
171.5320 +                    // Testing for good suffix
171.5321 +                    if (src[j] == src[j-i]) {
171.5322 +                        // src[j..len] is a good suffix
171.5323 +                        optoSft[j-1] = i;
171.5324 +                    } else {
171.5325 +                        // No match. The array has already been
171.5326 +                        // filled up with correct values before.
171.5327 +                        continue NEXT;
171.5328 +                    }
171.5329 +                }
171.5330 +                // This fills up the remaining of optoSft
171.5331 +                // any suffix can not have larger shift amount
171.5332 +                // then its sub-suffix. Why???
171.5333 +                while (j > 0) {
171.5334 +                    optoSft[--j] = i;
171.5335 +                }
171.5336 +            }
171.5337 +            // Set the guard value because of unicode compression
171.5338 +            optoSft[patternLength-1] = 1;
171.5339 +            if (node instanceof SliceS)
171.5340 +                return new BnMS(src, lastOcc, optoSft, node.next);
171.5341 +            return new BnM(src, lastOcc, optoSft, node.next);
171.5342 +        }
171.5343 +        BnM(int[] src, int[] lastOcc, int[] optoSft, Node next) {
171.5344 +            this.buffer = src;
171.5345 +            this.lastOcc = lastOcc;
171.5346 +            this.optoSft = optoSft;
171.5347 +            this.next = next;
171.5348 +        }
171.5349 +        boolean match(Matcher matcher, int i, CharSequence seq) {
171.5350 +            int[] src = buffer;
171.5351 +            int patternLength = src.length;
171.5352 +            int last = matcher.to - patternLength;
171.5353 +
171.5354 +            // Loop over all possible match positions in text
171.5355 +NEXT:       while (i <= last) {
171.5356 +                // Loop over pattern from right to left
171.5357 +                for (int j = patternLength - 1; j >= 0; j--) {
171.5358 +                    int ch = seq.charAt(i+j);
171.5359 +                    if (ch != src[j]) {
171.5360 +                        // Shift search to the right by the maximum of the
171.5361 +                        // bad character shift and the good suffix shift
171.5362 +                        i += Math.max(j + 1 - lastOcc[ch&0x7F], optoSft[j]);
171.5363 +                        continue NEXT;
171.5364 +                    }
171.5365 +                }
171.5366 +                // Entire pattern matched starting at i
171.5367 +                matcher.first = i;
171.5368 +                boolean ret = next.match(matcher, i + patternLength, seq);
171.5369 +                if (ret) {
171.5370 +                    matcher.first = i;
171.5371 +                    matcher.groups[0] = matcher.first;
171.5372 +                    matcher.groups[1] = matcher.last;
171.5373 +                    return true;
171.5374 +                }
171.5375 +                i++;
171.5376 +            }
171.5377 +            // BnM is only used as the leading node in the unanchored case,
171.5378 +            // and it replaced its Start() which always searches to the end
171.5379 +            // if it doesn't find what it's looking for, so hitEnd is true.
171.5380 +            matcher.hitEnd = true;
171.5381 +            return false;
171.5382 +        }
171.5383 +        boolean study(TreeInfo info) {
171.5384 +            info.minLength += buffer.length;
171.5385 +            info.maxValid = false;
171.5386 +            return next.study(info);
171.5387 +        }
171.5388 +    }
171.5389 +
171.5390 +    /**
171.5391 +     * Supplementary support version of BnM(). Unpaired surrogates are
171.5392 +     * also handled by this class.
171.5393 +     */
171.5394 +    static final class BnMS extends BnM {
171.5395 +        int lengthInChars;
171.5396 +
171.5397 +        BnMS(int[] src, int[] lastOcc, int[] optoSft, Node next) {
171.5398 +            super(src, lastOcc, optoSft, next);
171.5399 +            for (int x = 0; x < buffer.length; x++) {
171.5400 +                lengthInChars += Character.charCount(buffer[x]);
171.5401 +            }
171.5402 +        }
171.5403 +        boolean match(Matcher matcher, int i, CharSequence seq) {
171.5404 +            int[] src = buffer;
171.5405 +            int patternLength = src.length;
171.5406 +            int last = matcher.to - lengthInChars;
171.5407 +
171.5408 +            // Loop over all possible match positions in text
171.5409 +NEXT:       while (i <= last) {
171.5410 +                // Loop over pattern from right to left
171.5411 +                int ch;
171.5412 +                for (int j = countChars(seq, i, patternLength), x = patternLength - 1;
171.5413 +                     j > 0; j -= Character.charCount(ch), x--) {
171.5414 +                    ch = Character.codePointBefore(seq, i+j);
171.5415 +                    if (ch != src[x]) {
171.5416 +                        // Shift search to the right by the maximum of the
171.5417 +                        // bad character shift and the good suffix shift
171.5418 +                        int n = Math.max(x + 1 - lastOcc[ch&0x7F], optoSft[x]);
171.5419 +                        i += countChars(seq, i, n);
171.5420 +                        continue NEXT;
171.5421 +                    }
171.5422 +                }
171.5423 +                // Entire pattern matched starting at i
171.5424 +                matcher.first = i;
171.5425 +                boolean ret = next.match(matcher, i + lengthInChars, seq);
171.5426 +                if (ret) {
171.5427 +                    matcher.first = i;
171.5428 +                    matcher.groups[0] = matcher.first;
171.5429 +                    matcher.groups[1] = matcher.last;
171.5430 +                    return true;
171.5431 +                }
171.5432 +                i += countChars(seq, i, 1);
171.5433 +            }
171.5434 +            matcher.hitEnd = true;
171.5435 +            return false;
171.5436 +        }
171.5437 +    }
171.5438 +
171.5439 +///////////////////////////////////////////////////////////////////////////////
171.5440 +///////////////////////////////////////////////////////////////////////////////
171.5441 +
171.5442 +    /**
171.5443 +     *  This must be the very first initializer.
171.5444 +     */
171.5445 +    static Node accept = new Node();
171.5446 +
171.5447 +    static Node lastAccept = new LastNode();
171.5448 +
171.5449 +    private static class CharPropertyNames {
171.5450 +
171.5451 +        static CharProperty charPropertyFor(String name) {
171.5452 +            CharPropertyFactory m = map.get(name);
171.5453 +            return m == null ? null : m.make();
171.5454 +        }
171.5455 +
171.5456 +        private static abstract class CharPropertyFactory {
171.5457 +            abstract CharProperty make();
171.5458 +        }
171.5459 +
171.5460 +        private static void defCategory(String name,
171.5461 +                                        final int typeMask) {
171.5462 +            map.put(name, new CharPropertyFactory() {
171.5463 +                    CharProperty make() { return new Category(typeMask);}});
171.5464 +        }
171.5465 +
171.5466 +        private static void defRange(String name,
171.5467 +                                     final int lower, final int upper) {
171.5468 +            map.put(name, new CharPropertyFactory() {
171.5469 +                    CharProperty make() { return rangeFor(lower, upper);}});
171.5470 +        }
171.5471 +
171.5472 +        private static void defCtype(String name,
171.5473 +                                     final int ctype) {
171.5474 +            map.put(name, new CharPropertyFactory() {
171.5475 +                    CharProperty make() { return new Ctype(ctype);}});
171.5476 +        }
171.5477 +
171.5478 +        private static abstract class CloneableProperty
171.5479 +            extends CharProperty implements Cloneable
171.5480 +        {
171.5481 +            public CloneableProperty clone() {
171.5482 +                try {
171.5483 +                    return (CloneableProperty) super.clone();
171.5484 +                } catch (CloneNotSupportedException e) {
171.5485 +                    throw new AssertionError(e);
171.5486 +                }
171.5487 +            }
171.5488 +        }
171.5489 +
171.5490 +        private static void defClone(String name,
171.5491 +                                     final CloneableProperty p) {
171.5492 +            map.put(name, new CharPropertyFactory() {
171.5493 +                    CharProperty make() { return p.clone();}});
171.5494 +        }
171.5495 +
171.5496 +        private static final HashMap<String, CharPropertyFactory> map
171.5497 +            = new HashMap<>();
171.5498 +
171.5499 +        static {
171.5500 +            // Unicode character property aliases, defined in
171.5501 +            // http://www.unicode.org/Public/UNIDATA/PropertyValueAliases.txt
171.5502 +            defCategory("Cn", 1<<Character.UNASSIGNED);
171.5503 +            defCategory("Lu", 1<<Character.UPPERCASE_LETTER);
171.5504 +            defCategory("Ll", 1<<Character.LOWERCASE_LETTER);
171.5505 +            defCategory("Lt", 1<<Character.TITLECASE_LETTER);
171.5506 +            defCategory("Lm", 1<<Character.MODIFIER_LETTER);
171.5507 +            defCategory("Lo", 1<<Character.OTHER_LETTER);
171.5508 +            defCategory("Mn", 1<<Character.NON_SPACING_MARK);
171.5509 +            defCategory("Me", 1<<Character.ENCLOSING_MARK);
171.5510 +            defCategory("Mc", 1<<Character.COMBINING_SPACING_MARK);
171.5511 +            defCategory("Nd", 1<<Character.DECIMAL_DIGIT_NUMBER);
171.5512 +            defCategory("Nl", 1<<Character.LETTER_NUMBER);
171.5513 +            defCategory("No", 1<<Character.OTHER_NUMBER);
171.5514 +            defCategory("Zs", 1<<Character.SPACE_SEPARATOR);
171.5515 +            defCategory("Zl", 1<<Character.LINE_SEPARATOR);
171.5516 +            defCategory("Zp", 1<<Character.PARAGRAPH_SEPARATOR);
171.5517 +            defCategory("Cc", 1<<Character.CONTROL);
171.5518 +            defCategory("Cf", 1<<Character.FORMAT);
171.5519 +            defCategory("Co", 1<<Character.PRIVATE_USE);
171.5520 +            defCategory("Cs", 1<<Character.SURROGATE);
171.5521 +            defCategory("Pd", 1<<Character.DASH_PUNCTUATION);
171.5522 +            defCategory("Ps", 1<<Character.START_PUNCTUATION);
171.5523 +            defCategory("Pe", 1<<Character.END_PUNCTUATION);
171.5524 +            defCategory("Pc", 1<<Character.CONNECTOR_PUNCTUATION);
171.5525 +            defCategory("Po", 1<<Character.OTHER_PUNCTUATION);
171.5526 +            defCategory("Sm", 1<<Character.MATH_SYMBOL);
171.5527 +            defCategory("Sc", 1<<Character.CURRENCY_SYMBOL);
171.5528 +            defCategory("Sk", 1<<Character.MODIFIER_SYMBOL);
171.5529 +            defCategory("So", 1<<Character.OTHER_SYMBOL);
171.5530 +            defCategory("Pi", 1<<Character.INITIAL_QUOTE_PUNCTUATION);
171.5531 +            defCategory("Pf", 1<<Character.FINAL_QUOTE_PUNCTUATION);
171.5532 +            defCategory("L", ((1<<Character.UPPERCASE_LETTER) |
171.5533 +                              (1<<Character.LOWERCASE_LETTER) |
171.5534 +                              (1<<Character.TITLECASE_LETTER) |
171.5535 +                              (1<<Character.MODIFIER_LETTER)  |
171.5536 +                              (1<<Character.OTHER_LETTER)));
171.5537 +            defCategory("M", ((1<<Character.NON_SPACING_MARK) |
171.5538 +                              (1<<Character.ENCLOSING_MARK)   |
171.5539 +                              (1<<Character.COMBINING_SPACING_MARK)));
171.5540 +            defCategory("N", ((1<<Character.DECIMAL_DIGIT_NUMBER) |
171.5541 +                              (1<<Character.LETTER_NUMBER)        |
171.5542 +                              (1<<Character.OTHER_NUMBER)));
171.5543 +            defCategory("Z", ((1<<Character.SPACE_SEPARATOR) |
171.5544 +                              (1<<Character.LINE_SEPARATOR)  |
171.5545 +                              (1<<Character.PARAGRAPH_SEPARATOR)));
171.5546 +            defCategory("C", ((1<<Character.CONTROL)     |
171.5547 +                              (1<<Character.FORMAT)      |
171.5548 +                              (1<<Character.PRIVATE_USE) |
171.5549 +                              (1<<Character.SURROGATE))); // Other
171.5550 +            defCategory("P", ((1<<Character.DASH_PUNCTUATION)      |
171.5551 +                              (1<<Character.START_PUNCTUATION)     |
171.5552 +                              (1<<Character.END_PUNCTUATION)       |
171.5553 +                              (1<<Character.CONNECTOR_PUNCTUATION) |
171.5554 +                              (1<<Character.OTHER_PUNCTUATION)     |
171.5555 +                              (1<<Character.INITIAL_QUOTE_PUNCTUATION) |
171.5556 +                              (1<<Character.FINAL_QUOTE_PUNCTUATION)));
171.5557 +            defCategory("S", ((1<<Character.MATH_SYMBOL)     |
171.5558 +                              (1<<Character.CURRENCY_SYMBOL) |
171.5559 +                              (1<<Character.MODIFIER_SYMBOL) |
171.5560 +                              (1<<Character.OTHER_SYMBOL)));
171.5561 +            defCategory("LC", ((1<<Character.UPPERCASE_LETTER) |
171.5562 +                               (1<<Character.LOWERCASE_LETTER) |
171.5563 +                               (1<<Character.TITLECASE_LETTER)));
171.5564 +            defCategory("LD", ((1<<Character.UPPERCASE_LETTER) |
171.5565 +                               (1<<Character.LOWERCASE_LETTER) |
171.5566 +                               (1<<Character.TITLECASE_LETTER) |
171.5567 +                               (1<<Character.MODIFIER_LETTER)  |
171.5568 +                               (1<<Character.OTHER_LETTER)     |
171.5569 +                               (1<<Character.DECIMAL_DIGIT_NUMBER)));
171.5570 +            defRange("L1", 0x00, 0xFF); // Latin-1
171.5571 +            map.put("all", new CharPropertyFactory() {
171.5572 +                    CharProperty make() { return new All(); }});
171.5573 +
171.5574 +            // Posix regular expression character classes, defined in
171.5575 +            // http://www.unix.org/onlinepubs/009695399/basedefs/xbd_chap09.html
171.5576 +            defRange("ASCII", 0x00, 0x7F);   // ASCII
171.5577 +            defCtype("Alnum", ASCII.ALNUM);  // Alphanumeric characters
171.5578 +            defCtype("Alpha", ASCII.ALPHA);  // Alphabetic characters
171.5579 +            defCtype("Blank", ASCII.BLANK);  // Space and tab characters
171.5580 +            defCtype("Cntrl", ASCII.CNTRL);  // Control characters
171.5581 +            defRange("Digit", '0', '9');     // Numeric characters
171.5582 +            defCtype("Graph", ASCII.GRAPH);  // printable and visible
171.5583 +            defRange("Lower", 'a', 'z');     // Lower-case alphabetic
171.5584 +            defRange("Print", 0x20, 0x7E);   // Printable characters
171.5585 +            defCtype("Punct", ASCII.PUNCT);  // Punctuation characters
171.5586 +            defCtype("Space", ASCII.SPACE);  // Space characters
171.5587 +            defRange("Upper", 'A', 'Z');     // Upper-case alphabetic
171.5588 +            defCtype("XDigit",ASCII.XDIGIT); // hexadecimal digits
171.5589 +
171.5590 +            // Java character properties, defined by methods in Character.java
171.5591 +            defClone("javaLowerCase", new CloneableProperty() {
171.5592 +                boolean isSatisfiedBy(int ch) {
171.5593 +                    return Character.isLowerCase(ch);}});
171.5594 +            defClone("javaUpperCase", new CloneableProperty() {
171.5595 +                boolean isSatisfiedBy(int ch) {
171.5596 +                    return Character.isUpperCase(ch);}});
171.5597 +            defClone("javaAlphabetic", new CloneableProperty() {
171.5598 +                boolean isSatisfiedBy(int ch) {
171.5599 +                    return Character.isAlphabetic(ch);}});
171.5600 +            defClone("javaIdeographic", new CloneableProperty() {
171.5601 +                boolean isSatisfiedBy(int ch) {
171.5602 +                    return Character.isIdeographic(ch);}});
171.5603 +            defClone("javaTitleCase", new CloneableProperty() {
171.5604 +                boolean isSatisfiedBy(int ch) {
171.5605 +                    return Character.isTitleCase(ch);}});
171.5606 +            defClone("javaDigit", new CloneableProperty() {
171.5607 +                boolean isSatisfiedBy(int ch) {
171.5608 +                    return Character.isDigit(ch);}});
171.5609 +            defClone("javaDefined", new CloneableProperty() {
171.5610 +                boolean isSatisfiedBy(int ch) {
171.5611 +                    return Character.isDefined(ch);}});
171.5612 +            defClone("javaLetter", new CloneableProperty() {
171.5613 +                boolean isSatisfiedBy(int ch) {
171.5614 +                    return Character.isLetter(ch);}});
171.5615 +            defClone("javaLetterOrDigit", new CloneableProperty() {
171.5616 +                boolean isSatisfiedBy(int ch) {
171.5617 +                    return Character.isLetterOrDigit(ch);}});
171.5618 +            defClone("javaJavaIdentifierStart", new CloneableProperty() {
171.5619 +                boolean isSatisfiedBy(int ch) {
171.5620 +                    return Character.isJavaIdentifierStart(ch);}});
171.5621 +            defClone("javaJavaIdentifierPart", new CloneableProperty() {
171.5622 +                boolean isSatisfiedBy(int ch) {
171.5623 +                    return Character.isJavaIdentifierPart(ch);}});
171.5624 +            defClone("javaUnicodeIdentifierStart", new CloneableProperty() {
171.5625 +                boolean isSatisfiedBy(int ch) {
171.5626 +                    return Character.isUnicodeIdentifierStart(ch);}});
171.5627 +            defClone("javaUnicodeIdentifierPart", new CloneableProperty() {
171.5628 +                boolean isSatisfiedBy(int ch) {
171.5629 +                    return Character.isUnicodeIdentifierPart(ch);}});
171.5630 +            defClone("javaIdentifierIgnorable", new CloneableProperty() {
171.5631 +                boolean isSatisfiedBy(int ch) {
171.5632 +                    return Character.isIdentifierIgnorable(ch);}});
171.5633 +            defClone("javaSpaceChar", new CloneableProperty() {
171.5634 +                boolean isSatisfiedBy(int ch) {
171.5635 +                    return Character.isSpaceChar(ch);}});
171.5636 +            defClone("javaWhitespace", new CloneableProperty() {
171.5637 +                boolean isSatisfiedBy(int ch) {
171.5638 +                    return Character.isWhitespace(ch);}});
171.5639 +            defClone("javaISOControl", new CloneableProperty() {
171.5640 +                boolean isSatisfiedBy(int ch) {
171.5641 +                    return Character.isISOControl(ch);}});
171.5642 +            defClone("javaMirrored", new CloneableProperty() {
171.5643 +                boolean isSatisfiedBy(int ch) {
171.5644 +                    return Character.isMirrored(ch);}});
171.5645 +        }
171.5646 +    }
171.5647 +    
171.5648 +    private static final class Normalizer {
171.5649 +        public static final int NFD = 1;
171.5650 +        public static final int NFC = 2;
171.5651 +
171.5652 +        static String normalize(String pattern, int NFD) {
171.5653 +            return pattern;
171.5654 +        }
171.5655 +
171.5656 +        private static int getCombiningClass(int c) {
171.5657 +            return 1;
171.5658 +        }
171.5659 +    }
171.5660 +}
   172.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   172.2 +++ b/rt/emul/compact/src/main/java/java/util/regex/PatternSyntaxException.java	Tue Feb 11 13:31:42 2014 +0100
   172.3 @@ -0,0 +1,119 @@
   172.4 +/*
   172.5 + * Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved.
   172.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   172.7 + *
   172.8 + * This code is free software; you can redistribute it and/or modify it
   172.9 + * under the terms of the GNU General Public License version 2 only, as
  172.10 + * published by the Free Software Foundation.  Oracle designates this
  172.11 + * particular file as subject to the "Classpath" exception as provided
  172.12 + * by Oracle in the LICENSE file that accompanied this code.
  172.13 + *
  172.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  172.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  172.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  172.17 + * version 2 for more details (a copy is included in the LICENSE file that
  172.18 + * accompanied this code).
  172.19 + *
  172.20 + * You should have received a copy of the GNU General Public License version
  172.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  172.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  172.23 + *
  172.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  172.25 + * or visit www.oracle.com if you need additional information or have any
  172.26 + * questions.
  172.27 + */
  172.28 +
  172.29 +package java.util.regex;
  172.30 +
  172.31 +/**
  172.32 + * Unchecked exception thrown to indicate a syntax error in a
  172.33 + * regular-expression pattern.
  172.34 + *
  172.35 + * @author  unascribed
  172.36 + * @since 1.4
  172.37 + * @spec JSR-51
  172.38 + */
  172.39 +
  172.40 +public class PatternSyntaxException
  172.41 +    extends IllegalArgumentException
  172.42 +{
  172.43 +    private static final long serialVersionUID = -3864639126226059218L;
  172.44 +
  172.45 +    private final String desc;
  172.46 +    private final String pattern;
  172.47 +    private final int index;
  172.48 +
  172.49 +    /**
  172.50 +     * Constructs a new instance of this class.
  172.51 +     *
  172.52 +     * @param  desc
  172.53 +     *         A description of the error
  172.54 +     *
  172.55 +     * @param  regex
  172.56 +     *         The erroneous pattern
  172.57 +     *
  172.58 +     * @param  index
  172.59 +     *         The approximate index in the pattern of the error,
  172.60 +     *         or <tt>-1</tt> if the index is not known
  172.61 +     */
  172.62 +    public PatternSyntaxException(String desc, String regex, int index) {
  172.63 +        this.desc = desc;
  172.64 +        this.pattern = regex;
  172.65 +        this.index = index;
  172.66 +    }
  172.67 +
  172.68 +    /**
  172.69 +     * Retrieves the error index.
  172.70 +     *
  172.71 +     * @return  The approximate index in the pattern of the error,
  172.72 +     *         or <tt>-1</tt> if the index is not known
  172.73 +     */
  172.74 +    public int getIndex() {
  172.75 +        return index;
  172.76 +    }
  172.77 +
  172.78 +    /**
  172.79 +     * Retrieves the description of the error.
  172.80 +     *
  172.81 +     * @return  The description of the error
  172.82 +     */
  172.83 +    public String getDescription() {
  172.84 +        return desc;
  172.85 +    }
  172.86 +
  172.87 +    /**
  172.88 +     * Retrieves the erroneous regular-expression pattern.
  172.89 +     *
  172.90 +     * @return  The erroneous pattern
  172.91 +     */
  172.92 +    public String getPattern() {
  172.93 +        return pattern;
  172.94 +    }
  172.95 +
  172.96 +    private static final String nl = System.lineSeparator();
  172.97 +
  172.98 +    /**
  172.99 +     * Returns a multi-line string containing the description of the syntax
 172.100 +     * error and its index, the erroneous regular-expression pattern, and a
 172.101 +     * visual indication of the error index within the pattern.
 172.102 +     *
 172.103 +     * @return  The full detail message
 172.104 +     */
 172.105 +    public String getMessage() {
 172.106 +        StringBuffer sb = new StringBuffer();
 172.107 +        sb.append(desc);
 172.108 +        if (index >= 0) {
 172.109 +            sb.append(" near index ");
 172.110 +            sb.append(index);
 172.111 +        }
 172.112 +        sb.append(nl);
 172.113 +        sb.append(pattern);
 172.114 +        if (index >= 0) {
 172.115 +            sb.append(nl);
 172.116 +            for (int i = 0; i < index; i++) sb.append(' ');
 172.117 +            sb.append('^');
 172.118 +        }
 172.119 +        return sb.toString();
 172.120 +    }
 172.121 +
 172.122 +}
   173.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   173.2 +++ b/rt/emul/compact/src/main/java/java/util/regex/UnicodeProp.java	Tue Feb 11 13:31:42 2014 +0100
   173.3 @@ -0,0 +1,236 @@
   173.4 +/*
   173.5 + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
   173.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   173.7 + *
   173.8 + * This code is free software; you can redistribute it and/or modify it
   173.9 + * under the terms of the GNU General Public License version 2 only, as
  173.10 + * published by the Free Software Foundation.  Oracle designates this
  173.11 + * particular file as subject to the "Classpath" exception as provided
  173.12 + * by Oracle in the LICENSE file that accompanied this code.
  173.13 + *
  173.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  173.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  173.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  173.17 + * version 2 for more details (a copy is included in the LICENSE file that
  173.18 + * accompanied this code).
  173.19 + *
  173.20 + * You should have received a copy of the GNU General Public License version
  173.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  173.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  173.23 + *
  173.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  173.25 + * or visit www.oracle.com if you need additional information or have any
  173.26 + * questions.
  173.27 + */
  173.28 +
  173.29 +package java.util.regex;
  173.30 +
  173.31 +import java.util.HashMap;
  173.32 +import java.util.Locale;
  173.33 +
  173.34 +enum UnicodeProp {
  173.35 +
  173.36 +    ALPHABETIC {
  173.37 +        public boolean is(int ch) {
  173.38 +            return Character.isAlphabetic(ch);
  173.39 +        }
  173.40 +    },
  173.41 +
  173.42 +    LETTER {
  173.43 +        public boolean is(int ch) {
  173.44 +            return Character.isLetter(ch);
  173.45 +        }
  173.46 +    },
  173.47 +
  173.48 +    IDEOGRAPHIC {
  173.49 +        public boolean is(int ch) {
  173.50 +            return Character.isIdeographic(ch);
  173.51 +        }
  173.52 +    },
  173.53 +
  173.54 +    LOWERCASE {
  173.55 +        public boolean is(int ch) {
  173.56 +            return Character.isLowerCase(ch);
  173.57 +        }
  173.58 +    },
  173.59 +
  173.60 +    UPPERCASE {
  173.61 +        public boolean is(int ch) {
  173.62 +            return Character.isUpperCase(ch);
  173.63 +        }
  173.64 +    },
  173.65 +
  173.66 +    TITLECASE {
  173.67 +        public boolean is(int ch) {
  173.68 +            return Character.isTitleCase(ch);
  173.69 +        }
  173.70 +    },
  173.71 +
  173.72 +    WHITE_SPACE {
  173.73 +        // \p{Whitespace}
  173.74 +        public boolean is(int ch) {
  173.75 +            return ((((1 << Character.SPACE_SEPARATOR) |
  173.76 +                      (1 << Character.LINE_SEPARATOR) |
  173.77 +                      (1 << Character.PARAGRAPH_SEPARATOR)) >> Character.getType(ch)) & 1)
  173.78 +                   != 0 || (ch >= 0x9 && ch <= 0xd) || (ch == 0x85);
  173.79 +        }
  173.80 +    },
  173.81 +
  173.82 +    CONTROL {
  173.83 +        // \p{gc=Control}
  173.84 +        public boolean is(int ch) {
  173.85 +            return Character.getType(ch) == Character.CONTROL;
  173.86 +        }
  173.87 +    },
  173.88 +
  173.89 +    PUNCTUATION {
  173.90 +        // \p{gc=Punctuation}
  173.91 +        public boolean is(int ch) {
  173.92 +            return ((((1 << Character.CONNECTOR_PUNCTUATION) |
  173.93 +                      (1 << Character.DASH_PUNCTUATION) |
  173.94 +                      (1 << Character.START_PUNCTUATION) |
  173.95 +                      (1 << Character.END_PUNCTUATION) |
  173.96 +                      (1 << Character.OTHER_PUNCTUATION) |
  173.97 +                      (1 << Character.INITIAL_QUOTE_PUNCTUATION) |
  173.98 +                      (1 << Character.FINAL_QUOTE_PUNCTUATION)) >> Character.getType(ch)) & 1)
  173.99 +                   != 0;
 173.100 +        }
 173.101 +    },
 173.102 +
 173.103 +    HEX_DIGIT {
 173.104 +        // \p{gc=Decimal_Number}
 173.105 +        // \p{Hex_Digit}    -> PropList.txt: Hex_Digit
 173.106 +        public boolean is(int ch) {
 173.107 +            return DIGIT.is(ch) ||
 173.108 +                   (ch >= 0x0030 && ch <= 0x0039) ||
 173.109 +                   (ch >= 0x0041 && ch <= 0x0046) ||
 173.110 +                   (ch >= 0x0061 && ch <= 0x0066) ||
 173.111 +                   (ch >= 0xFF10 && ch <= 0xFF19) ||
 173.112 +                   (ch >= 0xFF21 && ch <= 0xFF26) ||
 173.113 +                   (ch >= 0xFF41 && ch <= 0xFF46);
 173.114 +        }
 173.115 +    },
 173.116 +
 173.117 +    ASSIGNED {
 173.118 +        public boolean is(int ch) {
 173.119 +            return Character.getType(ch) != Character.UNASSIGNED;
 173.120 +        }
 173.121 +    },
 173.122 +
 173.123 +    NONCHARACTER_CODE_POINT {
 173.124 +        // PropList.txt:Noncharacter_Code_Point
 173.125 +        public boolean is(int ch) {
 173.126 +            return (ch & 0xfffe) == 0xfffe || (ch >= 0xfdd0 && ch <= 0xfdef);
 173.127 +        }
 173.128 +    },
 173.129 +
 173.130 +    DIGIT {
 173.131 +        // \p{gc=Decimal_Number}
 173.132 +        public boolean is(int ch) {
 173.133 +            return Character.isDigit(ch);
 173.134 +        }
 173.135 +    },
 173.136 +
 173.137 +    ALNUM {
 173.138 +        // \p{alpha}
 173.139 +        // \p{digit}
 173.140 +        public boolean is(int ch) {
 173.141 +            return ALPHABETIC.is(ch) || DIGIT.is(ch);
 173.142 +        }
 173.143 +    },
 173.144 +
 173.145 +    BLANK {
 173.146 +        // \p{Whitespace} --
 173.147 +        // [\N{LF} \N{VT} \N{FF} \N{CR} \N{NEL}  -> 0xa, 0xb, 0xc, 0xd, 0x85
 173.148 +        //  \p{gc=Line_Separator}
 173.149 +        //  \p{gc=Paragraph_Separator}]
 173.150 +        public boolean is(int ch) {
 173.151 +            return Character.getType(ch) == Character.SPACE_SEPARATOR ||
 173.152 +                   ch == 0x9; // \N{HT}
 173.153 +        }
 173.154 +    },
 173.155 +
 173.156 +    GRAPH {
 173.157 +        // [^
 173.158 +        //  \p{space}
 173.159 +        //  \p{gc=Control}
 173.160 +        //  \p{gc=Surrogate}
 173.161 +        //  \p{gc=Unassigned}]
 173.162 +        public boolean is(int ch) {
 173.163 +            return ((((1 << Character.SPACE_SEPARATOR) |
 173.164 +                      (1 << Character.LINE_SEPARATOR) |
 173.165 +                      (1 << Character.PARAGRAPH_SEPARATOR) |
 173.166 +                      (1 << Character.CONTROL) |
 173.167 +                      (1 << Character.SURROGATE) |
 173.168 +                      (1 << Character.UNASSIGNED)) >> Character.getType(ch)) & 1)
 173.169 +                   == 0;
 173.170 +        }
 173.171 +    },
 173.172 +
 173.173 +    PRINT {
 173.174 +        // \p{graph}
 173.175 +        // \p{blank}
 173.176 +        // -- \p{cntrl}
 173.177 +        public boolean is(int ch) {
 173.178 +            return (GRAPH.is(ch) || BLANK.is(ch)) && !CONTROL.is(ch);
 173.179 +        }
 173.180 +    },
 173.181 +
 173.182 +    WORD {
 173.183 +        //  \p{alpha}
 173.184 +        //  \p{gc=Mark}
 173.185 +        //  \p{digit}
 173.186 +        //  \p{gc=Connector_Punctuation}
 173.187 +
 173.188 +        public boolean is(int ch) {
 173.189 +            return ALPHABETIC.is(ch) ||
 173.190 +                   ((((1 << Character.NON_SPACING_MARK) |
 173.191 +                      (1 << Character.ENCLOSING_MARK) |
 173.192 +                      (1 << Character.COMBINING_SPACING_MARK) |
 173.193 +                      (1 << Character.DECIMAL_DIGIT_NUMBER) |
 173.194 +                      (1 << Character.CONNECTOR_PUNCTUATION)) >> Character.getType(ch)) & 1)
 173.195 +                   != 0;
 173.196 +        }
 173.197 +    };
 173.198 +
 173.199 +    private final static HashMap<String, String> posix = new HashMap<>();
 173.200 +    private final static HashMap<String, String> aliases = new HashMap<>();
 173.201 +    static {
 173.202 +        posix.put("ALPHA", "ALPHABETIC");
 173.203 +        posix.put("LOWER", "LOWERCASE");
 173.204 +        posix.put("UPPER", "UPPERCASE");
 173.205 +        posix.put("SPACE", "WHITE_SPACE");
 173.206 +        posix.put("PUNCT", "PUNCTUATION");
 173.207 +        posix.put("XDIGIT","HEX_DIGIT");
 173.208 +        posix.put("ALNUM", "ALNUM");
 173.209 +        posix.put("CNTRL", "CONTROL");
 173.210 +        posix.put("DIGIT", "DIGIT");
 173.211 +        posix.put("BLANK", "BLANK");
 173.212 +        posix.put("GRAPH", "GRAPH");
 173.213 +        posix.put("PRINT", "PRINT");
 173.214 +
 173.215 +        aliases.put("WHITESPACE", "WHITE_SPACE");
 173.216 +        aliases.put("HEXDIGIT","HEX_DIGIT");
 173.217 +        aliases.put("NONCHARACTERCODEPOINT", "NONCHARACTER_CODE_POINT");
 173.218 +    }
 173.219 +
 173.220 +    public static UnicodeProp forName(String propName) {
 173.221 +        propName = propName.toUpperCase(Locale.ENGLISH);
 173.222 +        String alias = aliases.get(propName);
 173.223 +        if (alias != null)
 173.224 +            propName = alias;
 173.225 +        try {
 173.226 +            return valueOf (propName);
 173.227 +        } catch (IllegalArgumentException x) {}
 173.228 +        return null;
 173.229 +    }
 173.230 +
 173.231 +    public static UnicodeProp forPOSIXName(String propName) {
 173.232 +        propName = posix.get(propName.toUpperCase(Locale.ENGLISH));
 173.233 +        if (propName == null)
 173.234 +            return null;
 173.235 +        return valueOf (propName);
 173.236 +    }
 173.237 +
 173.238 +    public abstract boolean is(int ch);
 173.239 +}
   174.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   174.2 +++ b/rt/emul/compact/src/main/java/java/util/regex/package.html	Tue Feb 11 13:31:42 2014 +0100
   174.3 @@ -0,0 +1,66 @@
   174.4 +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
   174.5 +<html>
   174.6 +<head>
   174.7 +<!--
   174.8 +Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
   174.9 +DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  174.10 +
  174.11 +This code is free software; you can redistribute it and/or modify it
  174.12 +under the terms of the GNU General Public License version 2 only, as
  174.13 +published by the Free Software Foundation.  Oracle designates this
  174.14 +particular file as subject to the "Classpath" exception as provided
  174.15 +by Oracle in the LICENSE file that accompanied this code.
  174.16 +
  174.17 +This code is distributed in the hope that it will be useful, but WITHOUT
  174.18 +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  174.19 +FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  174.20 +version 2 for more details (a copy is included in the LICENSE file that
  174.21 +accompanied this code).
  174.22 +
  174.23 +You should have received a copy of the GNU General Public License version
  174.24 +2 along with this work; if not, write to the Free Software Foundation,
  174.25 +Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  174.26 +
  174.27 +Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  174.28 +or visit www.oracle.com if you need additional information or have any
  174.29 +questions.
  174.30 +-->
  174.31 +
  174.32 +</head>
  174.33 +<body bgcolor="white">
  174.34 +
  174.35 +Classes for matching character sequences against patterns specified by regular
  174.36 +expressions.
  174.37 +
  174.38 +<p> An instance of the {@link java.util.regex.Pattern} class represents a
  174.39 +regular expression that is specified in string form in a syntax similar to
  174.40 +that used by Perl.
  174.41 +
  174.42 +<p> Instances of the {@link java.util.regex.Matcher} class are used to match
  174.43 +character sequences against a given pattern.  Input is provided to matchers via
  174.44 +the {@link java.lang.CharSequence} interface in order to support matching
  174.45 +against characters from a wide variety of input sources. </p>
  174.46 +
  174.47 +<p> Unless otherwise noted, passing a <tt>null</tt> argument to a method
  174.48 +in any class or interface in this package will cause a
  174.49 +{@link java.lang.NullPointerException NullPointerException} to be thrown.
  174.50 +
  174.51 +<h2>Related Documentation</h2>
  174.52 +
  174.53 +<p> An excellent tutorial and overview of regular expressions is <a
  174.54 +href="http://www.oreilly.com/catalog/regex/"><i>Mastering Regular
  174.55 +Expressions</i>, Jeffrey E. F. Friedl, O'Reilly and Associates, 1997.</a> </p>
  174.56 +
  174.57 +<!--
  174.58 +For overviews, tutorials, examples, guides, and tool documentation, please see:
  174.59 +<ul>
  174.60 +  <li><a href="">##### REFER TO NON-SPEC DOCUMENTATION HERE #####</a>
  174.61 +</ul>
  174.62 +-->
  174.63 +
  174.64 +@since 1.4
  174.65 +@author Mike McCloskey
  174.66 +@author Mark Reinhold
  174.67 +
  174.68 +</body>
  174.69 +</html>
   175.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   175.2 +++ b/rt/emul/compact/src/main/java/org/apidesign/bck2brwsr/emul/reflect/ProxyImpl.java	Tue Feb 11 13:31:42 2014 +0100
   175.3 @@ -0,0 +1,1620 @@
   175.4 +/*
   175.5 + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
   175.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   175.7 + *
   175.8 + * This code is free software; you can redistribute it and/or modify it
   175.9 + * under the terms of the GNU General Public License version 2 only, as
  175.10 + * published by the Free Software Foundation.  Oracle designates this
  175.11 + * particular file as subject to the "Classpath" exception as provided
  175.12 + * by Oracle in the LICENSE file that accompanied this code.
  175.13 + *
  175.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
  175.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  175.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  175.17 + * version 2 for more details (a copy is included in the LICENSE file that
  175.18 + * accompanied this code).
  175.19 + *
  175.20 + * You should have received a copy of the GNU General Public License version
  175.21 + * 2 along with this work; if not, write to the Free Software Foundation,
  175.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  175.23 + *
  175.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  175.25 + * or visit www.oracle.com if you need additional information or have any
  175.26 + * questions.
  175.27 + */
  175.28 +
  175.29 +package org.apidesign.bck2brwsr.emul.reflect;
  175.30 +
  175.31 +import java.io.ByteArrayOutputStream;
  175.32 +import java.io.DataOutputStream;
  175.33 +import java.io.IOException;
  175.34 +import java.io.OutputStream;
  175.35 +import java.lang.ref.Reference;
  175.36 +import java.lang.ref.WeakReference;
  175.37 +import java.lang.reflect.Array;
  175.38 +import java.lang.reflect.Constructor;
  175.39 +import java.lang.reflect.InvocationHandler;
  175.40 +import java.lang.reflect.InvocationTargetException;
  175.41 +import java.lang.reflect.Method;
  175.42 +import java.lang.reflect.Modifier;
  175.43 +import java.util.ArrayList;
  175.44 +import java.util.Arrays;
  175.45 +import java.util.Collections;
  175.46 +import java.util.HashMap;
  175.47 +import java.util.HashSet;
  175.48 +import java.util.LinkedList;
  175.49 +import java.util.Map;
  175.50 +import java.util.Set;
  175.51 +import java.util.List;
  175.52 +import java.util.ListIterator;
  175.53 +import java.util.WeakHashMap;
  175.54 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
  175.55 +import org.apidesign.bck2brwsr.emul.reflect.MethodImpl;
  175.56 +
  175.57 +/**
  175.58 + * {@code Proxy} provides static methods for creating dynamic proxy
  175.59 + * classes and instances, and it is also the superclass of all
  175.60 + * dynamic proxy classes created by those methods.
  175.61 + *
  175.62 + * <p>To create a proxy for some interface {@code Foo}:
  175.63 + * <pre>
  175.64 + *     InvocationHandler handler = new MyInvocationHandler(...);
  175.65 + *     Class proxyClass = Proxy.getProxyClass(
  175.66 + *         Foo.class.getClassLoader(), new Class[] { Foo.class });
  175.67 + *     Foo f = (Foo) proxyClass.
  175.68 + *         getConstructor(new Class[] { InvocationHandler.class }).
  175.69 + *         newInstance(new Object[] { handler });
  175.70 + * </pre>
  175.71 + * or more simply:
  175.72 + * <pre>
  175.73 + *     Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
  175.74 + *                                          new Class[] { Foo.class },
  175.75 + *                                          handler);
  175.76 + * </pre>
  175.77 + *
  175.78 + * <p>A <i>dynamic proxy class</i> (simply referred to as a <i>proxy
  175.79 + * class</i> below) is a class that implements a list of interfaces
  175.80 + * specified at runtime when the class is created, with behavior as
  175.81 + * described below.
  175.82 + *
  175.83 + * A <i>proxy interface</i> is such an interface that is implemented
  175.84 + * by a proxy class.
  175.85 + *
  175.86 + * A <i>proxy instance</i> is an instance of a proxy class.
  175.87 + *
  175.88 + * Each proxy instance has an associated <i>invocation handler</i>
  175.89 + * object, which implements the interface {@link InvocationHandler}.
  175.90 + * A method invocation on a proxy instance through one of its proxy
  175.91 + * interfaces will be dispatched to the {@link InvocationHandler#invoke
  175.92 + * invoke} method of the instance's invocation handler, passing the proxy
  175.93 + * instance, a {@code java.lang.reflect.Method} object identifying
  175.94 + * the method that was invoked, and an array of type {@code Object}
  175.95 + * containing the arguments.  The invocation handler processes the
  175.96 + * encoded method invocation as appropriate and the result that it
  175.97 + * returns will be returned as the result of the method invocation on
  175.98 + * the proxy instance.
  175.99 + *
 175.100 + * <p>A proxy class has the following properties:
 175.101 + *
 175.102 + * <ul>
 175.103 + * <li>Proxy classes are public, final, and not abstract.
 175.104 + *
 175.105 + * <li>The unqualified name of a proxy class is unspecified.  The space
 175.106 + * of class names that begin with the string {@code "$Proxy"}
 175.107 + * should be, however, reserved for proxy classes.
 175.108 + *
 175.109 + * <li>A proxy class extends {@code java.lang.reflect.Proxy}.
 175.110 + *
 175.111 + * <li>A proxy class implements exactly the interfaces specified at its
 175.112 + * creation, in the same order.
 175.113 + *
 175.114 + * <li>If a proxy class implements a non-public interface, then it will
 175.115 + * be defined in the same package as that interface.  Otherwise, the
 175.116 + * package of a proxy class is also unspecified.  Note that package
 175.117 + * sealing will not prevent a proxy class from being successfully defined
 175.118 + * in a particular package at runtime, and neither will classes already
 175.119 + * defined by the same class loader and the same package with particular
 175.120 + * signers.
 175.121 + *
 175.122 + * <li>Since a proxy class implements all of the interfaces specified at
 175.123 + * its creation, invoking {@code getInterfaces} on its
 175.124 + * {@code Class} object will return an array containing the same
 175.125 + * list of interfaces (in the order specified at its creation), invoking
 175.126 + * {@code getMethods} on its {@code Class} object will return
 175.127 + * an array of {@code Method} objects that include all of the
 175.128 + * methods in those interfaces, and invoking {@code getMethod} will
 175.129 + * find methods in the proxy interfaces as would be expected.
 175.130 + *
 175.131 + * <li>The {@link Proxy#isProxyClass Proxy.isProxyClass} method will
 175.132 + * return true if it is passed a proxy class-- a class returned by
 175.133 + * {@code Proxy.getProxyClass} or the class of an object returned by
 175.134 + * {@code Proxy.newProxyInstance}-- and false otherwise.
 175.135 + *
 175.136 + * <li>The {@code java.security.ProtectionDomain} of a proxy class
 175.137 + * is the same as that of system classes loaded by the bootstrap class
 175.138 + * loader, such as {@code java.lang.Object}, because the code for a
 175.139 + * proxy class is generated by trusted system code.  This protection
 175.140 + * domain will typically be granted
 175.141 + * {@code java.security.AllPermission}.
 175.142 + *
 175.143 + * <li>Each proxy class has one public constructor that takes one argument,
 175.144 + * an implementation of the interface {@link InvocationHandler}, to set
 175.145 + * the invocation handler for a proxy instance.  Rather than having to use
 175.146 + * the reflection API to access the public constructor, a proxy instance
 175.147 + * can be also be created by calling the {@link Proxy#newProxyInstance
 175.148 + * Proxy.newProxyInstance} method, which combines the actions of calling
 175.149 + * {@link Proxy#getProxyClass Proxy.getProxyClass} with invoking the
 175.150 + * constructor with an invocation handler.
 175.151 + * </ul>
 175.152 + *
 175.153 + * <p>A proxy instance has the following properties:
 175.154 + *
 175.155 + * <ul>
 175.156 + * <li>Given a proxy instance {@code proxy} and one of the
 175.157 + * interfaces implemented by its proxy class {@code Foo}, the
 175.158 + * following expression will return true:
 175.159 + * <pre>
 175.160 + *     {@code proxy instanceof Foo}
 175.161 + * </pre>
 175.162 + * and the following cast operation will succeed (rather than throwing
 175.163 + * a {@code ClassCastException}):
 175.164 + * <pre>
 175.165 + *     {@code (Foo) proxy}
 175.166 + * </pre>
 175.167 + *
 175.168 + * <li>Each proxy instance has an associated invocation handler, the one
 175.169 + * that was passed to its constructor.  The static
 175.170 + * {@link Proxy#getInvocationHandler Proxy.getInvocationHandler} method
 175.171 + * will return the invocation handler associated with the proxy instance
 175.172 + * passed as its argument.
 175.173 + *
 175.174 + * <li>An interface method invocation on a proxy instance will be
 175.175 + * encoded and dispatched to the invocation handler's {@link
 175.176 + * InvocationHandler#invoke invoke} method as described in the
 175.177 + * documentation for that method.
 175.178 + *
 175.179 + * <li>An invocation of the {@code hashCode},
 175.180 + * {@code equals}, or {@code toString} methods declared in
 175.181 + * {@code java.lang.Object} on a proxy instance will be encoded and
 175.182 + * dispatched to the invocation handler's {@code invoke} method in
 175.183 + * the same manner as interface method invocations are encoded and
 175.184 + * dispatched, as described above.  The declaring class of the
 175.185 + * {@code Method} object passed to {@code invoke} will be
 175.186 + * {@code java.lang.Object}.  Other public methods of a proxy
 175.187 + * instance inherited from {@code java.lang.Object} are not
 175.188 + * overridden by a proxy class, so invocations of those methods behave
 175.189 + * like they do for instances of {@code java.lang.Object}.
 175.190 + * </ul>
 175.191 + *
 175.192 + * <h3>Methods Duplicated in Multiple Proxy Interfaces</h3>
 175.193 + *
 175.194 + * <p>When two or more interfaces of a proxy class contain a method with
 175.195 + * the same name and parameter signature, the order of the proxy class's
 175.196 + * interfaces becomes significant.  When such a <i>duplicate method</i>
 175.197 + * is invoked on a proxy instance, the {@code Method} object passed
 175.198 + * to the invocation handler will not necessarily be the one whose
 175.199 + * declaring class is assignable from the reference type of the interface
 175.200 + * that the proxy's method was invoked through.  This limitation exists
 175.201 + * because the corresponding method implementation in the generated proxy
 175.202 + * class cannot determine which interface it was invoked through.
 175.203 + * Therefore, when a duplicate method is invoked on a proxy instance,
 175.204 + * the {@code Method} object for the method in the foremost interface
 175.205 + * that contains the method (either directly or inherited through a
 175.206 + * superinterface) in the proxy class's list of interfaces is passed to
 175.207 + * the invocation handler's {@code invoke} method, regardless of the
 175.208 + * reference type through which the method invocation occurred.
 175.209 + *
 175.210 + * <p>If a proxy interface contains a method with the same name and
 175.211 + * parameter signature as the {@code hashCode}, {@code equals},
 175.212 + * or {@code toString} methods of {@code java.lang.Object},
 175.213 + * when such a method is invoked on a proxy instance, the
 175.214 + * {@code Method} object passed to the invocation handler will have
 175.215 + * {@code java.lang.Object} as its declaring class.  In other words,
 175.216 + * the public, non-final methods of {@code java.lang.Object}
 175.217 + * logically precede all of the proxy interfaces for the determination of
 175.218 + * which {@code Method} object to pass to the invocation handler.
 175.219 + *
 175.220 + * <p>Note also that when a duplicate method is dispatched to an
 175.221 + * invocation handler, the {@code invoke} method may only throw
 175.222 + * checked exception types that are assignable to one of the exception
 175.223 + * types in the {@code throws} clause of the method in <i>all</i> of
 175.224 + * the proxy interfaces that it can be invoked through.  If the
 175.225 + * {@code invoke} method throws a checked exception that is not
 175.226 + * assignable to any of the exception types declared by the method in one
 175.227 + * of the proxy interfaces that it can be invoked through, then an
 175.228 + * unchecked {@code UndeclaredThrowableException} will be thrown by
 175.229 + * the invocation on the proxy instance.  This restriction means that not
 175.230 + * all of the exception types returned by invoking
 175.231 + * {@code getExceptionTypes} on the {@code Method} object
 175.232 + * passed to the {@code invoke} method can necessarily be thrown
 175.233 + * successfully by the {@code invoke} method.
 175.234 + *
 175.235 + * @author      Peter Jones
 175.236 + * @see         InvocationHandler
 175.237 + * @since       1.3
 175.238 + */
 175.239 +public final class ProxyImpl implements java.io.Serializable {
 175.240 +
 175.241 +    private static final long serialVersionUID = -2222568056686623797L;
 175.242 +
 175.243 +    /** prefix for all proxy class names */
 175.244 +    private final static String proxyClassNamePrefix = "$Proxy";
 175.245 +
 175.246 +    /** parameter types of a proxy class constructor */
 175.247 +    private final static Class[] constructorParams =
 175.248 +        { InvocationHandler.class };
 175.249 +
 175.250 +    /** maps a class loader to the proxy class cache for that loader */
 175.251 +    private static Map<ClassLoader, Map<List<String>, Object>> loaderToCache
 175.252 +        = new WeakHashMap<>();
 175.253 +
 175.254 +    /** marks that a particular proxy class is currently being generated */
 175.255 +    private static Object pendingGenerationMarker = new Object();
 175.256 +
 175.257 +    /** next number to use for generation of unique proxy class names */
 175.258 +    private static long nextUniqueNumber = 0;
 175.259 +    private static Object nextUniqueNumberLock = new Object();
 175.260 +
 175.261 +    /** set of all generated proxy classes, for isProxyClass implementation */
 175.262 +    private static Map<Class<?>, Void> proxyClasses =
 175.263 +        Collections.synchronizedMap(new WeakHashMap<Class<?>, Void>());
 175.264 +
 175.265 +    /**
 175.266 +     * the invocation handler for this proxy instance.
 175.267 +     * @serial
 175.268 +     */
 175.269 +    protected InvocationHandler h;
 175.270 +
 175.271 +    /**
 175.272 +     * Prohibits instantiation.
 175.273 +     */
 175.274 +    private ProxyImpl() {
 175.275 +    }
 175.276 +
 175.277 +    /**
 175.278 +     * Constructs a new {@code Proxy} instance from a subclass
 175.279 +     * (typically, a dynamic proxy class) with the specified value
 175.280 +     * for its invocation handler.
 175.281 +     *
 175.282 +     * @param   h the invocation handler for this proxy instance
 175.283 +     */
 175.284 +    protected ProxyImpl(InvocationHandler h) {
 175.285 +        this.h = h;
 175.286 +    }
 175.287 +
 175.288 +    /**
 175.289 +     * Returns the {@code java.lang.Class} object for a proxy class
 175.290 +     * given a class loader and an array of interfaces.  The proxy class
 175.291 +     * will be defined by the specified class loader and will implement
 175.292 +     * all of the supplied interfaces.  If a proxy class for the same
 175.293 +     * permutation of interfaces has already been defined by the class
 175.294 +     * loader, then the existing proxy class will be returned; otherwise,
 175.295 +     * a proxy class for those interfaces will be generated dynamically
 175.296 +     * and defined by the class loader.
 175.297 +     *
 175.298 +     * <p>There are several restrictions on the parameters that may be
 175.299 +     * passed to {@code Proxy.getProxyClass}:
 175.300 +     *
 175.301 +     * <ul>
 175.302 +     * <li>All of the {@code Class} objects in the
 175.303 +     * {@code interfaces} array must represent interfaces, not
 175.304 +     * classes or primitive types.
 175.305 +     *
 175.306 +     * <li>No two elements in the {@code interfaces} array may
 175.307 +     * refer to identical {@code Class} objects.
 175.308 +     *
 175.309 +     * <li>All of the interface types must be visible by name through the
 175.310 +     * specified class loader.  In other words, for class loader
 175.311 +     * {@code cl} and every interface {@code i}, the following
 175.312 +     * expression must be true:
 175.313 +     * <pre>
 175.314 +     *     Class.forName(i.getName(), false, cl) == i
 175.315 +     * </pre>
 175.316 +     *
 175.317 +     * <li>All non-public interfaces must be in the same package;
 175.318 +     * otherwise, it would not be possible for the proxy class to
 175.319 +     * implement all of the interfaces, regardless of what package it is
 175.320 +     * defined in.
 175.321 +     *
 175.322 +     * <li>For any set of member methods of the specified interfaces
 175.323 +     * that have the same signature:
 175.324 +     * <ul>
 175.325 +     * <li>If the return type of any of the methods is a primitive
 175.326 +     * type or void, then all of the methods must have that same
 175.327 +     * return type.
 175.328 +     * <li>Otherwise, one of the methods must have a return type that
 175.329 +     * is assignable to all of the return types of the rest of the
 175.330 +     * methods.
 175.331 +     * </ul>
 175.332 +     *
 175.333 +     * <li>The resulting proxy class must not exceed any limits imposed
 175.334 +     * on classes by the virtual machine.  For example, the VM may limit
 175.335 +     * the number of interfaces that a class may implement to 65535; in
 175.336 +     * that case, the size of the {@code interfaces} array must not
 175.337 +     * exceed 65535.
 175.338 +     * </ul>
 175.339 +     *
 175.340 +     * <p>If any of these restrictions are violated,
 175.341 +     * {@code Proxy.getProxyClass} will throw an
 175.342 +     * {@code IllegalArgumentException}.  If the {@code interfaces}
 175.343 +     * array argument or any of its elements are {@code null}, a
 175.344 +     * {@code NullPointerException} will be thrown.
 175.345 +     *
 175.346 +     * <p>Note that the order of the specified proxy interfaces is
 175.347 +     * significant: two requests for a proxy class with the same combination
 175.348 +     * of interfaces but in a different order will result in two distinct
 175.349 +     * proxy classes.
 175.350 +     *
 175.351 +     * @param   loader the class loader to define the proxy class
 175.352 +     * @param   interfaces the list of interfaces for the proxy class
 175.353 +     *          to implement
 175.354 +     * @return  a proxy class that is defined in the specified class loader
 175.355 +     *          and that implements the specified interfaces
 175.356 +     * @throws  IllegalArgumentException if any of the restrictions on the
 175.357 +     *          parameters that may be passed to {@code getProxyClass}
 175.358 +     *          are violated
 175.359 +     * @throws  NullPointerException if the {@code interfaces} array
 175.360 +     *          argument or any of its elements are {@code null}
 175.361 +     */
 175.362 +    public static Class<?> getProxyClass(ClassLoader loader,
 175.363 +                                         Class<?>... interfaces)
 175.364 +        throws IllegalArgumentException
 175.365 +    {
 175.366 +        if (interfaces.length > 65535) {
 175.367 +            throw new IllegalArgumentException("interface limit exceeded");
 175.368 +        }
 175.369 +
 175.370 +        Class<?> proxyClass = null;
 175.371 +
 175.372 +        /* collect interface names to use as key for proxy class cache */
 175.373 +        String[] interfaceNames = new String[interfaces.length];
 175.374 +
 175.375 +        // for detecting duplicates
 175.376 +        Set<Class<?>> interfaceSet = new HashSet<>();
 175.377 +
 175.378 +        for (int i = 0; i < interfaces.length; i++) {
 175.379 +            /*
 175.380 +             * Verify that the class loader resolves the name of this
 175.381 +             * interface to the same Class object.
 175.382 +             */
 175.383 +            String interfaceName = interfaces[i].getName();
 175.384 +            Class<?> interfaceClass = null;
 175.385 +            try {
 175.386 +                interfaceClass = Class.forName(interfaceName, false, loader);
 175.387 +            } catch (ClassNotFoundException e) {
 175.388 +            }
 175.389 +            if (interfaceClass != interfaces[i]) {
 175.390 +                throw new IllegalArgumentException(
 175.391 +                    interfaces[i] + " is not visible from class loader");
 175.392 +            }
 175.393 +
 175.394 +            /*
 175.395 +             * Verify that the Class object actually represents an
 175.396 +             * interface.
 175.397 +             */
 175.398 +            if (!interfaceClass.isInterface()) {
 175.399 +                throw new IllegalArgumentException(
 175.400 +                    interfaceClass.getName() + " is not an interface");
 175.401 +            }
 175.402 +
 175.403 +            /*
 175.404 +             * Verify that this interface is not a duplicate.
 175.405 +             */
 175.406 +            if (interfaceSet.contains(interfaceClass)) {
 175.407 +                throw new IllegalArgumentException(
 175.408 +                    "repeated interface: " + interfaceClass.getName());
 175.409 +            }
 175.410 +            interfaceSet.add(interfaceClass);
 175.411 +
 175.412 +            interfaceNames[i] = interfaceName;
 175.413 +        }
 175.414 +
 175.415 +        /*
 175.416 +         * Using string representations of the proxy interfaces as
 175.417 +         * keys in the proxy class cache (instead of their Class
 175.418 +         * objects) is sufficient because we require the proxy
 175.419 +         * interfaces to be resolvable by name through the supplied
 175.420 +         * class loader, and it has the advantage that using a string
 175.421 +         * representation of a class makes for an implicit weak
 175.422 +         * reference to the class.
 175.423 +         */
 175.424 +        List<String> key = Arrays.asList(interfaceNames);
 175.425 +
 175.426 +        /*
 175.427 +         * Find or create the proxy class cache for the class loader.
 175.428 +         */
 175.429 +        Map<List<String>, Object> cache;
 175.430 +        synchronized (loaderToCache) {
 175.431 +            cache = loaderToCache.get(loader);
 175.432 +            if (cache == null) {
 175.433 +                cache = new HashMap<>();
 175.434 +                loaderToCache.put(loader, cache);
 175.435 +            }
 175.436 +            /*
 175.437 +             * This mapping will remain valid for the duration of this
 175.438 +             * method, without further synchronization, because the mapping
 175.439 +             * will only be removed if the class loader becomes unreachable.
 175.440 +             */
 175.441 +        }
 175.442 +
 175.443 +        /*
 175.444 +         * Look up the list of interfaces in the proxy class cache using
 175.445 +         * the key.  This lookup will result in one of three possible
 175.446 +         * kinds of values:
 175.447 +         *     null, if there is currently no proxy class for the list of
 175.448 +         *         interfaces in the class loader,
 175.449 +         *     the pendingGenerationMarker object, if a proxy class for the
 175.450 +         *         list of interfaces is currently being generated,
 175.451 +         *     or a weak reference to a Class object, if a proxy class for
 175.452 +         *         the list of interfaces has already been generated.
 175.453 +         */
 175.454 +        synchronized (cache) {
 175.455 +            /*
 175.456 +             * Note that we need not worry about reaping the cache for
 175.457 +             * entries with cleared weak references because if a proxy class
 175.458 +             * has been garbage collected, its class loader will have been
 175.459 +             * garbage collected as well, so the entire cache will be reaped
 175.460 +             * from the loaderToCache map.
 175.461 +             */
 175.462 +            do {
 175.463 +                Object value = cache.get(key);
 175.464 +                if (value instanceof Reference) {
 175.465 +                    proxyClass = (Class<?>) ((Reference) value).get();
 175.466 +                }
 175.467 +                if (proxyClass != null) {
 175.468 +                    // proxy class already generated: return it
 175.469 +                    return proxyClass;
 175.470 +                } else if (value == pendingGenerationMarker) {
 175.471 +                    // proxy class being generated: wait for it
 175.472 +                    try {
 175.473 +                        cache.wait();
 175.474 +                    } catch (InterruptedException e) {
 175.475 +                        /*
 175.476 +                         * The class generation that we are waiting for should
 175.477 +                         * take a small, bounded time, so we can safely ignore
 175.478 +                         * thread interrupts here.
 175.479 +                         */
 175.480 +                    }
 175.481 +                    continue;
 175.482 +                } else {
 175.483 +                    /*
 175.484 +                     * No proxy class for this list of interfaces has been
 175.485 +                     * generated or is being generated, so we will go and
 175.486 +                     * generate it now.  Mark it as pending generation.
 175.487 +                     */
 175.488 +                    cache.put(key, pendingGenerationMarker);
 175.489 +                    break;
 175.490 +                }
 175.491 +            } while (true);
 175.492 +        }
 175.493 +
 175.494 +        try {
 175.495 +            String proxyPkg = null;     // package to define proxy class in
 175.496 +
 175.497 +            /*
 175.498 +             * Record the package of a non-public proxy interface so that the
 175.499 +             * proxy class will be defined in the same package.  Verify that
 175.500 +             * all non-public proxy interfaces are in the same package.
 175.501 +             */
 175.502 +            for (int i = 0; i < interfaces.length; i++) {
 175.503 +                int flags = interfaces[i].getModifiers();
 175.504 +                if (!Modifier.isPublic(flags)) {
 175.505 +                    String name = interfaces[i].getName();
 175.506 +                    int n = name.lastIndexOf('.');
 175.507 +                    String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
 175.508 +                    if (proxyPkg == null) {
 175.509 +                        proxyPkg = pkg;
 175.510 +                    } else if (!pkg.equals(proxyPkg)) {
 175.511 +                        throw new IllegalArgumentException(
 175.512 +                            "non-public interfaces from different packages");
 175.513 +                    }
 175.514 +                }
 175.515 +            }
 175.516 +
 175.517 +            if (proxyPkg == null) {     // if no non-public proxy interfaces,
 175.518 +                proxyPkg = "";          // use the unnamed package
 175.519 +            }
 175.520 +
 175.521 +            {
 175.522 +                /*
 175.523 +                 * Choose a name for the proxy class to generate.
 175.524 +                 */
 175.525 +                long num;
 175.526 +                synchronized (nextUniqueNumberLock) {
 175.527 +                    num = nextUniqueNumber++;
 175.528 +                }
 175.529 +                String proxyName = proxyPkg + proxyClassNamePrefix + num;
 175.530 +                /*
 175.531 +                 * Verify that the class loader hasn't already
 175.532 +                 * defined a class with the chosen name.
 175.533 +                 */
 175.534 +
 175.535 +                /*
 175.536 +                 * Generate the specified proxy class.
 175.537 +                 */
 175.538 +                Generator gen = new Generator(proxyName, interfaces);
 175.539 +                final byte[] proxyClassFile = gen.generateClassFile();
 175.540 +                try {
 175.541 +                    proxyClass = defineClass0(loader, proxyName,
 175.542 +                        proxyClassFile);
 175.543 +                } catch (ClassFormatError e) {
 175.544 +                    /*
 175.545 +                     * A ClassFormatError here means that (barring bugs in the
 175.546 +                     * proxy class generation code) there was some other
 175.547 +                     * invalid aspect of the arguments supplied to the proxy
 175.548 +                     * class creation (such as virtual machine limitations
 175.549 +                     * exceeded).
 175.550 +                     */
 175.551 +                    throw new IllegalArgumentException(e.toString());
 175.552 +                }
 175.553 +                gen.fillInMethods(proxyClass);
 175.554 +            }
 175.555 +            // add to set of all generated proxy classes, for isProxyClass
 175.556 +            proxyClasses.put(proxyClass, null);
 175.557 +
 175.558 +        } finally {
 175.559 +            /*
 175.560 +             * We must clean up the "pending generation" state of the proxy
 175.561 +             * class cache entry somehow.  If a proxy class was successfully
 175.562 +             * generated, store it in the cache (with a weak reference);
 175.563 +             * otherwise, remove the reserved entry.  In all cases, notify
 175.564 +             * all waiters on reserved entries in this cache.
 175.565 +             */
 175.566 +            synchronized (cache) {
 175.567 +                if (proxyClass != null) {
 175.568 +                    cache.put(key, new WeakReference<Class<?>>(proxyClass));
 175.569 +                } else {
 175.570 +                    cache.remove(key);
 175.571 +                }
 175.572 +                cache.notifyAll();
 175.573 +            }
 175.574 +        }
 175.575 +        return proxyClass;
 175.576 +    }
 175.577 +
 175.578 +    /**
 175.579 +     * Returns an instance of a proxy class for the specified interfaces
 175.580 +     * that dispatches method invocations to the specified invocation
 175.581 +     * handler.  This method is equivalent to:
 175.582 +     * <pre>
 175.583 +     *     Proxy.getProxyClass(loader, interfaces).
 175.584 +     *         getConstructor(new Class[] { InvocationHandler.class }).
 175.585 +     *         newInstance(new Object[] { handler });
 175.586 +     * </pre>
 175.587 +     *
 175.588 +     * <p>{@code Proxy.newProxyInstance} throws
 175.589 +     * {@code IllegalArgumentException} for the same reasons that
 175.590 +     * {@code Proxy.getProxyClass} does.
 175.591 +     *
 175.592 +     * @param   loader the class loader to define the proxy class
 175.593 +     * @param   interfaces the list of interfaces for the proxy class
 175.594 +     *          to implement
 175.595 +     * @param   h the invocation handler to dispatch method invocations to
 175.596 +     * @return  a proxy instance with the specified invocation handler of a
 175.597 +     *          proxy class that is defined by the specified class loader
 175.598 +     *          and that implements the specified interfaces
 175.599 +     * @throws  IllegalArgumentException if any of the restrictions on the
 175.600 +     *          parameters that may be passed to {@code getProxyClass}
 175.601 +     *          are violated
 175.602 +     * @throws  NullPointerException if the {@code interfaces} array
 175.603 +     *          argument or any of its elements are {@code null}, or
 175.604 +     *          if the invocation handler, {@code h}, is
 175.605 +     *          {@code null}
 175.606 +     */
 175.607 +    public static Object newProxyInstance(ClassLoader loader,
 175.608 +                                          Class<?>[] interfaces,
 175.609 +                                          InvocationHandler h)
 175.610 +        throws IllegalArgumentException
 175.611 +    {
 175.612 +        if (h == null) {
 175.613 +            throw new NullPointerException();
 175.614 +        }
 175.615 +
 175.616 +        /*
 175.617 +         * Look up or generate the designated proxy class.
 175.618 +         */
 175.619 +        Class<?> cl = getProxyClass(loader, interfaces);
 175.620 +
 175.621 +        /*
 175.622 +         * Invoke its constructor with the designated invocation handler.
 175.623 +         */
 175.624 +        try {
 175.625 +            Constructor cons = cl.getConstructor(constructorParams);
 175.626 +            return cons.newInstance(new Object[] { h });
 175.627 +        } catch (NoSuchMethodException e) {
 175.628 +            throw new InternalError(e.toString());
 175.629 +        } catch (IllegalAccessException e) {
 175.630 +            throw new InternalError(e.toString());
 175.631 +        } catch (InstantiationException e) {
 175.632 +            throw new InternalError(e.toString());
 175.633 +        } catch (InvocationTargetException e) {
 175.634 +            throw new InternalError(e.toString());
 175.635 +        }
 175.636 +    }
 175.637 +
 175.638 +    /**
 175.639 +     * Returns true if and only if the specified class was dynamically
 175.640 +     * generated to be a proxy class using the {@code getProxyClass}
 175.641 +     * method or the {@code newProxyInstance} method.
 175.642 +     *
 175.643 +     * <p>The reliability of this method is important for the ability
 175.644 +     * to use it to make security decisions, so its implementation should
 175.645 +     * not just test if the class in question extends {@code Proxy}.
 175.646 +     *
 175.647 +     * @param   cl the class to test
 175.648 +     * @return  {@code true} if the class is a proxy class and
 175.649 +     *          {@code false} otherwise
 175.650 +     * @throws  NullPointerException if {@code cl} is {@code null}
 175.651 +     */
 175.652 +    public static boolean isProxyClass(Class<?> cl) {
 175.653 +        if (cl == null) {
 175.654 +            throw new NullPointerException();
 175.655 +        }
 175.656 +
 175.657 +        return proxyClasses.containsKey(cl);
 175.658 +    }
 175.659 +
 175.660 +    /**
 175.661 +     * Returns the invocation handler for the specified proxy instance.
 175.662 +     *
 175.663 +     * @param   proxy the proxy instance to return the invocation handler for
 175.664 +     * @return  the invocation handler for the proxy instance
 175.665 +     * @throws  IllegalArgumentException if the argument is not a
 175.666 +     *          proxy instance
 175.667 +     */
 175.668 +    public static InvocationHandler getInvocationHandler(Object proxy)
 175.669 +        throws IllegalArgumentException
 175.670 +    {
 175.671 +        /*
 175.672 +         * Verify that the object is actually a proxy instance.
 175.673 +         */
 175.674 +        if (!isProxyClass(proxy.getClass())) {
 175.675 +            throw new IllegalArgumentException("not a proxy instance");
 175.676 +        }
 175.677 +
 175.678 +        ProxyImpl p = (ProxyImpl) proxy;
 175.679 +        return p.h;
 175.680 +    }
 175.681 +
 175.682 +    @JavaScriptBody(args = { "ignore", "name", "byteCode" }, 
 175.683 +        body = "return vm._reload(name, byteCode).constructor.$class;"
 175.684 +    )
 175.685 +    private static native Class defineClass0(
 175.686 +        ClassLoader loader, String name, byte[] b
 175.687 +    );
 175.688 +    
 175.689 +    private static class Generator {
 175.690 +        /*
 175.691 +         * In the comments below, "JVMS" refers to The Java Virtual Machine
 175.692 +         * Specification Second Edition and "JLS" refers to the original
 175.693 +         * version of The Java Language Specification, unless otherwise
 175.694 +         * specified.
 175.695 +         */
 175.696 +
 175.697 +        /* need 1.6 bytecode */
 175.698 +        private static final int CLASSFILE_MAJOR_VERSION = 50;
 175.699 +        private static final int CLASSFILE_MINOR_VERSION = 0;
 175.700 +
 175.701 +        /*
 175.702 +         * beginning of constants copied from
 175.703 +         * sun.tools.java.RuntimeConstants (which no longer exists):
 175.704 +         */
 175.705 +
 175.706 +        /* constant pool tags */
 175.707 +        private static final int CONSTANT_UTF8 = 1;
 175.708 +        private static final int CONSTANT_UNICODE = 2;
 175.709 +        private static final int CONSTANT_INTEGER = 3;
 175.710 +        private static final int CONSTANT_FLOAT = 4;
 175.711 +        private static final int CONSTANT_LONG = 5;
 175.712 +        private static final int CONSTANT_DOUBLE = 6;
 175.713 +        private static final int CONSTANT_CLASS = 7;
 175.714 +        private static final int CONSTANT_STRING = 8;
 175.715 +        private static final int CONSTANT_FIELD = 9;
 175.716 +        private static final int CONSTANT_METHOD = 10;
 175.717 +        private static final int CONSTANT_INTERFACEMETHOD = 11;
 175.718 +        private static final int CONSTANT_NAMEANDTYPE = 12;
 175.719 +
 175.720 +        /* access and modifier flags */
 175.721 +        private static final int ACC_PUBLIC = 0x00000001;
 175.722 +        private static final int ACC_FINAL = 0x00000010;
 175.723 +        private static final int ACC_SUPER = 0x00000020;
 175.724 +
 175.725 +    // end of constants copied from sun.tools.java.RuntimeConstants
 175.726 +        /**
 175.727 +         * name of the superclass of proxy classes
 175.728 +         */
 175.729 +        private final static String superclassName = "java/lang/reflect/Proxy";
 175.730 +
 175.731 +        /**
 175.732 +         * name of field for storing a proxy instance's invocation handler
 175.733 +         */
 175.734 +        private final static String handlerFieldName = "h";
 175.735 +
 175.736 +        /* preloaded Method objects for methods in java.lang.Object */
 175.737 +        private static Method hashCodeMethod;
 175.738 +        private static Method equalsMethod;
 175.739 +        private static Method toStringMethod;
 175.740 +
 175.741 +        static {
 175.742 +            try {
 175.743 +                hashCodeMethod = Object.class.getMethod("hashCode");
 175.744 +                equalsMethod
 175.745 +                    = Object.class.getMethod("equals", new Class[]{Object.class});
 175.746 +                toStringMethod = Object.class.getMethod("toString");
 175.747 +            } catch (NoSuchMethodException e) {
 175.748 +                throw new IllegalStateException(e.getMessage());
 175.749 +            }
 175.750 +        }
 175.751 +
 175.752 +        /**
 175.753 +         * name of proxy class
 175.754 +         */
 175.755 +        private String className;
 175.756 +
 175.757 +        /**
 175.758 +         * proxy interfaces
 175.759 +         */
 175.760 +        private Class[] interfaces;
 175.761 +
 175.762 +        /**
 175.763 +         * constant pool of class being generated
 175.764 +         */
 175.765 +        private ConstantPool cp = new ConstantPool();
 175.766 +
 175.767 +        /**
 175.768 +         * maps method signature string to list of ProxyMethod objects for proxy
 175.769 +         * methods with that signature
 175.770 +         */
 175.771 +        private Map<String, List<ProxyMethod>> proxyMethods
 175.772 +            = new HashMap<String, List<ProxyMethod>>();
 175.773 +
 175.774 +        /**
 175.775 +         * count of ProxyMethod objects added to proxyMethods
 175.776 +         */
 175.777 +        private int proxyMethodCount = 0;
 175.778 +
 175.779 +        /**
 175.780 +         * Construct a ProxyGenerator to generate a proxy class with the
 175.781 +         * specified name and for the given interfaces.
 175.782 +         *
 175.783 +         * A ProxyGenerator object contains the state for the ongoing generation
 175.784 +         * of a particular proxy class.
 175.785 +         */
 175.786 +        private Generator(String className, Class[] interfaces) {
 175.787 +            this.className = className;
 175.788 +            this.interfaces = interfaces;
 175.789 +        }
 175.790 +
 175.791 +        /**
 175.792 +         * Generate a class file for the proxy class. This method drives the
 175.793 +         * class file generation process.
 175.794 +         */
 175.795 +        private byte[] generateClassFile() {
 175.796 +
 175.797 +            /* ============================================================
 175.798 +             * Step 1: Assemble ProxyMethod objects for all methods to
 175.799 +             * generate proxy dispatching code for.
 175.800 +             */
 175.801 +
 175.802 +            /*
 175.803 +             * Record that proxy methods are needed for the hashCode, equals,
 175.804 +             * and toString methods of java.lang.Object.  This is done before
 175.805 +             * the methods from the proxy interfaces so that the methods from
 175.806 +             * java.lang.Object take precedence over duplicate methods in the
 175.807 +             * proxy interfaces.
 175.808 +             */
 175.809 +            addProxyMethod(hashCodeMethod, Object.class);
 175.810 +            addProxyMethod(equalsMethod, Object.class);
 175.811 +            addProxyMethod(toStringMethod, Object.class);
 175.812 +
 175.813 +            /*
 175.814 +             * Now record all of the methods from the proxy interfaces, giving
 175.815 +             * earlier interfaces precedence over later ones with duplicate
 175.816 +             * methods.
 175.817 +             */
 175.818 +            for (int i = 0; i < interfaces.length; i++) {
 175.819 +                Method[] methods = interfaces[i].getMethods();
 175.820 +                for (int j = 0; j < methods.length; j++) {
 175.821 +                    addProxyMethod(methods[j], interfaces[i]);
 175.822 +                }
 175.823 +            }
 175.824 +
 175.825 +            /*
 175.826 +             * For each set of proxy methods with the same signature,
 175.827 +             * verify that the methods' return types are compatible.
 175.828 +             */
 175.829 +            for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
 175.830 +                checkReturnTypes(sigmethods);
 175.831 +            }
 175.832 +
 175.833 +            /* ============================================================
 175.834 +             * Step 2: Assemble FieldInfo and MethodInfo structs for all of
 175.835 +             * fields and methods in the class we are generating.
 175.836 +             */
 175.837 +            
 175.838 +            // will be done in fillInMethods
 175.839 +
 175.840 +            /* ============================================================
 175.841 +             * Step 3: Write the final class file.
 175.842 +             */
 175.843 +
 175.844 +            /*
 175.845 +             * Make sure that constant pool indexes are reserved for the
 175.846 +             * following items before starting to write the final class file.
 175.847 +             */
 175.848 +            cp.getClass(dotToSlash(className));
 175.849 +            cp.getClass(superclassName);
 175.850 +            for (int i = 0; i < interfaces.length; i++) {
 175.851 +                cp.getClass(dotToSlash(interfaces[i].getName()));
 175.852 +            }
 175.853 +
 175.854 +            /*
 175.855 +             * Disallow new constant pool additions beyond this point, since
 175.856 +             * we are about to write the final constant pool table.
 175.857 +             */
 175.858 +            cp.setReadOnly();
 175.859 +
 175.860 +            ByteArrayOutputStream bout = new ByteArrayOutputStream();
 175.861 +            DataOutputStream dout = new DataOutputStream(bout);
 175.862 +
 175.863 +            try {
 175.864 +                /*
 175.865 +                 * Write all the items of the "ClassFile" structure.
 175.866 +                 * See JVMS section 4.1.
 175.867 +                 */
 175.868 +                // u4 magic;
 175.869 +                dout.writeInt(0xCAFEBABE);
 175.870 +                // u2 minor_version;
 175.871 +                dout.writeShort(CLASSFILE_MINOR_VERSION);
 175.872 +                // u2 major_version;
 175.873 +                dout.writeShort(CLASSFILE_MAJOR_VERSION);
 175.874 +
 175.875 +                cp.write(dout);             // (write constant pool)
 175.876 +
 175.877 +                // u2 access_flags;
 175.878 +                dout.writeShort(ACC_PUBLIC | ACC_FINAL | ACC_SUPER);
 175.879 +                // u2 this_class;
 175.880 +                dout.writeShort(cp.getClass(dotToSlash(className)));
 175.881 +                // u2 super_class;
 175.882 +                dout.writeShort(cp.getClass(superclassName));
 175.883 +
 175.884 +                // u2 interfaces_count;
 175.885 +                dout.writeShort(interfaces.length);
 175.886 +                // u2 interfaces[interfaces_count];
 175.887 +                for (int i = 0; i < interfaces.length; i++) {
 175.888 +                    dout.writeShort(cp.getClass(
 175.889 +                        dotToSlash(interfaces[i].getName())));
 175.890 +                }
 175.891 +
 175.892 +                // u2 fields_count;
 175.893 +                dout.writeShort(0);
 175.894 +
 175.895 +                // u2 methods_count;
 175.896 +                dout.writeShort(0);
 175.897 +
 175.898 +                // u2 attributes_count;
 175.899 +                dout.writeShort(0); // (no ClassFile attributes for proxy classes)
 175.900 +
 175.901 +            } catch (IOException e) {
 175.902 +                throw new InternalError("unexpected I/O Exception");
 175.903 +            }
 175.904 +
 175.905 +            return bout.toByteArray();
 175.906 +        }
 175.907 +
 175.908 +        @JavaScriptBody(args = { "c", "sig", "method", "primitive" }, body = 
 175.909 +            "var p = c.cnstr.prototype;\n" +
 175.910 +            "p[sig] = function() {\n" +
 175.911 +            "  var h = this._h();\n" +
 175.912 +            "  var res = h.invoke__Ljava_lang_Object_2Ljava_lang_Object_2Ljava_lang_reflect_Method_2_3Ljava_lang_Object_2(this, method, arguments);\n" +
 175.913 +            "  \n" +
 175.914 +            "  \n" +
 175.915 +            "  return res;\n" +
 175.916 +            "};"
 175.917 +        )
 175.918 +        private static native void defineMethod(Class<?> proxyClass, String sig, Method method, boolean primitive);
 175.919 +
 175.920 +        @JavaScriptBody(args = "c", body = 
 175.921 +              "var h = c.cnstr.cons__VLjava_lang_reflect_InvocationHandler_2 = function(h) {\n"
 175.922 +            + "  c.superclass.cnstr.cons__VLjava_lang_reflect_InvocationHandler_2.call(this, h);\n"
 175.923 +            + "}\n"
 175.924 +            + "h.cls = c.cnstr;\n"
 175.925 +        )
 175.926 +        private static native void defineConstructor(Class<?> proxyClass);
 175.927 +        
 175.928 +        final void fillInMethods(Class<?> proxyClass) {
 175.929 +            for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
 175.930 +                for (ProxyMethod pm : sigmethods) {
 175.931 +                    String sig = MethodImpl.toSignature(pm.method);
 175.932 +                    defineMethod(proxyClass, sig, pm.method, pm.method.getReturnType().isPrimitive());
 175.933 +                }
 175.934 +            }
 175.935 +            defineConstructor(proxyClass);
 175.936 +        }
 175.937 +
 175.938 +        /**
 175.939 +         * Add another method to be proxied, either by creating a new
 175.940 +         * ProxyMethod object or augmenting an old one for a duplicate method.
 175.941 +         *
 175.942 +         * "fromClass" indicates the proxy interface that the method was found
 175.943 +         * through, which may be different from (a subinterface of) the method's
 175.944 +         * "declaring class". Note that the first Method object passed for a
 175.945 +         * given name and descriptor identifies the Method object (and thus the
 175.946 +         * declaring class) that will be passed to the invocation handler's
 175.947 +         * "invoke" method for a given set of duplicate methods.
 175.948 +         */
 175.949 +        private void addProxyMethod(Method m, Class fromClass) {
 175.950 +            String name = m.getName();
 175.951 +            Class[] parameterTypes = m.getParameterTypes();
 175.952 +            Class returnType = m.getReturnType();
 175.953 +            Class[] exceptionTypes = m.getExceptionTypes();
 175.954 +
 175.955 +            String sig = MethodImpl.toSignature(m);
 175.956 +            List<ProxyMethod> sigmethods = proxyMethods.get(sig);
 175.957 +            if (sigmethods != null) {
 175.958 +                for (ProxyMethod pm : sigmethods) {
 175.959 +                    if (returnType == pm.returnType) {
 175.960 +                        /*
 175.961 +                         * Found a match: reduce exception types to the
 175.962 +                         * greatest set of exceptions that can thrown
 175.963 +                         * compatibly with the throws clauses of both
 175.964 +                         * overridden methods.
 175.965 +                         */
 175.966 +                        List<Class<?>> legalExceptions = new ArrayList<Class<?>>();
 175.967 +                        collectCompatibleTypes(
 175.968 +                            exceptionTypes, pm.exceptionTypes, legalExceptions);
 175.969 +                        collectCompatibleTypes(
 175.970 +                            pm.exceptionTypes, exceptionTypes, legalExceptions);
 175.971 +                        pm.exceptionTypes = new Class[legalExceptions.size()];
 175.972 +                        pm.exceptionTypes
 175.973 +                            = legalExceptions.toArray(pm.exceptionTypes);
 175.974 +                        return;
 175.975 +                    }
 175.976 +                }
 175.977 +            } else {
 175.978 +                sigmethods = new ArrayList<ProxyMethod>(3);
 175.979 +                proxyMethods.put(sig, sigmethods);
 175.980 +            }
 175.981 +            sigmethods.add(new ProxyMethod(m, name, parameterTypes, returnType,
 175.982 +                exceptionTypes, fromClass));
 175.983 +        }
 175.984 +
 175.985 +        /**
 175.986 +         * For a given set of proxy methods with the same signature, check that
 175.987 +         * their return types are compatible according to the Proxy
 175.988 +         * specification.
 175.989 +         *
 175.990 +         * Specifically, if there is more than one such method, then all of the
 175.991 +         * return types must be reference types, and there must be one return
 175.992 +         * type that is assignable to each of the rest of them.
 175.993 +         */
 175.994 +        private static void checkReturnTypes(List<ProxyMethod> methods) {
 175.995 +            /*
 175.996 +             * If there is only one method with a given signature, there
 175.997 +             * cannot be a conflict.  This is the only case in which a
 175.998 +             * primitive (or void) return type is allowed.
 175.999 +             */
175.1000 +            if (methods.size() < 2) {
175.1001 +                return;
175.1002 +            }
175.1003 +
175.1004 +            /*
175.1005 +             * List of return types that are not yet known to be
175.1006 +             * assignable from ("covered" by) any of the others.
175.1007 +             */
175.1008 +            LinkedList<Class<?>> uncoveredReturnTypes = new LinkedList<Class<?>>();
175.1009 +
175.1010 +            nextNewReturnType:
175.1011 +            for (ProxyMethod pm : methods) {
175.1012 +                Class<?> newReturnType = pm.returnType;
175.1013 +                if (newReturnType.isPrimitive()) {
175.1014 +                    throw new IllegalArgumentException(
175.1015 +                        "methods with same signature "
175.1016 +                        + getFriendlyMethodSignature(pm.methodName,
175.1017 +                            pm.parameterTypes)
175.1018 +                        + " but incompatible return types: "
175.1019 +                        + newReturnType.getName() + " and others");
175.1020 +                }
175.1021 +                boolean added = false;
175.1022 +
175.1023 +                /*
175.1024 +                 * Compare the new return type to the existing uncovered
175.1025 +                 * return types.
175.1026 +                 */
175.1027 +                ListIterator<Class<?>> liter = uncoveredReturnTypes.listIterator();
175.1028 +                while (liter.hasNext()) {
175.1029 +                    Class<?> uncoveredReturnType = liter.next();
175.1030 +
175.1031 +                    /*
175.1032 +                     * If an existing uncovered return type is assignable
175.1033 +                     * to this new one, then we can forget the new one.
175.1034 +                     */
175.1035 +                    if (newReturnType.isAssignableFrom(uncoveredReturnType)) {
175.1036 +                        assert !added;
175.1037 +                        continue nextNewReturnType;
175.1038 +                    }
175.1039 +
175.1040 +                    /*
175.1041 +                     * If the new return type is assignable to an existing
175.1042 +                     * uncovered one, then should replace the existing one
175.1043 +                     * with the new one (or just forget the existing one,
175.1044 +                     * if the new one has already be put in the list).
175.1045 +                     */
175.1046 +                    if (uncoveredReturnType.isAssignableFrom(newReturnType)) {
175.1047 +                        // (we can assume that each return type is unique)
175.1048 +                        if (!added) {
175.1049 +                            liter.set(newReturnType);
175.1050 +                            added = true;
175.1051 +                        } else {
175.1052 +                            liter.remove();
175.1053 +                        }
175.1054 +                    }
175.1055 +                }
175.1056 +
175.1057 +                /*
175.1058 +                 * If we got through the list of existing uncovered return
175.1059 +                 * types without an assignability relationship, then add
175.1060 +                 * the new return type to the list of uncovered ones.
175.1061 +                 */
175.1062 +                if (!added) {
175.1063 +                    uncoveredReturnTypes.add(newReturnType);
175.1064 +                }
175.1065 +            }
175.1066 +
175.1067 +            /*
175.1068 +             * We shouldn't end up with more than one return type that is
175.1069 +             * not assignable from any of the others.
175.1070 +             */
175.1071 +            if (uncoveredReturnTypes.size() > 1) {
175.1072 +                ProxyMethod pm = methods.get(0);
175.1073 +                throw new IllegalArgumentException(
175.1074 +                    "methods with same signature "
175.1075 +                    + getFriendlyMethodSignature(pm.methodName, pm.parameterTypes)
175.1076 +                    + " but incompatible return types: " + uncoveredReturnTypes);
175.1077 +            }
175.1078 +        }
175.1079 +
175.1080 +
175.1081 +        /**
175.1082 +         * A ProxyMethod object represents a proxy method in the proxy class
175.1083 +         * being generated: a method whose implementation will encode and
175.1084 +         * dispatch invocations to the proxy instance's invocation handler.
175.1085 +         */
175.1086 +        private class ProxyMethod {
175.1087 +
175.1088 +            private final Method method;
175.1089 +            public String methodName;
175.1090 +            public Class[] parameterTypes;
175.1091 +            public Class returnType;
175.1092 +            public Class[] exceptionTypes;
175.1093 +            public Class fromClass;
175.1094 +            public String methodFieldName;
175.1095 +
175.1096 +            private ProxyMethod(Method m, 
175.1097 +                String methodName, Class[] parameterTypes, 
175.1098 +                Class returnType, Class[] exceptionTypes, 
175.1099 +                Class fromClass
175.1100 +            ) {
175.1101 +                this.method = m;
175.1102 +                this.methodName = methodName;
175.1103 +                this.parameterTypes = parameterTypes;
175.1104 +                this.returnType = returnType;
175.1105 +                this.exceptionTypes = exceptionTypes;
175.1106 +                this.fromClass = fromClass;
175.1107 +                this.methodFieldName = "m" + proxyMethodCount++;
175.1108 +            }
175.1109 +
175.1110 +        }
175.1111 +
175.1112 +        /*
175.1113 +         * ==================== General Utility Methods ====================
175.1114 +         */
175.1115 +        /**
175.1116 +         * Convert a fully qualified class name that uses '.' as the package
175.1117 +         * separator, the external representation used by the Java language and
175.1118 +         * APIs, to a fully qualified class name that uses '/' as the package
175.1119 +         * separator, the representation used in the class file format (see JVMS
175.1120 +         * section 4.2).
175.1121 +         */
175.1122 +        private static String dotToSlash(String name) {
175.1123 +            return name.replace('.', '/');
175.1124 +        }
175.1125 +
175.1126 +        /**
175.1127 +         * Return the list of "parameter descriptor" strings enclosed in
175.1128 +         * parentheses corresponding to the given parameter types (in other
175.1129 +         * words, a method descriptor without a return descriptor). This string
175.1130 +         * is useful for constructing string keys for methods without regard to
175.1131 +         * their return type.
175.1132 +         */
175.1133 +        private static String getParameterDescriptors(Class[] parameterTypes) {
175.1134 +            StringBuilder desc = new StringBuilder("(");
175.1135 +            for (int i = 0; i < parameterTypes.length; i++) {
175.1136 +                desc.append(getFieldType(parameterTypes[i]));
175.1137 +            }
175.1138 +            desc.append(')');
175.1139 +            return desc.toString();
175.1140 +        }
175.1141 +
175.1142 +        /**
175.1143 +         * Return the "field type" string for the given type, appropriate for a
175.1144 +         * field descriptor, a parameter descriptor, or a return descriptor
175.1145 +         * other than "void". See JVMS section 4.3.2.
175.1146 +         */
175.1147 +        private static String getFieldType(Class type) {
175.1148 +            if (type.isPrimitive()) {
175.1149 +                return PrimitiveTypeInfo.get(type).baseTypeString;
175.1150 +            } else if (type.isArray()) {
175.1151 +                /*
175.1152 +                 * According to JLS 20.3.2, the getName() method on Class does
175.1153 +                 * return the VM type descriptor format for array classes (only);
175.1154 +                 * using that should be quicker than the otherwise obvious code:
175.1155 +                 *
175.1156 +                 *     return "[" + getTypeDescriptor(type.getComponentType());
175.1157 +                 */
175.1158 +                return type.getName().replace('.', '/');
175.1159 +            } else {
175.1160 +                return "L" + dotToSlash(type.getName()) + ";";
175.1161 +            }
175.1162 +        }
175.1163 +
175.1164 +        /**
175.1165 +         * Returns a human-readable string representing the signature of a
175.1166 +         * method with the given name and parameter types.
175.1167 +         */
175.1168 +        private static String getFriendlyMethodSignature(String name,
175.1169 +            Class[] parameterTypes) {
175.1170 +            StringBuilder sig = new StringBuilder(name);
175.1171 +            sig.append('(');
175.1172 +            for (int i = 0; i < parameterTypes.length; i++) {
175.1173 +                if (i > 0) {
175.1174 +                    sig.append(',');
175.1175 +                }
175.1176 +                Class parameterType = parameterTypes[i];
175.1177 +                int dimensions = 0;
175.1178 +                while (parameterType.isArray()) {
175.1179 +                    parameterType = parameterType.getComponentType();
175.1180 +                    dimensions++;
175.1181 +                }
175.1182 +                sig.append(parameterType.getName());
175.1183 +                while (dimensions-- > 0) {
175.1184 +                    sig.append("[]");
175.1185 +                }
175.1186 +            }
175.1187 +            sig.append(')');
175.1188 +            return sig.toString();
175.1189 +        }
175.1190 +
175.1191 +        /**
175.1192 +         * Add to the given list all of the types in the "from" array that are
175.1193 +         * not already contained in the list and are assignable to at least one
175.1194 +         * of the types in the "with" array.
175.1195 +         *
175.1196 +         * This method is useful for computing the greatest common set of
175.1197 +         * declared exceptions from duplicate methods inherited from different
175.1198 +         * interfaces.
175.1199 +         */
175.1200 +        private static void collectCompatibleTypes(Class<?>[] from,
175.1201 +            Class<?>[] with,
175.1202 +            List<Class<?>> list) {
175.1203 +            for (int i = 0; i < from.length; i++) {
175.1204 +                if (!list.contains(from[i])) {
175.1205 +                    for (int j = 0; j < with.length; j++) {
175.1206 +                        if (with[j].isAssignableFrom(from[i])) {
175.1207 +                            list.add(from[i]);
175.1208 +                            break;
175.1209 +                        }
175.1210 +                    }
175.1211 +                }
175.1212 +            }
175.1213 +        }
175.1214 +
175.1215 +
175.1216 +        /**
175.1217 +         * A PrimitiveTypeInfo object contains assorted information about a
175.1218 +         * primitive type in its public fields. The struct for a particular
175.1219 +         * primitive type can be obtained using the static "get" method.
175.1220 +         */
175.1221 +        private static class PrimitiveTypeInfo {
175.1222 +
175.1223 +            /**
175.1224 +             * "base type" used in various descriptors (see JVMS section 4.3.2)
175.1225 +             */
175.1226 +            public String baseTypeString;
175.1227 +
175.1228 +            /**
175.1229 +             * name of corresponding wrapper class
175.1230 +             */
175.1231 +            public String wrapperClassName;
175.1232 +
175.1233 +            /**
175.1234 +             * method descriptor for wrapper class "valueOf" factory method
175.1235 +             */
175.1236 +            public String wrapperValueOfDesc;
175.1237 +
175.1238 +            /**
175.1239 +             * name of wrapper class method for retrieving primitive value
175.1240 +             */
175.1241 +            public String unwrapMethodName;
175.1242 +
175.1243 +            /**
175.1244 +             * descriptor of same method
175.1245 +             */
175.1246 +            public String unwrapMethodDesc;
175.1247 +
175.1248 +            private static Map<Class, PrimitiveTypeInfo> table
175.1249 +                = new HashMap<Class, PrimitiveTypeInfo>();
175.1250 +
175.1251 +            static {
175.1252 +                add(byte.class, Byte.class);
175.1253 +                add(char.class, Character.class);
175.1254 +                add(double.class, Double.class);
175.1255 +                add(float.class, Float.class);
175.1256 +                add(int.class, Integer.class);
175.1257 +                add(long.class, Long.class);
175.1258 +                add(short.class, Short.class);
175.1259 +                add(boolean.class, Boolean.class);
175.1260 +            }
175.1261 +
175.1262 +            private static void add(Class primitiveClass, Class wrapperClass) {
175.1263 +                table.put(primitiveClass,
175.1264 +                    new PrimitiveTypeInfo(primitiveClass, wrapperClass));
175.1265 +            }
175.1266 +
175.1267 +            private PrimitiveTypeInfo(Class primitiveClass, Class wrapperClass) {
175.1268 +                assert primitiveClass.isPrimitive();
175.1269 +
175.1270 +                baseTypeString
175.1271 +                    = Array.newInstance(primitiveClass, 0)
175.1272 +                    .getClass().getName().substring(1);
175.1273 +                wrapperClassName = dotToSlash(wrapperClass.getName());
175.1274 +                wrapperValueOfDesc
175.1275 +                    = "(" + baseTypeString + ")L" + wrapperClassName + ";";
175.1276 +                unwrapMethodName = primitiveClass.getName() + "Value";
175.1277 +                unwrapMethodDesc = "()" + baseTypeString;
175.1278 +            }
175.1279 +
175.1280 +            public static PrimitiveTypeInfo get(Class cl) {
175.1281 +                return table.get(cl);
175.1282 +            }
175.1283 +        }
175.1284 +
175.1285 +        /**
175.1286 +         * A ConstantPool object represents the constant pool of a class file
175.1287 +         * being generated. This representation of a constant pool is designed
175.1288 +         * specifically for use by ProxyGenerator; in particular, it assumes
175.1289 +         * that constant pool entries will not need to be resorted (for example,
175.1290 +         * by their type, as the Java compiler does), so that the final index
175.1291 +         * value can be assigned and used when an entry is first created.
175.1292 +         *
175.1293 +         * Note that new entries cannot be created after the constant pool has
175.1294 +         * been written to a class file. To prevent such logic errors, a
175.1295 +         * ConstantPool instance can be marked "read only", so that further
175.1296 +         * attempts to add new entries will fail with a runtime exception.
175.1297 +         *
175.1298 +         * See JVMS section 4.4 for more information about the constant pool of
175.1299 +         * a class file.
175.1300 +         */
175.1301 +        private static class ConstantPool {
175.1302 +
175.1303 +            /**
175.1304 +             * list of constant pool entries, in constant pool index order.
175.1305 +             *
175.1306 +             * This list is used when writing the constant pool to a stream and
175.1307 +             * for assigning the next index value. Note that element 0 of this
175.1308 +             * list corresponds to constant pool index 1.
175.1309 +             */
175.1310 +            private List<Entry> pool = new ArrayList<Entry>(32);
175.1311 +
175.1312 +            /**
175.1313 +             * maps constant pool data of all types to constant pool indexes.
175.1314 +             *
175.1315 +             * This map is used to look up the index of an existing entry for
175.1316 +             * values of all types.
175.1317 +             */
175.1318 +            private Map<Object, Short> map = new HashMap<Object, Short>(16);
175.1319 +
175.1320 +            /**
175.1321 +             * true if no new constant pool entries may be added
175.1322 +             */
175.1323 +            private boolean readOnly = false;
175.1324 +
175.1325 +            /**
175.1326 +             * Get or assign the index for a CONSTANT_Utf8 entry.
175.1327 +             */
175.1328 +            public short getUtf8(String s) {
175.1329 +                if (s == null) {
175.1330 +                    throw new NullPointerException();
175.1331 +                }
175.1332 +                return getValue(s);
175.1333 +            }
175.1334 +
175.1335 +            /**
175.1336 +             * Get or assign the index for a CONSTANT_Integer entry.
175.1337 +             */
175.1338 +            public short getInteger(int i) {
175.1339 +                return getValue(new Integer(i));
175.1340 +            }
175.1341 +
175.1342 +            /**
175.1343 +             * Get or assign the index for a CONSTANT_Float entry.
175.1344 +             */
175.1345 +            public short getFloat(float f) {
175.1346 +                return getValue(new Float(f));
175.1347 +            }
175.1348 +
175.1349 +            /**
175.1350 +             * Get or assign the index for a CONSTANT_Class entry.
175.1351 +             */
175.1352 +            public short getClass(String name) {
175.1353 +                short utf8Index = getUtf8(name);
175.1354 +                return getIndirect(new IndirectEntry(
175.1355 +                    CONSTANT_CLASS, utf8Index));
175.1356 +            }
175.1357 +
175.1358 +            /**
175.1359 +             * Get or assign the index for a CONSTANT_String entry.
175.1360 +             */
175.1361 +            public short getString(String s) {
175.1362 +                short utf8Index = getUtf8(s);
175.1363 +                return getIndirect(new IndirectEntry(
175.1364 +                    CONSTANT_STRING, utf8Index));
175.1365 +            }
175.1366 +
175.1367 +            /**
175.1368 +             * Get or assign the index for a CONSTANT_FieldRef entry.
175.1369 +             */
175.1370 +            public short getFieldRef(String className,
175.1371 +                String name, String descriptor) {
175.1372 +                short classIndex = getClass(className);
175.1373 +                short nameAndTypeIndex = getNameAndType(name, descriptor);
175.1374 +                return getIndirect(new IndirectEntry(
175.1375 +                    CONSTANT_FIELD, classIndex, nameAndTypeIndex));
175.1376 +            }
175.1377 +
175.1378 +            /**
175.1379 +             * Get or assign the index for a CONSTANT_MethodRef entry.
175.1380 +             */
175.1381 +            public short getMethodRef(String className,
175.1382 +                String name, String descriptor) {
175.1383 +                short classIndex = getClass(className);
175.1384 +                short nameAndTypeIndex = getNameAndType(name, descriptor);
175.1385 +                return getIndirect(new IndirectEntry(
175.1386 +                    CONSTANT_METHOD, classIndex, nameAndTypeIndex));
175.1387 +            }
175.1388 +
175.1389 +            /**
175.1390 +             * Get or assign the index for a CONSTANT_InterfaceMethodRef entry.
175.1391 +             */
175.1392 +            public short getInterfaceMethodRef(String className, String name,
175.1393 +                String descriptor) {
175.1394 +                short classIndex = getClass(className);
175.1395 +                short nameAndTypeIndex = getNameAndType(name, descriptor);
175.1396 +                return getIndirect(new IndirectEntry(
175.1397 +                    CONSTANT_INTERFACEMETHOD, classIndex, nameAndTypeIndex));
175.1398 +            }
175.1399 +
175.1400 +            /**
175.1401 +             * Get or assign the index for a CONSTANT_NameAndType entry.
175.1402 +             */
175.1403 +            public short getNameAndType(String name, String descriptor) {
175.1404 +                short nameIndex = getUtf8(name);
175.1405 +                short descriptorIndex = getUtf8(descriptor);
175.1406 +                return getIndirect(new IndirectEntry(
175.1407 +                    CONSTANT_NAMEANDTYPE, nameIndex, descriptorIndex));
175.1408 +            }
175.1409 +
175.1410 +            /**
175.1411 +             * Set this ConstantPool instance to be "read only".
175.1412 +             *
175.1413 +             * After this method has been called, further requests to get an
175.1414 +             * index for a non-existent entry will cause an InternalError to be
175.1415 +             * thrown instead of creating of the entry.
175.1416 +             */
175.1417 +            public void setReadOnly() {
175.1418 +                readOnly = true;
175.1419 +            }
175.1420 +
175.1421 +            /**
175.1422 +             * Write this constant pool to a stream as part of the class file
175.1423 +             * format.
175.1424 +             *
175.1425 +             * This consists of writing the "constant_pool_count" and
175.1426 +             * "constant_pool[]" items of the "ClassFile" structure, as
175.1427 +             * described in JVMS section 4.1.
175.1428 +             */
175.1429 +            public void write(OutputStream out) throws IOException {
175.1430 +                DataOutputStream dataOut = new DataOutputStream(out);
175.1431 +
175.1432 +                // constant_pool_count: number of entries plus one
175.1433 +                dataOut.writeShort(pool.size() + 1);
175.1434 +
175.1435 +                for (Entry e : pool) {
175.1436 +                    e.write(dataOut);
175.1437 +                }
175.1438 +            }
175.1439 +
175.1440 +            /**
175.1441 +             * Add a new constant pool entry and return its index.
175.1442 +             */
175.1443 +            private short addEntry(Entry entry) {
175.1444 +                pool.add(entry);
175.1445 +                /*
175.1446 +                 * Note that this way of determining the index of the
175.1447 +                 * added entry is wrong if this pool supports
175.1448 +                 * CONSTANT_Long or CONSTANT_Double entries.
175.1449 +                 */
175.1450 +                if (pool.size() >= 65535) {
175.1451 +                    throw new IllegalArgumentException(
175.1452 +                        "constant pool size limit exceeded");
175.1453 +                }
175.1454 +                return (short) pool.size();
175.1455 +            }
175.1456 +
175.1457 +            /**
175.1458 +             * Get or assign the index for an entry of a type that contains a
175.1459 +             * direct value. The type of the given object determines the type of
175.1460 +             * the desired entry as follows:
175.1461 +             *
175.1462 +             * java.lang.String CONSTANT_Utf8 java.lang.Integer CONSTANT_Integer
175.1463 +             * java.lang.Float CONSTANT_Float java.lang.Long CONSTANT_Long
175.1464 +             * java.lang.Double CONSTANT_DOUBLE
175.1465 +             */
175.1466 +            private short getValue(Object key) {
175.1467 +                Short index = map.get(key);
175.1468 +                if (index != null) {
175.1469 +                    return index.shortValue();
175.1470 +                } else {
175.1471 +                    if (readOnly) {
175.1472 +                        throw new InternalError(
175.1473 +                            "late constant pool addition: " + key);
175.1474 +                    }
175.1475 +                    short i = addEntry(new ValueEntry(key));
175.1476 +                    map.put(key, new Short(i));
175.1477 +                    return i;
175.1478 +                }
175.1479 +            }
175.1480 +
175.1481 +            /**
175.1482 +             * Get or assign the index for an entry of a type that contains
175.1483 +             * references to other constant pool entries.
175.1484 +             */
175.1485 +            private short getIndirect(IndirectEntry e) {
175.1486 +                Short index = map.get(e);
175.1487 +                if (index != null) {
175.1488 +                    return index.shortValue();
175.1489 +                } else {
175.1490 +                    if (readOnly) {
175.1491 +                        throw new InternalError("late constant pool addition");
175.1492 +                    }
175.1493 +                    short i = addEntry(e);
175.1494 +                    map.put(e, new Short(i));
175.1495 +                    return i;
175.1496 +                }
175.1497 +            }
175.1498 +
175.1499 +            /**
175.1500 +             * Entry is the abstact superclass of all constant pool entry types
175.1501 +             * that can be stored in the "pool" list; its purpose is to define a
175.1502 +             * common method for writing constant pool entries to a class file.
175.1503 +             */
175.1504 +            private static abstract class Entry {
175.1505 +
175.1506 +                public abstract void write(DataOutputStream out)
175.1507 +                    throws IOException;
175.1508 +            }
175.1509 +
175.1510 +            /**
175.1511 +             * ValueEntry represents a constant pool entry of a type that
175.1512 +             * contains a direct value (see the comments for the "getValue"
175.1513 +             * method for a list of such types).
175.1514 +             *
175.1515 +             * ValueEntry objects are not used as keys for their entries in the
175.1516 +             * Map "map", so no useful hashCode or equals methods are defined.
175.1517 +             */
175.1518 +            private static class ValueEntry extends Entry {
175.1519 +
175.1520 +                private Object value;
175.1521 +
175.1522 +                public ValueEntry(Object value) {
175.1523 +                    this.value = value;
175.1524 +                }
175.1525 +
175.1526 +                public void write(DataOutputStream out) throws IOException {
175.1527 +                    if (value instanceof String) {
175.1528 +                        out.writeByte(CONSTANT_UTF8);
175.1529 +                        out.writeUTF((String) value);
175.1530 +                    } else if (value instanceof Integer) {
175.1531 +                        out.writeByte(CONSTANT_INTEGER);
175.1532 +                        out.writeInt(((Integer) value).intValue());
175.1533 +                    } else if (value instanceof Float) {
175.1534 +                        out.writeByte(CONSTANT_FLOAT);
175.1535 +                        out.writeFloat(((Float) value).floatValue());
175.1536 +                    } else if (value instanceof Long) {
175.1537 +                        out.writeByte(CONSTANT_LONG);
175.1538 +                        out.writeLong(((Long) value).longValue());
175.1539 +                    } else if (value instanceof Double) {
175.1540 +                        out.writeDouble(CONSTANT_DOUBLE);
175.1541 +                        out.writeDouble(((Double) value).doubleValue());
175.1542 +                    } else {
175.1543 +                        throw new InternalError("bogus value entry: " + value);
175.1544 +                    }
175.1545 +                }
175.1546 +            }
175.1547 +
175.1548 +            /**
175.1549 +             * IndirectEntry represents a constant pool entry of a type that
175.1550 +             * references other constant pool entries, i.e., the following
175.1551 +             * types:
175.1552 +             *
175.1553 +             * CONSTANT_Class, CONSTANT_String, CONSTANT_Fieldref,
175.1554 +             * CONSTANT_Methodref, CONSTANT_InterfaceMethodref, and
175.1555 +             * CONSTANT_NameAndType.
175.1556 +             *
175.1557 +             * Each of these entry types contains either one or two indexes of
175.1558 +             * other constant pool entries.
175.1559 +             *
175.1560 +             * IndirectEntry objects are used as the keys for their entries in
175.1561 +             * the Map "map", so the hashCode and equals methods are overridden
175.1562 +             * to allow matching.
175.1563 +             */
175.1564 +            private static class IndirectEntry extends Entry {
175.1565 +
175.1566 +                private int tag;
175.1567 +                private short index0;
175.1568 +                private short index1;
175.1569 +
175.1570 +                /**
175.1571 +                 * Construct an IndirectEntry for a constant pool entry type
175.1572 +                 * that contains one index of another entry.
175.1573 +                 */
175.1574 +                public IndirectEntry(int tag, short index) {
175.1575 +                    this.tag = tag;
175.1576 +                    this.index0 = index;
175.1577 +                    this.index1 = 0;
175.1578 +                }
175.1579 +
175.1580 +                /**
175.1581 +                 * Construct an IndirectEntry for a constant pool entry type
175.1582 +                 * that contains two indexes for other entries.
175.1583 +                 */
175.1584 +                public IndirectEntry(int tag, short index0, short index1) {
175.1585 +                    this.tag = tag;
175.1586 +                    this.index0 = index0;
175.1587 +                    this.index1 = index1;
175.1588 +                }
175.1589 +
175.1590 +                public void write(DataOutputStream out) throws IOException {
175.1591 +                    out.writeByte(tag);
175.1592 +                    out.writeShort(index0);
175.1593 +                    /*
175.1594 +                     * If this entry type contains two indexes, write
175.1595 +                     * out the second, too.
175.1596 +                     */
175.1597 +                    if (tag == CONSTANT_FIELD
175.1598 +                        || tag == CONSTANT_METHOD
175.1599 +                        || tag == CONSTANT_INTERFACEMETHOD
175.1600 +                        || tag == CONSTANT_NAMEANDTYPE) {
175.1601 +                        out.writeShort(index1);
175.1602 +                    }
175.1603 +                }
175.1604 +
175.1605 +                public int hashCode() {
175.1606 +                    return tag + index0 + index1;
175.1607 +                }
175.1608 +
175.1609 +                public boolean equals(Object obj) {
175.1610 +                    if (obj instanceof IndirectEntry) {
175.1611 +                        IndirectEntry other = (IndirectEntry) obj;
175.1612 +                        if (tag == other.tag
175.1613 +                            && index0 == other.index0 && index1 == other.index1) {
175.1614 +                            return true;
175.1615 +                        }
175.1616 +                    }
175.1617 +                    return false;
175.1618 +                }
175.1619 +            }
175.1620 +        }
175.1621 +    }
175.1622 +    
175.1623 +}
   176.1 --- a/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/compact/tck/CollectionsTest.java	Tue Feb 11 10:48:24 2014 +0100
   176.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/compact/tck/CollectionsTest.java	Tue Feb 11 13:31:42 2014 +0100
   176.3 @@ -20,6 +20,7 @@
   176.4  import java.util.ArrayList;
   176.5  import java.util.Arrays;
   176.6  import java.util.Collection;
   176.7 +import java.util.Collections;
   176.8  import java.util.Comparator;
   176.9  import java.util.HashMap;
  176.10  import java.util.HashSet;
  176.11 @@ -96,6 +97,7 @@
  176.12          
  176.13          List<Entry<String,Integer>> arr = new Vector<>();
  176.14          arr.addAll(map.entrySet());
  176.15 +        Collections.sort(arr, new C());
  176.16          return arr.toString();
  176.17      }
  176.18      
   177.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   177.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/AtomicTest.java	Tue Feb 11 13:31:42 2014 +0100
   177.3 @@ -0,0 +1,54 @@
   177.4 +/**
   177.5 + * Back 2 Browser Bytecode Translator
   177.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
   177.7 + *
   177.8 + * This program is free software: you can redistribute it and/or modify
   177.9 + * it under the terms of the GNU General Public License as published by
  177.10 + * the Free Software Foundation, version 2 of the License.
  177.11 + *
  177.12 + * This program is distributed in the hope that it will be useful,
  177.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  177.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  177.15 + * GNU General Public License for more details.
  177.16 + *
  177.17 + * You should have received a copy of the GNU General Public License
  177.18 + * along with this program. Look for COPYING file in the top folder.
  177.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
  177.20 + */
  177.21 +package org.apidesign.bck2brwsr.tck;
  177.22 +
  177.23 +import java.util.concurrent.atomic.AtomicBoolean;
  177.24 +import java.util.concurrent.atomic.AtomicInteger;
  177.25 +import java.util.concurrent.atomic.AtomicReference;
  177.26 +import org.apidesign.bck2brwsr.vmtest.Compare;
  177.27 +import org.apidesign.bck2brwsr.vmtest.VMTest;
  177.28 +import org.testng.annotations.Factory;
  177.29 +
  177.30 +/**
  177.31 + *
  177.32 + * @author Jaroslav Tulach <jtulach@netbeans.org>
  177.33 + */
  177.34 +public class AtomicTest {
  177.35 +    @Compare public boolean atomicBoolean() {
  177.36 +        AtomicBoolean ab = new AtomicBoolean();
  177.37 +        ab.set(true);
  177.38 +        return ab.compareAndSet(true, false);
  177.39 +    }
  177.40 +
  177.41 +    @Compare public int atomicInt() {
  177.42 +        AtomicInteger ab = new AtomicInteger();
  177.43 +        ab.set(30);
  177.44 +        assert ab.compareAndSet(30, 10);
  177.45 +        return ab.get();
  177.46 +    }
  177.47 +    
  177.48 +    @Compare public String atomicRef() {
  177.49 +        AtomicReference<String> ar = new AtomicReference<String>("Ahoj");
  177.50 +        assert ar.compareAndSet("Ahoj", "Hello");
  177.51 +        return ar.getAndSet("Other");
  177.52 +    }
  177.53 +    
  177.54 +    @Factory public static Object[] create() {
  177.55 +        return VMTest.create(AtomicTest.class);
  177.56 +    }
  177.57 +}
   178.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   178.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/CharacterTest.java	Tue Feb 11 13:31:42 2014 +0100
   178.3 @@ -0,0 +1,51 @@
   178.4 +/**
   178.5 + * Back 2 Browser Bytecode Translator
   178.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
   178.7 + *
   178.8 + * This program is free software: you can redistribute it and/or modify
   178.9 + * it under the terms of the GNU General Public License as published by
  178.10 + * the Free Software Foundation, version 2 of the License.
  178.11 + *
  178.12 + * This program is distributed in the hope that it will be useful,
  178.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  178.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  178.15 + * GNU General Public License for more details.
  178.16 + *
  178.17 + * You should have received a copy of the GNU General Public License
  178.18 + * along with this program. Look for COPYING file in the top folder.
  178.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
  178.20 + */
  178.21 +package org.apidesign.bck2brwsr.tck;
  178.22 +
  178.23 +import org.apidesign.bck2brwsr.vmtest.Compare;
  178.24 +import org.apidesign.bck2brwsr.vmtest.VMTest;
  178.25 +import org.testng.annotations.Factory;
  178.26 +
  178.27 +/**
  178.28 + *
  178.29 + * @author Jaroslav Tulach <jtulach@netbeans.org>
  178.30 + */
  178.31 +public class CharacterTest {
  178.32 +    @Compare public boolean dolarJavaStart() {
  178.33 +        return Character.isJavaIdentifierStart('$');
  178.34 +    }
  178.35 +
  178.36 +    @Compare public boolean dolarJavaPart() {
  178.37 +        return Character.isJavaIdentifierPart('$');
  178.38 +    }
  178.39 +
  178.40 +    @Compare public boolean numberJavaStart() {
  178.41 +        return Character.isJavaIdentifierStart('3');
  178.42 +    }
  178.43 +
  178.44 +    @Compare public boolean numberJavaPart() {
  178.45 +        return Character.isJavaIdentifierPart('3');
  178.46 +    }
  178.47 +    
  178.48 +    
  178.49 +    @Factory
  178.50 +    public static Object[] create() {
  178.51 +        return VMTest.create(CharacterTest.class);
  178.52 +    }
  178.53 +
  178.54 +}
   179.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   179.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/ClassLoaderTest.java	Tue Feb 11 13:31:42 2014 +0100
   179.3 @@ -0,0 +1,41 @@
   179.4 +/**
   179.5 + * Back 2 Browser Bytecode Translator
   179.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
   179.7 + *
   179.8 + * This program is free software: you can redistribute it and/or modify
   179.9 + * it under the terms of the GNU General Public License as published by
  179.10 + * the Free Software Foundation, version 2 of the License.
  179.11 + *
  179.12 + * This program is distributed in the hope that it will be useful,
  179.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  179.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  179.15 + * GNU General Public License for more details.
  179.16 + *
  179.17 + * You should have received a copy of the GNU General Public License
  179.18 + * along with this program. Look for COPYING file in the top folder.
  179.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
  179.20 + */
  179.21 +package org.apidesign.bck2brwsr.tck;
  179.22 +
  179.23 +import org.apidesign.bck2brwsr.vmtest.Compare;
  179.24 +import org.apidesign.bck2brwsr.vmtest.VMTest;
  179.25 +import org.testng.annotations.Factory;
  179.26 +
  179.27 +/**
  179.28 + *
  179.29 + * @author Jaroslav Tulach <jtulach@netbeans.org>
  179.30 + */
  179.31 +public class ClassLoaderTest {
  179.32 +    @Compare public Object unknownResource() {
  179.33 +        return ClassLoader.getSystemResource("really/unknown/resource.txt");
  179.34 +    }
  179.35 +    
  179.36 +    @Compare public boolean indenpotentSetOfClassloaderIsOK() {
  179.37 +        Thread.currentThread().setContextClassLoader(ClassLoader.getSystemClassLoader());
  179.38 +        return Thread.currentThread().getContextClassLoader() == ClassLoader.getSystemClassLoader();
  179.39 +    }
  179.40 +
  179.41 +    @Factory public static Object[] create() {
  179.42 +        return VMTest.create(ClassLoaderTest.class);
  179.43 +    }
  179.44 +}
   180.1 --- a/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/CompareStringsTest.java	Tue Feb 11 10:48:24 2014 +0100
   180.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/CompareStringsTest.java	Tue Feb 11 13:31:42 2014 +0100
   180.3 @@ -19,7 +19,9 @@
   180.4  
   180.5  import java.io.UnsupportedEncodingException;
   180.6  import java.net.MalformedURLException;
   180.7 +import java.net.URISyntaxException;
   180.8  import java.net.URL;
   180.9 +import java.util.Locale;
  180.10  import org.apidesign.bck2brwsr.vmtest.Compare;
  180.11  import org.apidesign.bck2brwsr.vmtest.VMTest;
  180.12  import org.testng.annotations.Factory;
  180.13 @@ -47,6 +49,14 @@
  180.14          return "Ahoj".equals(null);
  180.15      }
  180.16      
  180.17 +    @Compare public boolean internIsSame() {
  180.18 +        return new String("Ahoj").intern() == another();
  180.19 +    }
  180.20 +    
  180.21 +    private static String another() {
  180.22 +        return new String("Ahoj").intern();
  180.23 +    }
  180.24 +    
  180.25      @Compare public int highByteLenght() {
  180.26          byte[] arr= { 77,97,110,105,102,101,115,116,45,86,101,114,115,105,111,110 };
  180.27          return new String(arr, 0).length();
  180.28 @@ -63,6 +73,10 @@
  180.29      @Compare public static Object compareURLs() throws MalformedURLException {
  180.30          return new URL("http://apidesign.org:8080/wiki/").toExternalForm().toString();
  180.31      }
  180.32 +
  180.33 +    @Compare public static Object compareURLsViaURIs() throws Exception {
  180.34 +        return new URL("http://apidesign.org:8080/wiki/").toURI().toString();
  180.35 +    }
  180.36      
  180.37      @Compare public String deleteLastTwoCharacters() {
  180.38          StringBuilder sb = new StringBuilder();
  180.39 @@ -161,7 +175,28 @@
  180.40          assert res.equals("ba") : "Expecting ba: " + res;
  180.41          return res;
  180.42      }
  180.43 +    
  180.44 +    @Compare public String localeUS() {
  180.45 +        return Locale.US.toString();
  180.46 +    }
  180.47 +    
  180.48 +    @Compare public String localeFrench() {
  180.49 +        return Locale.FRENCH.toString();
  180.50 +    }
  180.51 +    
  180.52 +    
  180.53 +    @Compare public String formatSimple() {
  180.54 +        return String.format((Locale)null, "Hello %s!", "World");
  180.55 +    }
  180.56  
  180.57 +    @Compare public String replaceWithItself() {
  180.58 +        return "org.apidesign.bck2brwsr.core.JavaScriptBody".replace(".", "\\.");
  180.59 +    }
  180.60 +    
  180.61 +    @Compare public boolean matchWithComplicatedRegExp() {
  180.62 +        return "Activates this model instance.".matches("(?sm).*^\\s*@deprecated( |$).*");
  180.63 +    }
  180.64 +    
  180.65      @Factory
  180.66      public static Object[] create() {
  180.67          return VMTest.create(CompareStringsTest.class);
   181.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   181.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/ConcurrentTest.java	Tue Feb 11 13:31:42 2014 +0100
   181.3 @@ -0,0 +1,40 @@
   181.4 +/**
   181.5 + * Back 2 Browser Bytecode Translator
   181.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
   181.7 + *
   181.8 + * This program is free software: you can redistribute it and/or modify
   181.9 + * it under the terms of the GNU General Public License as published by
  181.10 + * the Free Software Foundation, version 2 of the License.
  181.11 + *
  181.12 + * This program is distributed in the hope that it will be useful,
  181.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  181.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  181.15 + * GNU General Public License for more details.
  181.16 + *
  181.17 + * You should have received a copy of the GNU General Public License
  181.18 + * along with this program. Look for COPYING file in the top folder.
  181.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
  181.20 + */
  181.21 +package org.apidesign.bck2brwsr.tck;
  181.22 +
  181.23 +import java.util.concurrent.ConcurrentHashMap;
  181.24 +import org.apidesign.bck2brwsr.vmtest.Compare;
  181.25 +import org.apidesign.bck2brwsr.vmtest.VMTest;
  181.26 +import org.testng.annotations.Factory;
  181.27 +
  181.28 +/**
  181.29 + *
  181.30 + * @author Jaroslav Tulach <jtulach@netbeans.org>
  181.31 + */
  181.32 +public class ConcurrentTest {
  181.33 +    @Compare public String mapIfAbsent() {
  181.34 +        ConcurrentHashMap<String,String> m = new ConcurrentHashMap<>();
  181.35 +        m.putIfAbsent("Ahoj", "Jardo");
  181.36 +        m.putIfAbsent("Ahoj", "Dardo");
  181.37 +        return m.get("Ahoj");
  181.38 +    }
  181.39 +    
  181.40 +    @Factory public static Object[] create() {
  181.41 +        return VMTest.create(ConcurrentTest.class);
  181.42 +    }
  181.43 +}
   182.1 --- a/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/DoubleTest.java	Tue Feb 11 10:48:24 2014 +0100
   182.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/DoubleTest.java	Tue Feb 11 13:31:42 2014 +0100
   182.3 @@ -29,6 +29,10 @@
   182.4      @Compare public boolean parsedDoubleIsDouble() {
   182.5          return Double.valueOf("1.1") instanceof Double;
   182.6      }
   182.7 +
   182.8 +    @Compare public boolean parsedFloatIsFloat() {
   182.9 +        return Float.valueOf("1.1") instanceof Float;
  182.10 +    }
  182.11      
  182.12      @Compare public String integerToString() {
  182.13          return toStr(1);
   183.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   183.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/EnumsTest.java	Tue Feb 11 13:31:42 2014 +0100
   183.3 @@ -0,0 +1,76 @@
   183.4 +/**
   183.5 + * Back 2 Browser Bytecode Translator
   183.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
   183.7 + *
   183.8 + * This program is free software: you can redistribute it and/or modify
   183.9 + * it under the terms of the GNU General Public License as published by
  183.10 + * the Free Software Foundation, version 2 of the License.
  183.11 + *
  183.12 + * This program is distributed in the hope that it will be useful,
  183.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  183.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  183.15 + * GNU General Public License for more details.
  183.16 + *
  183.17 + * You should have received a copy of the GNU General Public License
  183.18 + * along with this program. Look for COPYING file in the top folder.
  183.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
  183.20 + */
  183.21 +package org.apidesign.bck2brwsr.tck;
  183.22 +
  183.23 +import java.util.EnumMap;
  183.24 +import java.util.EnumSet;
  183.25 +import org.apidesign.bck2brwsr.vmtest.Compare;
  183.26 +import org.apidesign.bck2brwsr.vmtest.VMTest;
  183.27 +import org.testng.annotations.Factory;
  183.28 +
  183.29 +/**
  183.30 + *
  183.31 + * @author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
  183.32 + */
  183.33 +public class EnumsTest {
  183.34 +    enum Color {
  183.35 +        B, W;
  183.36 +    }
  183.37 +
  183.38 +    @Compare public String enumSet() {
  183.39 +        try { throw new Exception(); } catch (Exception ex) {}
  183.40 +        EnumSet<Color> c = EnumSet.allOf(Color.class);
  183.41 +        return c.toString();
  183.42 +    }
  183.43 +
  183.44 +    @Compare public String enumSetOneByOne() {
  183.45 +        EnumSet<Color> c = EnumSet.of(Color.B, Color.W);
  183.46 +        return c.toString();
  183.47 +    }
  183.48 +
  183.49 +    @Compare public boolean enumFirstContains() {
  183.50 +        EnumSet<Color> c = EnumSet.of(Color.B);
  183.51 +        return c.contains(Color.B);
  183.52 +    }
  183.53 +
  183.54 +    @Compare public boolean enumFirstDoesNotContains() {
  183.55 +        EnumSet<Color> c = EnumSet.of(Color.B);
  183.56 +        return c.contains(Color.W);
  183.57 +    }
  183.58 +
  183.59 +    @Compare public boolean enumSndContains() {
  183.60 +        EnumSet<Color> c = EnumSet.of(Color.W);
  183.61 +        return c.contains(Color.W);
  183.62 +    }
  183.63 +
  183.64 +    @Compare public boolean enumSecondDoesNotContains() {
  183.65 +        EnumSet<Color> c = EnumSet.of(Color.W);
  183.66 +        return c.contains(Color.B);
  183.67 +    }
  183.68 +
  183.69 +    @Compare public String enumMap() {
  183.70 +        EnumMap<Color,String> c = new EnumMap(Color.class);
  183.71 +        c.put(Color.B, "Black");
  183.72 +        c.put(Color.W, "White");
  183.73 +        return c.toString();
  183.74 +    }
  183.75 +    
  183.76 +    @Factory public static Object[] create() {
  183.77 +        return VMTest.create(EnumsTest.class);
  183.78 +    }
  183.79 +}
   184.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   184.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/ExceptionsTest.java	Tue Feb 11 13:31:42 2014 +0100
   184.3 @@ -0,0 +1,68 @@
   184.4 +/**
   184.5 + * Back 2 Browser Bytecode Translator
   184.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
   184.7 + *
   184.8 + * This program is free software: you can redistribute it and/or modify
   184.9 + * it under the terms of the GNU General Public License as published by
  184.10 + * the Free Software Foundation, version 2 of the License.
  184.11 + *
  184.12 + * This program is distributed in the hope that it will be useful,
  184.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  184.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  184.15 + * GNU General Public License for more details.
  184.16 + *
  184.17 + * You should have received a copy of the GNU General Public License
  184.18 + * along with this program. Look for COPYING file in the top folder.
  184.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
  184.20 + */
  184.21 +package org.apidesign.bck2brwsr.tck;
  184.22 +
  184.23 +import java.io.ByteArrayOutputStream;
  184.24 +import java.io.PrintStream;
  184.25 +import java.io.PrintWriter;
  184.26 +import java.io.StringWriter;
  184.27 +import java.io.UnsupportedEncodingException;
  184.28 +import org.apidesign.bck2brwsr.vmtest.Compare;
  184.29 +import org.apidesign.bck2brwsr.vmtest.VMTest;
  184.30 +import org.testng.annotations.Factory;
  184.31 +
  184.32 +/**
  184.33 + *
  184.34 + * @author Jaroslav Tulach <jtulach@netbeans.org>
  184.35 + */
  184.36 +public class ExceptionsTest {
  184.37 +    @Compare public String firstLineIsTheSame() throws UnsupportedEncodingException {
  184.38 +        MyException ex = new MyException("Hello");
  184.39 +        ByteArrayOutputStream out = new ByteArrayOutputStream();
  184.40 +        PrintStream ps = new PrintStream(out);
  184.41 +        ex.printStackTrace(ps);
  184.42 +        ps.flush();
  184.43 +        
  184.44 +        String s = new String(out.toByteArray(), "UTF-8");
  184.45 +        int newLine = s.indexOf('\n');
  184.46 +        return s.substring(0, newLine);
  184.47 +    }
  184.48 +
  184.49 +    @Compare public String firstLineIsTheSameWithWriter() throws UnsupportedEncodingException {
  184.50 +        MyException ex = new MyException("Hello");
  184.51 +        StringWriter sw = new StringWriter();
  184.52 +        PrintWriter pw = new PrintWriter(sw);
  184.53 +        ex.printStackTrace(pw);
  184.54 +        pw.flush();
  184.55 +        
  184.56 +        String s = sw.toString();
  184.57 +        int newLine = s.indexOf('\n');
  184.58 +        return s.substring(0, newLine);
  184.59 +    }
  184.60 +    
  184.61 +    static class MyException extends Exception {
  184.62 +        public MyException(String message) {
  184.63 +            super(message);
  184.64 +        }
  184.65 +    }
  184.66 +    
  184.67 +    
  184.68 +    @Factory public static Object[] create() {
  184.69 +        return VMTest.create(ExceptionsTest.class);
  184.70 +    }
  184.71 +}
   185.1 --- a/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/LongArithmeticTest.java	Tue Feb 11 10:48:24 2014 +0100
   185.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/LongArithmeticTest.java	Tue Feb 11 13:31:42 2014 +0100
   185.3 @@ -304,6 +304,14 @@
   185.4      @Compare public long shiftL3() {
   185.5          return shl(0x00fa37d7763e0ca1l, 45);
   185.6      }
   185.7 +    
   185.8 +    @Compare public long shiftL4() {
   185.9 +        return shl(0x00fa37d7763e0ca1l, 0);
  185.10 +    }
  185.11 +    
  185.12 +    @Compare public long shiftL5() {
  185.13 +        return shl(0x00fa37d7763e0ca1l, 70);
  185.14 +    }
  185.15  
  185.16      @Compare public long shiftR1() {
  185.17          return shr(0x00fa37d7763e0ca1l, 5);
  185.18 @@ -316,6 +324,14 @@
  185.19      @Compare public long shiftR3() {
  185.20          return shr(0x00fa37d7763e0ca1l, 45);
  185.21      }
  185.22 +    
  185.23 +    @Compare public long shiftR4() {
  185.24 +        return shr(0x00fa37d7763e0ca1l, 0);
  185.25 +    }
  185.26 +    
  185.27 +    @Compare public long shiftR5() {
  185.28 +        return shr(0x00fa37d7763e0ca1l, 70);
  185.29 +    }
  185.30  
  185.31      @Compare public long uShiftR1() {
  185.32          return ushr(0x00fa37d7763e0ca1l, 5);
  185.33 @@ -324,14 +340,30 @@
  185.34      @Compare public long uShiftR2() {
  185.35          return ushr(0x00fa37d7763e0ca1l, 45);
  185.36      }
  185.37 +    
  185.38 +    @Compare public long uShiftR3() {
  185.39 +        return ushr(0x00fa37d7763e0ca1l, 0);
  185.40 +    }
  185.41 +    
  185.42 +    @Compare public long uShiftR4() {
  185.43 +        return ushr(0x00fa37d7763e0ca1l, 70);
  185.44 +    }
  185.45  
  185.46 -    @Compare public long uShiftR3() {
  185.47 +    @Compare public long uShiftR5() {
  185.48          return ushr(0xf0fa37d7763e0ca1l, 5);
  185.49      }
  185.50  
  185.51 -    @Compare public long uShiftR4() {
  185.52 +    @Compare public long uShiftR6() {
  185.53          return ushr(0xf0fa37d7763e0ca1l, 45);
  185.54      }
  185.55 +    
  185.56 +    @Compare public long uShiftR7() {
  185.57 +        return ushr(0xf0fa37d7763e0ca1l, 0);
  185.58 +    }
  185.59 +    
  185.60 +    @Compare public long uShiftR8() {
  185.61 +        return ushr(0xf0fa37d7763e0ca1l, 70);
  185.62 +    }
  185.63  
  185.64      @Compare public long and1() {
  185.65          return and(0x00fa37d7763e0ca1l, 0xa7b3432fff00123el);
   186.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   186.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/ProxyTest.java	Tue Feb 11 13:31:42 2014 +0100
   186.3 @@ -0,0 +1,71 @@
   186.4 +/**
   186.5 + * Back 2 Browser Bytecode Translator
   186.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
   186.7 + *
   186.8 + * This program is free software: you can redistribute it and/or modify
   186.9 + * it under the terms of the GNU General Public License as published by
  186.10 + * the Free Software Foundation, version 2 of the License.
  186.11 + *
  186.12 + * This program is distributed in the hope that it will be useful,
  186.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  186.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  186.15 + * GNU General Public License for more details.
  186.16 + *
  186.17 + * You should have received a copy of the GNU General Public License
  186.18 + * along with this program. Look for COPYING file in the top folder.
  186.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
  186.20 + */
  186.21 +package org.apidesign.bck2brwsr.tck;
  186.22 +
  186.23 +import java.lang.reflect.InvocationHandler;
  186.24 +import java.lang.reflect.Method;
  186.25 +import java.lang.reflect.Proxy;
  186.26 +import org.apidesign.bck2brwsr.vmtest.Compare;
  186.27 +import org.apidesign.bck2brwsr.vmtest.VMTest;
  186.28 +import org.testng.annotations.Factory;
  186.29 +
  186.30 +/**
  186.31 + *
  186.32 + * @author Jaroslav Tulach <jtulach@netbeans.org>
  186.33 + */
  186.34 +public class ProxyTest {
  186.35 +    @Compare public String generateAnnotation() throws Exception {
  186.36 +        class InvHandler implements InvocationHandler {
  186.37 +            @Override
  186.38 +            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  186.39 +                return "Joe Hacker";
  186.40 +            }
  186.41 +        }
  186.42 +        Anno anno = (Anno) Proxy.newProxyInstance(
  186.43 +            Anno.class.getClassLoader(), 
  186.44 +            new Class[] { Anno.class }, 
  186.45 +            new InvHandler()
  186.46 +        );
  186.47 +        return anno.name();
  186.48 +    }
  186.49 +
  186.50 +    @Compare public int getPrimitiveType() throws Exception {
  186.51 +        class InvHandler implements InvocationHandler {
  186.52 +            @Override
  186.53 +            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  186.54 +                return 40;
  186.55 +            }
  186.56 +        }
  186.57 +        Anno anno = (Anno) Proxy.newProxyInstance(
  186.58 +            Anno.class.getClassLoader(), 
  186.59 +            new Class[] { Anno.class }, 
  186.60 +            new InvHandler()
  186.61 +        );
  186.62 +        return 2 + anno.age();
  186.63 +    }
  186.64 +    
  186.65 +    public static @interface Anno {
  186.66 +        public String name();
  186.67 +        public int age();
  186.68 +    }
  186.69 +    
  186.70 +    @Factory
  186.71 +    public static Object[] create() {
  186.72 +        return VMTest.create(ProxyTest.class);
  186.73 +    }
  186.74 +}
   187.1 --- a/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/ReflectionArrayTest.java	Tue Feb 11 10:48:24 2014 +0100
   187.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/ReflectionArrayTest.java	Tue Feb 11 13:31:42 2014 +0100
   187.3 @@ -34,6 +34,11 @@
   187.4          return arr.length;
   187.5      }
   187.6      
   187.7 +    @Compare public String indexOutOfBounds() {
   187.8 +        String[] arr = { null, null };
   187.9 +        return arr[2];
  187.10 +    }
  187.11 +    
  187.12      @Compare public int reflectiveLengthOfStringArray() {
  187.13          Object arr = Array.newInstance(String.class, 10);
  187.14          return Array.getLength(arr);
   188.1 --- a/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/ReflectionTest.java	Tue Feb 11 10:48:24 2014 +0100
   188.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/ReflectionTest.java	Tue Feb 11 13:31:42 2014 +0100
   188.3 @@ -19,7 +19,9 @@
   188.4  
   188.5  import java.lang.annotation.Retention;
   188.6  import java.lang.annotation.RetentionPolicy;
   188.7 +import java.lang.reflect.Constructor;
   188.8  import java.lang.reflect.Method;
   188.9 +import java.lang.reflect.Proxy;
  188.10  import java.util.Arrays;
  188.11  import java.util.Collections;
  188.12  import java.util.List;
  188.13 @@ -72,6 +74,18 @@
  188.14      @Compare public String isRunnableHasRunMethod() throws NoSuchMethodException {
  188.15          return Runnable.class.getMethod("run").getName();
  188.16      }
  188.17 +
  188.18 +    @Compare public String isRunnableDeclaresRunMethod() throws NoSuchMethodException {
  188.19 +        return Runnable.class.getDeclaredMethod("run").getName();
  188.20 +    }
  188.21 +    
  188.22 +    @Compare public String intValue() throws Exception {
  188.23 +        return Integer.class.getConstructor(int.class).newInstance(10).toString();
  188.24 +    }
  188.25 +    
  188.26 +    @Compare public String getMethodWithArray() throws Exception {
  188.27 +        return Proxy.class.getMethod("getProxyClass", ClassLoader.class, Class[].class).getName();
  188.28 +    }
  188.29      
  188.30      @Compare public String namesOfMethods() {
  188.31          StringBuilder sb = new StringBuilder();
  188.32 @@ -86,6 +100,19 @@
  188.33          return sb.toString();
  188.34      }
  188.35  
  188.36 +    @Compare public String paramsOfConstructors() {
  188.37 +        StringBuilder sb = new StringBuilder();
  188.38 +        String[] arr = new String[20];
  188.39 +        int i = 0;
  188.40 +        for (Constructor<?> m : StaticUse.class.getConstructors()) {
  188.41 +            arr[i++] = m.getName();
  188.42 +        }
  188.43 +        for (String s : sort(arr, i)) {
  188.44 +            sb.append(s).append("\n");
  188.45 +        }
  188.46 +        return sb.toString();
  188.47 +    }
  188.48 +
  188.49      @Compare public String namesOfDeclaringClassesOfMethods() {
  188.50          StringBuilder sb = new StringBuilder();
  188.51          String[] arr = new String[20];
   189.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   189.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/RegExpReplaceAllTest.java	Tue Feb 11 13:31:42 2014 +0100
   189.3 @@ -0,0 +1,54 @@
   189.4 +/**
   189.5 + * Back 2 Browser Bytecode Translator
   189.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
   189.7 + *
   189.8 + * This program is free software: you can redistribute it and/or modify
   189.9 + * it under the terms of the GNU General Public License as published by
  189.10 + * the Free Software Foundation, version 2 of the License.
  189.11 + *
  189.12 + * This program is distributed in the hope that it will be useful,
  189.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  189.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  189.15 + * GNU General Public License for more details.
  189.16 + *
  189.17 + * You should have received a copy of the GNU General Public License
  189.18 + * along with this program. Look for COPYING file in the top folder.
  189.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
  189.20 + */
  189.21 +package org.apidesign.bck2brwsr.tck;
  189.22 +
  189.23 +import org.apidesign.bck2brwsr.vmtest.Compare;
  189.24 +import org.apidesign.bck2brwsr.vmtest.VMTest;
  189.25 +import org.testng.annotations.Factory;
  189.26 +
  189.27 +/**
  189.28 + *
  189.29 + * @author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
  189.30 + */
  189.31 +public class RegExpReplaceAllTest {
  189.32 +
  189.33 +    @Compare public String replaceAll() {
  189.34 +        return "JavaScript".replaceAll("Script", "One");
  189.35 +    }
  189.36 +
  189.37 +    @Compare public String replaceAllTwice() {
  189.38 +        return "Script JavaScript!".replaceAll("Script", "One");
  189.39 +    }
  189.40 +
  189.41 +    
  189.42 +    @Compare public String replaceAllRegexp() {
  189.43 +        return "JavaScript".replaceAll("S....t", "One");
  189.44 +    }
  189.45 +
  189.46 +    @Compare public String replaceAllRegexpTwice() {
  189.47 +        return "Script JavaScript!".replaceAll("S....t", "One");
  189.48 +    }
  189.49 +
  189.50 +    @Compare public String replaceFirstRegexpOnly() {
  189.51 +        return "Script JavaScript!".replaceFirst("S....t", "One");
  189.52 +    }
  189.53 +    
  189.54 +    @Factory public static Object[] create() {
  189.55 +        return VMTest.create(RegExpReplaceAllTest.class);
  189.56 +    }
  189.57 +}
   190.1 --- a/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/RegExpSplitTest.java	Tue Feb 11 10:48:24 2014 +0100
   190.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/RegExpSplitTest.java	Tue Feb 11 13:31:42 2014 +0100
   190.3 @@ -32,6 +32,10 @@
   190.4          return Arrays.asList("How are you today?".split(" "));
   190.5      }
   190.6  
   190.7 +    public @Compare String splitNewline() {
   190.8 +        return Arrays.toString("initializer must be able to complete normally".split("\n"));
   190.9 +    }
  190.10 +
  190.11      public @Compare Object splitSpaceTrimMinusOne() {
  190.12          return Arrays.asList(" How are you today? ".split(" ", -1));
  190.13      }
   191.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   191.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/ResourceBundleTest.java	Tue Feb 11 13:31:42 2014 +0100
   191.3 @@ -0,0 +1,45 @@
   191.4 +/**
   191.5 + * Back 2 Browser Bytecode Translator
   191.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
   191.7 + *
   191.8 + * This program is free software: you can redistribute it and/or modify
   191.9 + * it under the terms of the GNU General Public License as published by
  191.10 + * the Free Software Foundation, version 2 of the License.
  191.11 + *
  191.12 + * This program is distributed in the hope that it will be useful,
  191.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  191.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  191.15 + * GNU General Public License for more details.
  191.16 + *
  191.17 + * You should have received a copy of the GNU General Public License
  191.18 + * along with this program. Look for COPYING file in the top folder.
  191.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
  191.20 + */
  191.21 +package org.apidesign.bck2brwsr.tck;
  191.22 +
  191.23 +import java.net.URL;
  191.24 +import java.util.ResourceBundle;
  191.25 +import org.apidesign.bck2brwsr.vmtest.Compare;
  191.26 +import org.apidesign.bck2brwsr.vmtest.VMTest;
  191.27 +import org.testng.annotations.Factory;
  191.28 +
  191.29 +/**
  191.30 + *
  191.31 + * @author Jaroslav Tulach <jtulach@netbeans.org>
  191.32 + */
  191.33 +public class ResourceBundleTest {
  191.34 +    
  191.35 +    @Compare public String readFromBundle() throws Exception {
  191.36 +        ResourceBundle b = ResourceBundle.getBundle("org/apidesign/bck2brwsr/tck/Bundle");
  191.37 +        return b.getString("KEY");
  191.38 +    }
  191.39 +    
  191.40 +    @Compare public String toURIFromURL() throws Exception {
  191.41 +        URL u = new URL("http://apidesign.org");
  191.42 +        return u.toURI().toString();
  191.43 +    }
  191.44 +    
  191.45 +    @Factory public static Object[] create() {
  191.46 +        return VMTest.create(ResourceBundleTest.class);
  191.47 +    }
  191.48 +}
   192.1 --- a/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/ResourcesTest.java	Tue Feb 11 10:48:24 2014 +0100
   192.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/ResourcesTest.java	Tue Feb 11 13:31:42 2014 +0100
   192.3 @@ -17,7 +17,10 @@
   192.4   */
   192.5  package org.apidesign.bck2brwsr.tck;
   192.6  
   192.7 +import java.io.IOException;
   192.8  import java.io.InputStream;
   192.9 +import java.net.URL;
  192.10 +import java.util.Enumeration;
  192.11  import org.apidesign.bck2brwsr.vmtest.Compare;
  192.12  import org.apidesign.bck2brwsr.vmtest.VMTest;
  192.13  import org.testng.annotations.Factory;
  192.14 @@ -27,16 +30,62 @@
  192.15   * @author Jaroslav Tulach <jtulach@netbeans.org>
  192.16   */
  192.17  public class ResourcesTest {
  192.18 +    @Compare public String allManifests() throws Exception {
  192.19 +        Enumeration<URL> en = ClassLoader.getSystemResources("META-INF/MANIFEST.MF");
  192.20 +        assert en.hasMoreElements() : "Should have at least one manifest";
  192.21 +        String first = readString(en.nextElement().openStream());
  192.22 +        boolean different = false;
  192.23 +        int cnt = 1;
  192.24 +        while (en.hasMoreElements()) {
  192.25 +            URL url = en.nextElement();
  192.26 +            String now = readString(url.openStream());
  192.27 +            if (!first.equals(now)) {
  192.28 +                different = true;
  192.29 +            }
  192.30 +            cnt++;
  192.31 +            if (cnt > 500) {
  192.32 +                throw new IllegalStateException(
  192.33 +                    "Giving up. First manifest:\n" + first + 
  192.34 +                    "\nLast manifest:\n" + now
  192.35 +                );
  192.36 +            }
  192.37 +        }
  192.38 +        assert different : "Not all manifests should look like first one:\n" + first;
  192.39 +        return "" + cnt;
  192.40 +    }
  192.41      
  192.42      @Compare public String readResourceAsStream() throws Exception {
  192.43          InputStream is = getClass().getResourceAsStream("Resources.txt");
  192.44 -        byte[] b = new byte[30];
  192.45 -        int len = is.read(b);
  192.46 +        return readString(is);
  192.47 +    }
  192.48 +    
  192.49 +    @Compare public String readResourceViaConnection() throws Exception {
  192.50 +        InputStream is = getClass().getResource("Resources.txt").openConnection().getInputStream();
  192.51 +        return readString(is);
  192.52 +    }
  192.53 +
  192.54 +    private String readString(InputStream is) throws IOException {
  192.55          StringBuilder sb = new StringBuilder();
  192.56 -        for (int i = 0; i < len; i++) {
  192.57 -            sb.append((char)b[i]);
  192.58 +        byte[] b = new byte[512];
  192.59 +        for (;;) { 
  192.60 +            int len = is.read(b);
  192.61 +            if (len == -1) {
  192.62 +                return sb.toString();
  192.63 +            }
  192.64 +            for (int i = 0; i < len; i++) {
  192.65 +                sb.append((char)b[i]);
  192.66 +            }
  192.67          }
  192.68 -        return sb.toString();
  192.69 +    }
  192.70 +
  192.71 +    @Compare public String readResourceAsStreamFromClassLoader() throws Exception {
  192.72 +        InputStream is = getClass().getClassLoader().getResourceAsStream("org/apidesign/bck2brwsr/tck/Resources.txt");
  192.73 +        return readString(is);
  192.74 +    }
  192.75 +    
  192.76 +    @Compare public String toURIFromURL() throws Exception {
  192.77 +        URL u = new URL("http://apidesign.org");
  192.78 +        return u.toURI().toString();
  192.79      }
  192.80      
  192.81      @Factory public static Object[] create() {
   193.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   193.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/SystemTest.java	Tue Feb 11 13:31:42 2014 +0100
   193.3 @@ -0,0 +1,65 @@
   193.4 +/**
   193.5 + * Back 2 Browser Bytecode Translator
   193.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
   193.7 + *
   193.8 + * This program is free software: you can redistribute it and/or modify
   193.9 + * it under the terms of the GNU General Public License as published by
  193.10 + * the Free Software Foundation, version 2 of the License.
  193.11 + *
  193.12 + * This program is distributed in the hope that it will be useful,
  193.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  193.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  193.15 + * GNU General Public License for more details.
  193.16 + *
  193.17 + * You should have received a copy of the GNU General Public License
  193.18 + * along with this program. Look for COPYING file in the top folder.
  193.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
  193.20 + */
  193.21 +package org.apidesign.bck2brwsr.tck;
  193.22 +
  193.23 +import java.io.ByteArrayOutputStream;
  193.24 +import java.io.PrintStream;
  193.25 +import org.apidesign.bck2brwsr.core.ExtraJavaScript;
  193.26 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
  193.27 +import org.apidesign.bck2brwsr.vmtest.Compare;
  193.28 +import org.apidesign.bck2brwsr.vmtest.VMTest;
  193.29 +import org.testng.annotations.Factory;
  193.30 +
  193.31 +/**
  193.32 + *
  193.33 + * @author Jaroslav Tulach <jtulach@netbeans.org>
  193.34 + */
  193.35 +@ExtraJavaScript(resource = "/org/apidesign/bck2brwsr/tck/console.js")
  193.36 +public class SystemTest {
  193.37 +    @Compare public boolean nonNullOSName() {
  193.38 +        return System.getProperty("os.name") != null;
  193.39 +    }
  193.40 +
  193.41 +    @Compare public String captureStdOut() throws Exception {
  193.42 +        Object capture = initCapture();
  193.43 +        System.out.println("Ahoj");
  193.44 +        return textCapture(capture);
  193.45 +    }
  193.46 +    
  193.47 +    @JavaScriptBody(args = {}, body = ""
  193.48 +        + "var lines = [];"
  193.49 +        + "console.log = function(l) { lines.push(l); };"
  193.50 +        + "return lines;")
  193.51 +    Object initCapture() {
  193.52 +        ByteArrayOutputStream os = new ByteArrayOutputStream();
  193.53 +        PrintStream ps = new PrintStream(os);
  193.54 +        
  193.55 +        System.setOut(ps);
  193.56 +        return os;
  193.57 +    }
  193.58 +    
  193.59 +    @JavaScriptBody(args = { "o" }, body = "return o.join('');")
  193.60 +    String textCapture(Object o) throws java.io.IOException {
  193.61 +        ByteArrayOutputStream b = (ByteArrayOutputStream) o;
  193.62 +        return new String(b.toByteArray(), "UTF-8");
  193.63 +    }
  193.64 +    
  193.65 +    @Factory public static Object[] create() {
  193.66 +        return VMTest.create(SystemTest.class);
  193.67 +    }
  193.68 +}
   194.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   194.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/TimerTest.java	Tue Feb 11 13:31:42 2014 +0100
   194.3 @@ -0,0 +1,81 @@
   194.4 +/**
   194.5 + * Back 2 Browser Bytecode Translator
   194.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
   194.7 + *
   194.8 + * This program is free software: you can redistribute it and/or modify
   194.9 + * it under the terms of the GNU General Public License as published by
  194.10 + * the Free Software Foundation, version 2 of the License.
  194.11 + *
  194.12 + * This program is distributed in the hope that it will be useful,
  194.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  194.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  194.15 + * GNU General Public License for more details.
  194.16 + *
  194.17 + * You should have received a copy of the GNU General Public License
  194.18 + * along with this program. Look for COPYING file in the top folder.
  194.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
  194.20 + */
  194.21 +package org.apidesign.bck2brwsr.tck;
  194.22 +
  194.23 +import java.util.Timer;
  194.24 +import java.util.TimerTask;
  194.25 +import org.apidesign.bck2brwsr.vmtest.BrwsrTest;
  194.26 +import org.apidesign.bck2brwsr.vmtest.VMTest;
  194.27 +import org.testng.annotations.Factory;
  194.28 +
  194.29 +/**
  194.30 + *
  194.31 + * @author Jaroslav Tulach <jtulach@netbeans.org>
  194.32 + */
  194.33 +public class TimerTest {
  194.34 +    int miss;
  194.35 +    int exec;
  194.36 +    
  194.37 +    public TimerTest() {
  194.38 +    }
  194.39 +    
  194.40 +    @BrwsrTest public void scheduleTick() throws Exception {
  194.41 +        Timer t = new Timer("MyTest");
  194.42 +        class TT extends TimerTask {
  194.43 +            @Override
  194.44 +            public void run() {
  194.45 +                exec++;
  194.46 +            }
  194.47 +        }
  194.48 +        TT task = new TT();
  194.49 +        t.schedule(task, 15);
  194.50 +        
  194.51 +        if (exec == 0) {
  194.52 +            miss++;
  194.53 +            throw new InterruptedException();
  194.54 +        }
  194.55 +        
  194.56 +        assert exec == 1 : "One exec: " + exec;
  194.57 +        assert miss == 1 : "One miss: " + miss;
  194.58 +    }
  194.59 +    
  194.60 +    @BrwsrTest public void repeatedTicks() throws Exception {
  194.61 +        Timer t = new Timer("MyTest");
  194.62 +        class TT extends TimerTask {
  194.63 +            @Override
  194.64 +            public void run() {
  194.65 +                exec++;
  194.66 +            }
  194.67 +        }
  194.68 +        TT task = new TT();
  194.69 +        t.scheduleAtFixedRate(task, 15, 10);
  194.70 +        
  194.71 +        if (exec != 2) {
  194.72 +            miss++;
  194.73 +            throw new InterruptedException();
  194.74 +        }
  194.75 +        
  194.76 +        assert exec == 2 : "Two execs: " + exec;
  194.77 +        assert miss == 2 : "Two misses: " + miss;
  194.78 +    }
  194.79 +    
  194.80 +    @Factory public static Object[] create() {
  194.81 +        return VMTest.create(TimerTest.class);
  194.82 +    }
  194.83 +    
  194.84 +}
   195.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   195.2 +++ b/rt/emul/compact/src/test/resources/org/apidesign/bck2brwsr/tck/Bundle.properties	Tue Feb 11 13:31:42 2014 +0100
   195.3 @@ -0,0 +1,2 @@
   195.4 +KEY=Value
   195.5 +
   196.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   196.2 +++ b/rt/emul/compact/src/test/resources/org/apidesign/bck2brwsr/tck/console.js	Tue Feb 11 13:31:42 2014 +0100
   196.3 @@ -0,0 +1,22 @@
   196.4 +/**
   196.5 + * Back 2 Browser Bytecode Translator
   196.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
   196.7 + *
   196.8 + * This program is free software: you can redistribute it and/or modify
   196.9 + * it under the terms of the GNU General Public License as published by
  196.10 + * the Free Software Foundation, version 2 of the License.
  196.11 + *
  196.12 + * This program is distributed in the hope that it will be useful,
  196.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  196.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  196.15 + * GNU General Public License for more details.
  196.16 + *
  196.17 + * You should have received a copy of the GNU General Public License
  196.18 + * along with this program. Look for COPYING file in the top folder.
  196.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
  196.20 + */
  196.21 +
  196.22 +if (typeof console === 'undefined') {
  196.23 +    console = {};
  196.24 +}
  196.25 +
   197.1 --- a/rt/emul/mini/pom.xml	Tue Feb 11 10:48:24 2014 +0100
   197.2 +++ b/rt/emul/mini/pom.xml	Tue Feb 11 13:31:42 2014 +0100
   197.3 @@ -31,12 +31,49 @@
   197.4    <build>
   197.5        <plugins>
   197.6            <plugin>
   197.7 +              <artifactId>maven-antrun-plugin</artifactId>
   197.8 +              <version>1.7</version>
   197.9 +              <executions>
  197.10 +                  <execution>
  197.11 +                      <phase>generate-sources</phase>
  197.12 +                      <configuration>
  197.13 +                          <target>
  197.14 +                              <mkdir dir="${project.build.directory}/bootcp" />
  197.15 +                              <copy todir="${project.build.directory}/bootcp">
  197.16 +                                  <resources>
  197.17 +                                      <!-- copy all resources that are in
  197.18 +                                        compact profile, but are referenced from
  197.19 +                                        the mini profile
  197.20 +                                      -->
  197.21 +                                      <javaresource name="java/net/URI.class" />
  197.22 +                                      <javaresource name="java/net/URISyntaxException.class" />
  197.23 +                                      <javaresource name="java/net/URLConnection.class" />
  197.24 +                                      <javaresource name="java/util/Locale.class" />
  197.25 +                                      <javaresource name="java/io/OutputStream.class" />
  197.26 +                                      <javaresource name="java/io/FilterOutputStream.class" />
  197.27 +                                      <javaresource name="java/io/PrintStream.class" />
  197.28 +                                      <javaresource name="java/io/PrintWriter.class" />
  197.29 +                                      <javaresource name="java/io/Writer.class" />
  197.30 +                                  </resources>
  197.31 +                              </copy>
  197.32 +                          </target>
  197.33 +                      </configuration>
  197.34 +                      <goals>
  197.35 +                          <goal>run</goal>
  197.36 +                      </goals>
  197.37 +                  </execution>
  197.38 +              </executions>
  197.39 +          </plugin>
  197.40 +          <plugin>
  197.41                <groupId>org.apache.maven.plugins</groupId>
  197.42                <artifactId>maven-compiler-plugin</artifactId>
  197.43                <version>2.5.1</version>
  197.44                <configuration>
  197.45                    <compilerArguments>
  197.46 -                      <bootclasspath>netbeans.ignore.jdk.bootsclasspath</bootclasspath>
  197.47 +                      <!--
  197.48 +                        <bootclasspath>netbeans.ignore.jdk.bootsclasspath</bootclasspath>
  197.49 +                      -->
  197.50 +                      <bootclasspath>${project.build.directory}/bootcp/</bootclasspath>
  197.51                    </compilerArguments>
  197.52                   <source>1.7</source>
  197.53                   <target>1.7</target>
   198.1 --- a/rt/emul/mini/src/main/java/java/lang/Character.java	Tue Feb 11 10:48:24 2014 +0100
   198.2 +++ b/rt/emul/mini/src/main/java/java/lang/Character.java	Tue Feb 11 13:31:42 2014 +0100
   198.3 @@ -572,6 +572,46 @@
   198.4       */
   198.5      public static final int MAX_CODE_POINT = 0X10FFFF;
   198.6  
   198.7 +    public static boolean isAlphabetic(int ch) {
   198.8 +        throw new UnsupportedOperationException("isAlphabetic: " + (char)ch);
   198.9 +    }
  198.10 +
  198.11 +    public static boolean isIdeographic(int ch) {
  198.12 +        throw new UnsupportedOperationException("isIdeographic: " + (char)ch);
  198.13 +    }
  198.14 +
  198.15 +    public static boolean isLowerCase(int ch) {
  198.16 +        throw new UnsupportedOperationException("isLowerCase: " + (char)ch);
  198.17 +    }
  198.18 +
  198.19 +    public static boolean isUpperCase(int ch) {
  198.20 +        throw new UnsupportedOperationException("isUpperCase: " + (char)ch);
  198.21 +    }
  198.22 +
  198.23 +    public static boolean isMirrored(int ch) {
  198.24 +        throw new UnsupportedOperationException("isMirrored: " + (char)ch);
  198.25 +    }
  198.26 +
  198.27 +    public static boolean isIdentifierIgnorable(int ch) {
  198.28 +        throw new UnsupportedOperationException("isIdentifierIgnorable: " + (char)ch);
  198.29 +    }
  198.30 +
  198.31 +    public static boolean isUnicodeIdentifierPart(int ch) {
  198.32 +        throw new UnsupportedOperationException("isUnicodeIdentifierPart: " + (char)ch);
  198.33 +    }
  198.34 +
  198.35 +    public static boolean isUnicodeIdentifierStart(int ch) {
  198.36 +        throw new UnsupportedOperationException("isUnicodeIdentifierStart: " + (char)ch);
  198.37 +    }
  198.38 +
  198.39 +    public static char toUpperCase(int ch) {
  198.40 +        throw new UnsupportedOperationException("toUpperCase: " + (char)ch);
  198.41 +    }
  198.42 +
  198.43 +    public static int toLowerCase(int ch) {
  198.44 +        throw new UnsupportedOperationException("toLowerCase: " + (char)ch);
  198.45 +    }
  198.46 +
  198.47  
  198.48      /**
  198.49       * Instances of this class represent particular subsets of the Unicode
  198.50 @@ -1892,8 +1932,8 @@
  198.51          return fromCodeChars(codePoint).matches("\\w");
  198.52      }
  198.53      
  198.54 -    static int getType(int x) {
  198.55 -        throw new UnsupportedOperationException();
  198.56 +    public static int getType(int x) {
  198.57 +        throw new UnsupportedOperationException("getType: " + (char)x);
  198.58      }
  198.59   
  198.60      /**
  198.61 @@ -1955,7 +1995,8 @@
  198.62      public static boolean isJavaIdentifierStart(int codePoint) {
  198.63          return 
  198.64              ('A' <= codePoint && codePoint <= 'Z') ||
  198.65 -            ('a' <= codePoint && codePoint <= 'z');
  198.66 +            ('a' <= codePoint && codePoint <= 'z') ||
  198.67 +            codePoint == '$';
  198.68      }
  198.69  
  198.70      /**
  198.71 @@ -2375,7 +2416,14 @@
  198.72       * @since   1.5
  198.73       */
  198.74      public static boolean isWhitespace(int codePoint) {
  198.75 -        throw new UnsupportedOperationException();
  198.76 +        if (
  198.77 +            codePoint == SPACE_SEPARATOR || 
  198.78 +            codePoint == LINE_SEPARATOR || 
  198.79 +            codePoint == PARAGRAPH_SEPARATOR
  198.80 +        ) {
  198.81 +            return true;
  198.82 +        }
  198.83 +        return false;
  198.84      }
  198.85  
  198.86      /**
   199.1 --- a/rt/emul/mini/src/main/java/java/lang/Class.java	Tue Feb 11 10:48:24 2014 +0100
   199.2 +++ b/rt/emul/mini/src/main/java/java/lang/Class.java	Tue Feb 11 13:31:42 2014 +0100
   199.3 @@ -29,6 +29,7 @@
   199.4  import org.apidesign.bck2brwsr.emul.reflect.AnnotationImpl;
   199.5  import java.io.InputStream;
   199.6  import java.lang.annotation.Annotation;
   199.7 +import java.lang.reflect.Constructor;
   199.8  import java.lang.reflect.Field;
   199.9  import java.lang.reflect.Method;
  199.10  import java.lang.reflect.TypeVariable;
  199.11 @@ -631,6 +632,20 @@
  199.12          return getAccess();
  199.13      }
  199.14  
  199.15 +    /**
  199.16 +     * If the class or interface represented by this {@code Class} object
  199.17 +     * is a member of another class, returns the {@code Class} object
  199.18 +     * representing the class in which it was declared.  This method returns
  199.19 +     * null if this class or interface is not a member of any other class.  If
  199.20 +     * this {@code Class} object represents an array class, a primitive
  199.21 +     * type, or void,then this method returns null.
  199.22 +     *
  199.23 +     * @return the declaring class for this class
  199.24 +     * @since JDK1.1
  199.25 +     */
  199.26 +    public Class<?> getDeclaringClass() {
  199.27 +        throw new SecurityException();
  199.28 +    }
  199.29  
  199.30      /**
  199.31       * Returns the simple name of the underlying class as given in the
  199.32 @@ -975,6 +990,319 @@
  199.33      }
  199.34      
  199.35      /**
  199.36 +     * Returns an array of {@code Field} objects reflecting all the fields
  199.37 +     * declared by the class or interface represented by this
  199.38 +     * {@code Class} object. This includes public, protected, default
  199.39 +     * (package) access, and private fields, but excludes inherited fields.
  199.40 +     * The elements in the array returned are not sorted and are not in any
  199.41 +     * particular order.  This method returns an array of length 0 if the class
  199.42 +     * or interface declares no fields, or if this {@code Class} object
  199.43 +     * represents a primitive type, an array class, or void.
  199.44 +     *
  199.45 +     * <p> See <em>The Java Language Specification</em>, sections 8.2 and 8.3.
  199.46 +     *
  199.47 +     * @return    the array of {@code Field} objects representing all the
  199.48 +     * declared fields of this class
  199.49 +     * @exception  SecurityException
  199.50 +     *             If a security manager, <i>s</i>, is present and any of the
  199.51 +     *             following conditions is met:
  199.52 +     *
  199.53 +     *             <ul>
  199.54 +     *
  199.55 +     *             <li> invocation of
  199.56 +     *             {@link SecurityManager#checkMemberAccess
  199.57 +     *             s.checkMemberAccess(this, Member.DECLARED)} denies
  199.58 +     *             access to the declared fields within this class
  199.59 +     *
  199.60 +     *             <li> the caller's class loader is not the same as or an
  199.61 +     *             ancestor of the class loader for the current class and
  199.62 +     *             invocation of {@link SecurityManager#checkPackageAccess
  199.63 +     *             s.checkPackageAccess()} denies access to the package
  199.64 +     *             of this class
  199.65 +     *
  199.66 +     *             </ul>
  199.67 +     *
  199.68 +     * @since JDK1.1
  199.69 +     */
  199.70 +    public Field[] getDeclaredFields() throws SecurityException {
  199.71 +        throw new SecurityException();
  199.72 +    }
  199.73 +
  199.74 +    /**
  199.75 +     * <b>Bck2Brwsr</b> emulation can only seek public methods, otherwise it
  199.76 +     * throws a {@code SecurityException}.
  199.77 +     * <p>
  199.78 +     * Returns a {@code Method} object that reflects the specified
  199.79 +     * declared method of the class or interface represented by this
  199.80 +     * {@code Class} object. The {@code name} parameter is a
  199.81 +     * {@code String} that specifies the simple name of the desired
  199.82 +     * method, and the {@code parameterTypes} parameter is an array of
  199.83 +     * {@code Class} objects that identify the method's formal parameter
  199.84 +     * types, in declared order.  If more than one method with the same
  199.85 +     * parameter types is declared in a class, and one of these methods has a
  199.86 +     * return type that is more specific than any of the others, that method is
  199.87 +     * returned; otherwise one of the methods is chosen arbitrarily.  If the
  199.88 +     * name is "&lt;init&gt;"or "&lt;clinit&gt;" a {@code NoSuchMethodException}
  199.89 +     * is raised.
  199.90 +     *
  199.91 +     * @param name the name of the method
  199.92 +     * @param parameterTypes the parameter array
  199.93 +     * @return    the {@code Method} object for the method of this class
  199.94 +     * matching the specified name and parameters
  199.95 +     * @exception NoSuchMethodException if a matching method is not found.
  199.96 +     * @exception NullPointerException if {@code name} is {@code null}
  199.97 +     * @exception  SecurityException
  199.98 +     *             If a security manager, <i>s</i>, is present and any of the
  199.99 +     *             following conditions is met:
 199.100 +     *
 199.101 +     *             <ul>
 199.102 +     *
 199.103 +     *             <li> invocation of
 199.104 +     *             {@link SecurityManager#checkMemberAccess
 199.105 +     *             s.checkMemberAccess(this, Member.DECLARED)} denies
 199.106 +     *             access to the declared method
 199.107 +     *
 199.108 +     *             <li> the caller's class loader is not the same as or an
 199.109 +     *             ancestor of the class loader for the current class and
 199.110 +     *             invocation of {@link SecurityManager#checkPackageAccess
 199.111 +     *             s.checkPackageAccess()} denies access to the package
 199.112 +     *             of this class
 199.113 +     *
 199.114 +     *             </ul>
 199.115 +     *
 199.116 +     * @since JDK1.1
 199.117 +     */
 199.118 +    public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
 199.119 +    throws NoSuchMethodException, SecurityException {
 199.120 +        try {
 199.121 +            return getMethod(name, parameterTypes);
 199.122 +        } catch (NoSuchMethodException ex) {
 199.123 +            throw new SecurityException();
 199.124 +        }
 199.125 +    }
 199.126 +
 199.127 +    /**
 199.128 +     * Returns a {@code Field} object that reflects the specified declared
 199.129 +     * field of the class or interface represented by this {@code Class}
 199.130 +     * object. The {@code name} parameter is a {@code String} that
 199.131 +     * specifies the simple name of the desired field.  Note that this method
 199.132 +     * will not reflect the {@code length} field of an array class.
 199.133 +     *
 199.134 +     * @param name the name of the field
 199.135 +     * @return the {@code Field} object for the specified field in this
 199.136 +     * class
 199.137 +     * @exception NoSuchFieldException if a field with the specified name is
 199.138 +     *              not found.
 199.139 +     * @exception NullPointerException if {@code name} is {@code null}
 199.140 +     * @exception  SecurityException
 199.141 +     *             If a security manager, <i>s</i>, is present and any of the
 199.142 +     *             following conditions is met:
 199.143 +     *
 199.144 +     *             <ul>
 199.145 +     *
 199.146 +     *             <li> invocation of
 199.147 +     *             {@link SecurityManager#checkMemberAccess
 199.148 +     *             s.checkMemberAccess(this, Member.DECLARED)} denies
 199.149 +     *             access to the declared field
 199.150 +     *
 199.151 +     *             <li> the caller's class loader is not the same as or an
 199.152 +     *             ancestor of the class loader for the current class and
 199.153 +     *             invocation of {@link SecurityManager#checkPackageAccess
 199.154 +     *             s.checkPackageAccess()} denies access to the package
 199.155 +     *             of this class
 199.156 +     *
 199.157 +     *             </ul>
 199.158 +     *
 199.159 +     * @since JDK1.1
 199.160 +     */
 199.161 +    public Field getDeclaredField(String name)
 199.162 +    throws SecurityException {
 199.163 +        throw new SecurityException();
 199.164 +    }
 199.165 +    
 199.166 +    /**
 199.167 +     * Returns an array containing {@code Constructor} objects reflecting
 199.168 +     * all the public constructors of the class represented by this
 199.169 +     * {@code Class} object.  An array of length 0 is returned if the
 199.170 +     * class has no public constructors, or if the class is an array class, or
 199.171 +     * if the class reflects a primitive type or void.
 199.172 +     *
 199.173 +     * Note that while this method returns an array of {@code
 199.174 +     * Constructor<T>} objects (that is an array of constructors from
 199.175 +     * this class), the return type of this method is {@code
 199.176 +     * Constructor<?>[]} and <em>not</em> {@code Constructor<T>[]} as
 199.177 +     * might be expected.  This less informative return type is
 199.178 +     * necessary since after being returned from this method, the
 199.179 +     * array could be modified to hold {@code Constructor} objects for
 199.180 +     * different classes, which would violate the type guarantees of
 199.181 +     * {@code Constructor<T>[]}.
 199.182 +     *
 199.183 +     * @return the array of {@code Constructor} objects representing the
 199.184 +     *  public constructors of this class
 199.185 +     * @exception  SecurityException
 199.186 +     *             If a security manager, <i>s</i>, is present and any of the
 199.187 +     *             following conditions is met:
 199.188 +     *
 199.189 +     *             <ul>
 199.190 +     *
 199.191 +     *             <li> invocation of
 199.192 +     *             {@link SecurityManager#checkMemberAccess
 199.193 +     *             s.checkMemberAccess(this, Member.PUBLIC)} denies
 199.194 +     *             access to the constructors within this class
 199.195 +     *
 199.196 +     *             <li> the caller's class loader is not the same as or an
 199.197 +     *             ancestor of the class loader for the current class and
 199.198 +     *             invocation of {@link SecurityManager#checkPackageAccess
 199.199 +     *             s.checkPackageAccess()} denies access to the package
 199.200 +     *             of this class
 199.201 +     *
 199.202 +     *             </ul>
 199.203 +     *
 199.204 +     * @since JDK1.1
 199.205 +     */
 199.206 +    public Constructor<?>[] getConstructors() throws SecurityException {
 199.207 +        return MethodImpl.findConstructors(this, 0x01);
 199.208 +    }
 199.209 +
 199.210 +    /**
 199.211 +     * Returns a {@code Constructor} object that reflects the specified
 199.212 +     * public constructor of the class represented by this {@code Class}
 199.213 +     * object. The {@code parameterTypes} parameter is an array of
 199.214 +     * {@code Class} objects that identify the constructor's formal
 199.215 +     * parameter types, in declared order.
 199.216 +     *
 199.217 +     * If this {@code Class} object represents an inner class
 199.218 +     * declared in a non-static context, the formal parameter types
 199.219 +     * include the explicit enclosing instance as the first parameter.
 199.220 +     *
 199.221 +     * <p> The constructor to reflect is the public constructor of the class
 199.222 +     * represented by this {@code Class} object whose formal parameter
 199.223 +     * types match those specified by {@code parameterTypes}.
 199.224 +     *
 199.225 +     * @param parameterTypes the parameter array
 199.226 +     * @return the {@code Constructor} object of the public constructor that
 199.227 +     * matches the specified {@code parameterTypes}
 199.228 +     * @exception NoSuchMethodException if a matching method is not found.
 199.229 +     * @exception  SecurityException
 199.230 +     *             If a security manager, <i>s</i>, is present and any of the
 199.231 +     *             following conditions is met:
 199.232 +     *
 199.233 +     *             <ul>
 199.234 +     *
 199.235 +     *             <li> invocation of
 199.236 +     *             {@link SecurityManager#checkMemberAccess
 199.237 +     *             s.checkMemberAccess(this, Member.PUBLIC)} denies
 199.238 +     *             access to the constructor
 199.239 +     *
 199.240 +     *             <li> the caller's class loader is not the same as or an
 199.241 +     *             ancestor of the class loader for the current class and
 199.242 +     *             invocation of {@link SecurityManager#checkPackageAccess
 199.243 +     *             s.checkPackageAccess()} denies access to the package
 199.244 +     *             of this class
 199.245 +     *
 199.246 +     *             </ul>
 199.247 +     *
 199.248 +     * @since JDK1.1
 199.249 +     */
 199.250 +    public Constructor<T> getConstructor(Class<?>... parameterTypes)
 199.251 +    throws NoSuchMethodException, SecurityException {
 199.252 +        Constructor c = MethodImpl.findConstructor(this, parameterTypes);
 199.253 +        if (c == null) {
 199.254 +            StringBuilder sb = new StringBuilder();
 199.255 +            sb.append(getName()).append('(');
 199.256 +            String sep = "";
 199.257 +            for (int i = 0; i < parameterTypes.length; i++) {
 199.258 +                sb.append(sep).append(parameterTypes[i].getName());
 199.259 +                sep = ", ";
 199.260 +            }
 199.261 +            sb.append(')');
 199.262 +            throw new NoSuchMethodException(sb.toString());
 199.263 +        }
 199.264 +        return c;
 199.265 +    }
 199.266 +
 199.267 +    /**
 199.268 +     * Returns an array of {@code Constructor} objects reflecting all the
 199.269 +     * constructors declared by the class represented by this
 199.270 +     * {@code Class} object. These are public, protected, default
 199.271 +     * (package) access, and private constructors.  The elements in the array
 199.272 +     * returned are not sorted and are not in any particular order.  If the
 199.273 +     * class has a default constructor, it is included in the returned array.
 199.274 +     * This method returns an array of length 0 if this {@code Class}
 199.275 +     * object represents an interface, a primitive type, an array class, or
 199.276 +     * void.
 199.277 +     *
 199.278 +     * <p> See <em>The Java Language Specification</em>, section 8.2.
 199.279 +     *
 199.280 +     * @return    the array of {@code Constructor} objects representing all the
 199.281 +     * declared constructors of this class
 199.282 +     * @exception  SecurityException
 199.283 +     *             If a security manager, <i>s</i>, is present and any of the
 199.284 +     *             following conditions is met:
 199.285 +     *
 199.286 +     *             <ul>
 199.287 +     *
 199.288 +     *             <li> invocation of
 199.289 +     *             {@link SecurityManager#checkMemberAccess
 199.290 +     *             s.checkMemberAccess(this, Member.DECLARED)} denies
 199.291 +     *             access to the declared constructors within this class
 199.292 +     *
 199.293 +     *             <li> the caller's class loader is not the same as or an
 199.294 +     *             ancestor of the class loader for the current class and
 199.295 +     *             invocation of {@link SecurityManager#checkPackageAccess
 199.296 +     *             s.checkPackageAccess()} denies access to the package
 199.297 +     *             of this class
 199.298 +     *
 199.299 +     *             </ul>
 199.300 +     *
 199.301 +     * @since JDK1.1
 199.302 +     */
 199.303 +    public Constructor<?>[] getDeclaredConstructors() throws SecurityException {
 199.304 +        throw new SecurityException();
 199.305 +    }
 199.306 +    /**
 199.307 +     * Returns a {@code Constructor} object that reflects the specified
 199.308 +     * constructor of the class or interface represented by this
 199.309 +     * {@code Class} object.  The {@code parameterTypes} parameter is
 199.310 +     * an array of {@code Class} objects that identify the constructor's
 199.311 +     * formal parameter types, in declared order.
 199.312 +     *
 199.313 +     * If this {@code Class} object represents an inner class
 199.314 +     * declared in a non-static context, the formal parameter types
 199.315 +     * include the explicit enclosing instance as the first parameter.
 199.316 +     *
 199.317 +     * @param parameterTypes the parameter array
 199.318 +     * @return    The {@code Constructor} object for the constructor with the
 199.319 +     * specified parameter list
 199.320 +     * @exception NoSuchMethodException if a matching method is not found.
 199.321 +     * @exception  SecurityException
 199.322 +     *             If a security manager, <i>s</i>, is present and any of the
 199.323 +     *             following conditions is met:
 199.324 +     *
 199.325 +     *             <ul>
 199.326 +     *
 199.327 +     *             <li> invocation of
 199.328 +     *             {@link SecurityManager#checkMemberAccess
 199.329 +     *             s.checkMemberAccess(this, Member.DECLARED)} denies
 199.330 +     *             access to the declared constructor
 199.331 +     *
 199.332 +     *             <li> the caller's class loader is not the same as or an
 199.333 +     *             ancestor of the class loader for the current class and
 199.334 +     *             invocation of {@link SecurityManager#checkPackageAccess
 199.335 +     *             s.checkPackageAccess()} denies access to the package
 199.336 +     *             of this class
 199.337 +     *
 199.338 +     *             </ul>
 199.339 +     *
 199.340 +     * @since JDK1.1
 199.341 +     */
 199.342 +    public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
 199.343 +    throws NoSuchMethodException, SecurityException {
 199.344 +        return getConstructor(parameterTypes);
 199.345 +    }
 199.346 +    
 199.347 +    
 199.348 +    /**
 199.349       * Character.isDigit answers {@code true} to some non-ascii
 199.350       * digits.  This one does not.
 199.351       */
 199.352 @@ -1051,15 +1379,10 @@
 199.353       */
 199.354       public InputStream getResourceAsStream(String name) {
 199.355          name = resolveName(name);
 199.356 -        byte[] arr = getResourceAsStream0(name);
 199.357 +        byte[] arr = ClassLoader.getResourceAsStream0(name, 0);
 199.358          return arr == null ? null : new ByteArrayInputStream(arr);
 199.359       }
 199.360 -     
 199.361 -     @JavaScriptBody(args = "name", body = 
 199.362 -         "return (vm.loadBytes) ? vm.loadBytes(name) : null;"
 199.363 -     )
 199.364 -     private static native byte[] getResourceAsStream0(String name);
 199.365 -
 199.366 +    
 199.367      /**
 199.368       * Finds a resource with a given name.  The rules for searching resources
 199.369       * associated with a given class are implemented by the defining
 199.370 @@ -1095,8 +1418,11 @@
 199.371       * @since  JDK1.1
 199.372       */
 199.373      public java.net.URL getResource(String name) {
 199.374 -        InputStream is = getResourceAsStream(name);
 199.375 -        return is == null ? null : newResourceURL(URL.class, "res:/" + name, is);
 199.376 +        return newResourceURL(name, getResourceAsStream(name));
 199.377 +    }
 199.378 +
 199.379 +    static URL newResourceURL(String name, InputStream is) {
 199.380 +        return is == null ? null : newResourceURL0(URL.class, "res:/" + name, is);
 199.381      }
 199.382      
 199.383      @JavaScriptBody(args = { "url", "spec", "is" }, body = 
 199.384 @@ -1104,7 +1430,7 @@
 199.385        + "u.constructor.cons__VLjava_lang_String_2Ljava_io_InputStream_2.call(u, spec, is);\n"
 199.386        + "return u;"
 199.387      )
 199.388 -    private static native URL newResourceURL(Class<URL> url, String spec, InputStream is);
 199.389 +    private static native URL newResourceURL0(Class<URL> url, String spec, InputStream is);
 199.390  
 199.391     /**
 199.392       * Add a package name prefix if the name is not absolute Remove leading "/"
 199.393 @@ -1158,7 +1484,7 @@
 199.394       * @see java.lang.RuntimePermission
 199.395       */
 199.396      public ClassLoader getClassLoader() {
 199.397 -        throw new SecurityException();
 199.398 +        return ClassLoader.getSystemClassLoader();
 199.399      }
 199.400  
 199.401      /**
 199.402 @@ -1335,9 +1661,11 @@
 199.403  
 199.404      @JavaScriptBody(args = { "ac" }, 
 199.405          body = 
 199.406 -          "if (this.anno) {"
 199.407 -        + "  return this.anno['L' + ac.jvmName + ';'];"
 199.408 -        + "} else return null;"
 199.409 +          "if (this.anno) {\n"
 199.410 +        + "  var r = this.anno['L' + ac.jvmName + ';'];\n"
 199.411 +        + "  if (typeof r === 'undefined') r = null;\n"
 199.412 +        + "  return r;\n"
 199.413 +        + "} else return null;\n"
 199.414      )
 199.415      private Object getAnnotationData(Class<?> annotationClass) {
 199.416          throw new UnsupportedOperationException();
   200.1 --- a/rt/emul/mini/src/main/java/java/lang/ClassLoader.java	Tue Feb 11 10:48:24 2014 +0100
   200.2 +++ b/rt/emul/mini/src/main/java/java/lang/ClassLoader.java	Tue Feb 11 13:31:42 2014 +0100
   200.3 @@ -24,6 +24,7 @@
   200.4   */
   200.5  package java.lang;
   200.6  
   200.7 +import java.io.ByteArrayInputStream;
   200.8  import java.io.InputStream;
   200.9  import java.io.IOException;
  200.10  import java.net.URL;
  200.11 @@ -180,7 +181,7 @@
  200.12       * @since  1.2
  200.13       */
  200.14      protected ClassLoader(ClassLoader parent) {
  200.15 -        throw new SecurityException();
  200.16 +        this.parent = parent;
  200.17      }
  200.18  
  200.19      /**
  200.20 @@ -199,7 +200,7 @@
  200.21       *          of a new class loader.
  200.22       */
  200.23      protected ClassLoader() {
  200.24 -        throw new SecurityException();
  200.25 +        this.parent = null;
  200.26      }
  200.27  
  200.28      // -- Class --
  200.29 @@ -845,8 +846,27 @@
  200.30       * @revised  1.4
  200.31       */
  200.32      public static ClassLoader getSystemClassLoader() {
  200.33 -        throw new SecurityException();
  200.34 +        if (SYSTEM == null) {
  200.35 +            SYSTEM = new ClassLoader() {
  200.36 +                @Override
  200.37 +                protected Enumeration<URL> findResources(String name) throws IOException {
  200.38 +                    return getBootstrapResources(name);
  200.39 +                }
  200.40 +
  200.41 +                @Override
  200.42 +                protected URL findResource(String name) {
  200.43 +                    return getBootstrapResource(name);
  200.44 +                }
  200.45 +
  200.46 +                @Override
  200.47 +                protected Class<?> findClass(String name) throws ClassNotFoundException {
  200.48 +                    return Class.forName(name);
  200.49 +                }
  200.50 +            };
  200.51 +        }
  200.52 +        return SYSTEM;
  200.53      }
  200.54 +    private static ClassLoader SYSTEM;
  200.55  
  200.56      // Returns true if the specified class loader can be found in this class
  200.57      // loader's delegation chain.
  200.58 @@ -870,12 +890,48 @@
  200.59      }
  200.60  
  200.61      private static URL getBootstrapResource(String name) {
  200.62 -        throw new UnsupportedOperationException();
  200.63 +        return Object.class.getResource("/" + name);
  200.64      }
  200.65  
  200.66 +    @JavaScriptBody(args = { "name", "skip" }, body
  200.67 +        = "return (vm.loadBytes) ? vm.loadBytes(name, skip) : null;"
  200.68 +    )
  200.69 +    static native byte[] getResourceAsStream0(String name, int skip);
  200.70 +
  200.71      private static Enumeration<URL> getBootstrapResources(String name) {
  200.72 -        URL u = Object.class.getResource("/" + name);
  200.73 -        return new OneOrZeroEnum(u);
  200.74 +        return new ResEnum(name);
  200.75 +    }
  200.76 +    
  200.77 +    private static class ResEnum implements Enumeration<URL> {
  200.78 +        private final String name;
  200.79 +        private URL next;
  200.80 +        private int skip;
  200.81 +
  200.82 +        public ResEnum(String name) {
  200.83 +            this.name = name;
  200.84 +        }
  200.85 +
  200.86 +
  200.87 +        public boolean hasMoreElements() {
  200.88 +            if (next == null && skip >= 0) {
  200.89 +                byte[] arr = getResourceAsStream0(name, skip++);
  200.90 +                if (arr != null) {
  200.91 +                    next = Class.newResourceURL(name, new ByteArrayInputStream(arr));
  200.92 +                } else {
  200.93 +                    skip = -1;
  200.94 +                }
  200.95 +            }
  200.96 +            return next != null;
  200.97 +        }
  200.98 +
  200.99 +        public URL nextElement() {
 200.100 +            URL r = next;
 200.101 +            if (r == null) {
 200.102 +                throw new NoSuchElementException();
 200.103 +            }
 200.104 +            next = null;
 200.105 +            return r;
 200.106 +        }
 200.107      }
 200.108      
 200.109      private static class OneOrZeroEnum implements Enumeration<URL> {
 200.110 @@ -910,7 +966,7 @@
 200.111          }
 200.112  
 200.113          public boolean hasMoreElements() {
 200.114 -            if (next == null) {
 200.115 +            if (next == null && index < arr.length) {
 200.116                  if (arr[index].hasMoreElements()) {
 200.117                      next = (URL) arr[index].nextElement();
 200.118                  } else {
   201.1 --- a/rt/emul/mini/src/main/java/java/lang/Double.java	Tue Feb 11 10:48:24 2014 +0100
   201.2 +++ b/rt/emul/mini/src/main/java/java/lang/Double.java	Tue Feb 11 13:31:42 2014 +0100
   201.3 @@ -540,8 +540,7 @@
   201.4       */
   201.5      @JavaScriptBody(args="s", body="return parseFloat(s);")
   201.6      public static double parseDouble(String s) throws NumberFormatException {
   201.7 -        throw new UnsupportedOperationException();
   201.8 -//        return FloatingDecimal.readJavaFormatString(s).doubleValue();
   201.9 +        return 0;
  201.10      }
  201.11  
  201.12      /**
   202.1 --- a/rt/emul/mini/src/main/java/java/lang/Enum.java	Tue Feb 11 10:48:24 2014 +0100
   202.2 +++ b/rt/emul/mini/src/main/java/java/lang/Enum.java	Tue Feb 11 13:31:42 2014 +0100
   202.3 @@ -235,7 +235,7 @@
   202.4          throw new IllegalArgumentException();
   202.5      }
   202.6      
   202.7 -    @JavaScriptBody(args = { "enumType" }, body = "return enumType.cnstr.$VALUES;")
   202.8 +    @JavaScriptBody(args = { "enumType" }, body = "return enumType.cnstr.fld_$VALUES;")
   202.9      private static native Object[] values(Class<?> enumType);
  202.10  
  202.11      /**
   203.1 --- a/rt/emul/mini/src/main/java/java/lang/Float.java	Tue Feb 11 10:48:24 2014 +0100
   203.2 +++ b/rt/emul/mini/src/main/java/java/lang/Float.java	Tue Feb 11 13:31:42 2014 +0100
   203.3 @@ -412,8 +412,7 @@
   203.4       *          parsable number.
   203.5       */
   203.6      public static Float valueOf(String s) throws NumberFormatException {
   203.7 -        throw new UnsupportedOperationException();
   203.8 -//        return new Float(FloatingDecimal.readJavaFormatString(s).floatValue());
   203.9 +        return new Float(parseFloat(s));
  203.10      }
  203.11  
  203.12      /**
  203.13 @@ -447,9 +446,9 @@
  203.14       * @see    java.lang.Float#valueOf(String)
  203.15       * @since 1.2
  203.16       */
  203.17 +    @JavaScriptBody(args="s", body="return parseFloat(s);")
  203.18      public static float parseFloat(String s) throws NumberFormatException {
  203.19 -        throw new UnsupportedOperationException();
  203.20 -//        return FloatingDecimal.readJavaFormatString(s).floatValue();
  203.21 +        return 0;
  203.22      }
  203.23  
  203.24      /**
   204.1 --- a/rt/emul/mini/src/main/java/java/lang/String.java	Tue Feb 11 10:48:24 2014 +0100
   204.2 +++ b/rt/emul/mini/src/main/java/java/lang/String.java	Tue Feb 11 13:31:42 2014 +0100
   204.3 @@ -26,7 +26,10 @@
   204.4  package java.lang;
   204.5  
   204.6  import java.io.UnsupportedEncodingException;
   204.7 +import java.lang.reflect.InvocationTargetException;
   204.8 +import java.lang.reflect.Method;
   204.9  import java.util.Comparator;
  204.10 +import java.util.Locale;
  204.11  import org.apidesign.bck2brwsr.core.ExtraJavaScript;
  204.12  import org.apidesign.bck2brwsr.core.JavaScriptBody;
  204.13  import org.apidesign.bck2brwsr.core.JavaScriptOnly;
  204.14 @@ -984,12 +987,12 @@
  204.15                  continue;
  204.16              }
  204.17              if (v < 0x0800) {
  204.18 -                arr = System.expandArray(arr, i + 1);
  204.19 +                arr = System.expandArray(arr, arr.length + 1);
  204.20                  arr[i++] = (byte) (0xC0 | (v >> 6));
  204.21                  arr[i++] = (byte) (0x80 | (0x3F & v));
  204.22                  continue;
  204.23              }
  204.24 -            arr = System.expandArray(arr, i + 2);
  204.25 +            arr = System.expandArray(arr, arr.length + 2);
  204.26              arr[i++] = (byte) (0xE0 | (v >> 12));
  204.27              arr[i++] = (byte) (0x80 | ((v >> 6) & 0x7F));
  204.28              arr[i++] = (byte) (0x80 | (0x3F & v));
  204.29 @@ -2097,13 +2100,31 @@
  204.30       * @since 1.4
  204.31       * @spec JSR-51
  204.32       */
  204.33 +    public boolean matches(String regex) {
  204.34 +        try {
  204.35 +            return matchesViaJS(regex);
  204.36 +        } catch (Throwable t) {
  204.37 +            // fallback to classical behavior
  204.38 +            try {
  204.39 +                Method m = Class.forName("java.util.regex.Pattern").getMethod("matches", String.class, CharSequence.class);
  204.40 +                return (Boolean)m.invoke(null, regex, this);
  204.41 +            } catch (InvocationTargetException ex) {
  204.42 +                if (ex.getTargetException() instanceof RuntimeException) {
  204.43 +                    throw (RuntimeException)ex.getTargetException();
  204.44 +                }
  204.45 +            } catch (Throwable another) {
  204.46 +                // will report the old one
  204.47 +            }
  204.48 +            throw new RuntimeException(t);
  204.49 +        }
  204.50 +    }
  204.51      @JavaScriptBody(args = { "regex" }, body = 
  204.52            "var self = this.toString();\n"
  204.53          + "var re = new RegExp(regex.toString());\n"
  204.54          + "var r = re.exec(self);\n"
  204.55          + "return r != null && r.length > 0 && self.length == r[0].length;"
  204.56      )
  204.57 -    public boolean matches(String regex) {
  204.58 +    private boolean matchesViaJS(String regex) {
  204.59          throw new UnsupportedOperationException();
  204.60      }
  204.61  
  204.62 @@ -2159,6 +2180,14 @@
  204.63       * @since 1.4
  204.64       * @spec JSR-51
  204.65       */
  204.66 +    @JavaScriptBody(args = { "regex", "newText" }, body = 
  204.67 +          "var self = this.toString();\n"
  204.68 +        + "var re = new RegExp(regex.toString());\n"
  204.69 +        + "var r = re.exec(self);\n"
  204.70 +        + "if (r === null || r.length === 0) return this;\n"
  204.71 +        + "var from = self.indexOf(r[0]);\n"
  204.72 +        + "return this.substring(0, from) + newText + this.substring(from + r[0].length);\n"
  204.73 +    )
  204.74      public String replaceFirst(String regex, String replacement) {
  204.75          throw new UnsupportedOperationException();
  204.76      }
  204.77 @@ -2203,7 +2232,14 @@
  204.78       * @spec JSR-51
  204.79       */
  204.80      public String replaceAll(String regex, String replacement) {
  204.81 -        throw new UnsupportedOperationException();
  204.82 +        String p = this;
  204.83 +        for (;;) {
  204.84 +            String n = p.replaceFirst(regex, replacement);
  204.85 +            if (n == p) {
  204.86 +                return n;
  204.87 +            }
  204.88 +            p = n;
  204.89 +        }
  204.90      }
  204.91  
  204.92      /**
  204.93 @@ -2224,12 +2260,14 @@
  204.94            "var s = this.toString();\n"
  204.95          + "target = target.toString();\n"
  204.96          + "replacement = replacement.toString();\n"
  204.97 +        + "var pos = 0;\n"
  204.98          + "for (;;) {\n"
  204.99 -        + "  var ret = s.replace(target, replacement);\n"
 204.100 -        + "  if (ret === s) {\n"
 204.101 -        + "    return ret;\n"
 204.102 +        + "  var indx = s.indexOf(target, pos);\n"
 204.103 +        + "  if (indx === -1) {\n"
 204.104 +        + "    return s;\n"
 204.105          + "  }\n"
 204.106 -        + "  s = ret;\n"
 204.107 +        + "  pos = indx + replacement.length;\n"
 204.108 +        + "  s = s.substring(0, indx) + replacement + s.substring(indx + target.length);\n"
 204.109          + "}"
 204.110      )
 204.111      public native String replace(CharSequence target, CharSequence replacement);
 204.112 @@ -2318,8 +2356,8 @@
 204.113          if (limit <= 0) {
 204.114              Object[] arr = splitImpl(this, regex, Integer.MAX_VALUE);
 204.115              int to = arr.length;
 204.116 -            if (limit == 0) {
 204.117 -                while (to > 1 && ((String)arr[--to]).isEmpty()) {
 204.118 +            if (limit == 0 && to > 0) {
 204.119 +                while (to > 0 && ((String)arr[--to]).isEmpty()) {
 204.120                  }
 204.121                  to++;
 204.122              }
 204.123 @@ -2439,7 +2477,9 @@
 204.124       * @see     java.lang.String#toUpperCase(Locale)
 204.125       * @since   1.1
 204.126       */
 204.127 -//    public String toLowerCase(Locale locale) {
 204.128 +    public String toLowerCase(java.util.Locale locale) {
 204.129 +        return toLowerCase();
 204.130 +    }
 204.131  //        if (locale == null) {
 204.132  //            throw new NullPointerException();
 204.133  //        }
 204.134 @@ -2554,7 +2594,7 @@
 204.135       */
 204.136      @JavaScriptBody(args = {}, body = "return this.toLowerCase();")
 204.137      public String toLowerCase() {
 204.138 -        throw new UnsupportedOperationException("Should be supported but without connection to locale");
 204.139 +        return null;
 204.140      }
 204.141  
 204.142      /**
 204.143 @@ -2605,8 +2645,10 @@
 204.144       * @see     java.lang.String#toLowerCase(Locale)
 204.145       * @since   1.1
 204.146       */
 204.147 +    public String toUpperCase(Locale locale) {
 204.148 +        return toUpperCase();
 204.149 +    }
 204.150      /* not for javascript 
 204.151 -    public String toUpperCase(Locale locale) {
 204.152          if (locale == null) {
 204.153              throw new NullPointerException();
 204.154          }
 204.155 @@ -2720,7 +2762,7 @@
 204.156       */
 204.157      @JavaScriptBody(args = {}, body = "return this.toUpperCase();")
 204.158      public String toUpperCase() {
 204.159 -        throw new UnsupportedOperationException();
 204.160 +        return null;
 204.161      }
 204.162  
 204.163      /**
 204.164 @@ -2831,7 +2873,7 @@
 204.165       * @since  1.5
 204.166       */
 204.167      public static String format(String format, Object ... args) {
 204.168 -        throw new UnsupportedOperationException();
 204.169 +        return format((Locale)null, format, args);
 204.170      }
 204.171  
 204.172      /**
 204.173 @@ -2874,9 +2916,15 @@
 204.174       * @see  java.util.Formatter
 204.175       * @since  1.5
 204.176       */
 204.177 -//    public static String format(Locale l, String format, Object ... args) {
 204.178 -//        return new Formatter(l).format(format, args).toString();
 204.179 -//    }
 204.180 +    public static String format(Locale l, String format, Object ... args) {
 204.181 +        String p = format;
 204.182 +        for (int i = 0; i < args.length; i++) {
 204.183 +            String v = args[i] == null ? "null" : args[i].toString();
 204.184 +            p = p.replaceFirst("%s", v);
 204.185 +        }
 204.186 +        return p;
 204.187 +        // return new Formatter(l).format(format, args).toString();
 204.188 +    }
 204.189  
 204.190      /**
 204.191       * Returns the string representation of the <code>Object</code> argument.
 204.192 @@ -3061,6 +3109,14 @@
 204.193       * @return  a string that has the same contents as this string, but is
 204.194       *          guaranteed to be from a pool of unique strings.
 204.195       */
 204.196 +    @JavaScriptBody(args = {}, body = 
 204.197 +        "var s = this.toString().toString();\n" +
 204.198 +        "var i = String.intern || (String.intern = {})\n" + 
 204.199 +        "if (!i[s]) {\n" +
 204.200 +        "  i[s] = s;\n" +
 204.201 +        "}\n" +
 204.202 +        "return i[s];"
 204.203 +    )
 204.204      public native String intern();
 204.205      
 204.206      
   205.1 --- a/rt/emul/mini/src/main/java/java/lang/Throwable.java	Tue Feb 11 10:48:24 2014 +0100
   205.2 +++ b/rt/emul/mini/src/main/java/java/lang/Throwable.java	Tue Feb 11 13:31:42 2014 +0100
   205.3 @@ -638,93 +638,34 @@
   205.4       *          ... 2 more
   205.5       * </pre>
   205.6       */
   205.7 -    @JavaScriptBody(args = {  }, body = "console.warn(this.toString());")
   205.8 -    public native void printStackTrace();
   205.9 +    public void printStackTrace() {
  205.10 +        warn(getClass().getName() + ": " + getMessage());
  205.11 +    }
  205.12 +    @JavaScriptBody(args = { "msg" }, body = "if (console) console.warn(msg.toString());")
  205.13 +    private native void warn(String msg);
  205.14  
  205.15 -//    /**
  205.16 -//     * Prints this throwable and its backtrace to the specified print stream.
  205.17 -//     *
  205.18 -//     * @param s {@code PrintStream} to use for output
  205.19 -//     */
  205.20 -//    public void printStackTrace(PrintStream s) {
  205.21 -//        printStackTrace(new WrappedPrintStream(s));
  205.22 -//    }
  205.23 -//
  205.24 -//    private void printStackTrace(PrintStreamOrWriter s) {
  205.25 -//        // Guard against malicious overrides of Throwable.equals by
  205.26 -//        // using a Set with identity equality semantics.
  205.27 -////        Set<Throwable> dejaVu =
  205.28 -////            Collections.newSetFromMap(new IdentityHashMap<Throwable, Boolean>());
  205.29 -////        dejaVu.add(this);
  205.30 -//
  205.31 -//        synchronized (s.lock()) {
  205.32 -//            // Print our stack trace
  205.33 -//            s.println(this);
  205.34 -//            StackTraceElement[] trace = getOurStackTrace();
  205.35 -//            for (StackTraceElement traceElement : trace)
  205.36 -//                s.println("\tat " + traceElement);
  205.37 -//
  205.38 -//            // Print suppressed exceptions, if any
  205.39 -////            for (Throwable se : getSuppressed())
  205.40 -////                se.printEnclosedStackTrace(s, trace, SUPPRESSED_CAPTION, "\t", dejaVu);
  205.41 -//
  205.42 -//            // Print cause, if any
  205.43 -//            Throwable ourCause = getCause();
  205.44 -////            if (ourCause != null)
  205.45 -////                ourCause.printEnclosedStackTrace(s, trace, CAUSE_CAPTION, "", dejaVu);
  205.46 -//        }
  205.47 -//    }
  205.48 -//
  205.49 -//    /**
  205.50 -//     * Print our stack trace as an enclosed exception for the specified
  205.51 -//     * stack trace.
  205.52 -//     */
  205.53 -//    private void printEnclosedStackTrace(PrintStreamOrWriter s,
  205.54 -//                                         StackTraceElement[] enclosingTrace,
  205.55 -//                                         String caption,
  205.56 -//                                         String prefix,
  205.57 -//                                         Object dejaVu) {
  205.58 -//        assert Thread.holdsLock(s.lock());
  205.59 -//        {
  205.60 -//            // Compute number of frames in common between this and enclosing trace
  205.61 -//            StackTraceElement[] trace = getOurStackTrace();
  205.62 -//            int m = trace.length - 1;
  205.63 -//            int n = enclosingTrace.length - 1;
  205.64 -//            while (m >= 0 && n >=0 && trace[m].equals(enclosingTrace[n])) {
  205.65 -//                m--; n--;
  205.66 -//            }
  205.67 -//            int framesInCommon = trace.length - 1 - m;
  205.68 -//
  205.69 -//            // Print our stack trace
  205.70 -//            s.println(prefix + caption + this);
  205.71 -//            for (int i = 0; i <= m; i++)
  205.72 -//                s.println(prefix + "\tat " + trace[i]);
  205.73 -//            if (framesInCommon != 0)
  205.74 -//                s.println(prefix + "\t... " + framesInCommon + " more");
  205.75 -//
  205.76 -//            // Print suppressed exceptions, if any
  205.77 -//            for (Throwable se : getSuppressed())
  205.78 -//                se.printEnclosedStackTrace(s, trace, SUPPRESSED_CAPTION,
  205.79 -//                                           prefix +"\t", dejaVu);
  205.80 -//
  205.81 -//            // Print cause, if any
  205.82 -//            Throwable ourCause = getCause();
  205.83 -//            if (ourCause != null)
  205.84 -//                ourCause.printEnclosedStackTrace(s, trace, CAUSE_CAPTION, prefix, dejaVu);
  205.85 -//        }
  205.86 -//    }
  205.87 -//
  205.88 -//    /**
  205.89 -//     * Prints this throwable and its backtrace to the specified
  205.90 -//     * print writer.
  205.91 -//     *
  205.92 -//     * @param s {@code PrintWriter} to use for output
  205.93 -//     * @since   JDK1.1
  205.94 -//     */
  205.95 -//    public void printStackTrace(PrintWriter s) {
  205.96 -//        printStackTrace(new WrappedPrintWriter(s));
  205.97 -//    }
  205.98 -//
  205.99 +    /**
 205.100 +     * Prints this throwable and its backtrace to the specified print stream.
 205.101 +     *
 205.102 +     * @param s {@code PrintStream} to use for output
 205.103 +     */
 205.104 +    public void printStackTrace(PrintStream s) {
 205.105 +        s.print(getClass().getName());
 205.106 +        s.print(": ");
 205.107 +        s.println(getMessage());
 205.108 +    }
 205.109 +
 205.110 +    /**
 205.111 +     * Prints this throwable and its backtrace to the specified
 205.112 +     * print writer.
 205.113 +     *
 205.114 +     * @param s {@code PrintWriter} to use for output
 205.115 +     * @since   JDK1.1
 205.116 +     */
 205.117 +    public void printStackTrace(PrintWriter s) {
 205.118 +        s.append(getClass().getName()).append(": ").println(getMessage());
 205.119 +    }
 205.120 +
 205.121  //    /**
 205.122  //     * Wrapper class for PrintStream and PrintWriter to enable a single
 205.123  //     * implementation of printStackTrace.
   206.1 --- a/rt/emul/mini/src/main/java/java/lang/reflect/Array.java	Tue Feb 11 10:48:24 2014 +0100
   206.2 +++ b/rt/emul/mini/src/main/java/java/lang/reflect/Array.java	Tue Feb 11 13:31:42 2014 +0100
   206.3 @@ -106,7 +106,7 @@
   206.4          if (type.getName().equals("void")) {
   206.5              throw new IllegalStateException("Can't create array for " + type);
   206.6          }
   206.7 -        return "[L" + type.getName() + ";";
   206.8 +        return "[L" + type.getName().replace('.', '/') + ";";
   206.9      }
  206.10      /**
  206.11       * Creates a new array
   207.1 --- a/rt/emul/mini/src/main/java/java/lang/reflect/Constructor.java	Tue Feb 11 10:48:24 2014 +0100
   207.2 +++ b/rt/emul/mini/src/main/java/java/lang/reflect/Constructor.java	Tue Feb 11 13:31:42 2014 +0100
   207.3 @@ -26,6 +26,10 @@
   207.4  package java.lang.reflect;
   207.5  
   207.6  import java.lang.annotation.Annotation;
   207.7 +import static java.lang.reflect.Method.fromPrimitive;
   207.8 +import static java.lang.reflect.Method.getAccess;
   207.9 +import static java.lang.reflect.Method.getParameterTypes;
  207.10 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
  207.11  import org.apidesign.bck2brwsr.emul.reflect.TypeProvider;
  207.12  
  207.13  /**
  207.14 @@ -53,44 +57,20 @@
  207.15                                                      GenericDeclaration,
  207.16                                                      Member {
  207.17  
  207.18 -    private Class<T>            clazz;
  207.19 -    private int                 slot;
  207.20 -    private Class<?>[]          parameterTypes;
  207.21 -    private Class<?>[]          exceptionTypes;
  207.22 -    private int                 modifiers;
  207.23 -    // Generics and annotations support
  207.24 -    private transient String    signature;
  207.25 -    private byte[]              annotations;
  207.26 -    private byte[]              parameterAnnotations;
  207.27 -
  207.28 -
  207.29 -    // For sharing of ConstructorAccessors. This branching structure
  207.30 -    // is currently only two levels deep (i.e., one root Constructor
  207.31 -    // and potentially many Constructor objects pointing to it.)
  207.32 -    private Constructor<T>      root;
  207.33 +    private final Class<T> clazz;
  207.34 +    private final Object data;
  207.35 +    private final String sig;
  207.36  
  207.37      /**
  207.38       * Package-private constructor used by ReflectAccess to enable
  207.39       * instantiation of these objects in Java code from the java.lang
  207.40       * package via sun.reflect.LangReflectAccess.
  207.41       */
  207.42 -    Constructor(Class<T> declaringClass,
  207.43 -                Class<?>[] parameterTypes,
  207.44 -                Class<?>[] checkedExceptions,
  207.45 -                int modifiers,
  207.46 -                int slot,
  207.47 -                String signature,
  207.48 -                byte[] annotations,
  207.49 -                byte[] parameterAnnotations)
  207.50 +    Constructor(Class<T> declaringClass, Object data, String sig)
  207.51      {
  207.52          this.clazz = declaringClass;
  207.53 -        this.parameterTypes = parameterTypes;
  207.54 -        this.exceptionTypes = checkedExceptions;
  207.55 -        this.modifiers = modifiers;
  207.56 -        this.slot = slot;
  207.57 -        this.signature = signature;
  207.58 -        this.annotations = annotations;
  207.59 -        this.parameterAnnotations = parameterAnnotations;
  207.60 +        this.data = data;
  207.61 +        this.sig = sig;
  207.62      }
  207.63  
  207.64      /**
  207.65 @@ -126,7 +106,7 @@
  207.66       * @see Modifier
  207.67       */
  207.68      public int getModifiers() {
  207.69 -        return modifiers;
  207.70 +        return getAccess(data);
  207.71      }
  207.72  
  207.73      /**
  207.74 @@ -159,7 +139,7 @@
  207.75       * represents
  207.76       */
  207.77      public Class<?>[] getParameterTypes() {
  207.78 -        return (Class<?>[]) parameterTypes.clone();
  207.79 +        return Method.getParameterTypes(sig);
  207.80      }
  207.81  
  207.82  
  207.83 @@ -205,7 +185,7 @@
  207.84       * constructor this object represents
  207.85       */
  207.86      public Class<?>[] getExceptionTypes() {
  207.87 -        return (Class<?>[])exceptionTypes.clone();
  207.88 +        return new Class[0];
  207.89      }
  207.90  
  207.91  
  207.92 @@ -242,20 +222,9 @@
  207.93       * same formal parameter types.
  207.94       */
  207.95      public boolean equals(Object obj) {
  207.96 -        if (obj != null && obj instanceof Constructor) {
  207.97 -            Constructor<?> other = (Constructor<?>)obj;
  207.98 -            if (getDeclaringClass() == other.getDeclaringClass()) {
  207.99 -                /* Avoid unnecessary cloning */
 207.100 -                Class<?>[] params1 = parameterTypes;
 207.101 -                Class<?>[] params2 = other.parameterTypes;
 207.102 -                if (params1.length == params2.length) {
 207.103 -                    for (int i = 0; i < params1.length; i++) {
 207.104 -                        if (params1[i] != params2[i])
 207.105 -                            return false;
 207.106 -                    }
 207.107 -                    return true;
 207.108 -                }
 207.109 -            }
 207.110 +        if (obj instanceof Constructor) {
 207.111 +            Constructor other = (Constructor)obj;
 207.112 +            return data == other.data;
 207.113          }
 207.114          return false;
 207.115      }
 207.116 @@ -293,13 +262,14 @@
 207.117              }
 207.118              sb.append(Field.getTypeName(getDeclaringClass()));
 207.119              sb.append("(");
 207.120 -            Class<?>[] params = parameterTypes; // avoid clone
 207.121 +            Class<?>[] params = getParameterTypes(); // avoid clone
 207.122              for (int j = 0; j < params.length; j++) {
 207.123                  sb.append(Field.getTypeName(params[j]));
 207.124                  if (j < (params.length - 1))
 207.125                      sb.append(",");
 207.126              }
 207.127              sb.append(")");
 207.128 +            /*
 207.129              Class<?>[] exceptions = exceptionTypes; // avoid clone
 207.130              if (exceptions.length > 0) {
 207.131                  sb.append(" throws ");
 207.132 @@ -309,6 +279,7 @@
 207.133                          sb.append(",");
 207.134                  }
 207.135              }
 207.136 +            */
 207.137              return sb.toString();
 207.138          } catch (Exception e) {
 207.139              return "<" + e + ">";
 207.140 @@ -452,9 +423,29 @@
 207.141          throws InstantiationException, IllegalAccessException,
 207.142                 IllegalArgumentException, InvocationTargetException
 207.143      {
 207.144 -        throw new SecurityException();
 207.145 +        Class[] types = getParameterTypes();
 207.146 +        if (types.length != initargs.length) {
 207.147 +            throw new IllegalArgumentException("Types len " + types.length + " args: " + initargs.length);
 207.148 +        } else {
 207.149 +            initargs = initargs.clone();
 207.150 +            for (int i = 0; i < types.length; i++) {
 207.151 +                Class c = types[i];
 207.152 +                if (c.isPrimitive() && initargs[i] != null) {
 207.153 +                    initargs[i] = Method.toPrimitive(initargs[i]);
 207.154 +                }
 207.155 +            }
 207.156 +        }
 207.157 +        return (T) newInstance0(this.getDeclaringClass(), "cons__" + sig, initargs);
 207.158      }
 207.159  
 207.160 +    @JavaScriptBody(args = { "self", "sig", "args" }, body =
 207.161 +          "\nvar c = self.cnstr;"
 207.162 +        + "\nvar inst = c();"
 207.163 +        + "\nc[sig].apply(inst, args);"
 207.164 +        + "\nreturn inst;"
 207.165 +    )
 207.166 +    private static native Object newInstance0(Class<?> self, String sig, Object[] args);
 207.167 +    
 207.168      /**
 207.169       * Returns {@code true} if this constructor was declared to take
 207.170       * a variable number of arguments; returns {@code false}
 207.171 @@ -481,22 +472,6 @@
 207.172          return Modifier.isSynthetic(getModifiers());
 207.173      }
 207.174  
 207.175 -    int getSlot() {
 207.176 -        return slot;
 207.177 -    }
 207.178 -
 207.179 -   String getSignature() {
 207.180 -            return signature;
 207.181 -   }
 207.182 -
 207.183 -    byte[] getRawAnnotations() {
 207.184 -        return annotations;
 207.185 -    }
 207.186 -
 207.187 -    byte[] getRawParameterAnnotations() {
 207.188 -        return parameterAnnotations;
 207.189 -    }
 207.190 -
 207.191      /**
 207.192       * @throws NullPointerException {@inheritDoc}
 207.193       * @since 1.5
 207.194 @@ -532,11 +507,11 @@
 207.195       * @since 1.5
 207.196       */
 207.197      public Annotation[][] getParameterAnnotations() {
 207.198 -        int numParameters = parameterTypes.length;
 207.199 -        if (parameterAnnotations == null)
 207.200 -            return new Annotation[numParameters][0];
 207.201 +//        int numParameters = parameterTypes.length;
 207.202 +//        if (parameterAnnotations == null)
 207.203 +//            return new Annotation[numParameters][0];
 207.204          
 207.205 -        return new Annotation[numParameters][0]; // XXX
 207.206 +        return new Annotation[0][0]; // XXX
 207.207  /*
 207.208          Annotation[][] result = AnnotationParser.parseParameterAnnotations(
 207.209              parameterAnnotations,
   208.1 --- a/rt/emul/mini/src/main/java/java/lang/reflect/Method.java	Tue Feb 11 10:48:24 2014 +0100
   208.2 +++ b/rt/emul/mini/src/main/java/java/lang/reflect/Method.java	Tue Feb 11 13:31:42 2014 +0100
   208.3 @@ -113,7 +113,7 @@
   208.4      }
   208.5      
   208.6      @JavaScriptBody(args = "self", body = "return self.access;")
   208.7 -    private static native int getAccess(Object self);
   208.8 +    static native int getAccess(Object self);
   208.9      
  208.10      /**
  208.11       * Returns an array of {@code TypeVariable} objects that represent the
  208.12 @@ -183,6 +183,10 @@
  208.13       * represents
  208.14       */
  208.15      public Class<?>[] getParameterTypes() {
  208.16 +        return getParameterTypes(sig);
  208.17 +    }
  208.18 +    
  208.19 +    static Class<?>[] getParameterTypes(String sig) {
  208.20          Class[] arr = new Class[MethodImpl.signatureElements(sig) - 1];
  208.21          Enumeration<Class> en = MethodImpl.signatureParser(sig);
  208.22          en.nextElement(); // return type
  208.23 @@ -235,8 +239,7 @@
  208.24       * method this object represents
  208.25       */
  208.26      public Class<?>[] getExceptionTypes() {
  208.27 -        throw new UnsupportedOperationException();
  208.28 -        //return (Class<?>[]) exceptionTypes.clone();
  208.29 +        return new Class[0];
  208.30      }
  208.31  
  208.32      /**
  208.33 @@ -583,7 +586,7 @@
  208.34      private static native Integer fromRaw(Class<?> cls, String m, Object o);
  208.35  
  208.36      @JavaScriptBody(args = { "o" }, body = "return o.valueOf();")
  208.37 -    private static native Object toPrimitive(Object o);
  208.38 +    static native Object toPrimitive(Object o);
  208.39      
  208.40      /**
  208.41       * Returns {@code true} if this method is a bridge
  208.42 @@ -692,6 +695,11 @@
  208.43              protected Method create(Class<?> declaringClass, String name, Object data, String sig) {
  208.44                  return new Method(declaringClass, name, data, sig);
  208.45              }
  208.46 +
  208.47 +            @Override
  208.48 +            protected Constructor create(Class<?> declaringClass, Object data, String sig) {
  208.49 +                return new Constructor(declaringClass, data, sig);
  208.50 +            }
  208.51          };
  208.52      }
  208.53  }
   209.1 --- a/rt/emul/mini/src/main/java/java/lang/reflect/Proxy.java	Tue Feb 11 10:48:24 2014 +0100
   209.2 +++ b/rt/emul/mini/src/main/java/java/lang/reflect/Proxy.java	Tue Feb 11 13:31:42 2014 +0100
   209.3 @@ -212,7 +212,16 @@
   209.4  
   209.5      private static final long serialVersionUID = -2222568056686623797L;
   209.6  
   209.7 -
   209.8 +    private final static Method getProxyClass;
   209.9 +    static {
  209.10 +        Class<?> pg;
  209.11 +        try {
  209.12 +            pg = Class.forName("org.apidesign.bck2brwsr.emul.reflect.ProxyImpl");
  209.13 +            getProxyClass = pg.getMethod("getProxyClass", ClassLoader.class, Class[].class);
  209.14 +        } catch (Exception ex) {
  209.15 +            throw new IllegalStateException(ex);
  209.16 +        }
  209.17 +    }
  209.18  
  209.19      /**
  209.20       * the invocation handler for this proxy instance.
  209.21 @@ -315,7 +324,13 @@
  209.22                                           Class<?>... interfaces)
  209.23          throws IllegalArgumentException
  209.24      {
  209.25 -        throw new IllegalArgumentException();
  209.26 +        try {
  209.27 +            return (Class<?>) getProxyClass.invoke(null, loader, interfaces);
  209.28 +        } catch (IllegalAccessException ex) {
  209.29 +            throw new IllegalStateException(ex);
  209.30 +        } catch (InvocationTargetException ex) {
  209.31 +            throw (RuntimeException)ex.getTargetException();
  209.32 +        }
  209.33      }
  209.34  
  209.35      /**
  209.36 @@ -355,7 +370,27 @@
  209.37          if (h == null) {
  209.38              throw new NullPointerException();
  209.39          }
  209.40 -        throw new IllegalArgumentException();
  209.41 +
  209.42 +        /*
  209.43 +         * Look up or generate the designated proxy class.
  209.44 +         */
  209.45 +        Class<?> cl = getProxyClass(loader, interfaces);
  209.46 +
  209.47 +        /*
  209.48 +         * Invoke its constructor with the designated invocation handler.
  209.49 +         */
  209.50 +        try {
  209.51 +            Constructor cons = cl.getConstructor(InvocationHandler.class);
  209.52 +            return cons.newInstance(new Object[] { h });
  209.53 +        } catch (NoSuchMethodException e) {
  209.54 +            throw new IllegalStateException(e.toString());
  209.55 +        } catch (IllegalAccessException e) {
  209.56 +            throw new IllegalStateException(e.toString());
  209.57 +        } catch (InstantiationException e) {
  209.58 +            throw new IllegalStateException(e.toString());
  209.59 +        } catch (InvocationTargetException e) {
  209.60 +            throw new IllegalStateException(e.toString());
  209.61 +        }
  209.62      }
  209.63  
  209.64      /**
  209.65 @@ -376,8 +411,7 @@
  209.66          if (cl == null) {
  209.67              throw new NullPointerException();
  209.68          }
  209.69 -
  209.70 -        return false;
  209.71 +        return Proxy.class.isAssignableFrom(cl);
  209.72      }
  209.73  
  209.74      /**
  209.75 @@ -401,7 +435,4 @@
  209.76          Proxy p = (Proxy) proxy;
  209.77          return p.h;
  209.78      }
  209.79 -
  209.80 -    private static native Class defineClass0(ClassLoader loader, String name,
  209.81 -                                             byte[] b, int off, int len);
  209.82  }
   210.1 --- a/rt/emul/mini/src/main/java/java/net/URL.java	Tue Feb 11 10:48:24 2014 +0100
   210.2 +++ b/rt/emul/mini/src/main/java/java/net/URL.java	Tue Feb 11 13:31:42 2014 +0100
   210.3 @@ -920,6 +920,23 @@
   210.4      }
   210.5  
   210.6      /**
   210.7 +     * Returns a {@link java.net.URI} equivalent to this URL.
   210.8 +     * This method functions in the same way as <code>new URI (this.toString())</code>.
   210.9 +     * <p>Note, any URL instance that complies with RFC 2396 can be converted
  210.10 +     * to a URI. However, some URLs that are not strictly in compliance
  210.11 +     * can not be converted to a URI.
  210.12 +     *
  210.13 +     * @exception URISyntaxException if this URL is not formatted strictly according to
  210.14 +     *            to RFC2396 and cannot be converted to a URI.
  210.15 +     *
  210.16 +     * @return    a URI instance equivalent to this URL.
  210.17 +     * @since 1.5
  210.18 +     */
  210.19 +    public URI toURI() throws URISyntaxException {
  210.20 +        return new URI (toString());
  210.21 +    }
  210.22 +
  210.23 +    /**
  210.24       * Returns a {@link java.net.URLConnection URLConnection} instance that
  210.25       * represents a connection to the remote object referred to by the
  210.26       * {@code URL}.
  210.27 @@ -948,9 +965,9 @@
  210.28       * @see        java.net.URL#URL(java.lang.String, java.lang.String,
  210.29       *             int, java.lang.String)
  210.30       */
  210.31 -//    public URLConnection openConnection() throws java.io.IOException {
  210.32 -//        return handler.openConnection(this);
  210.33 -//    }
  210.34 +    public URLConnection openConnection() throws java.io.IOException {
  210.35 +        return handler.openConnection(this);
  210.36 +    }
  210.37  
  210.38  
  210.39      /**
  210.40 @@ -1027,18 +1044,53 @@
  210.41      public final Object getContent(Class[] classes)
  210.42      throws java.io.IOException {
  210.43          for (Class<?> c : classes) {
  210.44 -            if (c == String.class) {
  210.45 -                return loadText(toExternalForm());
  210.46 -            }
  210.47 -            if (c == byte[].class) {
  210.48 -                return loadBytes(toExternalForm(), new byte[0]);
  210.49 +            try {
  210.50 +                if (c == String.class) {
  210.51 +                    return loadText(toExternalForm());
  210.52 +                }
  210.53 +                if (c == byte[].class) {
  210.54 +                    return loadBytes(toExternalForm(), new byte[0]);
  210.55 +                }
  210.56 +            } catch (Throwable t) {
  210.57 +                throw new IOException(t);
  210.58              }
  210.59          }
  210.60          return null;
  210.61      }
  210.62  
  210.63 -    static URLStreamHandler getURLStreamHandler(String protocol) {
  210.64 -        URLStreamHandler universal = new URLStreamHandler() {};
  210.65 +    static URLStreamHandler getURLStreamHandler(final String protocol) {
  210.66 +        URLStreamHandler universal = new URLStreamHandler() {
  210.67 +            @Override
  210.68 +            protected URLConnection openConnection(URL u) throws IOException {
  210.69 +                return new URLConnection(u) {
  210.70 +                    Object stream = url.is;
  210.71 +                    
  210.72 +                    @Override
  210.73 +                    public void connect() throws IOException {
  210.74 +                        if (stream == null) {
  210.75 +                            try {
  210.76 +                                byte[] arr = (byte[]) url.getContent(new Class[]{byte[].class});
  210.77 +                                stream = new ByteArrayInputStream(arr);
  210.78 +                            } catch (IOException ex) {
  210.79 +                                stream = ex;
  210.80 +                                throw ex;
  210.81 +                            }
  210.82 +                        }
  210.83 +                    }
  210.84 +
  210.85 +                    @Override
  210.86 +                    public InputStream getInputStream() throws IOException {
  210.87 +                        connect();
  210.88 +                        if (stream instanceof IOException) {
  210.89 +                            throw (IOException)stream;
  210.90 +                        }
  210.91 +                        return (InputStream)stream;
  210.92 +                    }
  210.93 +                    
  210.94 +                    
  210.95 +                };
  210.96 +            }
  210.97 +        };
  210.98          return universal;
  210.99      }
 210.100  
 210.101 @@ -1053,10 +1105,16 @@
 210.102      }
 210.103      
 210.104      @JavaScriptBody(args = {}, body = 
 210.105 -          "if (typeof window !== 'object') return null;\n"
 210.106 -        + "if (!window.location) return null;\n"
 210.107 -        + "if (!window.location.href) return null;\n"
 210.108 -        + "return window.location.href;\n"
 210.109 +          "var l;\n"
 210.110 +        + "if (typeof location !== 'object') {"
 210.111 +        + "  if (typeof window !== 'object') return null;\n"
 210.112 +        + "  if (!window.location) return null;\n"
 210.113 +        + "  l = window.location;\n"
 210.114 +        + "} else {\n"
 210.115 +        + "  l = location;\n"
 210.116 +        + "}\n"
 210.117 +        + "if (!l.href) return null;\n"
 210.118 +        + "return l.href;\n"
 210.119      )
 210.120      private static native String findBaseURL();
 210.121  }
   211.1 --- a/rt/emul/mini/src/main/java/java/net/URLStreamHandler.java	Tue Feb 11 10:48:24 2014 +0100
   211.2 +++ b/rt/emul/mini/src/main/java/java/net/URLStreamHandler.java	Tue Feb 11 13:31:42 2014 +0100
   211.3 @@ -25,6 +25,8 @@
   211.4  
   211.5  package java.net;
   211.6  
   211.7 +import java.io.IOException;
   211.8 +
   211.9  
  211.10  /**
  211.11   * The abstract class <code>URLStreamHandler</code> is the common
  211.12 @@ -62,7 +64,7 @@
  211.13       * @exception  IOException  if an I/O error occurs while opening the
  211.14       *               connection.
  211.15       */
  211.16 -//    abstract protected URLConnection openConnection(URL u) throws IOException;
  211.17 +    abstract protected URLConnection openConnection(URL u) throws IOException;
  211.18  
  211.19      /**
  211.20       * Same as openConnection(URL), except that the connection will be
   212.1 --- a/rt/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/lang/System.java	Tue Feb 11 10:48:24 2014 +0100
   212.2 +++ b/rt/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/lang/System.java	Tue Feb 11 13:31:42 2014 +0100
   212.3 @@ -19,6 +19,7 @@
   212.4  
   212.5  import java.lang.reflect.Method;
   212.6  import org.apidesign.bck2brwsr.core.JavaScriptBody;
   212.7 +import org.apidesign.bck2brwsr.core.JavaScriptOnly;
   212.8  
   212.9  /**
  212.10   *
  212.11 @@ -71,4 +72,27 @@
  212.12      }
  212.13      @JavaScriptBody(args = { "obj" }, body="return vm.java_lang_Object(false).hashCode__I.call(obj);")
  212.14      public static native int identityHashCode(Object obj);
  212.15 +    
  212.16 +    @JavaScriptOnly(name = "toJS", value = "function(v) {\n" + 
  212.17 +        "  if (v === null) return null;\n" +
  212.18 +        "  if (Object.prototype.toString.call(v) === '[object Array]') {\n" +
  212.19 +        "    return vm.org_apidesign_bck2brwsr_emul_lang_System(false).convArray__Ljava_lang_Object_2Ljava_lang_Object_2(v);\n" +
  212.20 +        "  }\n" +
  212.21 +        "  return v.valueOf();\n" +
  212.22 +        "}\n"
  212.23 +    )
  212.24 +    public static native int toJS();
  212.25 +    
  212.26 +    private static Object convArray(Object o) {
  212.27 +        if (o instanceof Object[]) {
  212.28 +            Object[] arr = (Object[]) o;
  212.29 +            final int l = arr.length;
  212.30 +            Object[] ret = new Object[l];
  212.31 +            for (int i = 0; i < l; i++) {
  212.32 +                ret[i] = convArray(arr[i]);
  212.33 +            }
  212.34 +            return ret;
  212.35 +        }
  212.36 +        return o;
  212.37 +    }
  212.38  }
   213.1 --- a/rt/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/reflect/MethodImpl.java	Tue Feb 11 10:48:24 2014 +0100
   213.2 +++ b/rt/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/reflect/MethodImpl.java	Tue Feb 11 13:31:42 2014 +0100
   213.3 @@ -18,6 +18,7 @@
   213.4  package org.apidesign.bck2brwsr.emul.reflect;
   213.5  
   213.6  import java.lang.reflect.Array;
   213.7 +import java.lang.reflect.Constructor;
   213.8  import java.lang.reflect.Method;
   213.9  import java.util.Enumeration;
  213.10  import org.apidesign.bck2brwsr.core.JavaScriptBody;
  213.11 @@ -37,15 +38,17 @@
  213.12      }
  213.13  
  213.14      protected abstract Method create(Class<?> declaringClass, String name, Object data, String sig);
  213.15 +    protected abstract Constructor create(Class<?> declaringClass, Object data, String sig);
  213.16      
  213.17      
  213.18      //
  213.19      // bck2brwsr implementation
  213.20      //
  213.21  
  213.22 -    @JavaScriptBody(args = {"clazz", "prefix"},
  213.23 +    @JavaScriptBody(args = {"clazz", "prefix", "cnstr"},
  213.24          body = ""
  213.25 -        + "var c = clazz.cnstr.prototype;"
  213.26 +        + "var c = clazz.cnstr;\n"
  213.27 +        + "if (!cnstr) c = c.prototype;"
  213.28          + "var arr = new Array();\n"
  213.29          + "for (m in c) {\n"
  213.30          + "  if (m.indexOf(prefix) === 0) {\n"
  213.31 @@ -57,11 +60,55 @@
  213.32          + "}\n"
  213.33          + "return arr;")
  213.34      private static native Object[] findMethodData(
  213.35 -        Class<?> clazz, String prefix);
  213.36 +        Class<?> clazz, String prefix, boolean cnstr);
  213.37  
  213.38 +    public static Constructor findConstructor(
  213.39 +        Class<?> clazz, Class<?>... parameterTypes) {
  213.40 +        Object[] data = findMethodData(clazz, "cons__", true);
  213.41 +        BIG: for (int i = 0; i < data.length; i += 3) {
  213.42 +            String sig = ((String) data[i]).substring(6);
  213.43 +            Class<?> cls = (Class<?>) data[i + 2];
  213.44 +            Constructor tmp = INSTANCE.create(cls, data[i + 1], sig);
  213.45 +            Class<?>[] tmpParms = tmp.getParameterTypes();
  213.46 +            if (parameterTypes.length != tmpParms.length) {
  213.47 +                continue;
  213.48 +            }
  213.49 +            for (int j = 0; j < tmpParms.length; j++) {
  213.50 +                if (!parameterTypes[j].equals(tmpParms[j])) {
  213.51 +                    continue BIG;
  213.52 +                }
  213.53 +            }
  213.54 +            return tmp;
  213.55 +        }
  213.56 +        return null;
  213.57 +    }
  213.58 +
  213.59 +    public static Constructor[] findConstructors(Class<?> clazz, int mask) {
  213.60 +        Object[] namesAndData = findMethodData(clazz, "", true);
  213.61 +        int cnt = 0;
  213.62 +        for (int i = 0; i < namesAndData.length; i += 3) {
  213.63 +            String sig = (String) namesAndData[i];
  213.64 +            Object data = namesAndData[i + 1];
  213.65 +            if (!sig.startsWith("cons__")) {
  213.66 +                continue;
  213.67 +            }
  213.68 +            sig = sig.substring(6);
  213.69 +            Class<?> cls = (Class<?>) namesAndData[i + 2];
  213.70 +            final Constructor m = INSTANCE.create(cls, data, sig);
  213.71 +            if ((m.getModifiers() & mask) == 0) {
  213.72 +                continue;
  213.73 +            }
  213.74 +            namesAndData[cnt++] = m;
  213.75 +        }
  213.76 +        Constructor[] arr = new Constructor[cnt];
  213.77 +        for (int i = 0; i < cnt; i++) {
  213.78 +            arr[i] = (Constructor) namesAndData[i];
  213.79 +        }
  213.80 +        return arr;
  213.81 +    }
  213.82      public static Method findMethod(
  213.83          Class<?> clazz, String name, Class<?>... parameterTypes) {
  213.84 -        Object[] data = findMethodData(clazz, name + "__");
  213.85 +        Object[] data = findMethodData(clazz, name + "__", false);
  213.86          BIG: for (int i = 0; i < data.length; i += 3) {
  213.87              String sig = ((String) data[i]).substring(name.length() + 2);
  213.88              Class<?> cls = (Class<?>) data[i + 2];
  213.89 @@ -81,7 +128,7 @@
  213.90      }
  213.91  
  213.92      public static Method[] findMethods(Class<?> clazz, int mask) {
  213.93 -        Object[] namesAndData = findMethodData(clazz, "");
  213.94 +        Object[] namesAndData = findMethodData(clazz, "", false);
  213.95          int cnt = 0;
  213.96          for (int i = 0; i < namesAndData.length; i += 3) {
  213.97              String sig = (String) namesAndData[i];
   214.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   214.2 +++ b/rt/emul/mini/src/main/java/org/apidesign/vm4brwsr/api/VM.java	Tue Feb 11 13:31:42 2014 +0100
   214.3 @@ -0,0 +1,47 @@
   214.4 +/**
   214.5 + * Back 2 Browser Bytecode Translator
   214.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
   214.7 + *
   214.8 + * This program is free software: you can redistribute it and/or modify
   214.9 + * it under the terms of the GNU General Public License as published by
  214.10 + * the Free Software Foundation, version 2 of the License.
  214.11 + *
  214.12 + * This program is distributed in the hope that it will be useful,
  214.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  214.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  214.15 + * GNU General Public License for more details.
  214.16 + *
  214.17 + * You should have received a copy of the GNU General Public License
  214.18 + * along with this program. Look for COPYING file in the top folder.
  214.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
  214.20 + */
  214.21 +package org.apidesign.vm4brwsr.api;
  214.22 +
  214.23 +import java.io.IOException;
  214.24 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
  214.25 +
  214.26 +/** Utility methods to talk to the Bck2Brwsr virtual machine.
  214.27 + *
  214.28 + * @author Jaroslav Tulach <jtulach@netbeans.org>
  214.29 + * @since 0.9
  214.30 + */
  214.31 +public final class VM {
  214.32 +    private VM() {
  214.33 +    }
  214.34 +
  214.35 +    /** Takes an existing class and replaces its existing byte code 
  214.36 +     * with new one.
  214.37 +     * 
  214.38 +     * @param clazz existing class to reload
  214.39 +     * @param byteCode new bytecode
  214.40 +     * @throws IOException an exception is something goes wrong
  214.41 +     */
  214.42 +    public static void reload(Class<?> clazz, byte[] byteCode) throws IOException {
  214.43 +        reloadImpl(clazz.getName(), byteCode);
  214.44 +    }
  214.45 +    
  214.46 +    @JavaScriptBody(args = { "name", "byteCode" }, body = "vm._reload(name, byteCode);")
  214.47 +    private static void reloadImpl(String name, byte[] byteCode) throws IOException {
  214.48 +        throw new IOException();
  214.49 +    }
  214.50 +}
   215.1 --- a/rt/emul/mini/src/main/resources/org/apidesign/vm4brwsr/emul/lang/java_lang_Number.js	Tue Feb 11 10:48:24 2014 +0100
   215.2 +++ b/rt/emul/mini/src/main/resources/org/apidesign/vm4brwsr/emul/lang/java_lang_Number.js	Tue Feb 11 13:31:42 2014 +0100
   215.3 @@ -176,6 +176,8 @@
   215.4      };
   215.5  
   215.6      numberPrototype.shl64 = function(x) {
   215.7 +        x &= 0x3f;
   215.8 +        if (x == 0) return this;
   215.9          if (x >= 32) {
  215.10              var hi = this << (x - 32);
  215.11              return hi.next32(0);
  215.12 @@ -190,6 +192,8 @@
  215.13      };
  215.14  
  215.15      numberPrototype.shr64 = function(x) {
  215.16 +        x &= 0x3f;
  215.17 +        if (x == 0) return this;
  215.18          if (x >= 32) {
  215.19              var low = this.high32() >> (x - 32);
  215.20              low += (low < 0) ? (__m32 + 1) : 0;
  215.21 @@ -205,6 +209,8 @@
  215.22      };
  215.23  
  215.24      numberPrototype.ushr64 = function(x) {
  215.25 +        x &= 0x3f;
  215.26 +        if (x == 0) return this;
  215.27          if (x >= 32) {
  215.28              var low = this.high32() >>> (x - 32);
  215.29              low += (low < 0) ? (__m32 + 1) : 0;
   216.1 --- a/rt/emul/mini/src/main/resources/org/apidesign/vm4brwsr/emul/lang/java_lang_String.js	Tue Feb 11 10:48:24 2014 +0100
   216.2 +++ b/rt/emul/mini/src/main/resources/org/apidesign/vm4brwsr/emul/lang/java_lang_String.js	Tue Feb 11 13:31:42 2014 +0100
   216.3 @@ -2,16 +2,16 @@
   216.4  vm.java_lang_reflect_Array(false);
   216.5  vm.java_lang_String(false);
   216.6  
   216.7 -Array.prototype.at = function(indx, value) {
   216.8 -  if (indx < 0 || indx > this.length) {
   216.9 +Array.at = function(arr, indx, value) {
  216.10 +  if (indx < 0 || indx >= arr.length) {
  216.11        var e = vm.java_lang_ArrayIndexOutOfBoundsException(true);
  216.12        e.constructor.cons__VLjava_lang_String_2.call(e, indx.toString());
  216.13        throw e;
  216.14    }
  216.15 -  if (arguments.length === 2) {
  216.16 -      this[indx] = value;
  216.17 +  if (arguments.length === 3) {
  216.18 +      arr[indx] = value;
  216.19    }
  216.20 -  return this[indx];
  216.21 +  return arr[indx];
  216.22  };
  216.23  Array.prototype.getClass__Ljava_lang_Class_2 = function() {
  216.24    return vm.java_lang_Class(false).defineArray__Ljava_lang_Class_2Ljava_lang_String_2(this.jvmName);
   217.1 --- a/rt/mojo/src/main/java/org/apidesign/bck2brwsr/mojo/BrwsrMojo.java	Tue Feb 11 10:48:24 2014 +0100
   217.2 +++ b/rt/mojo/src/main/java/org/apidesign/bck2brwsr/mojo/BrwsrMojo.java	Tue Feb 11 13:31:42 2014 +0100
   217.3 @@ -70,12 +70,18 @@
   217.4      /** Root of all pages, and files, etc. */
   217.5      @Parameter
   217.6      private File directory;
   217.7 +    
   217.8 +    @Parameter(defaultValue="${project.build.directory}/bck2brwsr.js")
   217.9 +    private File javascript;
  217.10  
  217.11      @Override
  217.12      public void execute() throws MojoExecutionException {
  217.13          if (startpage == null) {
  217.14              throw new MojoExecutionException("You have to provide a start page");
  217.15          }
  217.16 +        if (javascript != null && javascript.isFile()) {
  217.17 +            System.setProperty("bck2brwsr.js", javascript.toURI().toString());
  217.18 +        }
  217.19          try {
  217.20              Closeable httpServer;
  217.21              if (directory != null) {
   218.1 --- a/rt/mojo/src/main/java/org/apidesign/bck2brwsr/mojo/Java2JavaScript.java	Tue Feb 11 10:48:24 2014 +0100
   218.2 +++ b/rt/mojo/src/main/java/org/apidesign/bck2brwsr/mojo/Java2JavaScript.java	Tue Feb 11 13:31:42 2014 +0100
   218.3 @@ -50,7 +50,7 @@
   218.4      @Parameter(defaultValue="${project.build.directory}/classes")
   218.5      private File classes;
   218.6      /** JavaScript file to generate */
   218.7 -    @Parameter
   218.8 +    @Parameter(defaultValue="${project.build.directory}/bck2brwsr.js")
   218.9      private File javascript;
  218.10  
  218.11      /** Additional classes that should be pre-compiled into the javascript 
  218.12 @@ -70,12 +70,19 @@
  218.13       */
  218.14      @Parameter(defaultValue="NONE")
  218.15      private ObfuscationLevel obfuscation;
  218.16 +    
  218.17 +    /** Should classes from rt.jar be included? */
  218.18 +    @Parameter(defaultValue = "false")
  218.19 +    private boolean ignoreBootClassPath;
  218.20  
  218.21      @Override
  218.22      public void execute() throws MojoExecutionException {
  218.23          if (!classes.isDirectory()) {
  218.24              throw new MojoExecutionException("Can't find " + classes);
  218.25          }
  218.26 +        if (javascript == null) {
  218.27 +            throw new MojoExecutionException("Need to define 'javascript' attribute with a path to file to generate");
  218.28 +        }
  218.29  
  218.30          List<String> arr = new ArrayList<String>();
  218.31          long newest = collectAllClasses("", classes, arr);
  218.32 @@ -94,7 +101,7 @@
  218.33              FileWriter w = new FileWriter(javascript);
  218.34              Bck2Brwsr.newCompiler().
  218.35                  obfuscation(obfuscation).
  218.36 -                resources(url).
  218.37 +                resources(url, ignoreBootClassPath).
  218.38                  addRootClasses(arr.toArray(new String[0])).
  218.39                  generate(w);
  218.40              w.close();
   219.1 --- a/rt/vm/pom.xml	Tue Feb 11 10:48:24 2014 +0100
   219.2 +++ b/rt/vm/pom.xml	Tue Feb 11 13:31:42 2014 +0100
   219.3 @@ -18,6 +18,7 @@
   219.4      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
   219.5      <author.name>Jaroslav Tulach</author.name>
   219.6      <author.email>jaroslav.tulach@apidesign.org</author.email>
   219.7 +    <bck2brwsr.obfuscationlevel>MINIMAL</bck2brwsr.obfuscationlevel>
   219.8    </properties>
   219.9    
  219.10    <repositories>
  219.11 @@ -91,7 +92,7 @@
  219.12                              <classpath />
  219.13                              <argument>org.apidesign.vm4brwsr.Main</argument>
  219.14                              <argument>--obfuscatelevel</argument>
  219.15 -                            <argument>MINIMAL</argument>
  219.16 +                            <argument>${bck2brwsr.obfuscationlevel}</argument>
  219.17                              <argument>${project.build.directory}/bck2brwsr.js</argument>
  219.18                              <argument>org/apidesign/vm4brwsr/Bck2Brwsr</argument>
  219.19                          </arguments>
  219.20 @@ -153,7 +154,7 @@
  219.21        <scope>compile</scope>
  219.22      </dependency>
  219.23      <dependency>
  219.24 -      <groupId>org.apidesign.html</groupId>
  219.25 +      <groupId>org.netbeans.html</groupId>
  219.26        <artifactId>net.java.html.boot</artifactId>
  219.27        <scope>test</scope>
  219.28        <version>${net.java.html.version}</version>
   220.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/Bck2Brwsr.java	Tue Feb 11 10:48:24 2014 +0100
   220.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/Bck2Brwsr.java	Tue Feb 11 13:31:42 2014 +0100
   220.3 @@ -19,8 +19,6 @@
   220.4  
   220.5  import java.io.IOException;
   220.6  import java.io.InputStream;
   220.7 -import java.net.URL;
   220.8 -import java.util.Enumeration;
   220.9  
  220.10  /** Build your own virtual machine! Use methods in this class to generate
  220.11   * a skeleton JVM in JavaScript that contains pre-compiled classes of your
  220.12 @@ -151,7 +149,21 @@
  220.13       * @since 0.5
  220.14       */
  220.15      public Bck2Brwsr resources(final ClassLoader loader) {
  220.16 -        return resources(new LdrRsrcs(loader));
  220.17 +        return resources(loader, false);
  220.18 +    }
  220.19 +
  220.20 +    /** A way to change the provider of additional resources (classes) for the 
  220.21 +     * compiler by specifying classloader to use for loading them.
  220.22 +     * 
  220.23 +     * @param loader class loader to load the resources from
  220.24 +     * @param ignoreBootClassPath <code>true</code> if classes loaded
  220.25 +     *    from <code>rt.jar</code> 
  220.26 +     * @return new instance of the compiler with all values being the same, just 
  220.27 +     *   different resources provider
  220.28 +     * @since 0.9
  220.29 +     */
  220.30 +    public Bck2Brwsr resources(final ClassLoader loader, boolean ignoreBootClassPath) {
  220.31 +        return resources(new LdrRsrcs(loader, ignoreBootClassPath));
  220.32      }
  220.33      
  220.34      /** Generates virtual machine based on previous configuration of the 
  220.35 @@ -161,7 +173,7 @@
  220.36       * @since 0.5
  220.37       */
  220.38      public void generate(Appendable out) throws IOException {
  220.39 -        Resources r = res != null ? res : new LdrRsrcs(Bck2Brwsr.class.getClassLoader());
  220.40 +        Resources r = res != null ? res : new LdrRsrcs(Bck2Brwsr.class.getClassLoader(), false);
  220.41          if (level != ObfuscationLevel.NONE) {
  220.42              try {
  220.43                  ClosureWrapper.produceTo(out, level, r, classes);
   221.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeParser.java	Tue Feb 11 10:48:24 2014 +0100
   221.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeParser.java	Tue Feb 11 13:31:42 2014 +0100
   221.3 @@ -1845,6 +1845,12 @@
   221.4                              case '\"':
   221.5                                  sb.append('\\').append('\"');
   221.6                                  break;
   221.7 +                            case '\u2028':
   221.8 +                                sb.append("\\u2028");
   221.9 +                                break;
  221.10 +                            case '\u2029':
  221.11 +                                sb.append("\\u2029");
  221.12 +                                break;
  221.13                              default:
  221.14                                  sb.append(c);
  221.15                          }
   222.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java	Tue Feb 11 10:48:24 2014 +0100
   222.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java	Tue Feb 11 13:31:42 2014 +0100
   222.3 @@ -139,7 +139,7 @@
   222.4          if (proto == null) {
   222.5              String sc = jc.getSuperClassName(); // with _
   222.6              out.append("\n    var pp = ").
   222.7 -                append(accessClass(sc.replace('/', '_'))).append("(true);");
   222.8 +                append(accessClass(mangleClassName(sc))).append("(true);");
   222.9              out.append("\n    var p = CLS.prototype = pp;");
  222.10              out.append("\n    var c = p;");
  222.11              out.append("\n    var sprcls = pp.constructor.$class;");
  222.12 @@ -153,10 +153,10 @@
  222.13          }
  222.14          for (FieldData v : jc.getFields()) {
  222.15              if (v.isStatic()) {
  222.16 -                out.append("\n  CLS.").append(v.getName()).append(initField(v));
  222.17 +                out.append("\n  CLS.fld_").append(v.getName()).append(initField(v));
  222.18                  out.append("\n  c._").append(v.getName()).append(" = function (v) {")
  222.19 -                   .append("  if (arguments.length == 1) CLS.").append(v.getName())
  222.20 -                   .append(" = v; return CLS.").
  222.21 +                   .append("  if (arguments.length == 1) CLS.fld_").append(v.getName())
  222.22 +                   .append(" = v; return CLS.fld_").
  222.23                      append(v.getName()).append("; };");
  222.24              } else {
  222.25                  out.append("\n  c._").append(v.getName()).append(" = function (v) {")
  222.26 @@ -975,7 +975,7 @@
  222.27                      int indx = readUShortArg(byteCodes, i);
  222.28                      String ci = jc.getClassName(indx);
  222.29                      emit(out, "var @1 = new @2;",
  222.30 -                         smapper.pushA(), accessClass(ci.replace('/', '_')));
  222.31 +                         smapper.pushA(), accessClass(mangleClassName(ci)));
  222.32                      addReference(ci);
  222.33                      i += 2;
  222.34                      break;
  222.35 @@ -1001,49 +1001,49 @@
  222.36                           smapper.popA(), smapper.pushI());
  222.37                      break;
  222.38                  case opc_lastore:
  222.39 -                    emit(out, "@3.at(@2, @1);",
  222.40 +                    emit(out, "Array.at(@3, @2, @1);",
  222.41                           smapper.popL(), smapper.popI(), smapper.popA());
  222.42                      break;
  222.43                  case opc_fastore:
  222.44 -                    emit(out, "@3.at(@2, @1);",
  222.45 +                    emit(out, "Array.at(@3, @2, @1);",
  222.46                           smapper.popF(), smapper.popI(), smapper.popA());
  222.47                      break;
  222.48                  case opc_dastore:
  222.49 -                    emit(out, "@3.at(@2, @1);",
  222.50 +                    emit(out, "Array.at(@3, @2, @1);",
  222.51                           smapper.popD(), smapper.popI(), smapper.popA());
  222.52                      break;
  222.53                  case opc_aastore:
  222.54 -                    emit(out, "@3.at(@2, @1);",
  222.55 +                    emit(out, "Array.at(@3, @2, @1);",
  222.56                           smapper.popA(), smapper.popI(), smapper.popA());
  222.57                      break;
  222.58                  case opc_iastore:
  222.59                  case opc_bastore:
  222.60                  case opc_castore:
  222.61                  case opc_sastore:
  222.62 -                    emit(out, "@3.at(@2, @1);",
  222.63 +                    emit(out, "Array.at(@3, @2, @1);",
  222.64                           smapper.popI(), smapper.popI(), smapper.popA());
  222.65                      break;
  222.66                  case opc_laload:
  222.67 -                    emit(out, "var @3 = @2.at(@1);",
  222.68 +                    emit(out, "var @3 = Array.at(@2, @1);",
  222.69                           smapper.popI(), smapper.popA(), smapper.pushL());
  222.70                      break;
  222.71                  case opc_faload:
  222.72 -                    emit(out, "var @3 = @2.at(@1);",
  222.73 +                    emit(out, "var @3 = Array.at(@2, @1);",
  222.74                           smapper.popI(), smapper.popA(), smapper.pushF());
  222.75                      break;
  222.76                  case opc_daload:
  222.77 -                    emit(out, "var @3 = @2.at(@1);",
  222.78 +                    emit(out, "var @3 = Array.at(@2, @1);",
  222.79                           smapper.popI(), smapper.popA(), smapper.pushD());
  222.80                      break;
  222.81                  case opc_aaload:
  222.82 -                    emit(out, "var @3 = @2.at(@1);",
  222.83 +                    emit(out, "var @3 = Array.at(@2, @1);",
  222.84                           smapper.popI(), smapper.popA(), smapper.pushA());
  222.85                      break;
  222.86                  case opc_iaload:
  222.87                  case opc_baload:
  222.88                  case opc_caload:
  222.89                  case opc_saload:
  222.90 -                    emit(out, "var @3 = @2.at(@1);",
  222.91 +                    emit(out, "var @3 = Array.at(@2, @1);",
  222.92                           smapper.popI(), smapper.popA(), smapper.pushI());
  222.93                      break;
  222.94                  case opc_pop:
  222.95 @@ -1214,7 +1214,7 @@
  222.96                      int indx = readUShortArg(byteCodes, i);
  222.97                      String[] fi = jc.getFieldInfoName(indx);
  222.98                      final int type = VarType.fromFieldType(fi[2].charAt(0));
  222.99 -                    final String mangleClass = mangleSig(fi[0]);
 222.100 +                    final String mangleClass = mangleClassName(fi[0]);
 222.101                      final String mangleClassAccess = accessClass(mangleClass);
 222.102                      emit(out, "var @2 = @4(false)._@3.call(@1);",
 222.103                           smapper.popA(),
 222.104 @@ -1227,7 +1227,7 @@
 222.105                      int indx = readUShortArg(byteCodes, i);
 222.106                      String[] fi = jc.getFieldInfoName(indx);
 222.107                      final int type = VarType.fromFieldType(fi[2].charAt(0));
 222.108 -                    final String mangleClass = mangleSig(fi[0]);
 222.109 +                    final String mangleClass = mangleClassName(fi[0]);
 222.110                      final String mangleClassAccess = accessClass(mangleClass);
 222.111                      emit(out, "@4(false)._@3.call(@2, @1);",
 222.112                           smapper.popT(type),
 222.113 @@ -1243,7 +1243,7 @@
 222.114                      final int type = VarType.fromFieldType(fi[2].charAt(0));
 222.115                      emit(out, "var @1 = @2(false)._@3();",
 222.116                           smapper.pushT(type),
 222.117 -                         accessClass(fi[0].replace('/', '_')), fi[1]);
 222.118 +                         accessClass(mangleClassName(fi[0])), fi[1]);
 222.119                      i += 2;
 222.120                      addReference(fi[0]);
 222.121                      break;
 222.122 @@ -1253,7 +1253,7 @@
 222.123                      String[] fi = jc.getFieldInfoName(indx);
 222.124                      final int type = VarType.fromFieldType(fi[2].charAt(0));
 222.125                      emit(out, "@1(false)._@2(@3);",
 222.126 -                         accessClass(fi[0].replace('/', '_')), fi[1],
 222.127 +                         accessClass(mangleClassName(fi[0])), fi[1],
 222.128                           smapper.popT(type));
 222.129                      i += 2;
 222.130                      addReference(fi[0]);
 222.131 @@ -1435,8 +1435,20 @@
 222.132          return mangleSig(sig, 0, sig.length());
 222.133      }
 222.134      
 222.135 +    private static String mangleMethodName(String name) {
 222.136 +        StringBuilder sb = new StringBuilder(name.length() * 2);
 222.137 +        int last = name.length();
 222.138 +        for (int i = 0; i < last; i++) {
 222.139 +            final char ch = name.charAt(i);
 222.140 +            switch (ch) {
 222.141 +                case '_': sb.append("_1"); break;
 222.142 +                default: sb.append(ch); break;
 222.143 +            }
 222.144 +        }
 222.145 +        return sb.toString();
 222.146 +    }
 222.147      private static String mangleSig(String txt, int first, int last) {
 222.148 -        StringBuilder sb = new StringBuilder();
 222.149 +        StringBuilder sb = new StringBuilder((last - first) * 2);
 222.150          for (int i = first; i < last; i++) {
 222.151              final char ch = txt.charAt(i);
 222.152              switch (ch) {
 222.153 @@ -1449,6 +1461,10 @@
 222.154          }
 222.155          return sb.toString();
 222.156      }
 222.157 +    
 222.158 +    private static String mangleClassName(String name) {
 222.159 +        return mangleSig(name);
 222.160 +    }
 222.161  
 222.162      private static String findMethodName(MethodData m, StringBuilder cnt) {
 222.163          StringBuilder name = new StringBuilder();
 222.164 @@ -1457,7 +1473,7 @@
 222.165          } else if ("<clinit>".equals(m.getName())) { // NOI18N
 222.166              name.append("class"); // NOI18N
 222.167          } else {
 222.168 -            name.append(m.getName());
 222.169 +            name.append(mangleMethodName(m.getName()));
 222.170          } 
 222.171          
 222.172          countArgs(m.getInternalSig(), new char[1], name, cnt);
 222.173 @@ -1471,7 +1487,7 @@
 222.174          if ("<init>".equals(nm)) { // NOI18N
 222.175              name.append("cons"); // NOI18N
 222.176          } else {
 222.177 -            name.append(nm);
 222.178 +            name.append(mangleMethodName(nm));
 222.179          }
 222.180          countArgs(descr, returnType, name, cnt);
 222.181          return name.toString();
 222.182 @@ -1499,7 +1515,7 @@
 222.183          }
 222.184  
 222.185          final String in = mi[0];
 222.186 -        out.append(accessClass(in.replace('/', '_')));
 222.187 +        out.append(accessClass(mangleClassName(in)));
 222.188          out.append("(false).");
 222.189          if (mn.startsWith("cons_")) {
 222.190              out.append("constructor.");
 222.191 @@ -1585,7 +1601,7 @@
 222.192                  s = accessClass("java_lang_Class") + "(false).forName__Ljava_lang_Class_2Ljava_lang_String_2('" + classRef[0] + "');";
 222.193              } else {
 222.194                  addReference(classRef[0]);
 222.195 -                s = accessClass(s.replace('/', '_')) + "(false).constructor.$class";
 222.196 +                s = accessClass(mangleClassName(s)) + "(false).constructor.$class";
 222.197              }
 222.198          }
 222.199          return s;
 222.200 @@ -1607,6 +1623,7 @@
 222.201              String[] args = new String[30];
 222.202              String body;
 222.203              boolean javacall;
 222.204 +            boolean html4j;
 222.205              
 222.206              @Override
 222.207              protected void visitAttr(String type, String attr, String at, String value) {
 222.208 @@ -1620,6 +1637,7 @@
 222.209                      }
 222.210                  }
 222.211                  if (type.equals(htmlType)) {
 222.212 +                    html4j = true;
 222.213                      if ("body".equals(attr)) {
 222.214                          body = value;
 222.215                      } else if ("args".equals(attr)) {
 222.216 @@ -1643,12 +1661,18 @@
 222.217          out.append(" = function(");
 222.218          String space = "";
 222.219          int index = 0;
 222.220 +        StringBuilder toValue = new StringBuilder();
 222.221          for (int i = 0; i < cnt.length(); i++) {
 222.222              out.append(space);
 222.223              space = outputArg(out, p.args, index);
 222.224 +            if (p.html4j && space.length() > 0) {
 222.225 +                toValue.append("\n  ").append(p.args[index]).append(" = vm.org_apidesign_bck2brwsr_emul_lang_System(false).toJS(").
 222.226 +                    append(p.args[index]).append(");");
 222.227 +            }
 222.228              index++;
 222.229          }
 222.230          out.append(") {").append("\n");
 222.231 +        out.append(toValue.toString());
 222.232          if (p.javacall) {
 222.233              int lastSlash = jc.getClassName().lastIndexOf('/');
 222.234              final String pkg = jc.getClassName().substring(0, lastSlash);
 222.235 @@ -1695,7 +1719,7 @@
 222.236              int paramBeg = body.indexOf('(', sigEnd + 1);
 222.237              
 222.238              sb.append("vm.").append(pkgName.replace('/', '_')).append("_$JsCallbacks$(false)._VM().");
 222.239 -            sb.append(mangle(fqn, method, params, false));
 222.240 +            sb.append(mangleJsCallbacks(fqn, method, params, false));
 222.241              sb.append("(").append(refId);
 222.242              if (body.charAt(paramBeg + 1) != ')') {
 222.243                  sb.append(",");
 222.244 @@ -1732,12 +1756,13 @@
 222.245              int paramBeg = body.indexOf('(', sigEnd + 1);
 222.246              
 222.247              sb.append("vm.").append(pkgName.replace('/', '_')).append("_$JsCallbacks$(false)._VM().");
 222.248 -            sb.append(mangle(fqn, method, params, true));
 222.249 +            sb.append(mangleJsCallbacks(fqn, method, params, true));
 222.250              sb.append("(");
 222.251              pos = paramBeg + 1;
 222.252          }
 222.253      }
 222.254 -    private static String mangle(String fqn, String method, String params, boolean isStatic) {
 222.255 +
 222.256 +    static String mangleJsCallbacks(String fqn, String method, String params, boolean isStatic) {
 222.257          if (params.startsWith("(")) {
 222.258              params = params.substring(1);
 222.259          }
 222.260 @@ -1745,28 +1770,40 @@
 222.261              params = params.substring(0, params.length() - 1);
 222.262          }
 222.263          StringBuilder sb = new StringBuilder();
 222.264 -        final String rfqn = replace(fqn);
 222.265 -        final String rm = replace(method);
 222.266 -        final String rp = replace(params);
 222.267 +        final String fqnu = fqn.replace('.', '_');
 222.268 +        final String rfqn = mangleClassName(fqnu);
 222.269 +        final String rm = mangleMethodName(method);
 222.270 +        final String srp;
 222.271 +        {
 222.272 +            StringBuilder pb = new StringBuilder();
 222.273 +            int len = params.length();
 222.274 +            int indx = 0;
 222.275 +            while (indx < len) {
 222.276 +                char ch = params.charAt(indx);
 222.277 +                if (ch == '[' || ch == 'L') {
 222.278 +                    pb.append("Ljava/lang/Object;");
 222.279 +                    indx = params.indexOf(';', indx) + 1;
 222.280 +                } else {
 222.281 +                    pb.append(ch);
 222.282 +                    indx++;
 222.283 +                }
 222.284 +            }
 222.285 +            srp = mangleSig(pb.toString());
 222.286 +        }
 222.287 +        final String rp = mangleSig(params);
 222.288 +        final String mrp = mangleMethodName(rp);
 222.289          sb.append(rfqn).append("$").append(rm).
 222.290 -            append('$').append(rp).append("__Ljava_lang_Object_2");
 222.291 +            append('$').append(mrp).append("__Ljava_lang_Object_2");
 222.292          if (!isStatic) {
 222.293 -            sb.append('L').append(rfqn).append("_2");
 222.294 +            sb.append('L').append(fqnu).append("_2");
 222.295          }
 222.296 -        sb.append(rp);
 222.297 +        sb.append(srp);
 222.298          return sb.toString();
 222.299      }
 222.300  
 222.301 -    private static String replace(String orig) {
 222.302 -        return orig.replace("_", "_1").
 222.303 -            replace(";", "_2").
 222.304 -            replace("[", "_3").
 222.305 -            replace('.', '_').replace('/', '_');
 222.306 -    }
 222.307 -    
 222.308      private static String className(ClassData jc) {
 222.309          //return jc.getName().getInternalName().replace('/', '_');
 222.310 -        return jc.getClassName().replace('/', '_');
 222.311 +        return mangleClassName(jc.getClassName());
 222.312      }
 222.313      
 222.314      private static String[] findAnnotation(
 222.315 @@ -1879,8 +1916,8 @@
 222.316                  final String slashType = attrType.substring(1, attrType.length() - 1);
 222.317                  requireReference(slashType);
 222.318                  
 222.319 -                out.append(accessClass(slashType.replace('/', '_')))
 222.320 -                   .append("(false).constructor.").append(value);
 222.321 +                out.append(accessClass(mangleClassName(slashType)))
 222.322 +                   .append("(false).constructor.fld_").append(value);
 222.323              }
 222.324          };
 222.325          ap.parse(data, cd);
   223.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/LdrRsrcs.java	Tue Feb 11 10:48:24 2014 +0100
   223.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/LdrRsrcs.java	Tue Feb 11 13:31:42 2014 +0100
   223.3 @@ -28,9 +28,11 @@
   223.4   */
   223.5  final class LdrRsrcs implements Bck2Brwsr.Resources {
   223.6      private final ClassLoader loader;
   223.7 +    private final boolean skipRtJar;
   223.8  
   223.9 -    LdrRsrcs(ClassLoader loader) {
  223.10 +    LdrRsrcs(ClassLoader loader, boolean skipRtJar) {
  223.11          this.loader = loader;
  223.12 +        this.skipRtJar = skipRtJar;
  223.13      }
  223.14  
  223.15      @Override
  223.16 @@ -43,6 +45,9 @@
  223.17          if (u == null) {
  223.18              throw new IOException("Can't find " + name);
  223.19          }
  223.20 +        if (skipRtJar && u.toExternalForm().contains("lib/rt.jar!")) {
  223.21 +            return null;
  223.22 +        }
  223.23          return u.openStream();
  223.24      }
  223.25  }
   224.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/Main.java	Tue Feb 11 10:48:24 2014 +0100
   224.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/Main.java	Tue Feb 11 13:31:42 2014 +0100
   224.3 @@ -93,7 +93,7 @@
   224.4              Bck2Brwsr.newCompiler().
   224.5                  obfuscation(obfLevel).
   224.6                  addRootClasses(classes.toArray()).
   224.7 -                resources(Main.class.getClassLoader()).
   224.8 +                resources(new LdrRsrcs(Main.class.getClassLoader(), true)).
   224.9                  generate(w);
  224.10          }
  224.11      }
   225.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/VM.java	Tue Feb 11 10:48:24 2014 +0100
   225.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/VM.java	Tue Feb 11 13:31:42 2014 +0100
   225.3 @@ -61,11 +61,15 @@
   225.4          out.append("(function VM(global) {var fillInVMSkeleton = function(vm) {");
   225.5          StringArray processed = new StringArray();
   225.6          StringArray initCode = new StringArray();
   225.7 +        StringArray skipClass = new StringArray();
   225.8          for (String baseClass : names.toArray()) {
   225.9              references.add(baseClass);
  225.10              for (;;) {
  225.11                  String name = null;
  225.12                  for (String n : references.toArray()) {
  225.13 +                    if (skipClass.contains(n)) {
  225.14 +                        continue;
  225.15 +                    }
  225.16                      if (processed.contains(n)) {
  225.17                          continue;
  225.18                      }
  225.19 @@ -76,7 +80,9 @@
  225.20                  }
  225.21                  InputStream is = loadClass(l, name);
  225.22                  if (is == null) {
  225.23 -                    throw new IOException("Can't find class " + name); 
  225.24 +                    lazyReference(out, name);
  225.25 +                    skipClass.add(name);
  225.26 +                    continue;
  225.27                  }
  225.28                  try {
  225.29                      String ic = compile(is);
  225.30 @@ -131,13 +137,17 @@
  225.31          out.append(
  225.32                "  return vm;\n"
  225.33              + "  };\n"
  225.34 +            + "  function mangleClass(name) {\n"
  225.35 +            + "    return name.replace__Ljava_lang_String_2Ljava_lang_CharSequence_2Ljava_lang_CharSequence_2(\n"
  225.36 +            + "      '_', '_1').replace__Ljava_lang_String_2CC('.','_');\n"
  225.37 +            + "  };\n"
  225.38              + "  global.bck2brwsr = function() {\n"
  225.39              + "    var args = Array.prototype.slice.apply(arguments);\n"
  225.40              + "    var vm = fillInVMSkeleton({});\n"
  225.41              + "    var loader = {};\n"
  225.42              + "    loader.vm = vm;\n"
  225.43              + "    loader.loadClass = function(name) {\n"
  225.44 -            + "      var attr = name.replace__Ljava_lang_String_2CC('.','_');\n"
  225.45 +            + "      var attr = mangleClass(name);\n"
  225.46              + "      var fn = vm[attr];\n"
  225.47              + "      if (fn) return fn(false);\n"
  225.48              + "      return vm.org_apidesign_vm4brwsr_VMLazy(false).\n"
  225.49 @@ -147,13 +157,19 @@
  225.50              + "      throw 'Cannot initialize the bck2brwsr VM twice!';\n"
  225.51              + "    }\n"
  225.52              + "    vm.loadClass = loader.loadClass;\n"
  225.53 -            + "    vm.loadBytes = function(name) {\n"
  225.54 +            + "    vm._reload = function(name, byteCode) {;\n"
  225.55 +            + "      var attr = mangleClass(name);\n"
  225.56 +            + "      delete vm[attr];\n"
  225.57              + "      return vm.org_apidesign_vm4brwsr_VMLazy(false).\n"
  225.58 -            + "        loadBytes___3BLjava_lang_Object_2Ljava_lang_String_2_3Ljava_lang_Object_2(loader, name, args);\n"
  225.59 +            + "        reload__Ljava_lang_Object_2Ljava_lang_Object_2Ljava_lang_String_2_3Ljava_lang_Object_2_3B(loader, name, args, byteCode);\n"
  225.60 +            + "    };\n"
  225.61 +            + "    vm.loadBytes = function(name, skip) {\n"
  225.62 +            + "      return vm.org_apidesign_vm4brwsr_VMLazy(false).\n"
  225.63 +            + "        loadBytes___3BLjava_lang_Object_2Ljava_lang_String_2_3Ljava_lang_Object_2I(loader, name, args, typeof skip == 'number' ? skip : 0);\n"
  225.64              + "    }\n"
  225.65              + "    vm.java_lang_reflect_Array(false);\n"
  225.66              + "    vm.org_apidesign_vm4brwsr_VMLazy(false).\n"
  225.67 -            + "      loadBytes___3BLjava_lang_Object_2Ljava_lang_String_2_3Ljava_lang_Object_2(loader, null, args);\n"
  225.68 +            + "      loadBytes___3BLjava_lang_Object_2Ljava_lang_String_2_3Ljava_lang_Object_2I(loader, null, args, 0);\n"
  225.69              + "    return loader;\n"
  225.70              + "  };\n");
  225.71          out.append("}(this));");
  225.72 @@ -245,4 +261,16 @@
  225.73      String getVMObject() {
  225.74          return "vm";
  225.75      }
  225.76 +    
  225.77 +    private static void lazyReference(Appendable out, String n) throws IOException {
  225.78 +        String cls = n.replace('/', '_');
  225.79 +        String dot = n.replace('/', '.');
  225.80 +        
  225.81 +        out.append("\nvm.").append(cls).append(" = function() {");
  225.82 +        out.append("\n  var instance = arguments.length == 0 || arguments[0] === true;");
  225.83 +        out.append("\n  delete vm.").append(cls).append(";");
  225.84 +        out.append("\n  var c = vm.loadClass('").append(dot).append("');");
  225.85 +        out.append("\n  return vm.").append(cls).append("(instance);");
  225.86 +        out.append("\n}");
  225.87 +    }
  225.88  }
   226.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/VMLazy.java	Tue Feb 11 10:48:24 2014 +0100
   226.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/VMLazy.java	Tue Feb 11 13:31:42 2014 +0100
   226.3 @@ -20,7 +20,6 @@
   226.4  import java.io.ByteArrayInputStream;
   226.5  import java.io.IOException;
   226.6  import java.io.InputStream;
   226.7 -import java.lang.reflect.Array;
   226.8  import org.apidesign.bck2brwsr.core.JavaScriptBody;
   226.9  
  226.10  /**
  226.11 @@ -43,27 +42,34 @@
  226.12      throws IOException, ClassNotFoundException {
  226.13          return new VMLazy(loader, arguments).load(name, false);
  226.14      }
  226.15 +
  226.16 +    static Object reload(Object loader, String name, Object[] arguments, byte[] arr) 
  226.17 +    throws IOException, ClassNotFoundException {
  226.18 +        return new VMLazy(loader, arguments).defineClass(arr, name, false);
  226.19 +    }
  226.20      
  226.21 -    static byte[] loadBytes(Object loader, String name, Object[] arguments) throws Exception {
  226.22 -        return Zips.loadFromCp(arguments, name);
  226.23 +    static byte[] loadBytes(Object loader, String name, Object[] arguments, int skip) throws Exception {
  226.24 +        return Zips.loadFromCp(arguments, name, skip);
  226.25      }
  226.26      
  226.27      private Object load(String name, boolean instance)
  226.28      throws IOException, ClassNotFoundException {
  226.29          String res = name.replace('.', '/') + ".class";
  226.30 -        byte[] arr = Zips.loadFromCp(args, res);
  226.31 +        byte[] arr = Zips.loadFromCp(args, res, 0);
  226.32          if (arr == null) {
  226.33              throw new ClassNotFoundException(name);
  226.34          }
  226.35 -//        beingDefined(loader, name);
  226.36 +        
  226.37 +        return defineClass(arr, name, instance);
  226.38 +    }
  226.39 +
  226.40 +    private Object defineClass(byte[] arr, String name, boolean instance) throws IOException {
  226.41          StringBuilder out = new StringBuilder(65535);
  226.42          out.append("var loader = arguments[0];\n");
  226.43          out.append("var vm = loader.vm;\n");
  226.44          int prelude = out.length();
  226.45          String initCode = new Gen(this, out).compile(new ByteArrayInputStream(arr));
  226.46          String code = out.toString().toString();
  226.47 -//        dump("Loading " + name);
  226.48 -        dump(code);
  226.49          String under = name.replace('.', '_');
  226.50          Object fn = applyCode(loader, under, code, instance);
  226.51          
  226.52 @@ -71,26 +77,12 @@
  226.53              out.setLength(prelude);
  226.54              out.append(initCode);
  226.55              code = out.toString().toString();
  226.56 -            dump(code);
  226.57              applyCode(loader, null, code, false);
  226.58          }            
  226.59          
  226.60          return fn;
  226.61      }
  226.62  
  226.63 -//    @JavaScriptBody(args = "s", body = "java.lang.System.out.println(s.toString());")
  226.64 -    static void dump(String s) {
  226.65 -    }
  226.66 -
  226.67 -/* possibly not needed:
  226.68 -    @JavaScriptBody(args = {"loader", "n" }, body =
  226.69 -        "var cls = n.replace__Ljava_lang_String_2CC(n, '.','_').toString();" +
  226.70 -        "loader.vm[cls] = true;\n"
  226.71 -    )
  226.72 -    private static native void beingDefined(Object loader, String name);
  226.73 -*/
  226.74 -    
  226.75 -
  226.76      @JavaScriptBody(args = {"loader", "name", "script", "instance" }, body =
  226.77          "try {\n" +
  226.78          "  new Function(script)(loader, name);\n" +
   227.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/Zips.java	Tue Feb 11 10:48:24 2014 +0100
   227.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/Zips.java	Tue Feb 11 13:31:42 2014 +0100
   227.3 @@ -49,7 +49,7 @@
   227.4      @JavaScriptBody(args = { "arr", "index", "value" }, body = "arr[index] = value; return value;")
   227.5      private static native Object set(Object arr, int index, Object value);
   227.6      
   227.7 -    public static byte[] loadFromCp(Object classpath, String res) 
   227.8 +    public static byte[] loadFromCp(Object classpath, String res, int skip) 
   227.9      throws IOException, ClassNotFoundException {
  227.10          for (int i = 0; i < length(classpath); i++) {
  227.11              Object c = at(classpath, i);
  227.12 @@ -74,24 +74,27 @@
  227.13                  byte[] checkRes;
  227.14                  if (c instanceof Zips) {
  227.15                      checkRes = ((Zips)c).findRes(res);
  227.16 +                    if (checkRes != null && --skip < 0) {
  227.17 +                        return checkRes;
  227.18 +                    }
  227.19                  } else {
  227.20 -                    checkRes = callFunction(c, res);
  227.21 -                }
  227.22 -                if (checkRes != null) {
  227.23 -                    return checkRes;
  227.24 +                    checkRes = callFunction(c, res, skip);
  227.25 +                    if (checkRes != null) {
  227.26 +                        return checkRes;
  227.27 +                    }
  227.28                  }
  227.29              }
  227.30          }
  227.31          return null;
  227.32      }
  227.33      
  227.34 -    @JavaScriptBody(args = { "fn", "res" }, body = 
  227.35 -        "if (typeof fn === 'function') return fn(res);\n"
  227.36 +    @JavaScriptBody(args = { "fn", "res", "skip" }, body = 
  227.37 +        "if (typeof fn === 'function') return fn(res, skip);\n"
  227.38        + "return null;"
  227.39      )
  227.40 -    private static native byte[] callFunction(Object fn, String res);
  227.41 +    private static native byte[] callFunction(Object fn, String res, int skip);
  227.42      
  227.43 -    @JavaScriptBody(args = { "msg" }, body = "console.log(msg.toString());")
  227.44 +    @JavaScriptBody(args = { "msg" }, body = "if (typeof console !== 'undefined') console.log(msg.toString());")
  227.45      private static native void log(String msg);
  227.46  
  227.47      private byte[] findRes(String res) throws IOException {
   228.1 --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/ByteCodeToJavaScriptTest.java	Tue Feb 11 10:48:24 2014 +0100
   228.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/ByteCodeToJavaScriptTest.java	Tue Feb 11 13:31:42 2014 +0100
   228.3 @@ -52,4 +52,15 @@
   228.4          assertTrue(returnType[0] != 'V', "Returns string");
   228.5          assertEquals(ret, "toJavaScript__Ljava_lang_String_2_3B");
   228.6      }
   228.7 +    
   228.8 +    @Test public void mangleJsCallbackToAType() throws Exception {
   228.9 +        String res = ByteCodeToJavaScript.mangleJsCallbacks(
  228.10 +            "org.apidesign.bck2brwsr.vmtest.impl.HtmlAnnotations",
  228.11 +            "onError", "Ljava/lang/Object;", false
  228.12 +        );
  228.13 +        assertEquals(res, 
  228.14 +            "org_1apidesign_1bck2brwsr_1vmtest_1impl_1HtmlAnnotations$onError$Ljava_1lang_1Object_12__Ljava_lang_Object_2Lorg_apidesign_bck2brwsr_vmtest_impl_HtmlAnnotations_2Ljava_lang_Object_2",
  228.15 +            "Pretty long method name"
  228.16 +        );
  228.17 +    }
  228.18  }
   229.1 --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/BytesLoader.java	Tue Feb 11 10:48:24 2014 +0100
   229.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/BytesLoader.java	Tue Feb 11 13:31:42 2014 +0100
   229.3 @@ -21,20 +21,19 @@
   229.4  import java.io.InputStream;
   229.5  import java.net.URL;
   229.6  import java.util.Enumeration;
   229.7 -import java.util.Set;
   229.8 -import java.util.TreeSet;
   229.9  
  229.10  /**
  229.11   *
  229.12   * @author Jaroslav Tulach <jtulach@netbeans.org>
  229.13   */
  229.14  public final class BytesLoader {
  229.15 -    private static Set<String> requested = new TreeSet<String>();
  229.16 +    private static final StringArray requested = new StringArray();
  229.17  
  229.18      public byte[] get(String name) throws IOException {
  229.19 -        if (!requested.add(name)) {
  229.20 +        if (requested.contains(name)) {
  229.21              throw new IllegalStateException("Requested for second time: " + name);
  229.22          }
  229.23 +        requested.add(name);
  229.24          byte[] arr = readClass(name);
  229.25          /*
  229.26          System.err.print("loader['" + name + "'] = [");
   230.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   230.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/DelayedLoading.java	Tue Feb 11 13:31:42 2014 +0100
   230.3 @@ -0,0 +1,31 @@
   230.4 +/**
   230.5 + * Back 2 Browser Bytecode Translator
   230.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
   230.7 + *
   230.8 + * This program is free software: you can redistribute it and/or modify
   230.9 + * it under the terms of the GNU General Public License as published by
  230.10 + * the Free Software Foundation, version 2 of the License.
  230.11 + *
  230.12 + * This program is distributed in the hope that it will be useful,
  230.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  230.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  230.15 + * GNU General Public License for more details.
  230.16 + *
  230.17 + * You should have received a copy of the GNU General Public License
  230.18 + * along with this program. Look for COPYING file in the top folder.
  230.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
  230.20 + */
  230.21 +package org.apidesign.vm4brwsr;
  230.22 +
  230.23 +import java.net.URL;
  230.24 +
  230.25 +/**
  230.26 + *
  230.27 + * @author Jaroslav Tulach <jtulach@netbeans.org>
  230.28 + */
  230.29 +public class DelayedLoading {
  230.30 +    public static String toStrViaURI(String url) throws Exception {
  230.31 +        URL u = new URL(url);
  230.32 +        return u.toURI().toString();
  230.33 +    }
  230.34 +}
   231.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   231.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/DelayedLoadingTest.java	Tue Feb 11 13:31:42 2014 +0100
   231.3 @@ -0,0 +1,55 @@
   231.4 +/**
   231.5 + * Back 2 Browser Bytecode Translator
   231.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
   231.7 + *
   231.8 + * This program is free software: you can redistribute it and/or modify
   231.9 + * it under the terms of the GNU General Public License as published by
  231.10 + * the Free Software Foundation, version 2 of the License.
  231.11 + *
  231.12 + * This program is distributed in the hope that it will be useful,
  231.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  231.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  231.15 + * GNU General Public License for more details.
  231.16 + *
  231.17 + * You should have received a copy of the GNU General Public License
  231.18 + * along with this program. Look for COPYING file in the top folder.
  231.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
  231.20 + */
  231.21 +package org.apidesign.vm4brwsr;
  231.22 +
  231.23 +import java.net.URL;
  231.24 +import org.testng.annotations.BeforeClass;
  231.25 +import org.testng.annotations.AfterClass;
  231.26 +import org.testng.annotations.Test;
  231.27 +
  231.28 +/**
  231.29 + *
  231.30 + * @author Jaroslav Tulach <jtulach@netbeans.org>
  231.31 + */
  231.32 +public class DelayedLoadingTest {
  231.33 +    private static TestVM code;
  231.34 +    
  231.35 +    @Test public void verifyUsageOf() throws Exception {
  231.36 +        code.register(new BytesLoader());
  231.37 +        
  231.38 +        URL u = new URL("http://apidesign.org");
  231.39 +        
  231.40 +        Object str = code.execCode("Access URI", 
  231.41 +            DelayedLoading.class, "toStrViaURI__Ljava_lang_String_2Ljava_lang_String_2",
  231.42 +            u.toExternalForm(), u.toExternalForm()
  231.43 +        );
  231.44 +    }
  231.45 +    
  231.46 +    
  231.47 +    @BeforeClass 
  231.48 +    public static void compileTheCode() throws Exception {
  231.49 +        code = TestVM.compileClass(
  231.50 +            "org/apidesign/vm4brwsr/DelayedLoading");
  231.51 +    }
  231.52 +    @AfterClass
  231.53 +    public static void releaseTheCode() {
  231.54 +        code = null;
  231.55 +    }
  231.56 +    
  231.57 +}
  231.58 +
   232.1 --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/ExceptionsTest.java	Tue Feb 11 10:48:24 2014 +0100
   232.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/ExceptionsTest.java	Tue Feb 11 13:31:42 2014 +0100
   232.3 @@ -94,12 +94,14 @@
   232.4          {
   232.5              // 2nd invocation
   232.6              Object ret = code.invokeMethod(clazz, method, "java.lang.String");
   232.7 -            assertEquals(ret, Double.valueOf(2));
   232.8 +            assertTrue(ret instanceof Number, "Is number: " + ret);
   232.9 +            assertEquals(((Number)ret).doubleValue(), 2.0);
  232.10          }
  232.11          {
  232.12              // 3rd invocation
  232.13              Object ret = code.invokeMethod(clazz, method, "java.lang.Integer");
  232.14 -            assertEquals(ret, Double.valueOf(3));
  232.15 +            assertTrue(ret instanceof Number, "Is number: " + ret);
  232.16 +            assertEquals(((Number)ret).doubleValue(), 3.0);
  232.17          }
  232.18      }
  232.19      
   233.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   233.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/Hello.java	Tue Feb 11 13:31:42 2014 +0100
   233.3 @@ -0,0 +1,35 @@
   233.4 +/**
   233.5 + * Back 2 Browser Bytecode Translator
   233.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
   233.7 + *
   233.8 + * This program is free software: you can redistribute it and/or modify
   233.9 + * it under the terms of the GNU General Public License as published by
  233.10 + * the Free Software Foundation, version 2 of the License.
  233.11 + *
  233.12 + * This program is distributed in the hope that it will be useful,
  233.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  233.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  233.15 + * GNU General Public License for more details.
  233.16 + *
  233.17 + * You should have received a copy of the GNU General Public License
  233.18 + * along with this program. Look for COPYING file in the top folder.
  233.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
  233.20 + */
  233.21 +package org.apidesign.vm4brwsr;
  233.22 +
  233.23 +import java.io.IOException;
  233.24 +
  233.25 +/**
  233.26 + *
  233.27 + * @author Jaroslav Tulach <jtulach@netbeans.org>
  233.28 + */
  233.29 +public class Hello {
  233.30 +    public static String hello() {
  233.31 +        return "Hello World!";
  233.32 +    }
  233.33 +    
  233.34 +    public static Object reloadYourSelf(byte[] arr) throws IOException {
  233.35 +        org.apidesign.vm4brwsr.api.VM.reload(Hello.class, arr);
  233.36 +        return null;
  233.37 +    }
  233.38 +}
   234.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   234.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/ReloadingTest.java	Tue Feb 11 13:31:42 2014 +0100
   234.3 @@ -0,0 +1,72 @@
   234.4 +/**
   234.5 + * Back 2 Browser Bytecode Translator
   234.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
   234.7 + *
   234.8 + * This program is free software: you can redistribute it and/or modify
   234.9 + * it under the terms of the GNU General Public License as published by
  234.10 + * the Free Software Foundation, version 2 of the License.
  234.11 + *
  234.12 + * This program is distributed in the hope that it will be useful,
  234.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  234.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  234.15 + * GNU General Public License for more details.
  234.16 + *
  234.17 + * You should have received a copy of the GNU General Public License
  234.18 + * along with this program. Look for COPYING file in the top folder.
  234.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
  234.20 + */
  234.21 +package org.apidesign.vm4brwsr;
  234.22 +
  234.23 +import org.testng.annotations.BeforeClass;
  234.24 +import org.testng.annotations.AfterClass;
  234.25 +import org.testng.annotations.Test;
  234.26 +
  234.27 +/**
  234.28 + *
  234.29 + * @author Jaroslav Tulach <jtulach@netbeans.org>
  234.30 + */
  234.31 +public class ReloadingTest {
  234.32 +    private static TestVM code;
  234.33 +    
  234.34 +    @Test public void verifyUsageOf() throws Exception {
  234.35 +        code.execCode("First hello", 
  234.36 +            Hello.class, "hello__Ljava_lang_String_2",
  234.37 +            "Hello World!"
  234.38 +        );
  234.39 +
  234.40 +        byte[] arr = BytesLoader.readClass("org/apidesign/vm4brwsr/Hello.class");
  234.41 +        for (int i = 0; i < arr.length; i++) {
  234.42 +            if (arr[i] == 'H' && arr[i + 1] == 'e' && arr[i + 2] == 'l') {
  234.43 +                arr[i] = 'A';
  234.44 +                arr[i + 1] = 'h';
  234.45 +                arr[i + 2] = 'o';
  234.46 +                arr[i + 3] = 'y';
  234.47 +                arr[i + 4] = ' ';
  234.48 +                break;
  234.49 +            }
  234.50 +        }
  234.51 +        
  234.52 +        code.execCode("Redefine class",
  234.53 +            Hello.class, "reloadYourSelf__Ljava_lang_Object_2_3B",
  234.54 +            null, arr
  234.55 +        );
  234.56 +
  234.57 +        code.execCode("Second hello", 
  234.58 +            Hello.class, "hello__Ljava_lang_String_2",
  234.59 +            "Ahoy  World!"
  234.60 +        );
  234.61 +    }
  234.62 +    
  234.63 +    
  234.64 +    @BeforeClass 
  234.65 +    public static void compileTheCode() throws Exception {
  234.66 +        code = TestVM.compileClass(
  234.67 +            "org/apidesign/vm4brwsr/Hello");
  234.68 +    }
  234.69 +    @AfterClass
  234.70 +    public static void releaseTheCode() {
  234.71 +        code = null;
  234.72 +    }
  234.73 +    
  234.74 +}
  234.75 +
   235.1 --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/StringSample.java	Tue Feb 11 10:48:24 2014 +0100
   235.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/StringSample.java	Tue Feb 11 13:31:42 2014 +0100
   235.3 @@ -80,6 +80,10 @@
   235.4          return sb.toString().toString();
   235.5      }
   235.6      
   235.7 +    public static String unicode() {
   235.8 +        return "\r\n\u2028\u2029]";
   235.9 +    }
  235.10 +    
  235.11      public static String insertBuffer() {
  235.12          StringBuilder sb = new StringBuilder();
  235.13          sb.append("Jardo!");
   236.1 --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/StringTest.java	Tue Feb 11 10:48:24 2014 +0100
   236.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/StringTest.java	Tue Feb 11 13:31:42 2014 +0100
   236.3 @@ -213,6 +213,16 @@
   236.4              exp, false, true
   236.5          );
   236.6      }
   236.7 +    
   236.8 +    @Test public void weirdUnicodeCharacters() throws Exception {
   236.9 +        String exp = StringSample.unicode();
  236.10 +        
  236.11 +        assertExec(
  236.12 +            "Unicode is OK",
  236.13 +            StringSample.class, "unicode__Ljava_lang_String_2",
  236.14 +            exp
  236.15 +        );
  236.16 +    }
  236.17  
  236.18      @Test public void valueOfOnJSArray() throws Exception {
  236.19          assertExec(
   237.1 --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/TestVM.java	Tue Feb 11 10:48:24 2014 +0100
   237.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/TestVM.java	Tue Feb 11 13:31:42 2014 +0100
   237.3 @@ -24,23 +24,33 @@
   237.4  import java.net.URL;
   237.5  import java.util.Enumeration;
   237.6  import javax.script.Invocable;
   237.7 +import javax.script.ScriptContext;
   237.8  import javax.script.ScriptEngine;
   237.9  import javax.script.ScriptEngineManager;
  237.10  import javax.script.ScriptException;
  237.11  import static org.testng.Assert.*;
  237.12  
  237.13 -final class TestVM {
  237.14 +public final class TestVM {
  237.15      private final Invocable code;
  237.16      private final CharSequence codeSeq;
  237.17      private final Object bck2brwsr;
  237.18 +    private BytesLoader resources;
  237.19      
  237.20      
  237.21      private TestVM(Invocable code, CharSequence codeSeq) throws ScriptException, NoSuchMethodException {
  237.22          this.code = code;
  237.23          this.codeSeq = codeSeq;
  237.24 -        this.bck2brwsr = code.invokeFunction("bck2brwsr");
  237.25 +        this.bck2brwsr = ((ScriptEngine)code).eval("bck2brwsr(function(n) { return loader.get(n); })");
  237.26 +        ((ScriptEngine)code).getContext().setAttribute("loader", this, ScriptContext.ENGINE_SCOPE);
  237.27      }
  237.28      
  237.29 +    public void register(BytesLoader res) {
  237.30 +        this.resources = res;
  237.31 +    }
  237.32 +    
  237.33 +    public byte[] get(String res) throws IOException {
  237.34 +        return resources != null ? resources.get(res) : null;
  237.35 +    }
  237.36  
  237.37      public Object execCode(
  237.38          String msg, Class<?> clazz, String method, 
  237.39 @@ -65,7 +75,10 @@
  237.40              // in case of Long it is necessary convert it to number
  237.41              // since the Long is represented by two numbers in JavaScript
  237.42              try {
  237.43 -                ret = code.invokeMethod(ret, "toFP");
  237.44 +                final Object toFP = ((ScriptEngine)code).eval("Number.prototype.toFP");
  237.45 +                if (ret instanceof Long) {
  237.46 +                    ret = code.invokeMethod(toFP, "call", ret);
  237.47 +                }
  237.48                  ret = code.invokeFunction("Number", ret);
  237.49              } catch (ScriptException ex) {
  237.50                  fail("Conversion to number failed in " + dumpJS(codeSeq) + ": " + ex.getMessage(), ex);
  237.51 @@ -83,6 +96,9 @@
  237.52          if (ret == null) {
  237.53              return;
  237.54          }
  237.55 +        if (expRes instanceof Integer && ret instanceof Double) {
  237.56 +            expRes = ((Integer)expRes).doubleValue();
  237.57 +        }
  237.58          if (expRes != null && expRes.equals(ret)) {
  237.59              return;
  237.60          }
  237.61 @@ -153,6 +169,18 @@
  237.62      private static class EmulationResources implements Bck2Brwsr.Resources {
  237.63          @Override
  237.64          public InputStream get(String name) throws IOException {
  237.65 +            if ("java/net/URI.class".equals(name)) {
  237.66 +                // skip
  237.67 +                return null;
  237.68 +            }
  237.69 +            if ("java/net/URLConnection.class".equals(name)) {
  237.70 +                // skip
  237.71 +                return null;
  237.72 +            }
  237.73 +            if ("java/lang/System.class".equals(name)) {
  237.74 +                // skip
  237.75 +                return null;
  237.76 +            }
  237.77              Enumeration<URL> en = StaticMethodTest.class.getClassLoader().getResources(name);
  237.78              URL u = null;
  237.79              while (en.hasMoreElements()) {
   238.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   238.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/UnderTest.java	Tue Feb 11 13:31:42 2014 +0100
   238.3 @@ -0,0 +1,88 @@
   238.4 +/**
   238.5 + * Back 2 Browser Bytecode Translator
   238.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
   238.7 + *
   238.8 + * This program is free software: you can redistribute it and/or modify
   238.9 + * it under the terms of the GNU General Public License as published by
  238.10 + * the Free Software Foundation, version 2 of the License.
  238.11 + *
  238.12 + * This program is distributed in the hope that it will be useful,
  238.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  238.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  238.15 + * GNU General Public License for more details.
  238.16 + *
  238.17 + * You should have received a copy of the GNU General Public License
  238.18 + * along with this program. Look for COPYING file in the top folder.
  238.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
  238.20 + */
  238.21 +package org.apidesign.vm4brwsr;
  238.22 +
  238.23 +import org.testng.annotations.AfterClass;
  238.24 +import org.testng.annotations.BeforeClass;
  238.25 +import org.testng.annotations.Test;
  238.26 +
  238.27 +/** Checks behavior of classes and methods with underscore.
  238.28 + *
  238.29 + * @author Jaroslav Tulach <jtulach@netbeans.org>
  238.30 + */
  238.31 +public class UnderTest {
  238.32 +    @Test public void one() throws Exception {
  238.33 +        assertExec(
  238.34 +            "Should be one", 
  238.35 +            Under_Score.class, "one__I", 
  238.36 +            Double.valueOf(1)
  238.37 +        );
  238.38 +    }
  238.39 +
  238.40 +    @Test public void onePlusOne() throws Exception {
  238.41 +        assertExec(
  238.42 +            "Should be two", 
  238.43 +            Under_Score.class, "one_1plus_1one__I", 
  238.44 +            Double.valueOf(2)
  238.45 +        );
  238.46 +    }
  238.47 +
  238.48 +    @Test public void two() throws Exception {
  238.49 +        assertExec(
  238.50 +            "Should be two", 
  238.51 +            Under_Score.class, "two__I", 
  238.52 +            Double.valueOf(2)
  238.53 +        );
  238.54 +    }
  238.55 +
  238.56 +    @Test public void staticField() throws Exception {
  238.57 +        assertExec(
  238.58 +            "Should be ten", 
  238.59 +            Under_Score.class, "staticField__I", 
  238.60 +            Double.valueOf(10)
  238.61 +        );
  238.62 +    }
  238.63 +
  238.64 +    @Test public void instance() throws Exception {
  238.65 +        assertExec(
  238.66 +            "Should be five", 
  238.67 +            Under_Score.class, "instance__I", 
  238.68 +            Double.valueOf(5)
  238.69 +        );
  238.70 +    }
  238.71 +
  238.72 +    
  238.73 +    private static TestVM code;
  238.74 +    
  238.75 +    @BeforeClass 
  238.76 +    public static void compileTheCode() throws Exception {
  238.77 +        StringBuilder sb = new StringBuilder();
  238.78 +        code = TestVM.compileClass(sb, "org/apidesign/vm4brwsr/Under_Score");
  238.79 +    }
  238.80 +    @AfterClass
  238.81 +    public static void releaseTheCode() {
  238.82 +        code = null;
  238.83 +    }
  238.84 +
  238.85 +    private void assertExec(
  238.86 +        String msg, Class<?> clazz, String method, 
  238.87 +        Object ret, Object... args
  238.88 +    ) throws Exception {
  238.89 +        code.assertExec(msg, clazz, method, ret, args);
  238.90 +    }
  238.91 +}
   239.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   239.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/Under_Score.java	Tue Feb 11 13:31:42 2014 +0100
   239.3 @@ -0,0 +1,51 @@
   239.4 +/**
   239.5 + * Back 2 Browser Bytecode Translator
   239.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
   239.7 + *
   239.8 + * This program is free software: you can redistribute it and/or modify
   239.9 + * it under the terms of the GNU General Public License as published by
  239.10 + * the Free Software Foundation, version 2 of the License.
  239.11 + *
  239.12 + * This program is distributed in the hope that it will be useful,
  239.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  239.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  239.15 + * GNU General Public License for more details.
  239.16 + *
  239.17 + * You should have received a copy of the GNU General Public License
  239.18 + * along with this program. Look for COPYING file in the top folder.
  239.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
  239.20 + */
  239.21 +package org.apidesign.vm4brwsr;
  239.22 +
  239.23 +/**
  239.24 + *
  239.25 + * @author Jaroslav Tulach <jtulach@netbeans.org>
  239.26 + */
  239.27 +public class Under_Score {
  239.28 +    public static int under_field = 10;
  239.29 +    public int instance_field = 5;
  239.30 +    
  239.31 +    public static int one() {
  239.32 +        return 1;
  239.33 +    }
  239.34 +    
  239.35 +    public static int one_plus_one() {
  239.36 +        return 1 + 1;
  239.37 +    }
  239.38 +    
  239.39 +    public static int two() {
  239.40 +        return one_plus_one();
  239.41 +    }
  239.42 +    
  239.43 +    public static int staticField() {
  239.44 +        return under_field;
  239.45 +    }
  239.46 +    
  239.47 +    public static int instance() {
  239.48 +        return new Under_Score().get_fld();
  239.49 +    }
  239.50 +    
  239.51 +    private int get_fld() {
  239.52 +        return instance_field;
  239.53 +    }
  239.54 +}
   240.1 --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/VMLazyTest.java	Tue Feb 11 10:48:24 2014 +0100
   240.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/VMLazyTest.java	Tue Feb 11 13:31:42 2014 +0100
   240.3 @@ -90,6 +90,9 @@
   240.4          if (ret == null && expRes == null) {
   240.5              return;
   240.6          }
   240.7 +        if (expRes instanceof Double && ret instanceof Number) {
   240.8 +            ret = ((Number)ret).doubleValue();
   240.9 +        }
  240.10          if (expRes.equals(ret)) {
  240.11              return;
  240.12          }