shindig-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mherma...@apache.org
Subject svn commit: r1148035 - in /shindig/trunk/java/gadgets/src: main/java/org/apache/shindig/gadgets/js/ test/java/org/apache/shindig/gadgets/js/
Date Mon, 18 Jul 2011 20:10:15 GMT
Author: mhermanto
Date: Mon Jul 18 20:10:13 2011
New Revision: 1148035

URL: http://svn.apache.org/viewvc?rev=1148035&view=rev
Log:
Avoid dual-mode deferred (and immediate) export JS processor.
http://codereview.appspot.com/4748053/

Added:
    shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/DeferredExportJsProcessor.java
    shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/DeferredExportJsProcessorTest.java
Modified:
    shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/ExportJsProcessor.java
    shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/JsServingPipelineModule.java
    shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/ExportJsProcessorTest.java

Added: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/DeferredExportJsProcessor.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/DeferredExportJsProcessor.java?rev=1148035&view=auto
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/DeferredExportJsProcessor.java
(added)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/DeferredExportJsProcessor.java
Mon Jul 18 20:10:13 2011
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package org.apache.shindig.gadgets.js;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+
+import org.apache.shindig.gadgets.GadgetContext;
+import org.apache.shindig.gadgets.GadgetException;
+import org.apache.shindig.gadgets.JsCompileMode;
+import org.apache.shindig.gadgets.features.ApiDirective;
+import org.apache.shindig.gadgets.features.FeatureRegistry;
+import org.apache.shindig.gadgets.features.FeatureRegistry.FeatureBundle;
+import org.apache.shindig.gadgets.features.FeatureRegistry.LookupResult;
+import org.apache.shindig.gadgets.features.FeatureRegistryProvider;
+import org.apache.shindig.gadgets.features.FeatureResource;
+import org.apache.shindig.gadgets.uri.JsUriManager.JsUri;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+public class DeferredExportJsProcessor extends ExportJsProcessor {
+
+  @VisibleForTesting
+  static final String FEATURE_NAME = "exportjs";
+
+  private static final String FUNCTION_NAME = "exportJs";
+
+  @Inject
+  public DeferredExportJsProcessor(FeatureRegistryProvider featureRegistryProvider,
+      Provider<GadgetContext> context) {
+    super(featureRegistryProvider, context);
+  }
+
+  @Override
+  public boolean process(JsRequest jsRequest, JsResponseBuilder builder) throws JsException
{
+    JsUri jsUri = jsRequest.getJsUri();
+    ImmutableList.Builder<JsContent> resp = ImmutableList.builder();
+
+    FeatureRegistry featureRegistry;
+    try {
+      featureRegistry = featureRegistryProvider.get(jsUri.getRepository());
+    } catch (GadgetException e) {
+      throw new JsException(e.getHttpStatusCode(), e.getMessage());
+    }
+
+    boolean neededExportJs = false;
+    FeatureBundle last = null;
+    if (jsUri.isJsload()) {
+      // append all exports for deferred symbols
+      neededExportJs = appendExportJsStatementsDeferred(featureRegistry, resp, jsRequest);
+    }
+    
+    builder.clearJs();
+    if (neededExportJs) {
+      builder.appendAllJs(getExportJsContents(featureRegistry));
+    }
+    builder.appendAllJs(resp.build());
+    return true;
+  }
+
+  private boolean appendExportJsStatementsDeferred(FeatureRegistry registry,
+      ImmutableList.Builder<JsContent> builder, JsRequest jsRequest) {
+    LookupResult lookup = registry.getFeatureResources(context.get(),
+        jsRequest.getNewFeatures(), null, false);
+    
+    boolean neededExports = false;
+    for (FeatureBundle bundle : lookup.getBundles()) {
+      if (bundle.isSupportDefer()) {
+        neededExports |= appendExportJsStatementsForFeature(builder, jsRequest.getJsUri(),
bundle);
+      }
+    }
+    
+    return neededExports;
+  }
+}

