freemarker-notifications mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ddek...@apache.org
Subject [2/2] incubator-freemarker git commit: (Moving around test classes a bit)
Date Thu, 23 Feb 2017 23:00:06 GMT
(Moving around test classes a bit)


Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/5c98c0ed
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/5c98c0ed
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/5c98c0ed

Branch: refs/heads/3
Commit: 5c98c0ed5d517e8d64b966c878ef3f056f324cda
Parents: ace88bf
Author: ddekany <ddekany@apache.org>
Authored: Thu Feb 23 23:59:55 2017 +0100
Committer: ddekany <ddekany@apache.org>
Committed: Thu Feb 23 23:59:55 2017 +0100

----------------------------------------------------------------------
 .../core/AppMetaTemplateDateFormatFactory.java  | 121 ----------------
 .../core/BaseNTemplateNumberFormatFactory.java  | 121 ----------------
 .../freemarker/core/CoercionToTextualTest.java  |   2 +
 .../freemarker/core/ConfigurationTest.java      |   4 +
 .../apache/freemarker/core/DateFormatTest.java  |   5 +
 ...EpochMillisDivTemplateDateFormatFactory.java |  94 -------------
 .../EpochMillisTemplateDateFormatFactory.java   |  85 ------------
 .../core/HTMLISOTemplateDateFormatFactory.java  | 105 --------------
 .../core/HexTemplateNumberFormatFactory.java    |  71 ----------
 ...AndTZSensitiveTemplateDateFormatFactory.java |  89 ------------
 ...aleSensitiveTemplateNumberFormatFactory.java |  72 ----------
 .../freemarker/core/NumberFormatTest.java       |   4 +
 .../core/ObjectBuilderSettingsTest.java         |  18 +--
 .../PrintfGTemplateNumberFormatFactory.java     | 132 ------------------
 .../core/StringLiteralInterpolationTest.java    |   1 +
 .../core/TemplateConfigurationTest.java         |   6 +
 .../core/subpkg/PackageVisibleAll.java          |  26 ----
 .../subpkg/PackageVisibleAllWithBuilder.java    |  26 ----
 .../PackageVisibleAllWithBuilderBuilder.java    |  28 ----
 .../PackageVisibleWithPublicConstructor.java    |  27 ----
 .../freemarker/core/subpkg/PublicAll.java       |  24 ----
 .../subpkg/PublicWithMixedConstructors.java     |  38 -----
 .../PublicWithPackageVisibleConstructor.java    |  26 ----
 .../AppMetaTemplateDateFormatFactory.java       | 129 +++++++++++++++++
 .../BaseNTemplateNumberFormatFactory.java       | 128 +++++++++++++++++
 ...EpochMillisDivTemplateDateFormatFactory.java | 102 ++++++++++++++
 .../EpochMillisTemplateDateFormatFactory.java   |  92 +++++++++++++
 .../HTMLISOTemplateDateFormatFactory.java       | 114 +++++++++++++++
 .../userpkg/HexTemplateNumberFormatFactory.java |  77 +++++++++++
 ...AndTZSensitiveTemplateDateFormatFactory.java |  97 +++++++++++++
 ...aleSensitiveTemplateNumberFormatFactory.java |  78 +++++++++++
 .../core/userpkg/PackageVisibleAll.java         |  26 ++++
 .../userpkg/PackageVisibleAllWithBuilder.java   |  26 ++++
 .../PackageVisibleAllWithBuilderBuilder.java    |  28 ++++
 .../PackageVisibleWithPublicConstructor.java    |  27 ++++
 .../PrintfGTemplateNumberFormatFactory.java     | 138 +++++++++++++++++++
 .../freemarker/core/userpkg/PublicAll.java      |  24 ++++
 .../userpkg/PublicWithMixedConstructors.java    |  38 +++++
 .../PublicWithPackageVisibleConstructor.java    |  26 ++++
 .../manualtest/CustomFormatsExample.java        |   2 +-
 40 files changed, 1182 insertions(+), 1095 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/5c98c0ed/src/test/java/org/apache/freemarker/core/AppMetaTemplateDateFormatFactory.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/freemarker/core/AppMetaTemplateDateFormatFactory.java b/src/test/java/org/apache/freemarker/core/AppMetaTemplateDateFormatFactory.java
