maplibre-gl 2.2.0-pre.2 → 2.2.0
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.
- package/README.md +73 -8
- package/build/generate-debug-index-file.ts +19 -0
- package/build/generate-style-code.ts +6 -1
- package/build/generate-style-spec.ts +151 -35
- package/build/rollup_plugins.ts +4 -1
- package/dist/maplibre-gl-csp-worker.js +1 -1
- package/dist/maplibre-gl-csp-worker.js.map +1 -1
- package/dist/maplibre-gl-csp.js +1 -1
- package/dist/maplibre-gl-csp.js.map +1 -1
- package/dist/maplibre-gl-dev.js +1317 -4304
- package/dist/maplibre-gl.css +1 -1
- package/dist/maplibre-gl.d.ts +443 -145
- package/dist/maplibre-gl.js +4 -4
- package/dist/maplibre-gl.js.map +1 -1
- package/package.json +70 -67
- package/src/css/maplibre-gl.css +48 -32
- package/src/data/bucket/fill_bucket.test.ts +1 -0
- package/src/data/bucket/symbol_bucket.test.ts +2 -0
- package/src/data/bucket/symbol_bucket.ts +1 -1
- package/src/data/evaluation_feature.ts +1 -1
- package/src/data/program_configuration.ts +2 -2
- package/src/geo/transform.test.ts +34 -1
- package/src/geo/transform.ts +25 -15
- package/src/gl/vertex_buffer.ts +4 -4
- package/src/index.ts +1 -1
- package/src/render/draw_debug.ts +1 -1
- package/src/render/draw_symbol.test.ts +2 -23
- package/src/render/draw_terrain.ts +1 -1
- package/src/render/image_atlas.ts +1 -0
- package/src/render/image_manager.ts +1 -0
- package/src/render/program/debug_program.ts +1 -1
- package/src/render/render_to_texture.ts +3 -0
- package/src/render/terrain.test.ts +119 -17
- package/src/render/terrain.ts +39 -21
- package/src/shaders/README.md +2 -2
- package/src/shaders/shaders.ts +3 -1
- package/src/source/geojson_worker_source.test.ts +2 -2
- package/src/source/geojson_wrapper.test.ts +1 -1
- package/src/source/image_source.test.ts +8 -8
- package/src/source/image_source.ts +1 -1
- package/src/source/load_tilejson.ts +6 -1
- package/src/source/pixels_to_tile_units.ts +1 -1
- package/src/source/raster_tile_source.test.ts +1 -1
- package/src/source/source_cache.test.ts +12 -12
- package/src/source/source_cache.ts +1 -1
- package/src/source/terrain_source_cache.test.ts +17 -2
- package/src/source/terrain_source_cache.ts +16 -12
- package/src/source/vector_tile_source.test.ts +1 -1
- package/src/source/vector_tile_worker_source.test.ts +1 -1
- package/src/source/video_source.test.ts +2 -2
- package/src/style/light.test.ts +1 -1
- package/src/style/load_sprite.ts +1 -1
- package/src/style/parse_glyph_pbf.ts +1 -1
- package/src/style/style.test.ts +3 -3
- package/src/style/style.ts +2 -2
- package/src/style/style_layer/background_style_layer_properties.g.ts +1 -0
- package/src/style/style_layer/circle_style_layer_properties.g.ts +1 -0
- package/src/style/style_layer/fill_extrusion_style_layer_properties.g.ts +1 -0
- package/src/style/style_layer/fill_style_layer_properties.g.ts +1 -0
- package/src/style/style_layer/heatmap_style_layer_properties.g.ts +1 -0
- package/src/style/style_layer/hillshade_style_layer_properties.g.ts +1 -0
- package/src/style/style_layer/line_style_layer_properties.g.ts +1 -0
- package/src/style/style_layer/raster_style_layer_properties.g.ts +1 -0
- package/src/style/style_layer/symbol_style_layer.ts +16 -1
- package/src/style/style_layer/symbol_style_layer_properties.g.ts +4 -3
- package/src/style-spec/CHANGELOG.md +5 -0
- package/src/style-spec/composite.test.ts +2 -0
- package/src/style-spec/composite.ts +3 -2
- package/src/style-spec/diff.test.ts +3 -3
- package/src/style-spec/empty.ts +3 -2
- package/src/style-spec/expression/compound_expression.ts +0 -4
- package/src/style-spec/expression/definitions/assertion.ts +0 -18
- package/src/style-spec/expression/definitions/at.ts +0 -4
- package/src/style-spec/expression/definitions/case.ts +0 -6
- package/src/style-spec/expression/definitions/coalesce.ts +0 -6
- package/src/style-spec/expression/definitions/coercion.ts +13 -18
- package/src/style-spec/expression/definitions/collator.ts +0 -10
- package/src/style-spec/expression/definitions/comparison.ts +0 -6
- package/src/style-spec/expression/definitions/format.ts +0 -19
- package/src/style-spec/expression/definitions/image.ts +0 -4
- package/src/style-spec/expression/definitions/in.ts +0 -4
- package/src/style-spec/expression/definitions/index_of.ts +0 -8
- package/src/style-spec/expression/definitions/interpolate.ts +1 -25
- package/src/style-spec/expression/definitions/length.ts +0 -6
- package/src/style-spec/expression/definitions/let.ts +0 -9
- package/src/style-spec/expression/definitions/literal.ts +1 -23
- package/src/style-spec/expression/definitions/match.ts +0 -41
- package/src/style-spec/expression/definitions/number_format.ts +0 -17
- package/src/style-spec/expression/definitions/slice.ts +0 -8
- package/src/style-spec/expression/definitions/step.ts +0 -11
- package/src/style-spec/expression/definitions/var.ts +0 -4
- package/src/style-spec/expression/definitions/within.ts +0 -5
- package/src/style-spec/expression/expression.test.ts +1 -1
- package/src/style-spec/expression/expression.ts +3 -3
- package/src/style-spec/expression/index.ts +8 -2
- package/src/style-spec/expression/parsing_context.ts +2 -0
- package/src/style-spec/expression/types/formatted.ts +0 -23
- package/src/style-spec/expression/types/resolved_image.ts +0 -4
- package/src/style-spec/expression/types.ts +6 -1
- package/src/style-spec/expression/values.ts +9 -4
- package/src/style-spec/feature_filter/convert.ts +65 -65
- package/src/style-spec/feature_filter/feature_filter.test.ts +45 -4
- package/src/style-spec/feature_filter/index.ts +2 -1
- package/src/style-spec/function/index.test.ts +117 -1
- package/src/style-spec/function/index.ts +24 -12
- package/src/style-spec/migrate/expressions.ts +2 -2
- package/src/style-spec/migrate/v8.test.ts +2 -0
- package/src/style-spec/migrate/v8.ts +8 -7
- package/src/style-spec/migrate/v9.test.ts +6 -4
- package/src/style-spec/migrate/v9.ts +3 -2
- package/src/style-spec/migrate.test.ts +3 -1
- package/src/style-spec/migrate.ts +5 -4
- package/src/style-spec/package.json +1 -1
- package/src/style-spec/read_style.ts +2 -1
- package/src/style-spec/reference/latest.ts +1 -1
- package/src/style-spec/reference/v8.json +9 -6
- package/src/style-spec/style-spec.test.ts +2 -1
- package/src/style-spec/style-spec.ts +8 -0
- package/src/style-spec/types.g.ts +152 -36
- package/src/style-spec/util/extend.ts +1 -1
- package/src/style-spec/util/interpolate.test.ts +5 -0
- package/src/style-spec/util/interpolate.ts +12 -0
- package/src/style-spec/util/padding.test.ts +27 -0
- package/src/style-spec/util/padding.ts +64 -0
- package/src/style-spec/util/ref_properties.ts +2 -1
- package/src/style-spec/validate/validate.ts +3 -1
- package/src/style-spec/validate/validate_expression.ts +2 -1
- package/src/style-spec/validate/validate_function.ts +2 -2
- package/src/style-spec/validate/validate_glyphs_url.ts +1 -1
- package/src/style-spec/validate/validate_object.ts +2 -2
- package/src/style-spec/validate/validate_padding.test.ts +82 -0
- package/src/style-spec/validate/validate_padding.ts +36 -0
- package/src/style-spec/validate_style.min.ts +4 -3
- package/src/style-spec/validate_style.ts +4 -3
- package/src/symbol/check_max_angle.test.ts +5 -5
- package/src/symbol/collision_feature.test.ts +22 -5
- package/src/symbol/collision_feature.ts +7 -5
- package/src/symbol/collision_index.ts +1 -1
- package/src/symbol/get_anchors.test.ts +4 -4
- package/src/symbol/{mergelines.test.ts → merge_lines.test.ts} +1 -1
- package/src/symbol/{mergelines.ts → merge_lines.ts} +1 -1
- package/src/symbol/projection.ts +1 -1
- package/src/symbol/quads.test.ts +1 -1
- package/src/symbol/shaping.ts +10 -10
- package/src/symbol/symbol_layout.ts +5 -4
- package/src/symbol/symbol_style_layer.test.ts +1 -1
- package/src/symbol/transform_text.ts +3 -3
- package/src/ui/camera.test.ts +11 -11
- package/src/ui/control/geolocate_control.ts +1 -1
- package/src/ui/control/terrain_control.ts +4 -4
- package/src/ui/handler/cooperative_gestures.test.ts +167 -0
- package/src/ui/handler/drag_pan.test.ts +2 -1
- package/src/ui/handler/scroll_zoom.ts +7 -0
- package/src/ui/handler/touch_pan.ts +22 -2
- package/src/ui/handler/touch_zoom_rotate.ts +18 -1
- package/src/ui/handler_manager.ts +2 -2
- package/src/ui/map.test.ts +17 -17
- package/src/ui/map.ts +76 -8
- package/src/ui/map_events.test.ts +33 -32
- package/src/ui/popup.test.ts +2 -2
- package/src/util/ajax.test.ts +5 -5
- package/src/util/ajax.ts +1 -1
- package/src/util/classify_rings.test.ts +27 -27
- package/src/util/find_pole_of_inaccessibility.ts +1 -1
- package/src/util/primitives.ts +4 -4
- package/src/util/resolve_tokens.test.ts +1 -1
- package/src/util/smart_wrap.ts +1 -1
- package/src/util/tile_request_cache.test.ts +5 -5
- package/src/util/util.test.ts +5 -5
|
@@ -3,42 +3,160 @@
|
|
|
3
3
|
|
|
4
4
|
export type ColorSpecification = string;
|
|
5
5
|
|
|
6
|
+
export type PaddingSpecification = number | number[];
|
|
7
|
+
|
|
6
8
|
export type FormattedSpecification = string;
|
|
7
9
|
|
|
8
10
|
export type ResolvedImageSpecification = string;
|
|
9
11
|
|
|
10
12
|
export type PromoteIdSpecification = {[_: string]: string} | string;
|
|
11
13
|
|
|
12
|
-
export type
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
14
|
+
export type ExpressionInputType = string | number | boolean;
|
|
15
|
+
|
|
16
|
+
export type CollatorExpressionSpecification =
|
|
17
|
+
['collator', {
|
|
18
|
+
'case-sensitive'?: boolean | ExpressionSpecification,
|
|
19
|
+
'diacritic-sensitive'?: boolean | ExpressionSpecification,
|
|
20
|
+
locale?: string | ExpressionSpecification}
|
|
21
|
+
]; // collator
|
|
22
|
+
|
|
23
|
+
export type InterpolationSpecification =
|
|
24
|
+
| ['linear']
|
|
25
|
+
| ['exponential', number | ExpressionSpecification]
|
|
26
|
+
| ['cubic-bezier', number | ExpressionSpecification, number | ExpressionSpecification, number | ExpressionSpecification, number | ExpressionSpecification]
|
|
27
|
+
|
|
28
|
+
export type ExpressionSpecification =
|
|
29
|
+
// types
|
|
30
|
+
| ['array', unknown | ExpressionSpecification] // array
|
|
31
|
+
| ['array', ExpressionInputType | ExpressionSpecification, unknown | ExpressionSpecification] // array
|
|
32
|
+
| ['array', ExpressionInputType | ExpressionSpecification, number | ExpressionSpecification, unknown | ExpressionSpecification] // array
|
|
33
|
+
| ['boolean', ...(unknown | ExpressionSpecification)[], unknown | ExpressionSpecification] // boolean
|
|
34
|
+
| CollatorExpressionSpecification
|
|
35
|
+
| ['format', ...(string | ['image', ExpressionSpecification] | ExpressionSpecification | {'font-scale'?: number | ExpressionSpecification, 'text-font'?: string[] | ExpressionSpecification, 'text-color': ColorSpecification | ExpressionSpecification})[]] // string
|
|
36
|
+
| ['image', unknown | ExpressionSpecification] // image
|
|
37
|
+
| ['literal', unknown]
|
|
38
|
+
| ['number', unknown | ExpressionSpecification, ...(unknown | ExpressionSpecification)[]] // number
|
|
39
|
+
| ['number-format', number | ExpressionSpecification, {'locale'?: string | ExpressionSpecification, 'currency'?: string | ExpressionSpecification, 'min-fraction-digits'?: number | ExpressionSpecification, 'max-fraction-digits'?: number | ExpressionSpecification}] // string
|
|
40
|
+
| ['object', unknown | ExpressionSpecification, ...(unknown | ExpressionSpecification)[]] // object
|
|
41
|
+
| ['string', unknown | ExpressionSpecification, ...(unknown | ExpressionSpecification)[]] // string
|
|
42
|
+
| ['to-boolean', unknown | ExpressionSpecification] // boolean
|
|
43
|
+
| ['to-color', unknown | ExpressionSpecification, ...(unknown | ExpressionSpecification)[]] // color
|
|
44
|
+
| ['to-number', unknown | ExpressionSpecification, ...(unknown | ExpressionSpecification)[]] // number
|
|
45
|
+
| ['to-string', unknown | ExpressionSpecification] // string
|
|
46
|
+
// feature data
|
|
47
|
+
| ['accumulated']
|
|
48
|
+
| ['feature-state', string]
|
|
49
|
+
| ['geometry-type'] // string
|
|
50
|
+
| ['id']
|
|
51
|
+
| ['line-progress'] // number
|
|
52
|
+
| ['properties'] // object
|
|
53
|
+
// lookup
|
|
54
|
+
| ['at', number | ExpressionSpecification, ExpressionSpecification]
|
|
55
|
+
| ['get', string | ExpressionSpecification, (Record<string, unknown> | ExpressionSpecification)?]
|
|
56
|
+
| ['has', string | ExpressionSpecification, (Record<string, unknown> | ExpressionSpecification)?]
|
|
57
|
+
| ['in', ExpressionInputType | ExpressionSpecification, ExpressionInputType | ExpressionSpecification]
|
|
58
|
+
| ['index-of', ExpressionInputType | ExpressionSpecification, ExpressionInputType | ExpressionSpecification] // number
|
|
59
|
+
| ['length', string | ExpressionSpecification]
|
|
60
|
+
| ['slice', string | ExpressionSpecification, number | ExpressionSpecification]
|
|
22
61
|
// Decision
|
|
23
|
-
| ['!',
|
|
24
|
-
| ['!=',
|
|
25
|
-
| ['<',
|
|
26
|
-
| ['<=',
|
|
27
|
-
| ['==',
|
|
28
|
-
| ['>',
|
|
29
|
-
| ['>=',
|
|
30
|
-
| [
|
|
31
|
-
| [
|
|
32
|
-
| [
|
|
33
|
-
|
|
34
|
-
| [
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
62
|
+
| ['!', boolean | ExpressionSpecification] // boolean
|
|
63
|
+
| ['!=', ExpressionInputType | ExpressionSpecification, ExpressionInputType | ExpressionSpecification, CollatorExpressionSpecification?] // boolean
|
|
64
|
+
| ['<', ExpressionInputType | ExpressionSpecification, ExpressionInputType | ExpressionSpecification, CollatorExpressionSpecification?] // boolean
|
|
65
|
+
| ['<=', ExpressionInputType | ExpressionSpecification, ExpressionInputType | ExpressionSpecification, CollatorExpressionSpecification?] // boolean
|
|
66
|
+
| ['==', ExpressionInputType | ExpressionSpecification, ExpressionInputType | ExpressionSpecification, CollatorExpressionSpecification?] // boolean
|
|
67
|
+
| ['>', ExpressionInputType | ExpressionSpecification, ExpressionInputType | ExpressionSpecification, CollatorExpressionSpecification?] // boolean
|
|
68
|
+
| ['>=', ExpressionInputType | ExpressionSpecification, ExpressionInputType | ExpressionSpecification, CollatorExpressionSpecification?] // boolean
|
|
69
|
+
| ['all', ...(boolean | ExpressionSpecification)[]] // boolean
|
|
70
|
+
| ['any', ...(boolean | ExpressionSpecification)[]] // boolean
|
|
71
|
+
| ['case', boolean | ExpressionSpecification, ExpressionInputType | ExpressionSpecification,
|
|
72
|
+
...(boolean | ExpressionInputType | ExpressionSpecification)[], ExpressionInputType | ExpressionSpecification]
|
|
73
|
+
| ['coalesce', ExpressionInputType | ExpressionSpecification, ExpressionInputType | ExpressionSpecification,
|
|
74
|
+
...(ExpressionInputType | ExpressionSpecification)[]]
|
|
75
|
+
| ['match', ExpressionInputType | ExpressionSpecification,
|
|
76
|
+
ExpressionInputType | ExpressionInputType[], ExpressionInputType | ExpressionSpecification,
|
|
77
|
+
...(ExpressionInputType | ExpressionInputType[] | ExpressionSpecification)[], // repeated as above
|
|
78
|
+
ExpressionInputType]
|
|
79
|
+
| ['within', unknown | ExpressionSpecification]
|
|
80
|
+
// Ramps, scales, curves
|
|
81
|
+
| ['interpolate', InterpolationSpecification,
|
|
82
|
+
number | ExpressionSpecification, number | ExpressionSpecification, ExpressionInputType | ExpressionSpecification,
|
|
83
|
+
...(number | ExpressionInputType | ExpressionSpecification)[]]
|
|
84
|
+
| ['interpolate-hcl', InterpolationSpecification,
|
|
85
|
+
number | ExpressionSpecification, number | ExpressionSpecification, ExpressionInputType | ExpressionSpecification,
|
|
86
|
+
...(number | ColorSpecification | ExpressionSpecification)[]]
|
|
87
|
+
| ['interpolate-lab', InterpolationSpecification,
|
|
88
|
+
number | ExpressionSpecification, number | ExpressionSpecification, ExpressionInputType | ExpressionSpecification,
|
|
89
|
+
...(number | ColorSpecification | ExpressionSpecification)[]]
|
|
90
|
+
| ['step', number | ExpressionSpecification, number | ExpressionSpecification, ExpressionInputType | ExpressionSpecification,
|
|
91
|
+
...(number | ExpressionInputType | ExpressionSpecification)[]]
|
|
92
|
+
// Variable binding
|
|
93
|
+
| ['let', string, ExpressionInputType | ExpressionSpecification, ...(string | ExpressionInputType | ExpressionSpecification)[]]
|
|
94
|
+
| ['var', string]
|
|
95
|
+
// String
|
|
96
|
+
| ['concat', ExpressionInputType | ExpressionSpecification, ExpressionInputType | ExpressionSpecification,
|
|
97
|
+
...(ExpressionInputType | ExpressionSpecification)[]] // string
|
|
98
|
+
| ['downcase', string | ExpressionSpecification] // string
|
|
99
|
+
| ['is-supported-script', string | ExpressionSpecification] // boolean
|
|
100
|
+
| ['resolved-locale', CollatorExpressionSpecification] // string
|
|
101
|
+
| ['upcase', string | ExpressionSpecification] // string
|
|
102
|
+
// Color
|
|
103
|
+
| ['rgb', number | ExpressionSpecification, number | ExpressionSpecification, number | ExpressionSpecification] // color
|
|
104
|
+
| ['rgba', number | ExpressionSpecification, number | ExpressionSpecification, number | ExpressionSpecification, number | ExpressionSpecification]
|
|
105
|
+
| ['to-rgba', ColorSpecification | ExpressionSpecification]
|
|
106
|
+
// Math
|
|
107
|
+
| ['-', number | ExpressionSpecification, (number | ExpressionSpecification)?] // number
|
|
108
|
+
| ['*', number | ExpressionSpecification, number | ExpressionSpecification, ...(number | ExpressionSpecification)[]] // number
|
|
109
|
+
| ['/', number | ExpressionSpecification, number | ExpressionSpecification] // number
|
|
110
|
+
| ['%', number | ExpressionSpecification, number | ExpressionSpecification] // number
|
|
111
|
+
| ['^', number | ExpressionSpecification, number | ExpressionSpecification] // number
|
|
112
|
+
| ['+', number | ExpressionSpecification, number | ExpressionSpecification, ...(number | ExpressionSpecification)[]] // number
|
|
113
|
+
| ['abs', number | ExpressionSpecification] // number
|
|
114
|
+
| ['acos', number | ExpressionSpecification] // number
|
|
115
|
+
| ['asin', number | ExpressionSpecification] // number
|
|
116
|
+
| ['atan', number | ExpressionSpecification] // number
|
|
117
|
+
| ['ceil', number | ExpressionSpecification] // number
|
|
118
|
+
| ['cos', number | ExpressionSpecification] // number
|
|
119
|
+
| ['distance', Record<string, unknown> | ExpressionSpecification] // number
|
|
120
|
+
| ['ExpressionSpecification'] // number
|
|
121
|
+
| ['floor', number | ExpressionSpecification] // number
|
|
122
|
+
| ['ln', number | ExpressionSpecification] // number
|
|
123
|
+
| ['ln2'] // number
|
|
124
|
+
| ['log10', number | ExpressionSpecification] // number
|
|
125
|
+
| ['log2', number | ExpressionSpecification] // number
|
|
126
|
+
| ['max', number | ExpressionSpecification, ...(number | ExpressionSpecification)[]] // number
|
|
127
|
+
| ['min', number | ExpressionSpecification, ...(number | ExpressionSpecification)[]] // number
|
|
128
|
+
| ['pi'] // number
|
|
129
|
+
| ['round', number | ExpressionSpecification] // number
|
|
130
|
+
| ['sin', number | ExpressionSpecification] // number
|
|
131
|
+
| ['sqrt', number | ExpressionSpecification] // number
|
|
132
|
+
| ['tan', number | ExpressionSpecification] // number
|
|
133
|
+
// Zoom
|
|
134
|
+
| ['zoom'] // number
|
|
135
|
+
// Heatmap
|
|
136
|
+
| ['heatmap-density'] // number
|
|
137
|
+
|
|
138
|
+
export type ExpressionFilterSpecification = boolean | ExpressionSpecification
|
|
139
|
+
|
|
140
|
+
export type LegacyFilterSpecification =
|
|
141
|
+
// Existential
|
|
142
|
+
| ['has', string]
|
|
143
|
+
| ['!has', string]
|
|
144
|
+
// Comparison
|
|
145
|
+
| ['==', string, string | number | boolean]
|
|
146
|
+
| ['!=', string, string | number | boolean]
|
|
147
|
+
| ['>', string, string | number | boolean]
|
|
148
|
+
| ['>=', string, string | number | boolean]
|
|
149
|
+
| ['<', string, string | number | boolean]
|
|
150
|
+
| ['<=', string, string | number | boolean]
|
|
151
|
+
// Set membership
|
|
152
|
+
| ['in', string, ...(string | number | boolean)[]]
|
|
153
|
+
| ['!in', string, ...(string | number | boolean)[]]
|
|
154
|
+
// Combining
|
|
155
|
+
| ['all', ...LegacyFilterSpecification[]]
|
|
156
|
+
| ['any', ...LegacyFilterSpecification[]]
|
|
157
|
+
| ['none', ...LegacyFilterSpecification[]]
|
|
158
|
+
|
|
159
|
+
export type FilterSpecification = ExpressionFilterSpecification | LegacyFilterSpecification
|
|
42
160
|
|
|
43
161
|
export type TransitionSpecification = {
|
|
44
162
|
duration?: number,
|
|
@@ -62,19 +180,17 @@ export type CompositeFunctionSpecification<T> =
|
|
|
62
180
|
| { type: 'interval', stops: Array<[{zoom: number, value: number}, T]>, property: string, default?: T }
|
|
63
181
|
| { type: 'categorical', stops: Array<[{zoom: number, value: string | number | boolean}, T]>, property: string, default?: T };
|
|
64
182
|
|
|
65
|
-
export type ExpressionSpecificationArray = Array<unknown>;
|
|
66
|
-
|
|
67
183
|
export type PropertyValueSpecification<T> =
|
|
68
184
|
T
|
|
69
185
|
| CameraFunctionSpecification<T>
|
|
70
|
-
|
|
|
186
|
+
| ExpressionSpecification;
|
|
71
187
|
|
|
72
188
|
export type DataDrivenPropertyValueSpecification<T> =
|
|
73
189
|
T
|
|
74
190
|
| CameraFunctionSpecification<T>
|
|
75
191
|
| SourceFunctionSpecification<T>
|
|
76
192
|
| CompositeFunctionSpecification<T>
|
|
77
|
-
|
|
|
193
|
+
| ExpressionSpecification;
|
|
78
194
|
|
|
79
195
|
export type StyleSpecification = {
|
|
80
196
|
"version": 8,
|
|
@@ -235,7 +351,7 @@ export type LineLayerSpecification = {
|
|
|
235
351
|
"line-blur"?: DataDrivenPropertyValueSpecification<number>,
|
|
236
352
|
"line-dasharray"?: PropertyValueSpecification<Array<number>>,
|
|
237
353
|
"line-pattern"?: DataDrivenPropertyValueSpecification<ResolvedImageSpecification>,
|
|
238
|
-
"line-gradient"?:
|
|
354
|
+
"line-gradient"?: ExpressionSpecification
|
|
239
355
|
}
|
|
240
356
|
};
|
|
241
357
|
|
|
@@ -264,7 +380,7 @@ export type SymbolLayerSpecification = {
|
|
|
264
380
|
"icon-text-fit-padding"?: PropertyValueSpecification<[number, number, number, number]>,
|
|
265
381
|
"icon-image"?: DataDrivenPropertyValueSpecification<ResolvedImageSpecification>,
|
|
266
382
|
"icon-rotate"?: DataDrivenPropertyValueSpecification<number>,
|
|
267
|
-
"icon-padding"?:
|
|
383
|
+
"icon-padding"?: DataDrivenPropertyValueSpecification<PaddingSpecification>,
|
|
268
384
|
"icon-keep-upright"?: PropertyValueSpecification<boolean>,
|
|
269
385
|
"icon-offset"?: DataDrivenPropertyValueSpecification<[number, number]>,
|
|
270
386
|
"icon-anchor"?: DataDrivenPropertyValueSpecification<"center" | "left" | "right" | "top" | "bottom" | "top-left" | "top-right" | "bottom-left" | "bottom-right">,
|
|
@@ -356,7 +472,7 @@ export type HeatmapLayerSpecification = {
|
|
|
356
472
|
"heatmap-radius"?: DataDrivenPropertyValueSpecification<number>,
|
|
357
473
|
"heatmap-weight"?: DataDrivenPropertyValueSpecification<number>,
|
|
358
474
|
"heatmap-intensity"?: PropertyValueSpecification<number>,
|
|
359
|
-
"heatmap-color"?:
|
|
475
|
+
"heatmap-color"?: ExpressionSpecification,
|
|
360
476
|
"heatmap-opacity"?: PropertyValueSpecification<number>
|
|
361
477
|
}
|
|
362
478
|
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as interpolate from './interpolate';
|
|
2
2
|
import Color from './color';
|
|
3
|
+
import Padding from './padding';
|
|
3
4
|
|
|
4
5
|
describe('interpolate', () => {
|
|
5
6
|
test('interpolate.number', () => {
|
|
@@ -13,4 +14,8 @@ describe('interpolate', () => {
|
|
|
13
14
|
test('interpolate.array', () => {
|
|
14
15
|
expect(interpolate.array([0, 0, 0, 0], [1, 2, 3, 4], 0.5)).toEqual([0.5, 1, 3 / 2, 2]);
|
|
15
16
|
});
|
|
17
|
+
|
|
18
|
+
test('interpolate.padding', () => {
|
|
19
|
+
expect(interpolate.padding(new Padding([0, 0, 0, 0]), new Padding([1, 2, 3, 4]), 0.5)).toEqual(new Padding([0.5, 1, 3 / 2, 2]));
|
|
20
|
+
});
|
|
16
21
|
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import Color from './color';
|
|
2
|
+
import Padding from './padding';
|
|
2
3
|
|
|
3
4
|
export function number(a: number, b: number, t: number) {
|
|
4
5
|
return (a * (1 - t)) + (b * t);
|
|
@@ -18,3 +19,14 @@ export function array(from: Array<number>, to: Array<number>, t: number): Array<
|
|
|
18
19
|
return number(d, to[i], t);
|
|
19
20
|
});
|
|
20
21
|
}
|
|
22
|
+
|
|
23
|
+
export function padding(from: Padding, to: Padding, t: number): Padding {
|
|
24
|
+
const fromVal = from.values;
|
|
25
|
+
const toVal = to.values;
|
|
26
|
+
return new Padding([
|
|
27
|
+
number(fromVal[0], toVal[0], t),
|
|
28
|
+
number(fromVal[1], toVal[1], t),
|
|
29
|
+
number(fromVal[2], toVal[2], t),
|
|
30
|
+
number(fromVal[3], toVal[3], t)
|
|
31
|
+
]);
|
|
32
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import Padding from './padding';
|
|
2
|
+
|
|
3
|
+
describe('Padding', () => {
|
|
4
|
+
test('Padding.parse', () => {
|
|
5
|
+
expect(Padding.parse()).toBeUndefined();
|
|
6
|
+
expect(Padding.parse(null)).toBeUndefined();
|
|
7
|
+
expect(Padding.parse(undefined)).toBeUndefined();
|
|
8
|
+
expect(Padding.parse('Dennis' as any)).toBeUndefined();
|
|
9
|
+
expect(Padding.parse('3' as any)).toBeUndefined();
|
|
10
|
+
expect(Padding.parse([])).toBeUndefined();
|
|
11
|
+
expect(Padding.parse([3, '4'] as any)).toBeUndefined();
|
|
12
|
+
expect(Padding.parse(5)).toEqual(new Padding([5, 5, 5, 5]));
|
|
13
|
+
expect(Padding.parse([1])).toEqual(new Padding([1, 1, 1, 1]));
|
|
14
|
+
expect(Padding.parse([1, 2])).toEqual(new Padding([1, 2, 1, 2]));
|
|
15
|
+
expect(Padding.parse([1, 2, 3])).toEqual(new Padding([1, 2, 3, 2]));
|
|
16
|
+
expect(Padding.parse([1, 2, 3, 4])).toEqual(new Padding([1, 2, 3, 4]));
|
|
17
|
+
expect(Padding.parse([1, 2, 3, 4, 5])).toBeUndefined();
|
|
18
|
+
|
|
19
|
+
const passThru = new Padding([1, 2, 3, 4]);
|
|
20
|
+
expect(Padding.parse(passThru)).toBe(passThru);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
test('Padding#toString', () => {
|
|
24
|
+
const padding = new Padding([1, 2, 3, 4]);
|
|
25
|
+
expect(padding.toString()).toBe('[1,2,3,4]');
|
|
26
|
+
});
|
|
27
|
+
});
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A set of four numbers representing padding around a box. Create instances from
|
|
3
|
+
* bare arrays or numeric values using the static method `Padding.parse`.
|
|
4
|
+
* @private
|
|
5
|
+
*/
|
|
6
|
+
class Padding {
|
|
7
|
+
/** Padding values are in CSS order: top, right, bottom, left */
|
|
8
|
+
values: [number, number, number, number];
|
|
9
|
+
|
|
10
|
+
constructor(values: [number, number, number, number]) {
|
|
11
|
+
this.values = values.slice() as [number, number, number, number];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Numeric padding values
|
|
16
|
+
* @returns A `Padding` instance, or `undefined` if the input is not a valid padding value.
|
|
17
|
+
*/
|
|
18
|
+
static parse(input?: number | number[] | Padding | null): Padding | void {
|
|
19
|
+
if (input instanceof Padding) {
|
|
20
|
+
return input;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Backwards compatibility: bare number is treated the same as array with single value.
|
|
24
|
+
// Padding applies to all four sides.
|
|
25
|
+
if (typeof input === 'number') {
|
|
26
|
+
return new Padding([input, input, input, input]);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (!Array.isArray(input)) {
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (input.length < 1 || input.length > 4) {
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
for (const val of input) {
|
|
38
|
+
if (typeof val !== 'number') {
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Expand shortcut properties into explicit 4-sided values
|
|
44
|
+
switch (input.length) {
|
|
45
|
+
case 1:
|
|
46
|
+
input = [input[0], input[0], input[0], input[0]];
|
|
47
|
+
break;
|
|
48
|
+
case 2:
|
|
49
|
+
input = [input[0], input[1], input[0], input[1]];
|
|
50
|
+
break;
|
|
51
|
+
case 3:
|
|
52
|
+
input = [input[0], input[1], input[2], input[1]];
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return new Padding(input as [number, number, number, number]);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
toString(): string {
|
|
60
|
+
return JSON.stringify(this.values);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export default Padding;
|
|
@@ -21,6 +21,7 @@ import validateTerrain from './validate_terrain';
|
|
|
21
21
|
import validateString from './validate_string';
|
|
22
22
|
import validateFormatted from './validate_formatted';
|
|
23
23
|
import validateImage from './validate_image';
|
|
24
|
+
import validatePadding from './validate_padding';
|
|
24
25
|
|
|
25
26
|
const VALIDATORS = {
|
|
26
27
|
'*'() {
|
|
@@ -41,7 +42,8 @@ const VALIDATORS = {
|
|
|
41
42
|
'terrain': validateTerrain,
|
|
42
43
|
'string': validateString,
|
|
43
44
|
'formatted': validateFormatted,
|
|
44
|
-
'resolvedImage': validateImage
|
|
45
|
+
'resolvedImage': validateImage,
|
|
46
|
+
'padding': validatePadding
|
|
45
47
|
};
|
|
46
48
|
|
|
47
49
|
// Main recursive validation function. Tracks:
|
|
@@ -3,6 +3,7 @@ import ValidationError from '../error/validation_error';
|
|
|
3
3
|
import {createExpression, createPropertyExpression} from '../expression';
|
|
4
4
|
import {deepUnbundle} from '../util/unbundle_jsonlint';
|
|
5
5
|
import {isStateConstant, isGlobalPropertyConstant, isFeatureConstant} from '../expression/is_constant';
|
|
6
|
+
import {Expression} from '../expression/expression';
|
|
6
7
|
|
|
7
8
|
export default function validateExpression(options: any): Array<ValidationError> {
|
|
8
9
|
const expression = (options.expressionContext === 'property' ? createPropertyExpression : createExpression)(deepUnbundle(options.value), options.valueSpec);
|
|
@@ -12,7 +13,7 @@ export default function validateExpression(options: any): Array<ValidationError>
|
|
|
12
13
|
});
|
|
13
14
|
}
|
|
14
15
|
|
|
15
|
-
const expressionObj = (expression.value as any).expression || (expression.value as any)._styleExpression.expression;
|
|
16
|
+
const expressionObj: Expression = (expression.value as any).expression || (expression.value as any)._styleExpression.expression;
|
|
16
17
|
|
|
17
18
|
if (options.expressionContext === 'property' && (options.propertyKey === 'text-font') &&
|
|
18
19
|
!expressionObj.outputDefined()) {
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
supportsInterpolation
|
|
14
14
|
} from '../util/properties';
|
|
15
15
|
|
|
16
|
-
export default function validateFunction(options) {
|
|
16
|
+
export default function validateFunction(options): Array<ValidationError> {
|
|
17
17
|
const functionValueSpec = options.valueSpec;
|
|
18
18
|
const functionType = unbundle(options.value.type);
|
|
19
19
|
let stopKeyType;
|
|
@@ -195,7 +195,7 @@ export default function validateFunction(options) {
|
|
|
195
195
|
return [];
|
|
196
196
|
}
|
|
197
197
|
|
|
198
|
-
function validateFunctionDefault(options) {
|
|
198
|
+
function validateFunctionDefault(options): Array<ValidationError> {
|
|
199
199
|
return validate({
|
|
200
200
|
key: options.key,
|
|
201
201
|
value: options.value,
|
|
@@ -3,14 +3,14 @@ import ValidationError from '../error/validation_error';
|
|
|
3
3
|
import getType from '../util/get_type';
|
|
4
4
|
import validateSpec from './validate';
|
|
5
5
|
|
|
6
|
-
export default function validateObject(options) {
|
|
6
|
+
export default function validateObject(options): Array<ValidationError> {
|
|
7
7
|
const key = options.key;
|
|
8
8
|
const object = options.value;
|
|
9
9
|
const elementSpecs = options.valueSpec || {};
|
|
10
10
|
const elementValidators = options.objectElementValidators || {};
|
|
11
11
|
const style = options.style;
|
|
12
12
|
const styleSpec = options.styleSpec;
|
|
13
|
-
let errors = []
|
|
13
|
+
let errors = [] as Array<ValidationError>;
|
|
14
14
|
|
|
15
15
|
const type = getType(object);
|
|
16
16
|
if (type !== 'object') {
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import validatePadding from './validate_padding';
|
|
2
|
+
|
|
3
|
+
describe('Validate Padding', () => {
|
|
4
|
+
test('Should return error if type is not number or array', () => {
|
|
5
|
+
let errors = validatePadding({key: 'padding', value: '3'});
|
|
6
|
+
expect(errors).toHaveLength(1);
|
|
7
|
+
expect(errors[0].message).toBe('padding: number expected, string found');
|
|
8
|
+
|
|
9
|
+
errors = validatePadding({key: 'padding', value: true});
|
|
10
|
+
expect(errors).toHaveLength(1);
|
|
11
|
+
expect(errors[0].message).toBe('padding: number expected, boolean found');
|
|
12
|
+
|
|
13
|
+
errors = validatePadding({key: 'padding', value: null});
|
|
14
|
+
expect(errors).toHaveLength(1);
|
|
15
|
+
expect(errors[0].message).toBe('padding: number expected, null found');
|
|
16
|
+
|
|
17
|
+
errors = validatePadding({key: 'padding', value: {x: 1, y: 1}});
|
|
18
|
+
expect(errors).toHaveLength(1);
|
|
19
|
+
expect(errors[0].message).toBe('padding: number expected, object found');
|
|
20
|
+
|
|
21
|
+
errors = validatePadding({key: 'padding', value: NaN});
|
|
22
|
+
expect(errors).toHaveLength(1);
|
|
23
|
+
expect(errors[0].message).toBe('padding: number expected, NaN found');
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
test('Should pass if type is number', () => {
|
|
27
|
+
const errors = validatePadding({key: 'padding', value: 1});
|
|
28
|
+
expect(errors).toHaveLength(0);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test('Should return error if array length is invalid', () => {
|
|
32
|
+
let errors = validatePadding({key: 'padding', value: []});
|
|
33
|
+
expect(errors).toHaveLength(1);
|
|
34
|
+
expect(errors[0].message).toBe('padding: padding requires 1 to 4 values; 0 values found');
|
|
35
|
+
|
|
36
|
+
errors = validatePadding({key: 'padding', value: [1, 1, 1, 1, 1]});
|
|
37
|
+
expect(errors).toHaveLength(1);
|
|
38
|
+
expect(errors[0].message).toBe('padding: padding requires 1 to 4 values; 5 values found');
|
|
39
|
+
|
|
40
|
+
errors = validatePadding({key: 'padding', value: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]});
|
|
41
|
+
expect(errors).toHaveLength(1);
|
|
42
|
+
expect(errors[0].message).toBe('padding: padding requires 1 to 4 values; 12 values found');
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test('Should return error if array contains non-numeric values', () => {
|
|
46
|
+
let errors = validatePadding({key: 'padding', value: ['1']});
|
|
47
|
+
expect(errors).toHaveLength(1);
|
|
48
|
+
expect(errors[0].message).toBe('padding[0]: number expected, string found');
|
|
49
|
+
|
|
50
|
+
errors = validatePadding({key: 'padding', value: [true]});
|
|
51
|
+
expect(errors).toHaveLength(1);
|
|
52
|
+
expect(errors[0].message).toBe('padding[0]: number expected, boolean found');
|
|
53
|
+
|
|
54
|
+
errors = validatePadding({key: 'padding', value: [NaN]});
|
|
55
|
+
expect(errors).toHaveLength(1);
|
|
56
|
+
expect(errors[0].message).toBe('padding[0]: number expected, NaN found');
|
|
57
|
+
|
|
58
|
+
errors = validatePadding({key: 'padding', value: [{x: 1}]});
|
|
59
|
+
expect(errors).toHaveLength(1);
|
|
60
|
+
expect(errors[0].message).toBe('padding[0]: number expected, object found');
|
|
61
|
+
|
|
62
|
+
errors = validatePadding({key: 'padding', value: [1, 3, false]});
|
|
63
|
+
expect(errors).toHaveLength(1);
|
|
64
|
+
expect(errors[0].message).toBe('padding[2]: number expected, boolean found');
|
|
65
|
+
|
|
66
|
+
errors = validatePadding({key: 'padding', value: ['1', 3, false]});
|
|
67
|
+
expect(errors).toHaveLength(2);
|
|
68
|
+
expect(errors[0].message).toBe('padding[0]: number expected, string found');
|
|
69
|
+
expect(errors[1].message).toBe('padding[2]: number expected, boolean found');
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
test('Should pass if type is numeric array', () => {
|
|
73
|
+
let errors = validatePadding({key: 'padding', value: [1]});
|
|
74
|
+
expect(errors).toHaveLength(0);
|
|
75
|
+
errors = validatePadding({key: 'padding', value: [1, 1]});
|
|
76
|
+
expect(errors).toHaveLength(0);
|
|
77
|
+
errors = validatePadding({key: 'padding', value: [1, 1, 1]});
|
|
78
|
+
expect(errors).toHaveLength(0);
|
|
79
|
+
errors = validatePadding({key: 'padding', value: [1, 1, 1, 1]});
|
|
80
|
+
expect(errors).toHaveLength(0);
|
|
81
|
+
});
|
|
82
|
+
});
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import ValidationError from '../error/validation_error';
|
|
2
|
+
import getType from '../util/get_type';
|
|
3
|
+
import validate from './validate';
|
|
4
|
+
import validateNumber from './validate_number';
|
|
5
|
+
|
|
6
|
+
export default function validatePadding(options) {
|
|
7
|
+
const key = options.key;
|
|
8
|
+
const value = options.value;
|
|
9
|
+
const type = getType(value);
|
|
10
|
+
|
|
11
|
+
if (type === 'array') {
|
|
12
|
+
if (value.length < 1 || value.length > 4) {
|
|
13
|
+
return [new ValidationError(key, value, `padding requires 1 to 4 values; ${value.length} values found`)];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const arrayElementSpec = {
|
|
17
|
+
type: 'number'
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
let errors = [];
|
|
21
|
+
for (let i = 0; i < value.length; i++) {
|
|
22
|
+
errors = errors.concat(validate({
|
|
23
|
+
key: `${key}[${i}]`,
|
|
24
|
+
value: value[i],
|
|
25
|
+
valueSpec: arrayElementSpec
|
|
26
|
+
}));
|
|
27
|
+
}
|
|
28
|
+
return errors;
|
|
29
|
+
} else {
|
|
30
|
+
return validateNumber({
|
|
31
|
+
key,
|
|
32
|
+
value,
|
|
33
|
+
valueSpec: {}
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -11,6 +11,7 @@ import validateLayer from './validate/validate_layer';
|
|
|
11
11
|
import validateFilter from './validate/validate_filter';
|
|
12
12
|
import validatePaintProperty from './validate/validate_paint_property';
|
|
13
13
|
import validateLayoutProperty from './validate/validate_layout_property';
|
|
14
|
+
import type {StyleSpecification} from './types.g';
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* Validate a MapLibre GL style against the style specification. This entrypoint,
|
|
@@ -27,7 +28,7 @@ import validateLayoutProperty from './validate/validate_layout_property';
|
|
|
27
28
|
* var validate = require('maplibre-gl-style-spec/lib/validate_style.min');
|
|
28
29
|
* var errors = validate(style);
|
|
29
30
|
*/
|
|
30
|
-
function validateStyleMin(style, styleSpec = latestStyleSpec) {
|
|
31
|
+
function validateStyleMin(style: StyleSpecification, styleSpec = latestStyleSpec) {
|
|
31
32
|
|
|
32
33
|
let errors = [];
|
|
33
34
|
|
|
@@ -45,10 +46,10 @@ function validateStyleMin(style, styleSpec = latestStyleSpec) {
|
|
|
45
46
|
}
|
|
46
47
|
}));
|
|
47
48
|
|
|
48
|
-
if (style
|
|
49
|
+
if (style['constants']) {
|
|
49
50
|
errors = errors.concat(validateConstants({
|
|
50
51
|
key: 'constants',
|
|
51
|
-
value: style
|
|
52
|
+
value: style['constants'],
|
|
52
53
|
style,
|
|
53
54
|
styleSpec
|
|
54
55
|
}));
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
|
|
2
2
|
import validateStyleMin from './validate_style.min';
|
|
3
|
-
import {v8} from './style-spec';
|
|
3
|
+
import {v8, ValidationError} from './style-spec';
|
|
4
4
|
import readStyle from './read_style';
|
|
5
|
+
import type {StyleSpecification} from './types.g';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Validate a Mapbox GL style against the style specification.
|
|
8
9
|
*
|
|
9
10
|
* @private
|
|
10
11
|
* @alias validate
|
|
11
|
-
* @param {
|
|
12
|
+
* @param {StyleSpecification|string|Buffer} style The style to be validated. If a `String`
|
|
12
13
|
* or `Buffer` is provided, the returned errors will contain line numbers.
|
|
13
14
|
* @param {Object} [styleSpec] The style specification to validate against.
|
|
14
15
|
* If omitted, the spec version is inferred from the stylesheet.
|
|
@@ -19,7 +20,7 @@ import readStyle from './read_style';
|
|
|
19
20
|
* var errors = validate(style);
|
|
20
21
|
*/
|
|
21
22
|
|
|
22
|
-
export default function validateStyle(style, styleSpec = v8) {
|
|
23
|
+
export default function validateStyle(style: StyleSpecification | string | Buffer, styleSpec = v8): Array<ValidationError> {
|
|
23
24
|
let s = style;
|
|
24
25
|
|
|
25
26
|
try {
|