dcc 0.2.0 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (176) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +19 -0
  3. data/.github/workflows/release.yml +28 -0
  4. data/.gitignore +4 -0
  5. data/.rubocop_todo.yml +560 -10
  6. data/CHANGELOG.adoc +34 -1
  7. data/CONTRIBUTING.adoc +8 -1
  8. data/Gemfile +5 -7
  9. data/README.adoc +162 -7
  10. data/dcc.gemspec +9 -2
  11. data/docs/schema-versions.adoc +20 -7
  12. data/examples/build_minimal_dcc.rb +0 -0
  13. data/examples/convert_all_formats.rb +2 -1
  14. data/examples/parse_and_inspect.rb +0 -0
  15. data/examples/quantity_math_demo.rb +7 -7
  16. data/examples/validate_full.rb +1 -1
  17. data/lib/dcc/base/calibration_laboratory.rb +2 -1
  18. data/lib/dcc/base/condition.rb +5 -2
  19. data/lib/dcc/base/core_data.rb +8 -3
  20. data/lib/dcc/base/formula.rb +3 -3
  21. data/lib/dcc/base/identification.rb +6 -3
  22. data/lib/dcc/base/mathml.rb +33 -0
  23. data/lib/dcc/base/quantity.rb +2 -1
  24. data/lib/dcc/base/resp_person.rb +4 -2
  25. data/lib/dcc/base/text.rb +1 -1
  26. data/lib/dcc/base.rb +2 -1
  27. data/lib/dcc/builder/dsl.rb +1 -1
  28. data/lib/dcc/builder/session.rb +16 -14
  29. data/lib/dcc/builder.rb +3 -3
  30. data/lib/dcc/cli/cli.rb +152 -26
  31. data/lib/dcc/cli/formatters.rb +35 -7
  32. data/lib/dcc/cli.rb +1 -1
  33. data/lib/dcc/context_configuration.rb +2 -1
  34. data/lib/dcc/context_options.rb +4 -2
  35. data/lib/dcc/convert/csv.rb +27 -9
  36. data/lib/dcc/convert/html.rb +26 -110
  37. data/lib/dcc/convert/json.rb +10 -7
  38. data/lib/dcc/convert/liquid_filters.rb +58 -0
  39. data/lib/dcc/convert/result.rb +1 -1
  40. data/lib/dcc/convert/templates/report.liquid +250 -0
  41. data/lib/dcc/convert/yaml.rb +1 -1
  42. data/lib/dcc/convert.rb +1 -0
  43. data/lib/dcc/diff/change.rb +1 -1
  44. data/lib/dcc/diff/result.rb +8 -4
  45. data/lib/dcc/diff.rb +43 -11
  46. data/lib/dcc/error.rb +7 -0
  47. data/lib/dcc/extract/file.rb +3 -4
  48. data/lib/dcc/extract/formula/ast.rb +137 -0
  49. data/lib/dcc/extract/formula/evaluator.rb +357 -0
  50. data/lib/dcc/extract/formula/parser.rb +305 -0
  51. data/lib/dcc/extract/formula/quantity.rb +89 -0
  52. data/lib/dcc/extract/formula.rb +110 -0
  53. data/lib/dcc/extract/ring.rb +1 -1
  54. data/lib/dcc/extract.rb +1 -1
  55. data/lib/dcc/i18n/text_lookup.rb +8 -4
  56. data/lib/dcc/i18n.rb +1 -1
  57. data/lib/dcc/inspect/report.rb +51 -14
  58. data/lib/dcc/inspect.rb +1 -1
  59. data/lib/dcc/migrate/route.rb +44 -0
  60. data/lib/dcc/migrate/v2_to_v3.rb +445 -0
  61. data/lib/dcc/migrate.rb +130 -26
  62. data/lib/dcc/plugin/base.rb +64 -0
  63. data/lib/dcc/plugin/registry.rb +7 -2
  64. data/lib/dcc/plugin.rb +6 -2
  65. data/lib/dcc/quantity_format/formatter.rb +16 -10
  66. data/lib/dcc/quantity_format.rb +1 -1
  67. data/lib/dcc/quantity_math/complex.rb +252 -0
  68. data/lib/dcc/quantity_math/matrix.rb +217 -0
  69. data/lib/dcc/quantity_math/quantity.rb +1 -1
  70. data/lib/dcc/quantity_math/real.rb +6 -6
  71. data/lib/dcc/quantity_math.rb +31 -3
  72. data/lib/dcc/schema/version.rb +2 -2
  73. data/lib/dcc/server/app.html +282 -0
  74. data/lib/dcc/server/app.rb +171 -87
  75. data/lib/dcc/server/demo_cert.xml +244 -0
  76. data/lib/dcc/server/storage/entry.rb +1 -1
  77. data/lib/dcc/server/storage/memory.rb +3 -2
  78. data/lib/dcc/server/storage.rb +1 -1
  79. data/lib/dcc/server.rb +1 -1
  80. data/lib/dcc/si/base/complex.rb +1 -1
  81. data/lib/dcc/si/base/complex_list_xml_list.rb +1 -1
  82. data/lib/dcc/si/base/constant.rb +1 -1
  83. data/lib/dcc/si/base/coverage_interval.rb +36 -0
  84. data/lib/dcc/si/base/coverage_interval_mu.rb +1 -1
  85. data/lib/dcc/si/base/expanded_mu.rb +1 -1
  86. data/lib/dcc/si/base/expanded_unc.rb +34 -0
  87. data/lib/dcc/si/base/expanded_unc_xml_list.rb +3 -2
  88. data/lib/dcc/si/base/hybrid.rb +3 -2
  89. data/lib/dcc/si/base/measurement_uncertainty_univariate.rb +1 -1
  90. data/lib/dcc/si/base/real.rb +13 -3
  91. data/lib/dcc/si/base/real_list_xml_list.rb +5 -3
  92. data/lib/dcc/si/base/si_list.rb +3 -2
  93. data/lib/dcc/si/base/standard_mu.rb +1 -1
  94. data/lib/dcc/si/base.rb +5 -2
  95. data/lib/dcc/si/v1/coverage_interval.rb +8 -0
  96. data/lib/dcc/si/v1/expanded_unc.rb +1 -16
  97. data/lib/dcc/si/v1/measurement_uncertainty_univariate.rb +2 -1
  98. data/lib/dcc/si/v1.rb +5 -2
  99. data/lib/dcc/si/v2/coverage_interval.rb +8 -0
  100. data/lib/dcc/si/v2/coverage_interval_mu_xml_list.rb +4 -2
  101. data/lib/dcc/si/v2/expanded_mu_xml_list.rb +2 -1
  102. data/lib/dcc/si/v2/expanded_unc.rb +8 -0
  103. data/lib/dcc/si/v2/measurement_uncertainty_univariate.rb +2 -1
  104. data/lib/dcc/si/v2.rb +8 -3
  105. data/lib/dcc/signature/result.rb +2 -2
  106. data/lib/dcc/signature/signer.rb +31 -18
  107. data/lib/dcc/signature/verifier.rb +23 -21
  108. data/lib/dcc/signature.rb +1 -1
  109. data/lib/dcc/streaming/reader.rb +246 -0
  110. data/lib/dcc/streaming.rb +79 -0
  111. data/lib/dcc/transform/result.rb +1 -1
  112. data/lib/dcc/transform/xslt.rb +22 -12
  113. data/lib/dcc/transform.rb +5 -4
  114. data/lib/dcc/type/base64_binary.rb +5 -3
  115. data/lib/dcc/type/decimal_xml_list.rb +99 -13
  116. data/lib/dcc/type/iso_country_code.rb +3 -2
  117. data/lib/dcc/type/iso_language_code.rb +3 -2
  118. data/lib/dcc/type/schema_version.rb +3 -2
  119. data/lib/dcc/type/si_unit.rb +3 -2
  120. data/lib/dcc/type_guards.rb +3 -3
  121. data/lib/dcc/v2/calibration_laboratory.rb +2 -1
  122. data/lib/dcc/v2/condition.rb +22 -1
  123. data/lib/dcc/v2/configuration.rb +1 -1
  124. data/lib/dcc/v2/digital_calibration_certificate.rb +2 -1
  125. data/lib/dcc/v2/identification.rb +14 -1
  126. data/lib/dcc/v2/mathml.rb +8 -0
  127. data/lib/dcc/v2/measurement_meta_data_list.rb +2 -1
  128. data/lib/dcc/v2/quantity.rb +4 -2
  129. data/lib/dcc/v2.rb +4 -2
  130. data/lib/dcc/v3/calibration_laboratory.rb +2 -1
  131. data/lib/dcc/v3/configuration.rb +1 -1
  132. data/lib/dcc/v3/digital_calibration_certificate.rb +2 -1
  133. data/lib/dcc/v3/mathml.rb +8 -0
  134. data/lib/dcc/v3/measurement_meta_data_list.rb +2 -1
  135. data/lib/dcc/v3/quantity.rb +4 -2
  136. data/lib/dcc/v3.rb +12 -2
  137. data/lib/dcc/validate/business_rules.rb +23 -9
  138. data/lib/dcc/validate/issue.rb +2 -1
  139. data/lib/dcc/validate/result.rb +6 -4
  140. data/lib/dcc/validate/schematron/profile.rb +73 -18
  141. data/lib/dcc/validate/schematron/rule.rb +13 -3
  142. data/lib/dcc/validate/schematron/rules/administrative_data_completeness.rb +11 -4
  143. data/lib/dcc/validate/schematron/rules/base.rb +1 -2
  144. data/lib/dcc/validate/schematron/rules/date_range_check.rb +11 -5
  145. data/lib/dcc/validate/schematron/rules/id_refid_linking.rb +0 -3
  146. data/lib/dcc/validate/schematron/rules/influence_conditions_placement.rb +22 -12
  147. data/lib/dcc/validate/schematron/rules/iso_code_validation.rb +31 -14
  148. data/lib/dcc/validate/schematron/rules/language_code_dedup.rb +12 -5
  149. data/lib/dcc/validate/schematron/rules/non_si_declaration.rb +7 -4
  150. data/lib/dcc/validate/schematron/rules/release_format_check.rb +7 -4
  151. data/lib/dcc/validate/schematron/rules/schema_version_check.rb +13 -9
  152. data/lib/dcc/validate/schematron/rules/uncertainty_consistency.rb +39 -10
  153. data/lib/dcc/validate/schematron/rules/unit_format_check.rb +2 -3
  154. data/lib/dcc/validate/schematron/rules/used_methods_placement.rb +15 -10
  155. data/lib/dcc/validate/schematron/rules/used_software_placement.rb +15 -10
  156. data/lib/dcc/validate/schematron/rules/xml_list_spacing.rb +4 -3
  157. data/lib/dcc/validate/schematron/rules.rb +28 -14
  158. data/lib/dcc/validate/schematron.rb +1 -1
  159. data/lib/dcc/validate/xsd.rb +9 -3
  160. data/lib/dcc/validate.rb +1 -1
  161. data/lib/dcc/version.rb +1 -1
  162. data/lib/dcc/versioned_parser.rb +1 -1
  163. data/lib/dcc.rb +68 -10
  164. data/sample_dcc.xml +140 -0
  165. data/web/index.html +12 -0
  166. data/web/package-lock.json +1599 -0
  167. data/web/package.json +22 -0
  168. data/web/src/App.vue +349 -0
  169. data/web/src/lib/builder.ts +171 -0
  170. data/web/src/lib/dcc.ts +338 -0
  171. data/web/src/lib/units.json +5581 -0
  172. data/web/src/main.ts +5 -0
  173. data/web/src/style.css +27 -0
  174. data/web/tsconfig.json +15 -0
  175. data/web/vite.config.ts +14 -0
  176. metadata +148 -9
