mirror of
				https://github.com/DanilaFe/abacus
				synced 2025-10-30 17:33:42 -07:00 
			
		
		
		
	Merge branch 'master' into context
This commit is contained in:
		
						commit
						1667edc72b
					
				| @ -1,4 +1,3 @@ | |||||||
| dependencies { | dependencies { | ||||||
|     compile 'com.moandjiezana.toml:toml4j:0.7.1' |  | ||||||
|     testCompile 'junit:junit:4.12' |     testCompile 'junit:junit:4.12' | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,159 +0,0 @@ | |||||||
| package org.nwapw.abacus.config; |  | ||||||
| 
 |  | ||||||
| import com.moandjiezana.toml.Toml; |  | ||||||
| import com.moandjiezana.toml.TomlWriter; |  | ||||||
| 
 |  | ||||||
| import java.io.File; |  | ||||||
| import java.io.IOException; |  | ||||||
| import java.util.Arrays; |  | ||||||
| import java.util.HashSet; |  | ||||||
| import java.util.Set; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * The configuration object that stores |  | ||||||
|  * options that the user can change. |  | ||||||
|  */ |  | ||||||
| public class Configuration { |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * The defaults TOML string. |  | ||||||
|      */ |  | ||||||
|     private static final String DEFAULT_CONFIG = |  | ||||||
|             "numberImplementation = \"naive\"\n" + |  | ||||||
|                     "disabledPlugins = []"; |  | ||||||
|     /** |  | ||||||
|      * The defaults TOML object, parsed from the string. |  | ||||||
|      */ |  | ||||||
|     private static final Toml DEFAULT_TOML = new Toml().read(DEFAULT_CONFIG); |  | ||||||
|     /** |  | ||||||
|      * The TOML writer used to write this configuration to a file. |  | ||||||
|      */ |  | ||||||
|     private static final TomlWriter TOML_WRITER = new TomlWriter(); |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * The computation delay for which the thread can run without interruption. |  | ||||||
|      */ |  | ||||||
|     private double computationDelay = 0; |  | ||||||
|     /** |  | ||||||
|      * The implementation of the number that should be used. |  | ||||||
|      */ |  | ||||||
|     private String numberImplementation = "<default>"; |  | ||||||
|     /** |  | ||||||
|      * The list of disabled plugins in this Configuration. |  | ||||||
|      */ |  | ||||||
|     private Set<String> disabledPlugins = new HashSet<>(); |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * Creates a new configuration form the given configuration. |  | ||||||
|      * |  | ||||||
|      * @param copyFrom the configuration to copy. |  | ||||||
|      */ |  | ||||||
|     public Configuration(Configuration copyFrom) { |  | ||||||
|         copyFrom(copyFrom); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * Creates a new configuration with the given values. |  | ||||||
|      * |  | ||||||
|      * @param computationDelay     the delay before the computation gets killed. |  | ||||||
|      * @param numberImplementation the number implementation, like "naive" or "precise" |  | ||||||
|      * @param disabledPlugins      the list of disabled plugins. |  | ||||||
|      */ |  | ||||||
|     public Configuration(double computationDelay, String numberImplementation, String[] disabledPlugins) { |  | ||||||
|         this.computationDelay = computationDelay; |  | ||||||
|         this.numberImplementation = numberImplementation; |  | ||||||
|         this.disabledPlugins.addAll(Arrays.asList(disabledPlugins)); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * Loads a configuration from a given file, keeping non-specified fields default. |  | ||||||
|      * |  | ||||||
|      * @param fromFile the file to load from. |  | ||||||
|      */ |  | ||||||
|     public Configuration(File fromFile) { |  | ||||||
|         if (!fromFile.exists()) return; |  | ||||||
|         copyFrom(new Toml(DEFAULT_TOML).read(fromFile).to(Configuration.class)); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * Copies the values from the given configuration into this one. |  | ||||||
|      * |  | ||||||
|      * @param otherConfiguration the configuration to copy from. |  | ||||||
|      */ |  | ||||||
|     public void copyFrom(Configuration otherConfiguration) { |  | ||||||
|         this.computationDelay = otherConfiguration.computationDelay; |  | ||||||
|         this.numberImplementation = otherConfiguration.numberImplementation; |  | ||||||
|         this.disabledPlugins.addAll(otherConfiguration.disabledPlugins); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * Saves this configuration to the given file, creating |  | ||||||
|      * any directories that do not exist. |  | ||||||
|      * |  | ||||||
|      * @param file the file to save to. |  | ||||||
|      */ |  | ||||||
|     public void saveTo(File file) { |  | ||||||
|         if (file.getParentFile() != null) file.getParentFile().mkdirs(); |  | ||||||
|         try { |  | ||||||
|             TOML_WRITER.write(this, file); |  | ||||||
|         } catch (IOException e) { |  | ||||||
|             e.printStackTrace(); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * Gets the value of this configuration as a string. |  | ||||||
|      * |  | ||||||
|      * @return the string that represents this configuration. |  | ||||||
|      */ |  | ||||||
|     public String asTomlString() { |  | ||||||
|         return TOML_WRITER.write(this); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * Gets the number implementation from this configuration. |  | ||||||
|      * |  | ||||||
|      * @return the number implementation. |  | ||||||
|      */ |  | ||||||
|     public String getNumberImplementation() { |  | ||||||
|         return numberImplementation; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * Sets the number implementation for the configuration |  | ||||||
|      * |  | ||||||
|      * @param numberImplementation the number implementation. |  | ||||||
|      */ |  | ||||||
|     public void setNumberImplementation(String numberImplementation) { |  | ||||||
|         this.numberImplementation = numberImplementation; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * Gets the list of disabled plugins. |  | ||||||
|      * |  | ||||||
|      * @return the list of disabled plugins. |  | ||||||
|      */ |  | ||||||
|     public Set<String> getDisabledPlugins() { |  | ||||||
|         return disabledPlugins; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * Gets the computation delay specified in the configuration. |  | ||||||
|      * |  | ||||||
|      * @return the computaton delay. |  | ||||||
|      */ |  | ||||||
|     public double getComputationDelay() { |  | ||||||
|         return computationDelay; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * Sets the computation delay. |  | ||||||
|      * |  | ||||||
|      * @param computationDelay the new computation delay. |  | ||||||
|      */ |  | ||||||
|     public void setComputationDelay(double computationDelay) { |  | ||||||
|         this.computationDelay = computationDelay; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
| @ -0,0 +1,20 @@ | |||||||
|  | package org.nwapw.abacus.config | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * A class that holds information that tells Abacus how to behave. | ||||||
|  |  * | ||||||
|  |  * Configuration stores information about how Abacus should behave, for | ||||||
|  |  * instance, what number implementation it should use and what | ||||||
|  |  * plugins should be ignored during loading. | ||||||
|  |  * | ||||||
|  |  * @property numberImplementation the number implementation Abacus should use for loading. | ||||||
|  |  * @param disabledPlugins the plugins that should be disabled and not loaded by the plugin manager. | ||||||
|  |  */ | ||||||
|  | open class Configuration(var numberImplementation: String = "<default>", disabledPlugins: Array<String> = emptyArray()) { | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * The set of disabled plugins that should be ignored by the plugin manager. | ||||||
|  |      */ | ||||||
|  |     val disabledPlugins = disabledPlugins.toMutableSet() | ||||||
|  | 
 | ||||||
|  | } | ||||||
| @ -12,7 +12,7 @@ import org.nwapw.abacus.tree.TreeNode; | |||||||
| 
 | 
 | ||||||
| public class CalculationTests { | public class CalculationTests { | ||||||
| 
 | 
 | ||||||
|     private static Abacus abacus = new Abacus(new Configuration(0, "precise", new String[]{})); |     private static Abacus abacus = new Abacus(new Configuration( "precise", new String[]{})); | ||||||
| 
 | 
 | ||||||
|     @BeforeClass |     @BeforeClass | ||||||
|     public static void prepareTests() { |     public static void prepareTests() { | ||||||
|  | |||||||
| @ -17,7 +17,7 @@ import java.util.List; | |||||||
| 
 | 
 | ||||||
| public class TokenizerTests { | public class TokenizerTests { | ||||||
| 
 | 
 | ||||||
|     private static Abacus abacus = new Abacus(new Configuration(0, "precise", new String[]{})); |     private static Abacus abacus = new Abacus(new Configuration("precise", new String[]{})); | ||||||
|     private static LexerTokenizer lexerTokenizer = new LexerTokenizer(); |     private static LexerTokenizer lexerTokenizer = new LexerTokenizer(); | ||||||
|     private static NumberFunction subtractFunction = new NumberFunction() { |     private static NumberFunction subtractFunction = new NumberFunction() { | ||||||
|         @Override |         @Override | ||||||
|  | |||||||
| @ -3,6 +3,7 @@ | |||||||
|   {% include head.html %} |   {% include head.html %} | ||||||
|   <style> |   <style> | ||||||
|   body { |   body { | ||||||
|  |     margin: 0px; | ||||||
|     margin-top: 50px; |     margin-top: 50px; | ||||||
|     color: white; |     color: white; | ||||||
|     text-align: center; |     text-align: center; | ||||||
| @ -37,6 +38,58 @@ | |||||||
|     background-color: #06e8a4; |     background-color: #06e8a4; | ||||||
|     color: white; |     color: white; | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   div.fullwidth { | ||||||
|  |     width: 100%; | ||||||
|  |     height: auto; | ||||||
|  |     overflow: hidden; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   div.fullwidth img { | ||||||
|  |     max-width: 100%; | ||||||
|  |     max-height: 450px; | ||||||
|  |     margin: auto; | ||||||
|  |     margin-top: 20px; | ||||||
|  |     margin-bottom: 20px; | ||||||
|  |     display: block; | ||||||
|  |     border-radius: 5px; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   div.white { | ||||||
|  |     background-color: white; | ||||||
|  |     color: black; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   div.green { | ||||||
|  |     background-color: #06e8a4; | ||||||
|  |     color: white; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   div.fullwidth div.double { | ||||||
|  |     height: 100%; | ||||||
|  |     text-align: left; | ||||||
|  |     width: 50%; | ||||||
|  |     box-sizing: border-box; | ||||||
|  |     padding: 40px; | ||||||
|  |     float: left; | ||||||
|  |     background-color: inherit; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @media (max-width: 750px) { | ||||||
|  |     div.fullwidth div.double { | ||||||
|  |       width: 100%; | ||||||
|  |       padding: 15px; | ||||||
|  |     } | ||||||
|  |     div.fullwidth img { | ||||||
|  |       margin-top: 0px; | ||||||
|  |       margin-bottom: 0px; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   div.fullwidth div.double h1, h2, h3, h4, h5, h6 { | ||||||
|  |     text-align: center; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   </style> |   </style> | ||||||
|   <body> |   <body> | ||||||
|   <img src="https://raw.githubusercontent.com/DanilaFe/abacus/master/image/logo.png" id="logo"> |   <img src="https://raw.githubusercontent.com/DanilaFe/abacus/master/image/logo.png" id="logo"> | ||||||
| @ -49,5 +102,58 @@ | |||||||
|     <a class="button inverted" href="https://github.com/DanilaFe/abacus/wiki">Wiki</a> |     <a class="button inverted" href="https://github.com/DanilaFe/abacus/wiki">Wiki</a> | ||||||
|   </div> |   </div> | ||||||
|   <img src="http://i.imgur.com/Min70QY.png" title="source: imgur.com" id="image_preview"/> |   <img src="http://i.imgur.com/Min70QY.png" title="source: imgur.com" id="image_preview"/> | ||||||
|  |   <h2>Features</h2> | ||||||
|  |   <div class="fullwidth white"> | ||||||
|  |     <div class="double"> | ||||||
|  |       <img src="https://i.imgur.com/gmGJBBK.png"> | ||||||
|  |     </div> | ||||||
|  |     <div class="double"> | ||||||
|  |       <h2>Precision</h2> | ||||||
|  |       Abacus uses a mathematical tool called Taylor Series to determine values | ||||||
|  |       as accurate as the user desires. Of course, this comes with some | ||||||
|  |       performance issues with larger numbers. However, Abacus has been | ||||||
|  |       tested to generate the value of e correctly to a thousand digits. | ||||||
|  |     </div> | ||||||
|  |   </div> | ||||||
|  |   <div class="fullwidth green"> | ||||||
|  |     <div class="double"> | ||||||
|  |       <h2>Configurable and Customizable</h2> | ||||||
|  |       The very first idea for Abacus was inspired by how difficult it was | ||||||
|  |       to program a TI-84 calculator. Only two languages were available, TI-BASIC | ||||||
|  |       and Assembly, the latter having virtually no documentation. Determined | ||||||
|  |       to be better than a TI-84, Abacus implemented a plugin system that allows | ||||||
|  |       users to easily create and add plugins written in the same programming | ||||||
|  |       language as Abacus itself - Java. These plugins can access the full | ||||||
|  |       power of the language, and implement their own ways of handling numbers, | ||||||
|  |       as well as their own functions and even operators.<br><br> | ||||||
|  |       Besides the ability to add plugins, Abacus also adds some general | ||||||
|  |       options that can be used to make the user's experience more pleasant. | ||||||
|  |       For instance, it allows for a computation limit to be set in order | ||||||
|  |       to prevent excessively long evaluation: 8!!! is, for example, an expression | ||||||
|  |       that even Wolfram Alpha doesn't compute accurately, and will never finish | ||||||
|  |       on Abacus (it's simply too large). The computation limit will allow Abacus | ||||||
|  |       to kill a computation if it takes too long. Support for user-definable | ||||||
|  |       precision is also planned. | ||||||
|  |     </div> | ||||||
|  |     <div class="double"> | ||||||
|  |       <img src="https://i.imgur.com/JzenWPV.png"> | ||||||
|  |     </div> | ||||||
|  |   </div> | ||||||
|  |   <div class="fullwidth white"> | ||||||
|  |     <div class="double"> | ||||||
|  |       <img src="https://i.imgur.com/jY17I3A.png"> | ||||||
|  |     </div> | ||||||
|  |     <div class="double"> | ||||||
|  |       <h2>Built-in Documentation</h2> | ||||||
|  |       Abacus plugins are given a mechanism to register documentation for | ||||||
|  |       the functions that they provide. The Abacus GUI displays these | ||||||
|  |       functions in a searchable list, allowing the user to read the parameters | ||||||
|  |       that have to be supplied to each function, as well as learn about | ||||||
|  |       its return value.<br><br> | ||||||
|  |       The search finds functions not only by their names, but also by relevant | ||||||
|  |       terms mentioned in the function's description, thus allowing related | ||||||
|  |       functions to be displayed together. | ||||||
|  |     </div> | ||||||
|  |   </div> | ||||||
|   </body> |   </body> | ||||||
| </html> | </html> | ||||||
|  | |||||||
| @ -7,7 +7,7 @@ $code-color: #efefef; | |||||||
| $accent-color: #00AFE8; | $accent-color: #00AFE8; | ||||||
| $clear-color: white; | $clear-color: white; | ||||||
| $title-font: "Open Sans"; | $title-font: "Open Sans"; | ||||||
| $text-font: Helvetica; | $text-font: "Raleway"; | ||||||
| $code-font: "Source Code Pro"; | $code-font: "Source Code Pro"; | ||||||
| $max-width: 850px; | $max-width: 850px; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,6 +1,7 @@ | |||||||
| apply plugin: 'application' | apply plugin: 'application' | ||||||
| 
 | 
 | ||||||
| dependencies { | dependencies { | ||||||
|  |     compile 'com.moandjiezana.toml:toml4j:0.7.1' | ||||||
|     compile project(':core') |     compile project(':core') | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -200,7 +200,7 @@ public class AbacusController implements PluginListener { | |||||||
|      */ |      */ | ||||||
|     private final Runnable TIMER_RUNNABLE = () -> { |     private final Runnable TIMER_RUNNABLE = () -> { | ||||||
|         try { |         try { | ||||||
|             Configuration abacusConfig = abacus.getConfiguration(); |             ExtendedConfiguration abacusConfig = (ExtendedConfiguration) abacus.getConfiguration(); | ||||||
|             if (abacusConfig.getComputationDelay() == 0) return; |             if (abacusConfig.getComputationDelay() == 0) return; | ||||||
|             Thread.sleep((long) (abacusConfig.getComputationDelay() * 1000)); |             Thread.sleep((long) (abacusConfig.getComputationDelay() * 1000)); | ||||||
|             performStop(); |             performStop(); | ||||||
| @ -260,12 +260,12 @@ public class AbacusController implements PluginListener { | |||||||
|             if (oldValue.equals(settingsTab)) alertIfApplyNeeded(true); |             if (oldValue.equals(settingsTab)) alertIfApplyNeeded(true); | ||||||
|         }); |         }); | ||||||
| 
 | 
 | ||||||
|         abacus = new Abacus(new Configuration(CONFIG_FILE)); |         abacus = new Abacus(new ExtendedConfiguration(CONFIG_FILE)); | ||||||
|         PluginManager abacusPluginManager = abacus.getPluginManager(); |         PluginManager abacusPluginManager = abacus.getPluginManager(); | ||||||
|         abacusPluginManager.addListener(this); |         abacusPluginManager.addListener(this); | ||||||
|         performScan(); |         performScan(); | ||||||
| 
 | 
 | ||||||
|         computationLimitField.setText(Double.toString(abacus.getConfiguration().getComputationDelay())); |         computationLimitField.setText(Double.toString(((ExtendedConfiguration) abacus.getConfiguration()).getComputationDelay())); | ||||||
|         computationLimitField.textProperty().addListener((observable, oldValue, newValue) -> { |         computationLimitField.textProperty().addListener((observable, oldValue, newValue) -> { | ||||||
|             if (!newValue.matches("(\\d+(\\.\\d*)?)?")) { |             if (!newValue.matches("(\\d+(\\.\\d*)?)?")) { | ||||||
|                 computationLimitField.setText(oldValue); |                 computationLimitField.setText(oldValue); | ||||||
| @ -342,8 +342,8 @@ public class AbacusController implements PluginListener { | |||||||
|             if (!pluginEntry.isEnabled()) disabledPlugins.add(pluginEntry.getClassName()); |             if (!pluginEntry.isEnabled()) disabledPlugins.add(pluginEntry.getClassName()); | ||||||
|         } |         } | ||||||
|         if (computationLimitField.getText().matches("\\d*(\\.\\d+)?") && computationLimitField.getText().length() != 0) |         if (computationLimitField.getText().matches("\\d*(\\.\\d+)?") && computationLimitField.getText().length() != 0) | ||||||
|             configuration.setComputationDelay(Double.parseDouble(computationLimitField.getText())); |             ((ExtendedConfiguration) configuration).setComputationDelay(Double.parseDouble(computationLimitField.getText())); | ||||||
|         configuration.saveTo(CONFIG_FILE); |         ((ExtendedConfiguration) configuration).saveTo(CONFIG_FILE); | ||||||
|         changesMade = false; |         changesMade = false; | ||||||
|         reloadAlertShown = false; |         reloadAlertShown = false; | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -0,0 +1,70 @@ | |||||||
|  | package org.nwapw.abacus.fx | ||||||
|  | 
 | ||||||
|  | import com.moandjiezana.toml.Toml | ||||||
|  | import com.moandjiezana.toml.TomlWriter | ||||||
|  | import org.nwapw.abacus.config.Configuration | ||||||
|  | import java.io.File | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Additional settings for user interface. | ||||||
|  |  * | ||||||
|  |  * ExtendedConfiguration is used to add other settings | ||||||
|  |  * that aren't built into Abacus core, but are necessary | ||||||
|  |  * for the fx module. | ||||||
|  |  * | ||||||
|  |  * @property computationDelay the delay before which the computation stops. | ||||||
|  |  * @param implementation the number implementation, same as [Configuration.numberImplementation] | ||||||
|  |  * @param disabledPlugins the list of plugins that should be disabled, same as [Configuration.disabledPlugins] | ||||||
|  |  */ | ||||||
|  | class ExtendedConfiguration(var computationDelay: Double = 0.0, | ||||||
|  |                      implementation: String = "<default>", | ||||||
|  |                      disabledPlugins: Array<String> = emptyArray()) | ||||||
|  |     : Configuration(implementation, disabledPlugins) { | ||||||
|  | 
 | ||||||
|  |     companion object { | ||||||
|  |         /** | ||||||
|  |          * The default TOML. | ||||||
|  |          */ | ||||||
|  |         val DEFAULT_TOML_STRING = """ | ||||||
|  |             computationDelay=0.0 | ||||||
|  |             implementation="naive" | ||||||
|  |             disabledPlugins=[] | ||||||
|  |             """ | ||||||
|  |         /** | ||||||
|  |          * A reader with the default TOML data. | ||||||
|  |          */ | ||||||
|  |         val DEFAULT_TOML_READER = Toml().read(DEFAULT_TOML_STRING) | ||||||
|  |         /** | ||||||
|  |          * A writer used to writing the configuration to disk. | ||||||
|  |          */ | ||||||
|  |         val DEFAULT_TOML_WRITER = TomlWriter() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Constructs a new configuration from a file on disk. | ||||||
|  |      * @param tomlFile the file from disk to load. | ||||||
|  |      */ | ||||||
|  |     constructor(tomlFile: File) : this() { | ||||||
|  |         copyFrom(Toml(DEFAULT_TOML_READER).read(tomlFile).to(ExtendedConfiguration::class.java)) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Copies data from another configuration into this one. | ||||||
|  |      * @param config the configuration to copy from. | ||||||
|  |      */ | ||||||
|  |     fun copyFrom(config: ExtendedConfiguration) { | ||||||
|  |         computationDelay = config.computationDelay | ||||||
|  |         numberImplementation = config.numberImplementation | ||||||
|  |         disabledPlugins.clear() | ||||||
|  |         disabledPlugins.addAll(config.disabledPlugins) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Saves this configuration to a file. | ||||||
|  |      * @param file the file to save to. | ||||||
|  |      */ | ||||||
|  |     fun saveTo(file: File) { | ||||||
|  |         DEFAULT_TOML_WRITER.write(this, file) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user