Config.java revision 9cc9bde8928b83e5de9cd1c521e157e1a584b2fd
1cfb3d242306311ce27ec51bf511764377c173a7cKiran Ryali + Christian Williamspackage org.robolectric.annotation;
2dd40f718cf785a56e63c0685feeb73d266c13e3fWenhui Yao
39cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrishimport android.app.Application;
4f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williamsimport org.jetbrains.annotations.NotNull;
5f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams
6f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williamsimport java.lang.annotation.Annotation;
7f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williamsimport java.lang.annotation.Documented;
8f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williamsimport java.lang.annotation.ElementType;
9f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williamsimport java.lang.annotation.Retention;
10f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williamsimport java.lang.annotation.RetentionPolicy;
11f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williamsimport java.lang.annotation.Target;
12f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williamsimport java.util.Arrays;
13c77f5791f081893a18f9db753bb5022269a7c5a6Simon Arlottimport java.util.HashSet;
1423a26cc3e5b33c0503a99847292ac99817f5af43Christian Williamsimport java.util.Properties;
15c77f5791f081893a18f9db753bb5022269a7c5a6Simon Arlottimport java.util.Set;
16f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams
17dd40f718cf785a56e63c0685feeb73d266c13e3fWenhui Yao/**
1880c8a1718d42c7e2165289a7bbfab5e7f3dc0513Christian Williams & Dimitris Couchell * Indicate that robolectric should look for values that is specific by those qualifiers
19dd40f718cf785a56e63c0685feeb73d266c13e3fWenhui Yao */
20f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams@Documented
21f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams@Retention(RetentionPolicy.RUNTIME)
22f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams@Target({ElementType.TYPE, ElementType.METHOD})
237be4d2ba0e45483ad70cbd994955ae1b70afafdcKiran Ryali + Christian Williamspublic @interface Config {
2429a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams  @SuppressWarnings("UnusedDeclaration")
2529a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams  public static final String NONE = "--none";
2629a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams  public static final String DEFAULT = "--default";
2729a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams
2829a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams  /**
29074a38a2ee8dd8cb1904853aebf2f30146d563a2Mike Grafton   * The Android SDK level to emulate. If not specified, Robolectric defaults to API 16.
3029a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams   */
31b2a2e594372228d4e4cae61730152d4e1047c8a7Erich Douglass  int emulateSdk() default -1;
3229a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams
3329a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams  /**
3429a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams   * The Android manifest file to load; Robolectric will look relative to the current directory.
3529a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams   * Resources and assets will be loaded relative to the manifest.
3629a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams   *
3729a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams   * If not specified, Robolectric defaults to {@code AndroidManifest.xml}.
3829a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams   *
3929a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams   * If your project has no manifest or resources, use {@link Config#NONE}.
4029a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams   */
4129a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams  String manifest() default DEFAULT;
4229a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams
4329a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams  /**
449cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish   * The {@link android.app.Application} class to use in the test, this takes precedence over any application
459cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish   * specified in the AndroidManifest.xml.
469cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish   */
479cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish  Class<? extends Application> application() default Application.class;
489cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish
499cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish  /**
5029a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams   * Qualifiers for the resource resolution, such as "fr-normal-port-hdpi".
5129a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams   *
5229a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams   * @see <a href="http://developer.android.com/guide/topics/resources/providing-resources.html">Providing Resources</a> in the Android Developer docs for more information.
5329a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams   */
5429a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams  String qualifiers() default "";
5529a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams
5629a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams  /**
575277f871bca2be31c657ace35ae305285b2e0c55Ryan Spore and Trevor John   * The Directory from which to load resources.  This should be relative from the directory containing the AndroidManifest.
585277f871bca2be31c657ace35ae305285b2e0c55Ryan Spore and Trevor John   *
595277f871bca2be31c657ace35ae305285b2e0c55Ryan Spore and Trevor John   * If not specified, Robolectric defaults to {@code res}.
605277f871bca2be31c657ace35ae305285b2e0c55Ryan Spore and Trevor John   */
615277f871bca2be31c657ace35ae305285b2e0c55Ryan Spore and Trevor John  String resourceDir() default "res";
625277f871bca2be31c657ace35ae305285b2e0c55Ryan Spore and Trevor John
635277f871bca2be31c657ace35ae305285b2e0c55Ryan Spore and Trevor John  /**
6429a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams   * The Android SDK level to report in Build.VERSION.SDK_INT.
6529a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams   *
6629a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams   * @see <a href="http://en.wikipedia.org/wiki/Android_version_history">Android Version History</a>.
6729a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams   */
6829a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams  int reportSdk() default -1;
6929a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams
7029a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams  /**
7129a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams   * A list of shadow classes to enable, in addition to those that are already present.
7229a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams   */
7329a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams  Class<?>[] shadows() default {};
7429a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams
7529a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams  public class Implementation implements Config {
7629a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams    private final int emulateSdk;
7729a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams    private final String manifest;
7829a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams    private final String qualifiers;
795277f871bca2be31c657ace35ae305285b2e0c55Ryan Spore and Trevor John    private final String resourceDir;
8029a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams    private final int reportSdk;
8129a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams    private final Class<?>[] shadows;
829cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish    private final Class<? extends Application> application;
8329a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams
8429a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams    public static Config fromProperties(Properties configProperties) {
8529a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams      if (configProperties == null || configProperties.size() == 0) return null;
8629a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams      return new Implementation(
8729a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams          Integer.parseInt(configProperties.getProperty("emulateSdk", "-1")),
8829a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams          configProperties.getProperty("manifest", DEFAULT),
8929a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams          configProperties.getProperty("qualifiers", ""),
905277f871bca2be31c657ace35ae305285b2e0c55Ryan Spore and Trevor John          configProperties.getProperty("resourceDir", "res"),
9129a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams          Integer.parseInt(configProperties.getProperty("reportSdk", "-1")),
929cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish          parseClasses(configProperties.getProperty("shadows", "")),
939cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish          parseApplication(configProperties.getProperty("application", "android.app.Application"))
9429a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams      );
9529a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams    }
9623a26cc3e5b33c0503a99847292ac99817f5af43Christian Williams
9729a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams    private static Class<?>[] parseClasses(String classList) {
9829a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams      if (classList.length() == 0) return new Class[0];
9929a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams      String[] classNames = classList.split("[, ]+");
10029a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams      Class[] classes = new Class[classNames.length];
10129a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams      for (int i = 0; i < classNames.length; i++) {
10229a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams        try {
10329a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams          classes[i] = Implementation.class.getClassLoader().loadClass(classNames[i]);
10429a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams        } catch (ClassNotFoundException e) {
10529a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams          throw new RuntimeException(e);
10623a26cc3e5b33c0503a99847292ac99817f5af43Christian Williams        }
10729a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams      }
10829a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams      return classes;
10929a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams    }
11023a26cc3e5b33c0503a99847292ac99817f5af43Christian Williams
1119cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish    private static <T extends Application> Class<T> parseApplication(String className) {
1129cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish      try {
1139cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish        Class<T> aClass = (Class<T>) Implementation.class.getClassLoader().loadClass(className);
1149cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish        return aClass;
1159cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish      } catch (ClassNotFoundException e) {
1169cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish        throw new RuntimeException(e);
1179cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish      }
1189cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish    }
1199cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish
1209cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish    public Implementation(int emulateSdk, String manifest, String qualifiers, String resourceDir, int reportSdk, Class<?>[] shadows, Class<? extends Application> application) {
12129a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams      this.emulateSdk = emulateSdk;
12229a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams      this.manifest = manifest;
12329a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams      this.qualifiers = qualifiers;
1245277f871bca2be31c657ace35ae305285b2e0c55Ryan Spore and Trevor John      this.resourceDir = resourceDir;
12529a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams      this.reportSdk = reportSdk;
12629a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams      this.shadows = shadows;
1279cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish      this.application = application;
12829a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams    }
129f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams
13029a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams    public Implementation(Config baseConfig, Config overlayConfig) {
131b2a2e594372228d4e4cae61730152d4e1047c8a7Erich Douglass      this.emulateSdk = pick(baseConfig.emulateSdk(), overlayConfig.emulateSdk(), -1);
13229a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams      this.manifest = pick(baseConfig.manifest(), overlayConfig.manifest(), DEFAULT);
13329a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams      this.qualifiers = pick(baseConfig.qualifiers(), overlayConfig.qualifiers(), "");
1345277f871bca2be31c657ace35ae305285b2e0c55Ryan Spore and Trevor John      this.resourceDir = pick(baseConfig.resourceDir(), overlayConfig.resourceDir(), "res");
13529a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams      this.reportSdk = pick(baseConfig.reportSdk(), overlayConfig.reportSdk(), -1);
136c77f5791f081893a18f9db753bb5022269a7c5a6Simon Arlott      Set<Class<?>> shadows = new HashSet<Class<?>>();
13729a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams      shadows.addAll(Arrays.asList(baseConfig.shadows()));
13829a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams      shadows.addAll(Arrays.asList(overlayConfig.shadows()));
13929a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams      this.shadows = shadows.toArray(new Class[shadows.size()]);
1409cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish      this.application = pick(baseConfig.application(), overlayConfig.application(), null);
14129a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams    }
142f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams
14329a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams    private <T> T pick(T baseValue, T overlayValue, T nullValue) {
14429a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams      return overlayValue.equals(nullValue) ? baseValue : overlayValue;
14529a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams    }
146f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams
14729a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams    @Override public int emulateSdk() {
14829a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams      return emulateSdk;
14929a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams    }
150f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams
15129a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams    @Override public String manifest() {
15229a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams      return manifest;
15329a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams    }
15448f95f3e0955035946f7c416dec56219a9b19886Christian Williams
1559cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish    @Override
1569cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish    public Class<? extends Application> application() {
1579cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish      return application;
1589cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish    }
1599cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish
16029a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams    @Override public String qualifiers() {
16129a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams      return qualifiers;
16229a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams    }
163f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams
1645277f871bca2be31c657ace35ae305285b2e0c55Ryan Spore and Trevor John    @Override
1655277f871bca2be31c657ace35ae305285b2e0c55Ryan Spore and Trevor John    public String resourceDir() {
1665277f871bca2be31c657ace35ae305285b2e0c55Ryan Spore and Trevor John      return resourceDir;
1675277f871bca2be31c657ace35ae305285b2e0c55Ryan Spore and Trevor John    }
1685277f871bca2be31c657ace35ae305285b2e0c55Ryan Spore and Trevor John
16929a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams    @Override public int reportSdk() {
17029a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams      return reportSdk;
17129a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams    }
172f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams
17329a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams    @Override public Class<?>[] shadows() {
17429a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams      return shadows;
17529a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams    }
176f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams
17729a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams    @NotNull @Override public Class<? extends Annotation> annotationType() {
17829a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams      return Config.class;
17929a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams    }
180f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams
18129a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams    @Override
18229a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams    public boolean equals(Object o) {
18329a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams      if (this == o) return true;
18429a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams      if (o == null || getClass() != o.getClass()) return false;
185f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams
18629a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams      Implementation other = (Implementation) o;
187f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams
18829a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams      if (emulateSdk != other.emulateSdk) return false;
18929a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams      if (reportSdk != other.reportSdk) return false;
19029a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams      if (!qualifiers.equals(other.qualifiers)) return false;
19129a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams      if (!Arrays.equals(shadows, other.shadows)) return false;
1929cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish      if (application != other.application) return false;
193f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams
19429a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams      return true;
19529a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams    }
196f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams
19729a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams    @Override
19829a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams    public int hashCode() {
19929a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams      int result = emulateSdk;
20029a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams      result = 31 * result + qualifiers.hashCode();
20129a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams      result = 31 * result + reportSdk;
20229a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams      result = 31 * result + Arrays.hashCode(shadows);
2039cc9bde8928b83e5de9cd1c521e157e1a584b2fdJonathan Gerrish      result = 31 * result + application.hashCode();
20429a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams      return result;
205f6df8a55ac378dee35324bc865fb4d741dcb4824Christian Williams    }
20629a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams  }
207dd40f718cf785a56e63c0685feeb73d266c13e3fWenhui Yao}
208