data/lib/dcc.rb CHANGED
@@ -41,6 +41,7 @@ module Dcc
41
41
  autoload :QuantityFormat, "dcc/quantity_format"
42
42
  autoload :QuantityMath, "dcc/quantity_math"
43
43
  autoload :Signature, "dcc/signature"
44
+ autoload :Streaming, "dcc/streaming"
44
45
  autoload :Transform, "dcc/transform"
45
46
  autoload :Validate, "dcc/validate"
46
47
  autoload :Server, "dcc/server"
@@ -74,16 +75,63 @@ module Dcc
74
75
  # Build a new DCC programmatically using the builder DSL.
75
76
  # @yield [Dcc::Builder::Session] builder session
76
77
  # @param version [Integer, nil] major DCC version (default: 3).
77
- def build(version: 3, &block)
78
- Builder.call(version: version, &block)
78
+ def build(version: 3, &)
79
+ Builder.call(version: version, &)
79
80
  end
80
81
 
81
- # Migrate a parsed DCC object from one schema version to another.
82
- # @param dcc [Dcc::V2::DigitalCalibrationCertificate, Dcc::V3::DigitalCalibrationCertificate]
82
+ # Load plugin gems by name.
83
+ #
84
+ # A gem name maps to its entry file the usual way: "dcc-audit" loads
85
+ # "dcc/audit". A slash-separated path is accepted unchanged.
86
+ #
87
+ # @param names [Array<String, Symbol>] plugin gem names.
88
+ # @raise [Dcc::PluginError] if a plugin's entry file cannot be loaded.
89
+ # @return [Array<String>] the entry-file path for each name given.
90
+ # A plugin already loaded is left alone and its path still returned.
91
+ #
92
+ # A plugin whose own `require` fails raises from inside a file we did
93
+ # find. Reporting that as a missing entry file points the author at the
94
+ # wrong problem, so only the entry path's own LoadError is wrapped.
95
+ def load_plugins(*names)
96
+ names.flatten.map do |name|
97
+ path = plugin_path(name)
98
+ require path
99
+ path
100
+ rescue ::LoadError => e
101
+ raise unless e.path == path
102
+
103
+ raise PluginError, "could not load plugin #{name}: tried " \
104
+ "require #{path.inspect} (#{e.message})"
105
+ end
106
+ end
107
+
108
+ # "dcc-audit" is a gem name and maps to "dcc/audit". Anything already
109
+ # carrying a slash is a require path and is left alone, hyphens included.
110
+ def plugin_path(name)
111
+ text = name.to_s
112
+ text.include?("/") ? text : text.tr("-", "/")
113
+ end
114
+ private :plugin_path
115
+
116
+ # Migrate a DCC from one schema version to another.
117
+ #
118
+ # Prefer passing the source XML. A parsed model has to be serialized back
119
+ # to XML before the transform runs, so anything the model could not
120
+ # round-trip is already gone and cannot be migrated or reported.
121
+ #
122
+ # @param input [String, IO, Dcc::V2::DigitalCalibrationCertificate,
123
+ # Dcc::V3::DigitalCalibrationCertificate] DCC source XML, or a parsed DCC.
83
124
  # @param from [String] source version, e.g. "2.3.0".
