├── .gitignore ├── .travis.yml ├── LICENSE.txt ├── README.md ├── appveyor.yml ├── pom.xml └── src └── main └── java └── org └── sourcefoundry └── glyphtester ├── CommandLine.java ├── FontBoxGlyphSource.java ├── GlyphImageRenderer.java ├── GlyphSource.java ├── Main.java └── TheFont.java /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/intellij,eclipse,vim,emacs 3 | 4 | ### Intellij ### 5 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 6 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 7 | 8 | # User-specific stuff: 9 | .idea/workspace.xml 10 | .idea/tasks.xml 11 | .idea/dictionaries 12 | .idea/vcs.xml 13 | .idea/jsLibraryMappings.xml 14 | 15 | # Sensitive or high-churn files: 16 | .idea/dataSources.ids 17 | .idea/dataSources.xml 18 | .idea/dataSources.local.xml 19 | .idea/sqlDataSources.xml 20 | .idea/dynamic.xml 21 | .idea/uiDesigner.xml 22 | 23 | # Gradle: 24 | .idea/gradle.xml 25 | .idea/libraries 26 | 27 | # Mongo Explorer plugin: 28 | .idea/mongoSettings.xml 29 | 30 | ## File-based project format: 31 | *.iws 32 | 33 | ## Plugin-specific files: 34 | 35 | # IntelliJ 36 | /out/ 37 | 38 | # mpeltonen/sbt-idea plugin 39 | .idea_modules/ 40 | 41 | # JIRA plugin 42 | atlassian-ide-plugin.xml 43 | 44 | # Crashlytics plugin (for Android Studio and IntelliJ) 45 | com_crashlytics_export_strings.xml 46 | crashlytics.properties 47 | crashlytics-build.properties 48 | fabric.properties 49 | 50 | ### Intellij Patch ### 51 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 52 | 53 | # *.iml 54 | # modules.xml 55 | 56 | 57 | ### Eclipse ### 58 | 59 | .metadata 60 | bin/ 61 | tmp/ 62 | *.tmp 63 | *.bak 64 | *.swp 65 | *~.nib 66 | local.properties 67 | .settings/ 68 | .loadpath 69 | .recommenders 70 | 71 | # Eclipse Core 72 | .project 73 | 74 | # External tool builders 75 | .externalToolBuilders/ 76 | 77 | # Locally stored "Eclipse launch configurations" 78 | *.launch 79 | 80 | # PyDev specific (Python IDE for Eclipse) 81 | *.pydevproject 82 | 83 | # CDT-specific (C/C++ Development Tooling) 84 | .cproject 85 | 86 | # JDT-specific (Eclipse Java Development Tools) 87 | .classpath 88 | 89 | # Java annotation processor (APT) 90 | .factorypath 91 | 92 | # PDT-specific (PHP Development Tools) 93 | .buildpath 94 | 95 | # sbteclipse plugin 96 | .target 97 | 98 | # Tern plugin 99 | .tern-project 100 | 101 | # TeXlipse plugin 102 | .texlipse 103 | 104 | # STS (Spring Tool Suite) 105 | .springBeans 106 | 107 | # Code Recommenders 108 | .recommenders/ 109 | 110 | 111 | ### Vim ### 112 | # swap 113 | [._]*.s[a-w][a-z] 114 | [._]s[a-w][a-z] 115 | # session 116 | Session.vim 117 | # temporary 118 | .netrwhist 119 | *~ 120 | # auto-generated tag files 121 | tags 122 | 123 | 124 | ### Emacs ### 125 | # -*- mode: gitignore; -*- 126 | *~ 127 | \#*\# 128 | /.emacs.desktop 129 | /.emacs.desktop.lock 130 | *.elc 131 | auto-save-list 132 | tramp 133 | .\#* 134 | 135 | # Org-mode 136 | .org-id-locations 137 | *_archive 138 | 139 | # flymake-mode 140 | *_flymake.* 141 | 142 | # eshell files 143 | /eshell/history 144 | /eshell/lastdir 145 | 146 | # elpa packages 147 | /elpa/ 148 | 149 | # reftex files 150 | *.rel 151 | 152 | # AUCTeX auto folder 153 | /auto/ 154 | 155 | # cask packages 156 | .cask/ 157 | dist/ 158 | 159 | # Flycheck 160 | flycheck_*.el 161 | 162 | # server auth directory 163 | /server/ 164 | 165 | # projectiles files 166 | .projectile -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | jdk: 3 | - oraclejdk8 4 | - oraclejdk7 5 | - openjdk7 -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Jorg Heymans 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Java Glyph Tester 2 | 3 | A tool for testing the JDK font rendering behaviour 4 | 5 | ###Build 6 | This project uses maven to build : `mvn clean install` builds the uberjar necessary to run the tool. 7 | 8 | ###Run 9 | Below command will generate an image for all glyphs contained in Hack-Regular, at size 14, using c:\tmp as output directory 10 | 11 | `java -jar java-glyphtester-0.1.jar --fontfile C:\Users\jorgheymans\Downloads\Hack-v2_020-ttf\Hack-Regular.ttf --fontsize 14 --fontstyle 12 | regular --outputdirectory c:\tmp` 13 | 14 | If you only want to test one or more specific glyphs you can specify them at the end like this: 15 | 16 | `java -jar java-glyphtester-0.1.jar --fontfile C:\Users\jorgheymans\Downloads\Hack-v2_020-ttf\Hack-Regular.ttf --fontsize 14 --fontstyle 17 | regular --outputdirectory c:\tmp A B C D` 18 | 19 | Add --repeatGlyph to repeat the glyph in the output, for example --glyphRepeat 5 will render aaaaa instead of just a. 20 | 21 | Note that per glyph 8 images are generated, one for each aliasing mode available in the standard jdk: 22 | - RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT 23 | - RenderingHints.VALUE_TEXT_ANTIALIAS_GASP 24 | - RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HBGR 25 | - RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB 26 | - RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_VBGR 27 | - RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_VRGB 28 | - RenderingHints.VALUE_TEXT_ANTIALIAS_OFF 29 | - RenderingHints.VALUE_TEXT_ANTIALIAS_ON 30 | 31 | See https://docs.oracle.com/javase/7/docs/api/java/awt/RenderingHints.html for more info 32 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: '{build}' 2 | os: Windows Server 2012 3 | install: 4 | - ps: | 5 | Add-Type -AssemblyName System.IO.Compression.FileSystem 6 | if (!(Test-Path -Path "C:\maven" )) { 7 | (new-object System.Net.WebClient).DownloadFile( 8 | 'http://www.us.apache.org/dist/maven/maven-3/3.2.5/binaries/apache-maven-3.2.5-bin.zip', 9 | 'C:\maven-bin.zip' 10 | ) 11 | [System.IO.Compression.ZipFile]::ExtractToDirectory("C:\maven-bin.zip", "C:\maven") 12 | } 13 | - cmd: SET PATH=C:\maven\apache-maven-3.2.5\bin;%JAVA_HOME%\bin;%PATH% 14 | - cmd: SET MAVEN_OPTS=-XX:MaxPermSize=2g -Xmx4g 15 | - cmd: SET JAVA_OPTS=-XX:MaxPermSize=2g -Xmx4g 16 | build_script: 17 | - mvn clean package --batch-mode -DskipTest 18 | test_script: 19 | - mvn clean install --batch-mode 20 | cache: 21 | - C:\maven\ 22 | - C:\Users\appveyor\.m2 23 | artifacts: 24 | - path: target/generated-glyphs 25 | name: generated-glyphs-windows 26 | type: zip 27 | 28 | - path: logs 29 | name: test logs 30 | type: zip -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | org.sourcefoundry.glyphtester 4 | java-glyphtester 5 | 0.1-SNAPSHOT 6 | 7 | 8 | 9 | org.apache.maven.plugins 10 | maven-compiler-plugin 11 | 3.5.1 12 | 13 | 1.7 14 | 1.7 15 | 16 | 17 | 18 | maven-shade-plugin 19 | 2.4.3 20 | 21 | 22 | package 23 | 24 | shade 25 | 26 | 27 | 28 | 29 | 30 | org.sourcefoundry.glyphtester.Main 31 | 1 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | com.googlecode.maven-download-plugin 41 | download-maven-plugin 42 | 1.3.0 43 | 44 | 45 | install-fonts 46 | generate-resources 47 | 48 | wget 49 | 50 | 51 | https://github.com/chrissimpkins/Hack/releases/download/v2.020/Hack-v2_020-ttf.zip 52 | true 53 | ${project.build.directory}/fontfiles 54 | 55 | 56 | 57 | 58 | 59 | org.codehaus.mojo 60 | exec-maven-plugin 61 | 1.2.1 62 | 63 | 64 | integration-test 65 | 66 | java 67 | 68 | 69 | 70 | 71 | org.sourcefoundry.glyphtester.Main 72 | 73 | --fontfile 74 | ${project.build.directory}/fontfiles 75 | --fontsize 76 | 12 77 | --outputdirectory 78 | ${project.build.directory}/generated-glyphs 79 | --repeatGlyph 80 | 5 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | com.beust 89 | jcommander 90 | 1.48 91 | 92 | 93 | junit 94 | junit 95 | 4.12 96 | test 97 | 98 | 99 | org.apache.pdfbox 100 | fontbox 101 | 2.0.1 102 | 103 | 104 | org.apache.pdfbox 105 | pdfbox 106 | 2.0.24 107 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /src/main/java/org/sourcefoundry/glyphtester/CommandLine.java: -------------------------------------------------------------------------------- 1 | package org.sourcefoundry.glyphtester; 2 | 3 | import com.beust.jcommander.JCommander; 4 | import com.beust.jcommander.Parameter; 5 | import com.beust.jcommander.converters.FileConverter; 6 | 7 | import java.io.File; 8 | import java.util.List; 9 | 10 | /** 11 | * Created by jorgheymans on 12/05/16. 12 | */ 13 | public class CommandLine { 14 | 15 | @Parameter(names = {"--fontfile"}, required = true, converter = FileConverter.class) 16 | File fontFile; 17 | 18 | @Parameter(names = {"--fontsize"}, required = true) 19 | int fontSize = 12; 20 | 21 | @Parameter(names = {"--fontstyle"}) 22 | String fontStyle; 23 | 24 | @Parameter(names = {"--canvaswidth"}) 25 | int canvasWidth = 200; 26 | 27 | @Parameter(names = {"--canvasheight"}) 28 | int canvasHeight = 200; 29 | 30 | @Parameter(names = {"--outputdirectory"}, required = true, converter = FileConverter.class) 31 | File outputDirectory; 32 | 33 | @Parameter(names = {"--renderinghints"}) 34 | String renderingHints; 35 | 36 | @Parameter(names = {"--repeatGlyph"}) 37 | int repeatGlyph = 1; 38 | 39 | @Parameter 40 | List glyphsToTest; 41 | private JCommander jCommander = null; 42 | 43 | public CommandLine(String[] args) { 44 | jCommander = new JCommander(this, args); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/org/sourcefoundry/glyphtester/FontBoxGlyphSource.java: -------------------------------------------------------------------------------- 1 | package org.sourcefoundry.glyphtester; 2 | 3 | import org.apache.fontbox.ttf.CmapSubtable; 4 | import org.apache.fontbox.ttf.TTFParser; 5 | import org.apache.fontbox.ttf.TrueTypeFont; 6 | 7 | import java.io.File; 8 | import java.util.ArrayList; 9 | import java.util.HashMap; 10 | import java.util.List; 11 | import java.util.ListIterator; 12 | import java.util.Map; 13 | 14 | /** 15 | * Created by jorgheymans on 09/05/16. 16 | */ 17 | public class FontBoxGlyphSource implements GlyphSource { 18 | 19 | private TrueTypeFont ttf; 20 | 21 | public FontBoxGlyphSource(File fontFile) throws Exception { 22 | System.out.println("Parsing font " + fontFile.getAbsolutePath()); 23 | ttf = new TTFParser().parse(fontFile); 24 | } 25 | 26 | @Override 27 | public String getFontName() throws Exception { 28 | return ttf.getNaming().getFontFamily(); 29 | } 30 | 31 | @Override 32 | public Map read() throws Exception { 33 | 34 | System.out.println(ttf.getFontBBox()); 35 | System.out.println("Detected font " + ttf.getNaming().getFontFamily() + " (" + 36 | ttf.getNaming().getFontSubFamily() + ") version " + ttf.getHeader().getFontRevision()); 37 | System.out.println("Total number of glyphs : " + ttf.getNumberOfGlyphs()); 38 | Map glyphs = new HashMap<>(); 39 | CmapSubtable unicodeCmap = ttf.getUnicodeCmap(); 40 | List unmappedCharacterCodes = new ArrayList<>(); 41 | for (int i = 0; i < ttf.getNumberOfGlyphs(); i++) { 42 | Integer characterCode = unicodeCmap.getCharacterCode(i); 43 | if (characterCode != null) { 44 | glyphs.put(characterCode, String.valueOf(Character.toChars(unicodeCmap.getCharacterCode(i)))); 45 | } else { 46 | unmappedCharacterCodes.add(String.valueOf(i)); 47 | } 48 | } 49 | if (!unmappedCharacterCodes.isEmpty()) { 50 | StringBuffer sb = new StringBuffer(); 51 | ListIterator it = unmappedCharacterCodes.listIterator(); 52 | while (it.hasNext()) { 53 | sb.append(it.next()); 54 | if (it.hasNext()) { 55 | sb.append(","); 56 | } 57 | } 58 | System.out.println("Glyph ids that cannot be rendered : " + sb); 59 | } 60 | return glyphs; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/org/sourcefoundry/glyphtester/GlyphImageRenderer.java: -------------------------------------------------------------------------------- 1 | package org.sourcefoundry.glyphtester; 2 | 3 | import javax.imageio.ImageIO; 4 | import java.awt.Graphics2D; 5 | import java.awt.RenderingHints; 6 | import java.awt.image.BufferedImage; 7 | import java.io.File; 8 | 9 | /** 10 | * Created by jorgheymans on 12/05/16. 11 | */ 12 | public class GlyphImageRenderer { 13 | 14 | private static final Object[] ALL_RENDERING_HINTS = new Object[]{RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT, 15 | RenderingHints.VALUE_TEXT_ANTIALIAS_GASP, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HBGR, 16 | RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_VBGR, 17 | RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_VRGB, RenderingHints.VALUE_TEXT_ANTIALIAS_OFF, 18 | RenderingHints.VALUE_TEXT_ANTIALIAS_ON}; 19 | 20 | private final int canvasWidth; 21 | private final int canvasHeight; 22 | private TheFont theFont; 23 | private File outputDirectory; 24 | 25 | public GlyphImageRenderer(int canvasWidth, int canvasHeight, TheFont theFont, File outputDirectory) { 26 | this.canvasWidth = canvasWidth; 27 | this.canvasHeight = canvasHeight; 28 | this.theFont = theFont; 29 | // todo take renderinghints from commandline ? 30 | // this.renderingHints = renderingHints.length == 0 ? ALL_RENDERING_HINTS : renderingHints; 31 | this.outputDirectory = outputDirectory; 32 | this.outputDirectory.mkdirs(); 33 | } 34 | 35 | public void render(Integer characterCode, String glyph) throws Exception { 36 | BufferedImage image = new BufferedImage(canvasWidth, canvasHeight, BufferedImage.TYPE_INT_RGB); 37 | final Graphics2D g = image.createGraphics(); 38 | for (Object renderingHint : ALL_RENDERING_HINTS) { 39 | g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, renderingHint); 40 | g.clearRect(0, 0, canvasWidth, canvasHeight); 41 | theFont.paint(g, glyph, canvasWidth, canvasHeight); 42 | ImageIO.write(image, "jpeg", new File(outputDirectory + "/" + characterCode + "_" + renderingHint.toString() + ".jpg")); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/org/sourcefoundry/glyphtester/GlyphSource.java: -------------------------------------------------------------------------------- 1 | package org.sourcefoundry.glyphtester; 2 | 3 | import java.util.Map; 4 | 5 | /** 6 | * Created by jorgheymans on 08/05/16. 7 | */ 8 | public interface GlyphSource { 9 | 10 | String getFontName() throws Exception; 11 | 12 | /** 13 | * @return a map of glyph id -> character 14 | */ 15 | Map read() throws Exception; 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/org/sourcefoundry/glyphtester/Main.java: -------------------------------------------------------------------------------- 1 | package org.sourcefoundry.glyphtester; 2 | 3 | import java.io.File; 4 | import java.io.FilenameFilter; 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | import java.util.Map; 8 | 9 | public class Main { 10 | 11 | /** 12 | * @param args 13 | */ 14 | public static void main(final String[] args) throws Exception { 15 | long now = System.currentTimeMillis(); 16 | final CommandLine commandLine = new CommandLine(args); 17 | List fontFiles = new ArrayList<>(); 18 | String fontStyle = commandLine.fontStyle; 19 | 20 | if (commandLine.fontFile.isDirectory()) { 21 | for (String f : commandLine.fontFile.list(new FilenameFilter() { 22 | @Override 23 | public boolean accept(File dir, String name) { 24 | return name.toLowerCase().endsWith(".ttf"); 25 | } 26 | })) { 27 | fontFiles.add(new File(commandLine.fontFile.getAbsolutePath() + "/" + f)); 28 | fontStyle = null; 29 | } 30 | } else { 31 | fontFiles.add(commandLine.fontFile); 32 | } 33 | for (File fontFile : fontFiles) { 34 | GlyphSource glyphSource = new FontBoxGlyphSource(fontFile); 35 | TheFont theFont = new TheFont(fontFile, fontStyle, glyphSource.getFontName(), commandLine.fontSize); 36 | Map fontGlyphs = glyphSource.read(); 37 | GlyphImageRenderer glyphImageRenderer = new GlyphImageRenderer(commandLine.canvasWidth, commandLine.canvasHeight, 38 | theFont, new File(commandLine.outputDirectory.getAbsolutePath() + "/" + fontFile.getName().replace(".ttf", ""))); 39 | if (commandLine.glyphsToTest != null && !commandLine.glyphsToTest.isEmpty()) { 40 | for (String glyph : commandLine.glyphsToTest) { 41 | String theGlyph = glyph; 42 | for (int i = 0; i < commandLine.repeatGlyph - 1; i++) { 43 | theGlyph += glyph; 44 | } 45 | glyphImageRenderer.render(commandLine.glyphsToTest.indexOf(glyph), theGlyph); 46 | } 47 | } else { 48 | for (Map.Entry entry : fontGlyphs.entrySet()) { 49 | glyphImageRenderer.render(entry.getKey(), entry.getValue()); 50 | } 51 | } 52 | System.out.println("took " + (System.currentTimeMillis() - now) + " ms"); 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /src/main/java/org/sourcefoundry/glyphtester/TheFont.java: -------------------------------------------------------------------------------- 1 | package org.sourcefoundry.glyphtester; 2 | 3 | import java.awt.Color; 4 | import java.awt.Font; 5 | import java.awt.FontMetrics; 6 | import java.awt.Graphics2D; 7 | import java.awt.GraphicsEnvironment; 8 | import java.io.File; 9 | 10 | /** 11 | * Encapsulates the font we are going to do tests on. 12 | *