Modified: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/ExportJsProcessor.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/ExportJsProcessor.java?rev=1148035&r1=1148034&r2=1148035&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/ExportJsProcessor.java
(original)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/ExportJsProcessor.java
Mon Jul 18 20:10:13 2011
@@ -47,25 +47,14 @@ public class ExportJsProcessor implement
 
   private static final String FUNCTION_NAME = "exportJs";
 
-  private final FeatureRegistryProvider featureRegistryProvider;
-  private final Provider<GadgetContext> context;
-  private final boolean deferredMode;
+  protected final FeatureRegistryProvider featureRegistryProvider;
+  protected final Provider<GadgetContext> context;
 
   @Inject
   public ExportJsProcessor(FeatureRegistryProvider featureRegistryProvider,
       Provider<GadgetContext> context) {
-    this(featureRegistryProvider, context, false);
-  }
-  
-  private ExportJsProcessor(FeatureRegistryProvider featureRegistryProvider,
-      Provider<GadgetContext> context, boolean defer) {
     this.featureRegistryProvider = featureRegistryProvider;
     this.context = context;
-    this.deferredMode = defer;
-  }
-  
-  public JsProcessor getDeferredInstance() {
-    return new ExportJsProcessor(featureRegistryProvider, context, true);
   }
 
   public boolean process(JsRequest jsRequest, JsResponseBuilder builder) throws JsException
{
@@ -93,9 +82,6 @@ public class ExportJsProcessor implement
       if (last != null) {
         neededExportJs |= appendExportJsStatementsForFeature(resp, jsUri, last);
       }
-    } else if (deferredMode) {
-      // append all exports for deferred symbols
-      neededExportJs = appendExportJsStatementsDeferred(featureRegistry, resp, jsRequest);
     }
     
     builder.clearJs();
@@ -106,7 +92,7 @@ public class ExportJsProcessor implement
     return true;
   }
 