84
125
  # @param to [String] target version, e.g. "3.3.0".
85
- def migrate(dcc, from:, to:)
86
- Migrate.call(dcc, from: from, to: to)
126
+ # @param on_loss [#call, nil] callable receiving each message describing a
127
+ # construct the migration changed or discarded (a String per loss).
128
+ # When given, the messages go to the callable and nothing is sent to
129
+ # `Kernel.warn`; when nil (the default), each loss report is warned to
130
+ # stderr as before.
131
+ # @return [Dcc::V2::DigitalCalibrationCertificate,
132
+ # Dcc::V3::DigitalCalibrationCertificate] always a parsed DCC.
133
+ def migrate(input, from:, to:, on_loss: nil)
134
+ Migrate.call(input, from: from, to: to, on_loss: on_loss)
87
135
  end
88
136
 
89
137
  # Return the parser module for the given major version.
@@ -94,7 +142,8 @@ module Dcc
94
142
  when 2 then V2
95
143
  when 3 then V3
96
144
  else
97
- raise UnknownVersionError, "Unsupported DCC version: #{version.inspect} (expected 2 or 3)"
145
+ raise UnknownVersionError,
146
+ "Unsupported DCC version: #{version.inspect} (expected 2 or 3)"
98
147
  end
99
148
  end