13 | * Created by jorgheymans on 12/05/16. 14 | */ 15 | public class TheFont { 16 | 17 | private Font font; 18 | 19 | public TheFont(File fontFile, String fontStyle, String fontName, int fontSize) throws Exception { 20 | GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); 21 | ge.registerFont(Font.createFont(Font.TRUETYPE_FONT, fontFile)); 22 | font = new Font(fontName, getFontStyle(fontStyle == null ? fontFile.getName() : fontStyle), fontSize); 23 | } 24 | 25 | public void paint(Graphics2D g, String glyph, int canvasWidth, int canvasHeight) { 26 | g.setFont(font); 27 | g.setColor(Color.WHITE); 28 | g.fillRect(0, 0, canvasWidth, canvasHeight); 29 | FontMetrics fm = g.getFontMetrics(); 30 | int x = (canvasWidth - fm.stringWidth(glyph)) / 2; 31 | // Determine the Y coordinate for the text (note we add the ascent, as in java 2d 0 is top of the screen) 32 | int y = ((canvasHeight - fm.getHeight()) / 2) + fm.getAscent(); 33 | g.setColor(Color.BLACK); 34 | g.drawString(glyph, x, y); 35 | } 36 | 37 | /** 38 | * @param fontStyle 39 | * @return 40 | */ 41 | protected int getFontStyle(String fontStyle) { 42 | if (fontStyle.toLowerCase().contains("regular")) { 43 | return Font.PLAIN; 44 | } else if (fontStyle.toLowerCase().contains("italic")) { 45 | return Font.ITALIC; 46 | } else if (fontStyle.toLowerCase().contains("bold")) { 47 | return Font.BOLD; 48 | } else if (fontStyle.toLowerCase().contains("bolditalic")) { 49 | return Font.BOLD + Font.ITALIC; 50 | } 51 | throw new IllegalArgumentException("cannot parse fontstyle " + fontStyle); 52 | } 53 | } 54 | --------------------------------------------------------------------------------