deleted file mode 100644
index 592dc65..0000000
--- a/src/test/java/org/apache/freemarker/core/AppMetaTemplateDateFormatFactory.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * 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.freemarker.core;
-
-import java.util.Date;
-import java.util.Locale;
-import java.util.TimeZone;
-
-import org.apache.freemarker.core.model.TemplateDateModel;
-import org.apache.freemarker.core.model.TemplateModelException;
-
-public class AppMetaTemplateDateFormatFactory extends TemplateDateFormatFactory {
-
-    public static final AppMetaTemplateDateFormatFactory INSTANCE = new AppMetaTemplateDateFormatFactory();
-    
-    private AppMetaTemplateDateFormatFactory() {
-        // Defined to decrease visibility
-    }
-    
-    @Override
-    public TemplateDateFormat get(String params, int dateType, Locale locale, TimeZone timeZone, boolean zonelessInput,
-            Environment env) throws UnknownDateTypeFormattingUnsupportedException, InvalidFormatParametersException {
-        TemplateFormatUtil.checkHasNoParameters(params);
-        return AppMetaTemplateDateFormat.INSTANCE;
-    }
-
-    private static class AppMetaTemplateDateFormat extends TemplateDateFormat {
-
-        private static final AppMetaTemplateDateFormat INSTANCE = new AppMetaTemplateDateFormat();
-        
-        private AppMetaTemplateDateFormat() { }
-        
-        @Override
-        public String formatToPlainText(TemplateDateModel dateModel)
-                throws UnformattableValueException, TemplateModelException {
-            String result = String.valueOf(TemplateFormatUtil.getNonNullDate(dateModel).getTime());
-            if (dateModel instanceof AppMetaTemplateDateModel) {
-                result += "/" + ((AppMetaTemplateDateModel) dateModel).getAppMeta(); 
-            }
-            return result;
-        }
-
-        @Override
-        public boolean isLocaleBound() {
-            return false;
-        }
-
-        @Override
-        public boolean isTimeZoneBound() {
-            return false;
-        }
-
-        @Override
-        public Object parse(String s, int dateType) throws UnparsableValueException {
-            int slashIdx = s.indexOf('/');
-            try {
-                if (slashIdx != -1) {
-                    return new AppMetaTemplateDateModel(
-                            new Date(Long.parseLong(s.substring(0,  slashIdx))),
-                            dateType,
-                            s.substring(slashIdx +1));
-                } else {
-                    return new Date(Long.parseLong(s));
-                }
-            } catch (NumberFormatException e) {
-                throw new UnparsableValueException("Malformed long");
-            }
-        }
-
-        @Override
-        public String getDescription() {
-            return "millis since the epoch";
-        }
-        
-    }
-    
-    public static class AppMetaTemplateDateModel implements TemplateDateModel {
-        
-        private final Date date;
-        private final int dateType;
-        private final String appMeta;
-
-        public AppMetaTemplateDateModel(Date date, int dateType, String appMeta) {
-            this.date = date;
-            this.dateType = dateType;
-            this.appMeta = appMeta;
-        }
-
-        @Override
-        public Date getAsDate() throws TemplateModelException {
-            return date;
-        }
-
-        @Override
-        public int getDateType() {
-            return dateType;
-        }
-
-        public String getAppMeta() {
-            return appMeta;
-        }
-        
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/5c98c0ed/src/test/java/org/apache/freemarker/core/BaseNTemplateNumberFormatFactory.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/freemarker/core/BaseNTemplateNumberFormatFactory.java b/src/test/java/org/apache/freemarker/core/BaseNTemplateNumberFormatFactory.java
deleted file mode 100644
index e1b8980..0000000
--- a/src/test/java/org/apache/freemarker/core/BaseNTemplateNumberFormatFactory.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * 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.freemarker.core;
-
-import java.util.Locale;
-
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.model.TemplateNumberModel;
-import org.apache.freemarker.core.util._NumberUtil;
-import org.apache.freemarker.core.util._StringUtil;
-
-/**
- * Shows a number in base N number system. Can only format numbers that fit into an {@code int},
- * however, optionally you can specify a fallback format. This format has one required parameter,
- * the numerical system base. That can be optionally followed by "|" and a fallback format.
- */
-public class BaseNTemplateNumberFormatFactory extends TemplateNumberFormatFactory {
-
-    public static final BaseNTemplateNumberFormatFactory INSTANCE
-            = new BaseNTemplateNumberFormatFactory();
-    
-    private BaseNTemplateNumberFormatFactory() {
-        // Defined to decrease visibility
-    }
-    
-    @Override
-    public TemplateNumberFormat get(String params, Locale locale, Environment env)
-            throws InvalidFormatParametersException {
-        TemplateNumberFormat fallbackFormat;
-        {
-            int barIdx = params.indexOf('|');
-            if (barIdx != -1) {
-                String fallbackFormatStr = params.substring(barIdx + 1);
-                params = params.substring(0, barIdx);
-                try {
-                    fallbackFormat = env.getTemplateNumberFormat(fallbackFormatStr, locale);
-                } catch (TemplateValueFormatException e) {
-                    throw new InvalidFormatParametersException(
-                            "Couldn't get the fallback number format (specified after the \"|\"), "
-                            + _StringUtil.jQuote(fallbackFormatStr) + ". Reason: " + e.getMessage(),
-                            e);
-                }
-            } else {
-                fallbackFormat = null;
-            }
-        }
-        
-        int base;
-        try {
-            base = Integer.parseInt(params);
-        } catch (NumberFormatException e) {
-            if (params.length() == 0) {
-                throw new InvalidFormatParametersException(
-                        "A format parameter is required to specify the numerical system base.");
-            }
-            throw new InvalidFormatParametersException(
-                    "The format paramter must be an integer, but was (shown quoted): "
-                    + _StringUtil.jQuote(params));
-        }
-        if (base < 2) {
-            throw new InvalidFormatParametersException("A base must be at least 2.");
-        }
-        return new BaseNTemplateNumberFormat(base, fallbackFormat);
-    }
-
-    private static class BaseNTemplateNumberFormat extends TemplateNumberFormat {
-
-        private final int base;
-        private final TemplateNumberFormat fallbackFormat;
-        
-        private BaseNTemplateNumberFormat(int base, TemplateNumberFormat fallbackFormat) {
-            this.base = base;
-            this.fallbackFormat = fallbackFormat;
-        }
-        
-        @Override
-        public String formatToPlainText(TemplateNumberModel numberModel)
-                throws TemplateModelException, TemplateValueFormatException {
-            Number n = TemplateFormatUtil.getNonNullNumber(numberModel);
-            try {
-                return Integer.toString(_NumberUtil.toIntExact(n), base);
-            } catch (ArithmeticException e) {
-                if (fallbackFormat == null) {
-                    throw new UnformattableValueException(
-                            n + " doesn't fit into an int, and there was no fallback format "
-                            + "specified.");
-                } else {
-                    return fallbackFormat.formatToPlainText(numberModel);
-                }
-            }
-        }
-
-        @Override
-        public boolean isLocaleBound() {
-            return false;
-        }
-
-        @Override
-        public String getDescription() {
-            return "base " + base;
-        }
-        
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/5c98c0ed/src/test/java/org/apache/freemarker/core/CoercionToTextualTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/freemarker/core/CoercionToTextualTest.java b/src/test/java/org/apache/freemarker/core/CoercionToTextualTest.java
index 47de779..ffb051a 100644
--- a/src/test/java/org/apache/freemarker/core/CoercionToTextualTest.java
+++ b/src/test/java/org/apache/freemarker/core/CoercionToTextualTest.java
@@ -26,6 +26,8 @@ import org.apache.freemarker.core.model.TemplateDateModel;
 import org.apache.freemarker.core.model.TemplateModelException;
 import org.apache.freemarker.core.model.impl.SimpleDate;
 import org.apache.freemarker.core.outputformat.impl.HTMLOutputFormat;
+import org.apache.freemarker.core.userpkg.HTMLISOTemplateDateFormatFactory;
+import org.apache.freemarker.core.userpkg.PrintfGTemplateNumberFormatFactory;
 import org.apache.freemarker.test.TemplateTest;
 import org.junit.Before;
 import org.junit.Test;

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/5c98c0ed/src/test/java/org/apache/freemarker/core/ConfigurationTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/freemarker/core/ConfigurationTest.java b/src/test/java/org/apache/freemarker/core/ConfigurationTest.java
index 7930632..cd8594b 100644
--- a/src/test/java/org/apache/freemarker/core/ConfigurationTest.java
+++ b/src/test/java/org/apache/freemarker/core/ConfigurationTest.java
@@ -75,8 +75,12 @@ import org.apache.freemarker.core.templateresolver.impl.NullCacheStorage;
 import org.apache.freemarker.core.templateresolver.impl.SoftCacheStorage;
 import org.apache.freemarker.core.templateresolver.impl.StringTemplateLoader;
 import org.apache.freemarker.core.templateresolver.impl.StrongCacheStorage;
+import org.apache.freemarker.core.userpkg.BaseNTemplateNumberFormatFactory;
 import org.apache.freemarker.core.userpkg.CustomHTMLOutputFormat;
 import org.apache.freemarker.core.userpkg.DummyOutputFormat;
+import org.apache.freemarker.core.userpkg.EpochMillisDivTemplateDateFormatFactory;
+import org.apache.freemarker.core.userpkg.EpochMillisTemplateDateFormatFactory;
+import org.apache.freemarker.core.userpkg.HexTemplateNumberFormatFactory;
 import org.apache.freemarker.core.util._DateUtil;
 import org.apache.freemarker.core.util._NullArgumentException;
 import org.apache.freemarker.core.util._NullWriter;

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/5c98c0ed/src/test/java/org/apache/freemarker/core/DateFormatTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/freemarker/core/DateFormatTest.java b/src/test/java/org/apache/freemarker/core/DateFormatTest.java
index acac66d..3e7cb41 100644
--- a/src/test/java/org/apache/freemarker/core/DateFormatTest.java
+++ b/src/test/java/org/apache/freemarker/core/DateFormatTest.java
@@ -36,6 +36,11 @@ import org.apache.freemarker.core.model.TemplateModelException;
 import org.apache.freemarker.core.model.impl.SimpleDate;
 import org.apache.freemarker.core.templateresolver.ConditionalTemplateConfigurationFactory;
 import org.apache.freemarker.core.templateresolver.FileNameGlobMatcher;
+import org.apache.freemarker.core.userpkg.AppMetaTemplateDateFormatFactory;
+import org.apache.freemarker.core.userpkg.EpochMillisDivTemplateDateFormatFactory;
+import org.apache.freemarker.core.userpkg.EpochMillisTemplateDateFormatFactory;
+import org.apache.freemarker.core.userpkg.HTMLISOTemplateDateFormatFactory;
+import org.apache.freemarker.core.userpkg.LocAndTZSensitiveTemplateDateFormatFactory;
 import org.apache.freemarker.test.TemplateTest;
 import org.junit.Before;
 import org.junit.Test;

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/5c98c0ed/src/test/java/org/apache/freemarker/core/EpochMillisDivTemplateDateFormatFactory.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/freemarker/core/EpochMillisDivTemplateDateFormatFactory.java b/src/test/java/org/apache/freemarker/core/EpochMillisDivTemplateDateFormatFactory.java
deleted file mode 100644
index 3e1f06d..0000000
--- a/src/test/java/org/apache/freemarker/core/EpochMillisDivTemplateDateFormatFactory.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * 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.freemarker.core;
-
-import java.util.Date;
-import java.util.Locale;
-import java.util.TimeZone;
-
-import org.apache.freemarker.core.model.TemplateDateModel;
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.util._StringUtil;
-
-public class EpochMillisDivTemplateDateFormatFactory extends TemplateDateFormatFactory {
-
-    public static final EpochMillisDivTemplateDateFormatFactory INSTANCE = new EpochMillisDivTemplateDateFormatFactory();
-    
-    private EpochMillisDivTemplateDateFormatFactory() {
-        // Defined to decrease visibility
-    }
-    
-    @Override
-    public TemplateDateFormat get(String params, int dateType, Locale locale, TimeZone timeZone, boolean zonelessInput,
-            Environment env) throws UnknownDateTypeFormattingUnsupportedException, InvalidFormatParametersException {
-        int divisor;
-        try {
-            divisor = Integer.parseInt(params);
-        } catch (NumberFormatException e) {
-            if (params.length() == 0) {
-                throw new InvalidFormatParametersException(
-                        "A format parameter is required, which specifies the divisor.");
-            }
-            throw new InvalidFormatParametersException(
-                    "The format paramter must be an integer, but was (shown quoted): " + _StringUtil.jQuote(params));
-        }
-        return new EpochMillisDivTemplateDateFormat(divisor);
-    }
-
-    private static class EpochMillisDivTemplateDateFormat extends TemplateDateFormat {
-
-        private final int divisor;
-        
-        private EpochMillisDivTemplateDateFormat(int divisor) {
-            this.divisor = divisor;
-        }
-        
-        @Override
-        public String formatToPlainText(TemplateDateModel dateModel)
-                throws UnformattableValueException, TemplateModelException {
-            return String.valueOf(TemplateFormatUtil.getNonNullDate(dateModel).getTime() / divisor);
-        }
-
-        @Override
-        public boolean isLocaleBound() {
-            return false;
-        }
-
-        @Override
-        public boolean isTimeZoneBound() {
-            return false;
-        }
-
-        @Override
-        public Date parse(String s, int dateType) throws UnparsableValueException {
-            try {
-                return new Date(Long.parseLong(s));
-            } catch (NumberFormatException e) {
-                throw new UnparsableValueException("Malformed long");
-            }
-        }
-
-        @Override
-        public String getDescription() {
-            return "millis since the epoch";
-        }
-        
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/5c98c0ed/src/test/java/org/apache/freemarker/core/EpochMillisTemplateDateFormatFactory.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/freemarker/core/EpochMillisTemplateDateFormatFactory.java b/src/test/java/org/apache/freemarker/core/EpochMillisTemplateDateFormatFactory.java
deleted file mode 100644
index 2200166..0000000
--- a/src/test/java/org/apache/freemarker/core/EpochMillisTemplateDateFormatFactory.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * 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.freemarker.core;
-
-import java.util.Date;
-import java.util.Locale;
-import java.util.TimeZone;
-
-import org.apache.freemarker.core.model.TemplateDateModel;
-import org.apache.freemarker.core.model.TemplateModelException;
-
-public class EpochMillisTemplateDateFormatFactory extends TemplateDateFormatFactory {
-
-    public static final EpochMillisTemplateDateFormatFactory INSTANCE
-            = new EpochMillisTemplateDateFormatFactory();
-    
-    private EpochMillisTemplateDateFormatFactory() {
-        // Defined to decrease visibility
-    }
-    
-    @Override
-    public TemplateDateFormat get(String params, int dateType,
-            Locale locale, TimeZone timeZone, boolean zonelessInput,
-            Environment env)
-            throws InvalidFormatParametersException {
-        TemplateFormatUtil.checkHasNoParameters(params);
-        return EpochMillisTemplateDateFormat.INSTANCE;
-    }
-
-    private static class EpochMillisTemplateDateFormat extends TemplateDateFormat {
-
-        private static final EpochMillisTemplateDateFormat INSTANCE
-                = new EpochMillisTemplateDateFormat();
-        
-        private EpochMillisTemplateDateFormat() { }
-        
-        @Override
-        public String formatToPlainText(TemplateDateModel dateModel)
-                throws UnformattableValueException, TemplateModelException {
-            return String.valueOf(TemplateFormatUtil.getNonNullDate(dateModel).getTime());
-        }
-
-        @Override
-        public boolean isLocaleBound() {
-            return false;
-        }
-
-        @Override
-        public boolean isTimeZoneBound() {
-            return false;
-        }
-
-        @Override
-        public Date parse(String s, int dateType) throws UnparsableValueException {
-            try {
-                return new Date(Long.parseLong(s));
-            } catch (NumberFormatException e) {
-                throw new UnparsableValueException("Malformed long");
-            }
-        }
-
-        @Override
-        public String getDescription() {
-            return "millis since the epoch";
-        }
-        
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/5c98c0ed/src/test/java/org/apache/freemarker/core/HTMLISOTemplateDateFormatFactory.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/freemarker/core/HTMLISOTemplateDateFormatFactory.java b/src/test/java/org/apache/freemarker/core/HTMLISOTemplateDateFormatFactory.java
deleted file mode 100644
index dbe84eb..0000000
--- a/src/test/java/org/apache/freemarker/core/HTMLISOTemplateDateFormatFactory.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * 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.freemarker.core;
-
-import java.util.Date;
-import java.util.Locale;
-import java.util.TimeZone;
-
-import org.apache.freemarker.core.model.TemplateDateModel;
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.outputformat.impl.HTMLOutputFormat;
-import org.apache.freemarker.core.util._DateUtil;
-import org.apache.freemarker.core.util._DateUtil.CalendarFieldsToDateConverter;
-import org.apache.freemarker.core.util._DateUtil.DateParseException;
-
-public class HTMLISOTemplateDateFormatFactory extends TemplateDateFormatFactory {
-
-    public static final HTMLISOTemplateDateFormatFactory INSTANCE = new HTMLISOTemplateDateFormatFactory();
-    
-    private HTMLISOTemplateDateFormatFactory() {
-        // Defined to decrease visibility
-    }
-    
-    @Override
-    public TemplateDateFormat get(String params, int dateType, Locale locale, TimeZone timeZone, boolean zonelessInput,
-            Environment env) throws UnknownDateTypeFormattingUnsupportedException, InvalidFormatParametersException {
-        TemplateFormatUtil.checkHasNoParameters(params);
-        return HTMLISOTemplateDateFormat.INSTANCE;
-    }
-
-    private static class HTMLISOTemplateDateFormat extends TemplateDateFormat {
-
-        private static final HTMLISOTemplateDateFormat INSTANCE = new HTMLISOTemplateDateFormat();
-
-        private _DateUtil.TrivialDateToISO8601CalendarFactory calendarFactory;
-
-        private CalendarFieldsToDateConverter calToDateConverter;
-        
-        private HTMLISOTemplateDateFormat() { }
-        
-        @Override
-        public String formatToPlainText(TemplateDateModel dateModel)
-                throws UnformattableValueException, TemplateModelException {
-            if (calendarFactory == null) {
-                calendarFactory = new _DateUtil.TrivialDateToISO8601CalendarFactory();
-            }
-            return _DateUtil.dateToISO8601String(
-                    TemplateFormatUtil.getNonNullDate(dateModel),
-                    true, true, true, _DateUtil.ACCURACY_SECONDS, _DateUtil.UTC,
-                    calendarFactory);
-        }
-
-        @Override
-        public boolean isLocaleBound() {
-            return false;
-        }
-
-        @Override
-        public boolean isTimeZoneBound() {
-            return false;
-        }
-
-        @Override
-        public Date parse(String s, int dateType) throws UnparsableValueException {
-            try {
-                if (calToDateConverter == null) {
-                    calToDateConverter = new _DateUtil.TrivialCalendarFieldsToDateConverter();
-                }
-                return _DateUtil.parseISO8601DateTime(s, _DateUtil.UTC, calToDateConverter);
-            } catch (DateParseException e) {
-                throw new UnparsableValueException("Malformed ISO date-time", e);
-            }
-        }
-
-        @Override
-        public Object format(TemplateDateModel dateModel) throws TemplateValueFormatException, TemplateModelException {
-            return HTMLOutputFormat.INSTANCE.fromMarkup(
-                    formatToPlainText(dateModel).replace("T", "<span class='T'>T</span>"));
-        }
-
-        @Override
-        public String getDescription() {
-            return "ISO UTC HTML";
-        }
-        
-    }
-
-}
- 
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/5c98c0ed/src/test/java/org/apache/freemarker/core/HexTemplateNumberFormatFactory.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/freemarker/core/HexTemplateNumberFormatFactory.java b/src/test/java/org/apache/freemarker/core/HexTemplateNumberFormatFactory.java
deleted file mode 100644
index 287b75c..0000000
--- a/src/test/java/org/apache/freemarker/core/HexTemplateNumberFormatFactory.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * 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.freemarker.core;
-
-import java.util.Locale;
-
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.model.TemplateNumberModel;
-import org.apache.freemarker.core.util._NumberUtil;
-
-public class HexTemplateNumberFormatFactory extends TemplateNumberFormatFactory {
-
-    public static final HexTemplateNumberFormatFactory INSTANCE = new HexTemplateNumberFormatFactory();
-    
-    private HexTemplateNumberFormatFactory() {
-        // Defined to decrease visibility
-    }
-    
-    @Override
-    public TemplateNumberFormat get(String params, Locale locale, Environment env)
-            throws InvalidFormatParametersException {
-        TemplateFormatUtil.checkHasNoParameters(params);
-        return HexTemplateNumberFormat.INSTANCE;
-    }
-
-    private static class HexTemplateNumberFormat extends TemplateNumberFormat {
-
-        private static final HexTemplateNumberFormat INSTANCE = new HexTemplateNumberFormat();
-        
-        private HexTemplateNumberFormat() { }
-        
-        @Override
-        public String formatToPlainText(TemplateNumberModel numberModel)
-                throws UnformattableValueException, TemplateModelException {
-            Number n = TemplateFormatUtil.getNonNullNumber(numberModel);
-            try {
-                return Integer.toHexString(_NumberUtil.toIntExact(n));
-            } catch (ArithmeticException e) {
-                throw new UnformattableValueException(n + " doesn't fit into an int");
-            }
-        }
-
-        @Override
-        public boolean isLocaleBound() {
-            return false;
-        }
-
-        @Override
-        public String getDescription() {
-            return "hexadecimal int";
-        }
-        
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/5c98c0ed/src/test/java/org/apache/freemarker/core/LocAndTZSensitiveTemplateDateFormatFactory.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/freemarker/core/LocAndTZSensitiveTemplateDateFormatFactory.java b/src/test/java/org/apache/freemarker/core/LocAndTZSensitiveTemplateDateFormatFactory.java
deleted file mode 100644
index 954fda3..0000000
--- a/src/test/java/org/apache/freemarker/core/LocAndTZSensitiveTemplateDateFormatFactory.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * 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.freemarker.core;
-
-import java.util.Date;
-import java.util.Locale;
-import java.util.TimeZone;
-
-import org.apache.freemarker.core.model.TemplateDateModel;
-import org.apache.freemarker.core.model.TemplateModelException;
-
-public class LocAndTZSensitiveTemplateDateFormatFactory extends TemplateDateFormatFactory {
-
-    public static final LocAndTZSensitiveTemplateDateFormatFactory INSTANCE = new LocAndTZSensitiveTemplateDateFormatFactory();
-    
-    private LocAndTZSensitiveTemplateDateFormatFactory() {
-        // Defined to decrease visibility
-    }
-    
-    @Override
-    public TemplateDateFormat get(String params, int dateType, Locale locale, TimeZone timeZone, boolean zonelessInput,
-            Environment env) throws UnknownDateTypeFormattingUnsupportedException, InvalidFormatParametersException {
-        TemplateFormatUtil.checkHasNoParameters(params);
-        return new LocAndTZSensitiveTemplateDateFormat(locale, timeZone);
-    }
-
-    private static class LocAndTZSensitiveTemplateDateFormat extends TemplateDateFormat {
-
-        private final Locale locale;
-        private final TimeZone timeZone;
-        
-        public LocAndTZSensitiveTemplateDateFormat(Locale locale, TimeZone timeZone) {
-            this.locale = locale;
-            this.timeZone = timeZone;
-        }
-
-        @Override
-        public String formatToPlainText(TemplateDateModel dateModel)
-                throws UnformattableValueException, TemplateModelException {
-            return String.valueOf(TemplateFormatUtil.getNonNullDate(dateModel).getTime() + "@" + locale + ":" + timeZone.getID());
-        }
-
-        @Override
-        public boolean isLocaleBound() {
-            return true;
-        }
-
-        @Override
-        public boolean isTimeZoneBound() {
-            return true;
-        }
-
-        @Override
-        public Date parse(String s, int dateType) throws UnparsableValueException {
-            try {
-                int atIdx = s.indexOf("@");
-                if (atIdx == -1) {
-                    throw new UnparsableValueException("Missing @");
-                }
-                return new Date(Long.parseLong(s.substring(0, atIdx)));
-            } catch (NumberFormatException e) {
-                throw new UnparsableValueException("Malformed long");
-            }
-        }
-
-        @Override
-        public String getDescription() {
-            return "millis since the epoch";
-        }
-        
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/5c98c0ed/src/test/java/org/apache/freemarker/core/LocaleSensitiveTemplateNumberFormatFactory.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/freemarker/core/LocaleSensitiveTemplateNumberFormatFactory.java b/src/test/java/org/apache/freemarker/core/LocaleSensitiveTemplateNumberFormatFactory.java
deleted file mode 100644
index 052f0c4..0000000
--- a/src/test/java/org/apache/freemarker/core/LocaleSensitiveTemplateNumberFormatFactory.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * 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.freemarker.core;
-
-import java.util.Locale;
-
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.model.TemplateNumberModel;
-
-public class LocaleSensitiveTemplateNumberFormatFactory extends TemplateNumberFormatFactory {
-
-    public static final LocaleSensitiveTemplateNumberFormatFactory INSTANCE = new LocaleSensitiveTemplateNumberFormatFactory();
-    
-    private LocaleSensitiveTemplateNumberFormatFactory() {
-        // Defined to decrease visibility
-    }
-    
-    @Override
-    public TemplateNumberFormat get(String params, Locale locale, Environment env)
-            throws InvalidFormatParametersException {
-        TemplateFormatUtil.checkHasNoParameters(params);
-        return new LocaleSensitiveTemplateNumberFormat(locale);
-    }
-
-    private static class LocaleSensitiveTemplateNumberFormat extends TemplateNumberFormat {
-    
-        private final Locale locale;
-        
-        private LocaleSensitiveTemplateNumberFormat(Locale locale) {
-            this.locale = locale;
-        }
-        
-        @Override
-        public String formatToPlainText(TemplateNumberModel numberModel)
-                throws UnformattableValueException, TemplateModelException {
-            Number n = numberModel.getAsNumber();
-            try {
-                return n + "_" + locale;
-            } catch (ArithmeticException e) {
-                throw new UnformattableValueException(n + " doesn't fit into an int");
-            }
-        }
-    
-        @Override
-        public boolean isLocaleBound() {
-            return true;
-        }
-    
-        @Override
-        public String getDescription() {
-            return "test locale sensitive";
-        }
-        
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/5c98c0ed/src/test/java/org/apache/freemarker/core/NumberFormatTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/freemarker/core/NumberFormatTest.java b/src/test/java/org/apache/freemarker/core/NumberFormatTest.java
index f3d0c3e..0d5650a 100644
--- a/src/test/java/org/apache/freemarker/core/NumberFormatTest.java
+++ b/src/test/java/org/apache/freemarker/core/NumberFormatTest.java
@@ -39,6 +39,10 @@ import org.apache.freemarker.core.model.TemplateNumberModel;
 import org.apache.freemarker.core.model.impl.SimpleNumber;
 import org.apache.freemarker.core.templateresolver.ConditionalTemplateConfigurationFactory;
 import org.apache.freemarker.core.templateresolver.FileNameGlobMatcher;
+import org.apache.freemarker.core.userpkg.BaseNTemplateNumberFormatFactory;
+import org.apache.freemarker.core.userpkg.HexTemplateNumberFormatFactory;
+import org.apache.freemarker.core.userpkg.LocaleSensitiveTemplateNumberFormatFactory;
+import org.apache.freemarker.core.userpkg.PrintfGTemplateNumberFormatFactory;
 import org.apache.freemarker.test.TemplateTest;
 import org.junit.Before;
 import org.junit.Test;

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/5c98c0ed/src/test/java/org/apache/freemarker/core/ObjectBuilderSettingsTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/freemarker/core/ObjectBuilderSettingsTest.java b/src/test/java/org/apache/freemarker/core/ObjectBuilderSettingsTest.java
index 14e8457..67336e0 100644
--- a/src/test/java/org/apache/freemarker/core/ObjectBuilderSettingsTest.java
+++ b/src/test/java/org/apache/freemarker/core/ObjectBuilderSettingsTest.java
@@ -49,13 +49,13 @@ import java.util.TimeZone;
 import org.apache.freemarker.core.model.ObjectWrapper;
 import org.apache.freemarker.core.model.impl.DefaultObjectWrapper;
 import org.apache.freemarker.core.model.impl.beans.BeansWrapper;
-import org.apache.freemarker.core.subpkg.PublicWithMixedConstructors;
 import org.apache.freemarker.core.templateresolver.CacheStorage;
 import org.apache.freemarker.core.templateresolver.TemplateLoader;
 import org.apache.freemarker.core.templateresolver.TemplateLoaderSession;
 import org.apache.freemarker.core.templateresolver.TemplateLoadingResult;
 import org.apache.freemarker.core.templateresolver.TemplateLoadingSource;
 import org.apache.freemarker.core.templateresolver.impl.MruCacheStorage;
+import org.apache.freemarker.core.userpkg.PublicWithMixedConstructors;
 import org.apache.freemarker.core.util.WriteProtectable;
 import org.junit.Test;
 
@@ -966,7 +966,7 @@ public class ObjectBuilderSettingsTest {
     public void visibilityTest() throws Exception {
         try {
             _ObjectBuilderSettingEvaluator.eval(
-                    "org.apache.freemarker.core.subpkg.PackageVisibleAll()",
+                    "org.apache.freemarker.core.userpkg.PackageVisibleAll()",
                     Object.class, false, _SettingEvaluationEnvironment.getCurrent());
             fail();
         } catch (_ObjectBuilderSettingEvaluationException e) {
@@ -975,7 +975,7 @@ public class ObjectBuilderSettingsTest {
 
         try {
             _ObjectBuilderSettingEvaluator.eval(
-                    "org.apache.freemarker.core.subpkg.PackageVisibleWithPublicConstructor()",
+                    "org.apache.freemarker.core.userpkg.PackageVisibleWithPublicConstructor()",
                     Object.class, false, _SettingEvaluationEnvironment.getCurrent());
             fail();
         } catch (_ObjectBuilderSettingEvaluationException e) {
@@ -984,7 +984,7 @@ public class ObjectBuilderSettingsTest {
 
         try {
             _ObjectBuilderSettingEvaluator.eval(
-                    "org.apache.freemarker.core.subpkg.PublicWithPackageVisibleConstructor()",
+                    "org.apache.freemarker.core.userpkg.PublicWithPackageVisibleConstructor()",
                     Object.class, false, _SettingEvaluationEnvironment.getCurrent());
             fail();
         } catch (_ObjectBuilderSettingEvaluationException e) {
@@ -993,14 +993,14 @@ public class ObjectBuilderSettingsTest {
         
         {
             Object o = _ObjectBuilderSettingEvaluator.eval(
-                    "org.apache.freemarker.core.subpkg.PublicAll()",
+                    "org.apache.freemarker.core.userpkg.PublicAll()",
                     Object.class, false, _SettingEvaluationEnvironment.getCurrent());
-            assertEquals(org.apache.freemarker.core.subpkg.PublicAll.class, o.getClass());
+            assertEquals(org.apache.freemarker.core.userpkg.PublicAll.class, o.getClass());
         }
         
         {
             Object o = _ObjectBuilderSettingEvaluator.eval(
-                    "org.apache.freemarker.core.subpkg.PublicWithMixedConstructors(1)",
+                    "org.apache.freemarker.core.userpkg.PublicWithMixedConstructors(1)",
                     Object.class, false, _SettingEvaluationEnvironment.getCurrent());
             assertEquals("Integer", ((PublicWithMixedConstructors) o).getS());
         }
@@ -1008,9 +1008,9 @@ public class ObjectBuilderSettingsTest {
         
         {
             Object o = _ObjectBuilderSettingEvaluator.eval(
-                    "org.apache.freemarker.core.subpkg.PackageVisibleAllWithBuilder()",
+                    "org.apache.freemarker.core.userpkg.PackageVisibleAllWithBuilder()",
                     Object.class, false, _SettingEvaluationEnvironment.getCurrent());
-            assertEquals("org.apache.freemarker.core.subpkg.PackageVisibleAllWithBuilder", o.getClass().getName());
+            assertEquals("org.apache.freemarker.core.userpkg.PackageVisibleAllWithBuilder", o.getClass().getName());
         }
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/5c98c0ed/src/test/java/org/apache/freemarker/core/PrintfGTemplateNumberFormatFactory.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/freemarker/core/PrintfGTemplateNumberFormatFactory.java b/src/test/java/org/apache/freemarker/core/PrintfGTemplateNumberFormatFactory.java
deleted file mode 100644
index 15031a4..0000000
--- a/src/test/java/org/apache/freemarker/core/PrintfGTemplateNumberFormatFactory.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * 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.freemarker.core;
-
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.util.Locale;
-
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.model.TemplateNumberModel;
-import org.apache.freemarker.core.outputformat.impl.HTMLOutputFormat;
-import org.apache.freemarker.core.util._StringUtil;
-
-/**
- * Formats like {@code %G} in {@code printf}, with the specified number of significant digits. Also has special
- * formatter for HTML output format, where it uses the HTML "sup" element for exponents.
- */
-public class PrintfGTemplateNumberFormatFactory extends TemplateNumberFormatFactory {
-
-    public static final PrintfGTemplateNumberFormatFactory INSTANCE = new PrintfGTemplateNumberFormatFactory();
-    
-    private PrintfGTemplateNumberFormatFactory() {
-        // Defined to decrease visibility
-    }
-    
-    @Override
-    public TemplateNumberFormat get(String params, Locale locale, Environment env)
-            throws InvalidFormatParametersException {
-        Integer significantDigits;
-        if (!params.isEmpty()) {
-            try {
-                significantDigits = Integer.valueOf(params);
-            } catch (NumberFormatException e) {
-                throw new InvalidFormatParametersException(
-                        "The format parameter must be an integer, but was (shown quoted) "
-                        + _StringUtil.jQuote(params) + ".");
-            }
-        } else {
-            // Use the default of %G
-            significantDigits = null;
-        }
-        return new PrintfGTemplateNumberFormat(significantDigits, locale);
-    }
-
-    private static class PrintfGTemplateNumberFormat extends TemplateNumberFormat {
-        
-        private final Locale locale;
-        private final String printfFormat; 
-
-        private PrintfGTemplateNumberFormat(Integer significantDigits, Locale locale) {
-            printfFormat = "%" + (significantDigits != null ? "." + significantDigits : "") + "G";
-            this.locale = locale;
-        }
-        
-        @Override
-        public String formatToPlainText(TemplateNumberModel numberModel)
-                throws UnformattableValueException, TemplateModelException {
-            final Number n = TemplateFormatUtil.getNonNullNumber(numberModel);
-            
-            // printf %G only accepts Double, BigDecimal and Float 
-            final Number gCompatibleN;
-            if (n instanceof Double  || n instanceof BigDecimal || n instanceof Float) {
-                gCompatibleN = n;
-            } else {
-                if (n instanceof BigInteger) {
-                    gCompatibleN = new BigDecimal((BigInteger) n);                        
-                } else if (n instanceof Long) {
-                    gCompatibleN = BigDecimal.valueOf(n.longValue());
-                } else {
-                    gCompatibleN = Double.valueOf(n.doubleValue());
-                }
-            }
-            
-            return String.format(locale, printfFormat, gCompatibleN);
-        }
-
-        @Override
-        public Object format(TemplateNumberModel numberModel)
-                throws UnformattableValueException, TemplateModelException {
-            String strResult = formatToPlainText(numberModel);
-            
-            int expIdx = strResult.indexOf('E');
-            if (expIdx == -1) {
-                return strResult;
-            }
-                
-            String expStr = strResult.substring(expIdx + 1);
-            int expSignifNumBegin = 0;
-            while (expSignifNumBegin < expStr.length() && isExpSignifNumPrefix(expStr.charAt(expSignifNumBegin))) {
-                expSignifNumBegin++;
-            }
-            
-            return HTMLOutputFormat.INSTANCE.fromMarkup(
-                    strResult.substring(0, expIdx)
-                    + "*10<sup>"
-                    + (expStr.charAt(0) == '-' ? "-" : "") + expStr.substring(expSignifNumBegin)
-                    + "</sup>");
-        }
-
-        private boolean isExpSignifNumPrefix(char c) {
-            return c == '+' || c == '-' || c == '0';
-        }
-
-        @Override
-        public boolean isLocaleBound() {
-            return true;
-        }
-
-        @Override
-        public String getDescription() {
-            return "printf " + printfFormat;
-        }
-        
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/5c98c0ed/src/test/java/org/apache/freemarker/core/StringLiteralInterpolationTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/freemarker/core/StringLiteralInterpolationTest.java b/src/test/java/org/apache/freemarker/core/StringLiteralInterpolationTest.java
index 29aa46e..d7055b8 100644
--- a/src/test/java/org/apache/freemarker/core/StringLiteralInterpolationTest.java
+++ b/src/test/java/org/apache/freemarker/core/StringLiteralInterpolationTest.java
@@ -22,6 +22,7 @@ import java.io.IOException;
 import java.util.Collections;
 
 import org.apache.freemarker.core.outputformat.impl.RTFOutputFormat;
+import org.apache.freemarker.core.userpkg.PrintfGTemplateNumberFormatFactory;
 import org.apache.freemarker.test.TemplateTest;
 import org.junit.Test;
 

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/5c98c0ed/src/test/java/org/apache/freemarker/core/TemplateConfigurationTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/freemarker/core/TemplateConfigurationTest.java b/src/test/java/org/apache/freemarker/core/TemplateConfigurationTest.java
index cfb17b0..6af8a25 100644
--- a/src/test/java/org/apache/freemarker/core/TemplateConfigurationTest.java
+++ b/src/test/java/org/apache/freemarker/core/TemplateConfigurationTest.java
@@ -54,6 +54,12 @@ import org.apache.freemarker.core.outputformat.impl.HTMLOutputFormat;
 import org.apache.freemarker.core.outputformat.impl.UndefinedOutputFormat;
 import org.apache.freemarker.core.outputformat.impl.XMLOutputFormat;
 import org.apache.freemarker.core.templateresolver.impl.StringTemplateLoader;
+import org.apache.freemarker.core.userpkg.BaseNTemplateNumberFormatFactory;
+import org.apache.freemarker.core.userpkg.EpochMillisDivTemplateDateFormatFactory;
+import org.apache.freemarker.core.userpkg.EpochMillisTemplateDateFormatFactory;
+import org.apache.freemarker.core.userpkg.HexTemplateNumberFormatFactory;
+import org.apache.freemarker.core.userpkg.LocAndTZSensitiveTemplateDateFormatFactory;
+import org.apache.freemarker.core.userpkg.LocaleSensitiveTemplateNumberFormatFactory;
 import org.apache.freemarker.core.util._NullArgumentException;
 import org.junit.Test;
 

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/5c98c0ed/src/test/java/org/apache/freemarker/core/subpkg/PackageVisibleAll.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/freemarker/core/subpkg/PackageVisibleAll.java b/src/test/java/org/apache/freemarker/core/subpkg/PackageVisibleAll.java
deleted file mode 100644
index 0aaf54b..0000000
--- a/src/test/java/org/apache/freemarker/core/subpkg/PackageVisibleAll.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * 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.freemarker.core.subpkg;
-
-class PackageVisibleAll {
-    
-    PackageVisibleAll() {}
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/5c98c0ed/src/test/java/org/apache/freemarker/core/subpkg/PackageVisibleAllWithBuilder.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/freemarker/core/subpkg/PackageVisibleAllWithBuilder.java b/src/test/java/org/apache/freemarker/core/subpkg/PackageVisibleAllWithBuilder.java
deleted file mode 100644
index c788f7d..0000000
--- a/src/test/java/org/apache/freemarker/core/subpkg/PackageVisibleAllWithBuilder.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * 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.freemarker.core.subpkg;
-
-class PackageVisibleAllWithBuilder {
-
-    PackageVisibleAllWithBuilder() {}
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/5c98c0ed/src/test/java/org/apache/freemarker/core/subpkg/PackageVisibleAllWithBuilderBuilder.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/freemarker/core/subpkg/PackageVisibleAllWithBuilderBuilder.java b/src/test/java/org/apache/freemarker/core/subpkg/PackageVisibleAllWithBuilderBuilder.java
deleted file mode 100644
index 4aa4e3f..0000000
--- a/src/test/java/org/apache/freemarker/core/subpkg/PackageVisibleAllWithBuilderBuilder.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * 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.freemarker.core.subpkg;
-
-public class PackageVisibleAllWithBuilderBuilder {
-    
-    public PackageVisibleAllWithBuilder build() {
-        return new PackageVisibleAllWithBuilder();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/5c98c0ed/src/test/java/org/apache/freemarker/core/subpkg/PackageVisibleWithPublicConstructor.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/freemarker/core/subpkg/PackageVisibleWithPublicConstructor.java b/src/test/java/org/apache/freemarker/core/subpkg/PackageVisibleWithPublicConstructor.java
deleted file mode 100644
index 474727b..0000000
--- a/src/test/java/org/apache/freemarker/core/subpkg/PackageVisibleWithPublicConstructor.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * 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.freemarker.core.subpkg;
-
-class PackageVisibleWithPublicConstructor {
-    
-    public PackageVisibleWithPublicConstructor() {
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/5c98c0ed/src/test/java/org/apache/freemarker/core/subpkg/PublicAll.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/freemarker/core/subpkg/PublicAll.java b/src/test/java/org/apache/freemarker/core/subpkg/PublicAll.java
deleted file mode 100644
index 0596c1c..0000000
--- a/src/test/java/org/apache/freemarker/core/subpkg/PublicAll.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * 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.freemarker.core.subpkg;
-
-public class PublicAll {
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/5c98c0ed/src/test/java/org/apache/freemarker/core/subpkg/PublicWithMixedConstructors.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/freemarker/core/subpkg/PublicWithMixedConstructors.java b/src/test/java/org/apache/freemarker/core/subpkg/PublicWithMixedConstructors.java
deleted file mode 100644
index cb639a7..0000000
--- a/src/test/java/org/apache/freemarker/core/subpkg/PublicWithMixedConstructors.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * 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.freemarker.core.subpkg;
-
-public class PublicWithMixedConstructors {
-    
-    private final String s;
-
-    public PublicWithMixedConstructors(Integer x) {
-        s = "Integer";
-    }
-
-    PublicWithMixedConstructors(int x) {
-        s = "int";
-    }
-
-    public String getS() {
-        return s;
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/5c98c0ed/src/test/java/org/apache/freemarker/core/subpkg/PublicWithPackageVisibleConstructor.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/freemarker/core/subpkg/PublicWithPackageVisibleConstructor.java b/src/test/java/org/apache/freemarker/core/subpkg/PublicWithPackageVisibleConstructor.java
deleted file mode 100644
index e4ab7ea..0000000
--- a/src/test/java/org/apache/freemarker/core/subpkg/PublicWithPackageVisibleConstructor.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * 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.freemarker.core.subpkg;
-
-public class PublicWithPackageVisibleConstructor {
-
-    PublicWithPackageVisibleConstructor() { }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/5c98c0ed/src/test/java/org/apache/freemarker/core/userpkg/AppMetaTemplateDateFormatFactory.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/freemarker/core/userpkg/AppMetaTemplateDateFormatFactory.java b/src/test/java/org/apache/freemarker/core/userpkg/AppMetaTemplateDateFormatFactory.java
new file mode 100644
index 0000000..be49664
--- /dev/null
+++ b/src/test/java/org/apache/freemarker/core/userpkg/AppMetaTemplateDateFormatFactory.java
@@ -0,0 +1,129 @@
+/*
+ * 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.freemarker.core.userpkg;
+
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+import org.apache.freemarker.core.Environment;
+import org.apache.freemarker.core.InvalidFormatParametersException;
+import org.apache.freemarker.core.TemplateDateFormat;
+import org.apache.freemarker.core.TemplateDateFormatFactory;
+import org.apache.freemarker.core.TemplateFormatUtil;
+import org.apache.freemarker.core.UnformattableValueException;
+import org.apache.freemarker.core.UnknownDateTypeFormattingUnsupportedException;
+import org.apache.freemarker.core.UnparsableValueException;
+import org.apache.freemarker.core.model.TemplateDateModel;
+import org.apache.freemarker.core.model.TemplateModelException;
+
+public class AppMetaTemplateDateFormatFactory extends TemplateDateFormatFactory {
+
+    public static final AppMetaTemplateDateFormatFactory INSTANCE = new AppMetaTemplateDateFormatFactory();
+    
+    private AppMetaTemplateDateFormatFactory() {
+        // Defined to decrease visibility
+    }
+    
+    @Override
+    public TemplateDateFormat get(String params, int dateType, Locale locale, TimeZone timeZone, boolean zonelessInput,
+            Environment env) throws UnknownDateTypeFormattingUnsupportedException, InvalidFormatParametersException {
+        TemplateFormatUtil.checkHasNoParameters(params);
+        return AppMetaTemplateDateFormat.INSTANCE;
+    }
+
+    private static class AppMetaTemplateDateFormat extends TemplateDateFormat {
+
+        private static final AppMetaTemplateDateFormat INSTANCE = new AppMetaTemplateDateFormat();
+        
+        private AppMetaTemplateDateFormat() { }
+        
+        @Override
+        public String formatToPlainText(TemplateDateModel dateModel)
+                throws UnformattableValueException, TemplateModelException {
+            String result = String.valueOf(TemplateFormatUtil.getNonNullDate(dateModel).getTime());
+            if (dateModel instanceof AppMetaTemplateDateModel) {
+                result += "/" + ((AppMetaTemplateDateModel) dateModel).getAppMeta(); 
+            }
+            return result;
+        }
+
+        @Override
+        public boolean isLocaleBound() {
+            return false;
+        }
+
+        @Override
+        public boolean isTimeZoneBound() {
+            return false;
+        }
+
+        @Override
+        public Object parse(String s, int dateType) throws UnparsableValueException {
+            int slashIdx = s.indexOf('/');
+            try {
+                if (slashIdx != -1) {
+                    return new AppMetaTemplateDateModel(
+                            new Date(Long.parseLong(s.substring(0,  slashIdx))),
+                            dateType,
+                            s.substring(slashIdx +1));
+                } else {
+                    return new Date(Long.parseLong(s));
+                }
+            } catch (NumberFormatException e) {
+                throw new UnparsableValueException("Malformed long");
+            }
+        }
+
+        @Override
+        public String getDescription() {
+            return "millis since the epoch";
+        }
+        
+    }
+    
+    public static class AppMetaTemplateDateModel implements TemplateDateModel {
+        
+        private final Date date;
+        private final int dateType;
+        private final String appMeta;
+
+        public AppMetaTemplateDateModel(Date date, int dateType, String appMeta) {
+            this.date = date;
+            this.dateType = dateType;
+            this.appMeta = appMeta;
+        }
+
+        @Override
+        public Date getAsDate() throws TemplateModelException {
+            return date;
+        }
+
+        @Override
+        public int getDateType() {
+            return dateType;
+        }
+
+        public String getAppMeta() {
+            return appMeta;
+        }
+        
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/5c98c0ed/src/test/java/org/apache/freemarker/core/userpkg/BaseNTemplateNumberFormatFactory.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/freemarker/core/userpkg/BaseNTemplateNumberFormatFactory.java b/src/test/java/org/apache/freemarker/core/userpkg/BaseNTemplateNumberFormatFactory.java
new file mode 100644
index 0000000..f310d30
--- /dev/null
+++ b/src/test/java/org/apache/freemarker/core/userpkg/BaseNTemplateNumberFormatFactory.java
@@ -0,0 +1,128 @@
+/*
+ * 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.freemarker.core.userpkg;
+
+import java.util.Locale;
+
+import org.apache.freemarker.core.Environment;
+import org.apache.freemarker.core.InvalidFormatParametersException;
+import org.apache.freemarker.core.TemplateFormatUtil;
+import org.apache.freemarker.core.TemplateNumberFormat;
+import org.apache.freemarker.core.TemplateNumberFormatFactory;
+import org.apache.freemarker.core.TemplateValueFormatException;
+import org.apache.freemarker.core.UnformattableValueException;
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.model.TemplateNumberModel;
+import org.apache.freemarker.core.util._NumberUtil;
+import org.apache.freemarker.core.util._StringUtil;
+
+/**
+ * Shows a number in base N number system. Can only format numbers that fit into an {@code int},
+ * however, optionally you can specify a fallback format. This format has one required parameter,
+ * the numerical system base. That can be optionally followed by "|" and a fallback format.
+ */
+public class BaseNTemplateNumberFormatFactory extends TemplateNumberFormatFactory {
+
+    public static final BaseNTemplateNumberFormatFactory INSTANCE
+            = new BaseNTemplateNumberFormatFactory();
+    
+    private BaseNTemplateNumberFormatFactory() {
+        // Defined to decrease visibility
+    }
+    
+    @Override
+    public TemplateNumberFormat get(String params, Locale locale, Environment env)
+            throws InvalidFormatParametersException {
+        TemplateNumberFormat fallbackFormat;
+        {
+            int barIdx = params.indexOf('|');
+            if (barIdx != -1) {
+                String fallbackFormatStr = params.substring(barIdx + 1);
+                params = params.substring(0, barIdx);
+                try {
+                    fallbackFormat = env.getTemplateNumberFormat(fallbackFormatStr, locale);
+                } catch (TemplateValueFormatException e) {
+                    throw new InvalidFormatParametersException(
+                            "Couldn't get the fallback number format (specified after the \"|\"), "
+                            + _StringUtil.jQuote(fallbackFormatStr) + ". Reason: " + e.getMessage(),
+                            e);
+                }
+            } else {
+                fallbackFormat = null;
+            }
+        }
+        
+        int base;
+        try {
+            base = Integer.parseInt(params);
+        } catch (NumberFormatException e) {
+            if (params.length() == 0) {
+                throw new InvalidFormatParametersException(
+                        "A format parameter is required to specify the numerical system base.");
+            }
+            throw new InvalidFormatParametersException(
+                    "The format paramter must be an integer, but was (shown quoted): "
+                    + _StringUtil.jQuote(params));
+        }
+        if (base < 2) {
+            throw new InvalidFormatParametersException("A base must be at least 2.");
+        }
+        return new BaseNTemplateNumberFormat(base, fallbackFormat);
+    }
+
+    private static class BaseNTemplateNumberFormat extends TemplateNumberFormat {
+
+        private final int base;
+        private final TemplateNumberFormat fallbackFormat;
+        
+        private BaseNTemplateNumberFormat(int base, TemplateNumberFormat fallbackFormat) {
+            this.base = base;
+            this.fallbackFormat = fallbackFormat;
+        }
+        
+        @Override
+        public String formatToPlainText(TemplateNumberModel numberModel)
+                throws TemplateModelException, TemplateValueFormatException {
+            Number n = TemplateFormatUtil.getNonNullNumber(numberModel);
+            try {
+                return Integer.toString(_NumberUtil.toIntExact(n), base);
+            } catch (ArithmeticException e) {
+                if (fallbackFormat == null) {
+                    throw new UnformattableValueException(
+                            n + " doesn't fit into an int, and there was no fallback format "
+                            + "specified.");
+                } else {
+                    return fallbackFormat.formatToPlainText(numberModel);
+                }
+            }
+        }
+
+        @Override
+        public boolean isLocaleBound() {
+            return false;
+        }
+
+        @Override
+        public String getDescription() {
+            return "base " + base;
+        }
+        
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/5c98c0ed/src/test/java/org/apache/freemarker/core/userpkg/EpochMillisDivTemplateDateFormatFactory.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/freemarker/core/userpkg/EpochMillisDivTemplateDateFormatFactory.java b/src/test/java/org/apache/freemarker/core/userpkg/EpochMillisDivTemplateDateFormatFactory.java
new file mode 100644
index 0000000..3eb8969
--- /dev/null
+++ b/src/test/java/org/apache/freemarker/core/userpkg/EpochMillisDivTemplateDateFormatFactory.java
@@ -0,0 +1,102 @@
+/*
+ * 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.freemarker.core.userpkg;
+
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+import org.apache.freemarker.core.Environment;
+import org.apache.freemarker.core.InvalidFormatParametersException;
+import org.apache.freemarker.core.TemplateDateFormat;
+import org.apache.freemarker.core.TemplateDateFormatFactory;
+import org.apache.freemarker.core.TemplateFormatUtil;
+import org.apache.freemarker.core.UnformattableValueException;
+import org.apache.freemarker.core.UnknownDateTypeFormattingUnsupportedException;
+import org.apache.freemarker.core.UnparsableValueException;
+import org.apache.freemarker.core.model.TemplateDateModel;
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.util._StringUtil;
+
+public class EpochMillisDivTemplateDateFormatFactory extends TemplateDateFormatFactory {
+
+    public static final EpochMillisDivTemplateDateFormatFactory INSTANCE = new EpochMillisDivTemplateDateFormatFactory();
+    
+    private EpochMillisDivTemplateDateFormatFactory() {
+        // Defined to decrease visibility
+    }
+    
+    @Override
+    public TemplateDateFormat get(String params, int dateType, Locale locale, TimeZone timeZone, boolean zonelessInput,
+            Environment env) throws UnknownDateTypeFormattingUnsupportedException, InvalidFormatParametersException {
+        int divisor;
+        try {
+            divisor = Integer.parseInt(params);
+        } catch (NumberFormatException e) {
+            if (params.length() == 0) {
+                throw new InvalidFormatParametersException(
+                        "A format parameter is required, which specifies the divisor.");
+            }
+            throw new InvalidFormatParametersException(
+                    "The format paramter must be an integer, but was (shown quoted): " + _StringUtil.jQuote(params));
+        }
+        return new EpochMillisDivTemplateDateFormat(divisor);
+    }
+
+    private static class EpochMillisDivTemplateDateFormat extends TemplateDateFormat {
+
+        private final int divisor;
+        
+        private EpochMillisDivTemplateDateFormat(int divisor) {
+            this.divisor = divisor;
+        }
+        
+        @Override
+        public String formatToPlainText(TemplateDateModel dateModel)
+                throws UnformattableValueException, TemplateModelException {
+            return String.valueOf(TemplateFormatUtil.getNonNullDate(dateModel).getTime() / divisor);
+        }
+
+        @Override
+        public boolean isLocaleBound() {
+            return false;
+        }
+
+        @Override
+        public boolean isTimeZoneBound() {
+            return false;
+        }
+
+        @Override
+        public Date parse(String s, int dateType) throws UnparsableValueException {
+            try {
+                return new Date(Long.parseLong(s));
+            } catch (NumberFormatException e) {
+                throw new UnparsableValueException("Malformed long");
+            }
+        }
+
+        @Override
+        public String getDescription() {
+            return "millis since the epoch";
+        }
+        
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/5c98c0ed/src/test/java/org/apache/freemarker/core/userpkg/EpochMillisTemplateDateFormatFactory.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/freemarker/core/userpkg/EpochMillisTemplateDateFormatFactory.java b/src/test/java/org/apache/freemarker/core/userpkg/EpochMillisTemplateDateFormatFactory.java
new file mode 100644
index 0000000..4e3394b
--- /dev/null
+++ b/src/test/java/org/apache/freemarker/core/userpkg/EpochMillisTemplateDateFormatFactory.java
@@ -0,0 +1,92 @@
+/*
+ * 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.freemarker.core.userpkg;
+
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+import org.apache.freemarker.core.Environment;
+import org.apache.freemarker.core.InvalidFormatParametersException;
+import org.apache.freemarker.core.TemplateDateFormat;
+import org.apache.freemarker.core.TemplateDateFormatFactory;
+import org.apache.freemarker.core.TemplateFormatUtil;
+import org.apache.freemarker.core.UnformattableValueException;
+import org.apache.freemarker.core.UnparsableValueException;
+import org.apache.freemarker.core.model.TemplateDateModel;
+import org.apache.freemarker.core.model.TemplateModelException;
+
+public class EpochMillisTemplateDateFormatFactory extends TemplateDateFormatFactory {
+
+    public static final EpochMillisTemplateDateFormatFactory INSTANCE
+            = new EpochMillisTemplateDateFormatFactory();
+    
+    private EpochMillisTemplateDateFormatFactory() {
+        // Defined to decrease visibility
+    }
+    
+    @Override
+    public TemplateDateFormat get(String params, int dateType,
+            Locale locale, TimeZone timeZone, boolean zonelessInput,
+            Environment env)
+            throws InvalidFormatParametersException {
+        TemplateFormatUtil.checkHasNoParameters(params);
+        return EpochMillisTemplateDateFormat.INSTANCE;
+    }
+
+    private static class EpochMillisTemplateDateFormat extends TemplateDateFormat {
+
+        private static final EpochMillisTemplateDateFormat INSTANCE
+                = new EpochMillisTemplateDateFormat();
+        
+        private EpochMillisTemplateDateFormat() { }
+        
+        @Override
+        public String formatToPlainText(TemplateDateModel dateModel)
+                throws UnformattableValueException, TemplateModelException {
+            return String.valueOf(TemplateFormatUtil.getNonNullDate(dateModel).getTime());
+        }
+
+        @Override
+        public boolean isLocaleBound() {
+            return false;
+        }
+
+        @Override
+        public boolean isTimeZoneBound() {
+            return false;
+        }
+
+        @Override
+        public Date parse(String s, int dateType) throws UnparsableValueException {
+            try {
+                return new Date(Long.parseLong(s));
+            } catch (NumberFormatException e) {
+                throw new UnparsableValueException("Malformed long");
+            }
+        }
+
+        @Override
+        public String getDescription() {
+            return "millis since the epoch";
+        }
+        
+    }
+
+}


Mime
View raw message