100
149
 
@@ -103,9 +152,18 @@ module Dcc
103
152
  # @return [Integer] 2 or 3.
104
153
  def detect_version(input)
105
154
  str = read_input(input)
106
- match = str.match(/schemaVersion\s*=\s*["'](\d+)\./)
107
- major = match && match[1] ? match[1].to_i : 3
108
- major == 2 ? 2 : 3
155
+ match = str.match(/schemaVersion\s*=\s*["'](\d+\.)/)
156
+ major_version_from(match && match[1])
157
+ end
158
+
159
+ # Map a `schemaVersion` attribute value to its major DCC version.
160
+ # Only a leading run of digits followed by a dot counts; anything else
161
+ # (missing, malformed, or an unsupported major) resolves to 3.
162
+ # @param schema_version [String, nil] e.g. "2.3.0".
163
+ # @return [Integer] 2 or 3.
164
+ def major_version_from(schema_version)
165
+ match = schema_version.to_s.match(/\A(\d+)\./)
166
+ match && match[1].to_i == 2 ? 2 : 3
109
167
  end
110
168
 
111
169
  # Read an input that may be a String or an IO-like object.
data/sample_dcc.xml ADDED
@@ -0,0 +1,140 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <dcc:digitalCalibrationCertificate
3
+ xmlns:dcc="https://ptb.de/dcc"
4
+ xmlns:si="https://ptb.de/si"
5
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
6
+ xsi:schemaLocation="https://ptb.de/dcc https://ptb.de/dcc/v3.3.0/dcc.xsd"
7
+ schemaVersion="3.3.0">
8
+
9
+ <dcc:administrativeData>
10
+ <dcc:dccSoftware>
11
+ <dcc:software>
12
+ <dcc:name><dcc:content lang="en">DCC Validator Builder</dcc:content></dcc:name>
13
+ <dcc:release>0.1.0</dcc:release>
14
+ </dcc:software>
15
+ </dcc:dccSoftware>
16
+
17
+ <dcc:coreData>
18
+ <dcc:countryCodeISO3166_1>DE</dcc:countryCodeISO3166_1>
19
+ <dcc:usedLangCodeISO639_1>en</dcc:usedLangCodeISO639_1>
20
+ <dcc:usedLangCodeISO639_1>de</dcc:usedLangCodeISO639_1>
21
+ <dcc:mandatoryLangCodeISO639_1>en</dcc:mandatoryLangCodeISO639_1>
22
+ <dcc:uniqueIdentifier>PTB-A0123-2026</dcc:uniqueIdentifier>
23
+ <dcc:beginPerformanceDate>2026-07-23</dcc:beginPerformanceDate>
24
+ <dcc:endPerformanceDate>2026-07-23</dcc:endPerformanceDate>
25
+ </dcc:coreData>
26
+
27
+ <dcc:items>
28
+ <dcc:item>
29
+ <dcc:name><dcc:content lang="en">Precision Resistance Decade 10 kΩ</dcc:content></dcc:name>
30
+ <dcc:manufacturer><dcc:name><dcc:content lang="en">Burster Präzisionsmesstechnik GmbH</dcc:content></dcc:name></dcc:manufacturer>
31
+ <dcc:model>BURSTER 1424</dcc:model>
32
+ </dcc:item>
33
+ </dcc:items>
34
+
35
+ <dcc:calibrationLaboratory>
36
+ <dcc:calibrationLaboratoryCode>DE1</dcc:calibrationLaboratoryCode>
37
+ <dcc:contact>
38
+ <dcc:name><dcc:content lang="en">Physikalisch-Technische Bundesanstalt</dcc:content></dcc:name>
39
+ <dcc:eMail>calibration@ptb.de</dcc:eMail>
40
+ </dcc:contact>
41
+ </dcc:calibrationLaboratory>
42
+
43
+ <dcc:respPersons>
44
+ <dcc:respPerson>
45
+ <dcc:person>
46
+ <dcc:name><dcc:content lang="en">Dr. Klaus-Dieter Sommer</dcc:content></dcc:name>
47
+ <dcc:eMail>k.sommer@ptb.de</dcc:eMail>
48
+ </dcc:person>
49
+ <dcc:mainSigner>true</dcc:mainSigner>
50
+ </dcc:respPerson>
51
+ </dcc:respPersons>
52
+
53
+ <dcc:customer>
54
+ <dcc:name><dcc:content lang="en">Burster Präzisionsmesstechnik GmbH</dcc:content></dcc:name>
55
+ </dcc:customer>
56
+ </dcc:administrativeData>
57
+
58
+ <dcc:measurementResults>
59
+ <dcc:measurementResult>
60
+ <dcc:name><dcc:content lang="en">Calibration Results</dcc:content></dcc:name>
61
+ <dcc:results>
62
+ <dcc:result>
63
+ <dcc:name><dcc:content lang="en">Resistance calibration at 1 kΩ</dcc:content></dcc:name>
64
+ <dcc:data>
65
+ <dcc:quantity>
66
+ <dcc:name><dcc:content lang="en">Actual resistance</dcc:content></dcc:name>
67
+ <si:real>
68
+ <si:value>999.982</si:value>
69
+ <si:unit>\ohm</si:unit>
70
+ <si:expandedMU>
71
+ <si:valueExpandedMU>0.012</si:valueExpandedMU>
72
+ <si:coverageFactor>2</si:coverageFactor>
73
+ <si:coverageProbability>0.95</si:coverageProbability>
74
+ </si:expandedMU>
75
+ </si:real>
76
+ </dcc:quantity>
77
+ <dcc:quantity>
78
+ <dcc:name><dcc:content lang="en">Temperature coefficient</dcc:content></dcc:name>
79
+ <si:real>
80
+ <si:value>5.2e-6</si:value>
81
+ <si:unit>\per\kelvin</si:unit>
82
+ <si:expandedMU>
83
+ <si:valueExpandedMU>0.3e-6</si:valueExpandedMU>
84
+ <si:coverageFactor>2</si:coverageFactor>
85
+ <si:coverageProbability>0.95</si:coverageProbability>
86
+ </si:expandedMU>
87
+ </si:real>
88
+ </dcc:quantity>
89
+ </dcc:data>
90
+ </dcc:result>
91
+ <dcc:result>
92
+ <dcc:name><dcc:content lang="en">Resistance calibration at 10 kΩ</dcc:content></dcc:name>
93
+ <dcc:data>
94
+ <dcc:quantity>
95
+ <dcc:name><dcc:content lang="en">Actual resistance</dcc:content></dcc:name>
96
+ <si:real>
97
+ <si:value>10000.04</si:value>
98
+ <si:unit>\kilo\ohm</si:unit>
99
+ <si:expandedMU>
100
+ <si:valueExpandedMU>0.03</si:valueExpandedMU>
101
+ <si:coverageFactor>2</si:coverageFactor>
102
+ <si:coverageProbability>0.95</si:coverageProbability>
103
+ </si:expandedMU>
104
+ </si:real>
105
+ </dcc:quantity>
106
+ </dcc:data>
107
+ </dcc:result>
108
+ <dcc:result>
109
+ <dcc:name><dcc:content lang="en">Environmental conditions</dcc:content></dcc:name>
110
+ <dcc:data>
111
+ <dcc:quantity>
112
+ <dcc:name><dcc:content lang="en">Ambient temperature</dcc:content></dcc:name>
113
+ <si:real>
114
+ <si:value>23.0</si:value>
115
+ <si:unit>\degreeCelsius</si:unit>
116
+ <si:expandedMU>
117
+ <si:valueExpandedMU>0.2</si:valueExpandedMU>
118
+ <si:coverageFactor>2</si:coverageFactor>
119
+ <si:coverageProbability>0.95</si:coverageProbability>
120
+ </si:expandedMU>
121
+ </si:real>
122
+ </dcc:quantity>
123
+ <dcc:quantity>
124
+ <dcc:name><dcc:content lang="en">Relative humidity</dcc:content></dcc:name>
125
+ <si:real>
126
+ <si:value>48</si:value>
127
+ <si:unit>\percent</si:unit>
128
+ <si:expandedMU>
129
+ <si:valueExpandedMU>2</si:valueExpandedMU>
130
+ <si:coverageFactor>2</si:coverageFactor>
131
+ <si:coverageProbability>0.95</si:coverageProbability>
132
+ </si:expandedMU>
133
+ </si:real>
134
+ </dcc:quantity>
135
+ </dcc:data>
136
+ </dcc:result>
137
+ </dcc:results>
138
+ </dcc:measurementResult>
139
+ </dcc:measurementResults>
140
+ </dcc:digitalCalibrationCertificate>
data/web/index.html ADDED
@@ -0,0 +1,12 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width,initial-scale=1.0" />
6
+ <title>DCC Validator</title>
7
+ </head>
8
+ <body>
9
+ <div id="app"></div>
10
+ <script type="module" src="/src/main.ts"></script>
11
+ </body>
12
+ </html>