-  private boolean appendExportJsStatementsForFeature(ImmutableList.Builder<JsContent>
builder,
+  protected boolean appendExportJsStatementsForFeature(ImmutableList.Builder<JsContent>
builder,
       JsUri jsUri, FeatureBundle bundle) {
     List<String> exports = Lists.newArrayList();
 
@@ -133,22 +119,7 @@ public class ExportJsProcessor implement
     return false;
   }
 
-  private boolean appendExportJsStatementsDeferred(FeatureRegistry registry,
-      ImmutableList.Builder<JsContent> builder, JsRequest jsRequest) {
-    LookupResult lookup = registry.getFeatureResources(context.get(),
-        jsRequest.getNewFeatures(), null, false);
-    
-    boolean neededExports = false;
-    for (FeatureBundle bundle : lookup.getBundles()) {
-      if (bundle.isSupportDefer()) {
-        neededExports |= appendExportJsStatementsForFeature(builder, jsRequest.getJsUri(),
bundle);
-      }
-    }
-    
-    return neededExports;
-  }
-
-  private List<JsContent> getExportJsContents(FeatureRegistry featureRegistry) {
+  protected List<JsContent> getExportJsContents(FeatureRegistry featureRegistry) {
     ImmutableList.Builder<JsContent> result = ImmutableList.builder();
     LookupResult lookup = featureRegistry.getFeatureResources(context.get(),
         ImmutableList.of(FEATURE_NAME), null);

Modified: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/JsServingPipelineModule.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/JsServingPipelineModule.java?rev=1148035&r1=1148034&r2=1148035&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/JsServingPipelineModule.java
(original)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/JsServingPipelineModule.java
Mon Jul 18 20:10:13 2011
@@ -41,6 +41,7 @@ public class JsServingPipelineModule ext
   @Named("shindig.js.optional-processors")
   public List<JsProcessor> provideProcessors(
       AddJslInfoVariableProcessor addJslInfoVariableProcessor,
+      DeferredExportJsProcessor deferredExportJsProcessor,
       JsLoadProcessor jsLoaderGeneratorProcessor,
       IfModifiedSinceProcessor ifModifiedSinceProcessor,
       GetJsContentProcessor getJsContentProcessor,
@@ -53,7 +54,7 @@ public class JsServingPipelineModule ext
     jsLoaderGeneratorProcessor.setUseAsync(true);
     return ImmutableList.of(
         addJslInfoVariableProcessor,
-        exportJsProcessor.getDeferredInstance(),
+        deferredExportJsProcessor,
         jsLoaderGeneratorProcessor,
         ifModifiedSinceProcessor,
         getJsContentProcessor,

Added: shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/DeferredExportJsProcessorTest.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/DeferredExportJsProcessorTest.java?rev=1148035&view=auto
==============================================================================
--- shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/DeferredExportJsProcessorTest.java
(added)
+++ shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/DeferredExportJsProcessorTest.java
Mon Jul 18 20:10:13 2011
@@ -0,0 +1,186 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package org.apache.shindig.gadgets.js;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.eq;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.isA;
+import static org.easymock.EasyMock.replay;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.google.inject.Provider;
+import com.google.inject.util.Providers;
+
+import org.apache.shindig.gadgets.GadgetContext;
+import org.apache.shindig.gadgets.JsCompileMode;
+import org.apache.shindig.gadgets.features.ApiDirective;
+import org.apache.shindig.gadgets.features.FeatureRegistry;
+import org.apache.shindig.gadgets.features.FeatureRegistry.FeatureBundle;
+import org.apache.shindig.gadgets.features.FeatureRegistry.LookupResult;
+import org.apache.shindig.gadgets.features.FeatureRegistryProvider;
+import org.apache.shindig.gadgets.features.FeatureResource;
+import org.apache.shindig.gadgets.uri.JsUriManager.JsUri;
+import org.easymock.EasyMock;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.List;
+
+public class DeferredExportJsProcessorTest {
+  private final String EXPORT_JS_DEB = "function exportJs() { };";
+
+  private final List<String> EXPORTS_1 = ImmutableList.of(
+      "gadgets",
+      "gadgets.rpc.call",
+      "shindig",
+      "shindig.random");
+
+  private final List<String> EXPORTS_2 = ImmutableList.of(
+      "foo",
+      "foo.prototype.bar");
+
+  private final String EXPORT_STRING_1_DEFER =
+    "exportJs('gadgets',[window.gadgets],{},1);" +
+    "exportJs('shindig',[window.shindig],{},1);" +
+    "exportJs('gadgets.rpc',[window.gadgets,gadgets.rpc],{call:'call'},1);" +
+    "exportJs('shindig',[window.shindig],{random:'random'},1);";
+
+  private final List<String> LIBS_WITH_DEFER = Lists.newArrayList("lib1");
+  private final List<String> LIBS_WITHOUT_DEFER = Lists.newArrayList("lib2");
+  private final List<String> LOADED = Lists.newArrayList();
+
+  private DeferredExportJsProcessor compiler;
+  private FeatureRegistry featureRegistry;
+
+  @Before
+  public void setUp() throws Exception {
+    GadgetContext ctx = new GadgetContext();
+    Provider<GadgetContext> contextProviderMock = Providers.of(ctx);
+    FeatureResource resource = mockResource(EXPORT_JS_DEB);
+    FeatureRegistry.FeatureBundle bundle = mockExportJsBundle(resource);
+    LookupResult lookupMock = mockLookupResult(bundle);
+    final FeatureRegistry featureRegistryMock = mockRegistry(lookupMock);
+    featureRegistry = featureRegistryMock;
+    FeatureRegistryProvider registryProvider = new FeatureRegistryProvider() {
+      public FeatureRegistry get(String repository) {
+        return featureRegistryMock;
+      }
+    };
+    compiler = new DeferredExportJsProcessor(registryProvider, contextProviderMock);
+  }
+
+  @Test
+  public void testProcessWithOneNonEmptyFeatureDeferred() throws Exception {
+    JsUri jsUri = mockJsUri(JsCompileMode.CONCAT_COMPILE_EXPORT_ALL, true, LIBS_WITH_DEFER);
+    JsRequest jsRequest = new JsRequest(jsUri, null, false, featureRegistry);
+    JsResponseBuilder jsBuilder = new JsResponseBuilder();
+    boolean actualReturnCode = compiler.process(jsRequest, jsBuilder);
+    assertTrue(actualReturnCode);
+    assertEquals(
+        EXPORT_JS_DEB + EXPORT_STRING_1_DEFER,
+        jsBuilder.build().toJsString());
+  }
+  
+  @Test
+  public void testProcessWithOneNonEmptyFeatureDeferredNotSupported() throws Exception {
+    JsUri jsUri = mockJsUri(JsCompileMode.CONCAT_COMPILE_EXPORT_ALL, true, LIBS_WITHOUT_DEFER);
+    JsRequest jsRequest = new JsRequest(jsUri, null, false, featureRegistry);
+    JsResponseBuilder jsBuilder = new JsResponseBuilder();
+    boolean actualReturnCode = compiler.process(jsRequest, jsBuilder);
+    assertTrue(actualReturnCode);
+    assertEquals(
+        "",
+        jsBuilder.build().toJsString());
+  }
+  
+  @SuppressWarnings("unchecked")
+  private FeatureRegistry mockRegistry(LookupResult lookupMock) {
+    FeatureRegistry result = createMock(FeatureRegistry.class);
+    expect(result.getFeatureResources(
+        isA(GadgetContext.class), isA(List.class), EasyMock.isNull(List.class))).
+        andReturn(lookupMock).anyTimes();
+    expect(result.getFeatureResources(
+        isA(GadgetContext.class), eq(LIBS_WITH_DEFER), EasyMock.isNull(List.class), eq(false))).
+        andReturn(mockLookupResult(mockBundle(EXPORTS_1, true))).anyTimes();
+    expect(result.getFeatureResources(
+        isA(GadgetContext.class), eq(LIBS_WITHOUT_DEFER), EasyMock.isNull(List.class), eq(false))).
+        andReturn(mockLookupResult(mockBundle(EXPORTS_2, false))).anyTimes();
+    expect(result.getFeatures(LIBS_WITHOUT_DEFER)).andReturn(LIBS_WITHOUT_DEFER).anyTimes();
+    expect(result.getFeatures(LIBS_WITH_DEFER)).andReturn(LIBS_WITH_DEFER).anyTimes();
+    expect(result.getFeatures(LOADED)).andReturn(LOADED).anyTimes();
+    replay(result);
+    return result;
+  }
+
+  private JsUri mockJsUri(JsCompileMode mode, boolean isJsload, List<String> libs)
{
+    JsUri result = createMock(JsUri.class);
+    expect(result.getCompileMode()).andStubReturn(mode);
+    expect(result.getRepository()).andStubReturn(null);
+    expect(result.isJsload()).andReturn(isJsload).anyTimes();
+    expect(result.getLibs()).andReturn(libs).anyTimes();
+    expect(result.getLoadedLibs()).andReturn(LOADED).anyTimes();
+    replay(result);
+    return result;
+  }
+
+  private LookupResult mockLookupResult(FeatureRegistry.FeatureBundle featureBundle) {
+    LookupResult result = createMock(LookupResult.class);
+    expect(result.getBundles()).andReturn(ImmutableList.of(featureBundle)).anyTimes();
+    replay(result);
+    return result;
+  }
+
+  private FeatureResource mockResource(String debContent) {
+    FeatureResource result = createMock(FeatureResource.class);
+    expect(result.getDebugContent()).andReturn(debContent).anyTimes();
+    expect(result.getName()).andReturn("js").anyTimes();
+    replay(result);
+    return result;
+  }
+
+  private FeatureBundle mockBundle(List<String> exports, boolean isDefer) {
+    List<ApiDirective> apis = Lists.newArrayList();
+    for (String e : exports) apis.add(mockApiDirective(true, e));
+    FeatureBundle result = createMock(FeatureBundle.class);
+    expect(result.getApis(ApiDirective.Type.JS, true)).andReturn(exports).anyTimes();
+    expect(result.isSupportDefer()).andReturn(isDefer).anyTimes();
+    replay(result);
+    return result;
+  }
+
+  private FeatureBundle mockExportJsBundle(FeatureResource featureResourceMock) {
+    FeatureRegistry.FeatureBundle featureBundle = createMock(FeatureBundle.class);
+    expect(featureBundle.getResources()).andReturn(
+        ImmutableList.of(featureResourceMock)).anyTimes();
+    replay(featureBundle);
+    return featureBundle;
+  }
+
+  private ApiDirective mockApiDirective(boolean isExports, String value) {
+    ApiDirective result = createMock(ApiDirective.class);
+    expect(result.getType()).andReturn(ApiDirective.Type.JS).anyTimes();
+    expect(result.getValue()).andReturn(value).anyTimes();
+    expect(result.isExports()).andReturn(isExports).anyTimes();
+    replay(result);
+    return result;
+  }
+}

Modified: shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/ExportJsProcessorTest.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/ExportJsProcessorTest.java?rev=1148035&r1=1148034&r2=1148035&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/ExportJsProcessorTest.java
(original)
+++ shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/ExportJsProcessorTest.java
Mon Jul 18 20:10:13 2011
@@ -126,7 +126,7 @@ public class ExportJsProcessorTest {
         andReturn(lookupMock).anyTimes();
     expect(result.getFeatureResources(
         isA(GadgetContext.class), eq(LIBS_DEFER), EasyMock.isNull(List.class), eq(false))).
-        andReturn(mockLookupResult(mockBundle(EXPORTS_1, true))).anyTimes();
+        andReturn(mockLookupResult(mockBundle(EXPORTS_1))).anyTimes();
     expect(result.getFeatureResources(
         isA(GadgetContext.class), eq(LIBS), EasyMock.isNull(List.class), eq(false))).
         andReturn(mockLookupResult(mockBundle(EXPORTS_2))).anyTimes();
@@ -172,15 +172,11 @@ public class ExportJsProcessorTest {
   }
 
   private FeatureBundle mockBundle(List<String> exports) {
-    return mockBundle(exports, false);
-  }
-  
-  private FeatureBundle mockBundle(List<String> exports, boolean isDefer) {
     List<ApiDirective> apis = Lists.newArrayList();
     for (String e : exports) apis.add(mockApiDirective(true, e));
     FeatureBundle result = createMock(FeatureBundle.class);
     expect(result.getApis(ApiDirective.Type.JS, true)).andReturn(exports).anyTimes();
-    expect(result.isSupportDefer()).andReturn(isDefer).anyTimes();
+    expect(result.isSupportDefer()).andReturn(false).anyTimes();
     replay(result);
     return result;
   }
@@ -237,31 +233,7 @@ public class ExportJsProcessorTest {
         EXPORT_JS_DEB + FEATURE_CONTENT_1 + EXPORT_STRING_1,
         jsBuilder.build().toJsString());
   }
-  
-  @Test
-  public void testProcessWithOneNonEmptyFeatureDeferred() throws Exception {
-    JsUri jsUri = mockJsUri(JsCompileMode.CONCAT_COMPILE_EXPORT_ALL, true, LIBS_DEFER);
-    JsRequest jsRequest = new JsRequest(jsUri, null, false, featureRegistry);
-    JsResponseBuilder jsBuilder = new JsResponseBuilder();
-    boolean actualReturnCode = compiler.getDeferredInstance().process(jsRequest, jsBuilder);
-    assertTrue(actualReturnCode);
-    assertEquals(
-        EXPORT_JS_DEB + EXPORT_STRING_1_DEFER,
-        jsBuilder.build().toJsString());
-  }
-  
-  @Test
-  public void testProcessWithOneNonEmptyFeatureDeferredNotSupported() throws Exception {
-    JsUri jsUri = mockJsUri(JsCompileMode.CONCAT_COMPILE_EXPORT_ALL, true, LIBS); // !deferred
-    JsRequest jsRequest = new JsRequest(jsUri, null, false, featureRegistry);
-    JsResponseBuilder jsBuilder = new JsResponseBuilder();
-    boolean actualReturnCode = compiler.getDeferredInstance().process(jsRequest, jsBuilder);
-    assertTrue(actualReturnCode);
-    assertEquals(
-        "",
-        jsBuilder.build().toJsString());
-  }
-  
+    
   @Test
   public void testProcessWithOneNonEmptyFeatureNotDeferredMode() throws Exception {
     JsUri jsUri = mockJsUri(JsCompileMode.CONCAT_COMPILE_EXPORT_ALL, true);



Mime
View raw message