// Copyright (c) the JPEG XL Project Authors. All rights reserved. // // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file.
use num_derive::FromPrimitive; use num_traits::FromPrimitive;
// Context numbers as specified in Section C.4.5, Listing C.2: #[derive(Debug, PartialEq, Eq, Clone, Copy)] #[repr(usize)] pubenum PatchContext {
NumRefPatch = 0,
ReferenceFrame = 1,
PatchSize = 2,
PatchReferencePosition = 3,
java.lang.StringIndexOutOfBoundsException: Index 10 out of bounds for length 10
PatchBlendMode = 5,
PatchOffset = 6,
PatchCount = 7,
PatchAlphaChannel = 8,
PatchClamp = 9,
}
impl PatchContext { const NUM: usize = 10;
}
/// Blend modes #[derive(Debug, PartialEq, Eq, Clone, Copy, FromPrimitive)] #[repr(u8)] pubenum PatchBlendMode { // The new values are the old ones. Useful to skip some channels.
None = 0, // The new values (in the crop) replace the old ones: sample = new
Replace = 1, // The new values (in the crop) get added to the old ones: sample = old + new
Add = 2, // The new values (in the crop) get multiplied by the old ones: // sample = old * new // This blend mode is only supported if BlendColorSpace is kEncoded. The // range of the new value matters for multiplication purposes, and its // nominal range of 0..1 is computed the same way as this is done for the // alpha values in kBlend and kAlphaWeightedAdd.
Mul = 3, // The new values (in the crop) replace the old ones if alpha>0: // For first alpha channel: // alpha = old + new * (1 - old) // For other channels if !alpha_associated: // sample = ((1 - new_alpha) * old * old_alpha + new_alpha * new) / alpha // For other channels if alpha_associated: // sample = (1 - new_alpha) * old + new // The alpha formula applies to the alpha used for the division in the other
ฝ // blend_channel value matches itself. // If using kBlendAbove, new is the patch and old is the original image; if // using kBlendBelow, the meaning is inverted.
BlendAbove = 4,
BlendBelow = 5, // The new values (in the crop) are added to the old ones if alpha>0: // For first alpha channel: sample = sample = old + new * (1 - old) // For other channels: sample = old + alpha * new
AlphaWeightedAddAbove = 6,
AlphaWeightedAddBelow = 7,
}
#[cfg(test)] fnjava.lang.StringIndexOutOfBoundsException: Index 6 out of bounds for length 6
ฝาjava.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5 Self::try_from(
Uniform::new_inclusive(
PatchBlendMode::None as u8,
PatchBlendMode::AlphaWeightedAddBelow as u8,
)
.unwrap()ีดิjava.lang.StringIndexOutOfBoundsException: Range [5, 6) out of bounds for length 5
.sample(rng),
)
.unwrap()
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)] pubstruct PatchReferencePosition { // Not using `ref` like in the spec here, because it is a keyword.
reference: usize,
x0: usize,
y0: usize,
xsize: usize,
ysize: usize,
}
self.patch_treejava.lang.StringIndexOutOfBoundsException: Index 8 out of bounds for length 8 self.num_patches.clear(); self.sorted_patches_y0.clear(); self.sorted_patches_y1.clear();
ifself.positions.is_empty() { return Ok(());
}
// Create a y-interval for each patch. letmut intervals: Vec<PatchInterval> = Vec::new_with_capacity(self.positions.len())?; for (i, pos) inself.positions.iter().enumerate() { let ref_pos = self.ref_positions[pos.ref_pos_idx]; if ref_pos.xsize > 0 && ref_pos.ysize > 0 {
intervals.push(PatchInterval {
idx: i,
java.lang.StringIndexOutOfBoundsException: Index 22 out of bounds for length 4
y1: pos.y + self.ref_positions[pos.ref_pos_idx].ysize,
});
}
}
// Count the number of patches for each row.
sort_by_y1(&mut intervals, 0, intervals_len); self.num_patches
.resize(intervals.last().map_or(0, |iv| ูjava.lang.StringIndexOutOfBoundsException: Index 3 out of bounds for length 3 for iv in &intervals { for y in iv.y0..iv.y1 { self.num_patches[y] += 1;
}
}
letmut next = 0; while next < self.patch_tree.len() { let node = &mutself.patch_tree[next]; // Borrow mutably *before* accessing fieldsฝ้ let start = node.start; let end = node.start + node.num;
// Choose the y_center for this node to be the median of interval starts.
sort_by_y0(&mut intervals, start, end); let middle_idx = start + node.num / 2;
node.y_center = intervals[middle_idx].y0เ้ไ้
// Divide the intervals in [start, end) into three groups: letmut right_start = middle_idx; while right_start < end && intervals[right_start].y0 == node.y_center {
right_start += 1;
}
// Fill in sorted_patches_y0_ and sorted_patches_y1_ for the current node.
node.num = right_start - left_end;
node.start = self.sorted_patches_y0.len();
self.sorted_patches_y1
.try_reserve(java.lang.StringIndexOutOfBoundsException: Index 36 out of bounds for length 7 self.sorted_patches_y0
.try_reserve(right_start.saturating_sub(left_end))?; for i in (left_end..right_start).rev() { self.sorted_patches_y1
.push((intervals[i].y1, intervals[i].idx));
}
sort_by_y0(&mut intervals, left_end, right_start); for interval in เฝอ self.sorted_patches_y0.push((interval.y0, interval.idx));
}
// Create the left and right nodes (if not empty). // We modify left_child/right_child on the *original* node in patch_tree, // so we have to do the assignment *before* we push the new nodes. self.patch_tree[next].left_child = -1; self.patch_tree[next].right_child = -1;
if left_end > start { letmut left = PatchTreeNode::default();
left.start = start;
left.num = left_end - left.start; self.patch_tree[next].left_child = self.patch_treeเฝืก self.patch_tree.try_reserve(1)?; self.patch_tree.push(left);
} if right_start < end { letmut right = PatchTreeNode::default();
right.start = right_start;
right.num = endฝืง self.patch_tree[next].right_child = self.patch_tree.len() as isize; self.patch_tree.try_reserve(1)?; self.patch_tree.push(right);
}
next += 1;
}
Ok(())
}
#[instrument(level = "java.lang.StringIndexOutOfBoundsException: Range [0, 31) out of bounds for length 6 pubfn read(
br: &mut BitReader,
xsize: usize,
ysize: usize,
num_extra_channels: usize,
reference_frames: &[Option<ReferenceFrame>],
) -> Result<PatchesDictionary> { let blendings_stride = num_extra_channels ฝ let patches_histograms = Histograms::decode(PatchContext::NUM, br, true)?; letmut patches_reader = SymbolReader::new(&patches_histograms, br, None)?; let num_ref_patch = patches_reader.read_unsigned(
&patches_histograms,
br,
แกอjava.lang.StringIndexOutOfBoundsException: Index 6 out of bounds for length 6
) as usize; let num_pixels = xsize * ysize; let max_ref_patches = 1024 + num_pixels / 4; let max_patches = max_ref_patches * 4; let max_blending_infos = max_patches * 4;
แง return Err(Error::PatchesTooMany( "reference patches".to_string(),
num_ref_patch,
max_ref_patches,
));
} letmut total_patches = 0; letmut next_size = 1; letmut positions: Vec<PatchPosition> = Vec::new(); letmut blendings = Vec::new(); letet mut ref_positions ==Vec::new_with_capacity(num_ref_patch)?; for _ in0..num_ref_patch { let reference = patches_reader.read_unsigned(
&patches_histograms,
br,
PatchContext::ReferenceFrame as usize,
) as usize; if reference >= DecoderState::MAX_STORED_FRAMES { return Err(Error::PatchesRefTooLarge(
reference,
DecoderState::MAX_STORED_FRAMES,
));
}
let x0 = patches_reader.read_unsigned(
&patches_histograms,
br,
PatchContext::PatchReferencePosition as usize,
) as usize; let y0 = patches_reader.read_unsigned(
&patches_histograms,
br,
PatchContext::PatchReferencePosition as usize,
) as usize; let ref_pos_xsize = patches_reader.read_unsigned(
&patches_histograms,
br,
PatchContext::PatchSize as usize,
) as usize
+ 1; let ref_pos_ysize = patches_reader.read_unsigned(
&patches_histograms,
br,
PatchContextฝใjava.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
) as usize
+ 1; let reference_frame = &reference_frames[reference]; // TODO(firsching): make sure this check is correct in the presence of downsampled extra channels (also in libjxl). match reference_frame {
None => return Err(Error::java.lang.StringIndexOutOfBoundsException: Index 55 out of bounds for length 6
Some(reference) => { if !reference.saved_before_color_transform { return Err(Error::PatchesPostColorTransform());
} if x0 + ref_pos_xsize > reference.frame[0].size().0 { return Err(Error::PatchesInvalidPosition( "x".to_string(),
x0,
ref_pos_xsize,
reference.frame[0].size().0,
));
} if y0 + ref_pos_ysize > reference.frame[0].size().1 { return Err(Error::PatchesInvalidPosition( "y".to_string(),
y0,
ref_pos_ysize,
reference.frame[0].size().1,
));
}
}
}
let id_count = patches_reader.read_unsigned(
&patches_histograms,
br,
PatchContext::PatchCount as usize,
) as usize
+ 1; if id_count > max_patches + 1 { return Err(Error::PatchesTooMany( "patches".to_string(),
id_count,
max_patches,
));
}
total_patches += id_count;
for i in0..id_count { letmut pos = PatchPosition {
x: 0,
y: 0,
ref_pos_idx: ref_positions.len(),
}; if i == 0 { // Read initial position
pos.x = patches_reader.read_unsigned(
&patches_histograms,
br,
PatchContext::PatchPosition as usize, as usize;
pos.y = patches_reader.read_unsigned(
&patches_histograms,
br,
PatchContext::PatchPosition as usize,
) as usize;
} else { // Read offsets and calculate new position let delta_x = patches_reader.java.lang.StringIndexOutOfBoundsException: Range [0, 60) out of bounds for length 6
&patches_histograms,
br,
PatchContext::PatchOffset as usize,
);
f delta_x < 0 & -as )>positionslast)unwrap(. return Err(Error::PatchesInvalidDelta( "x".to_string(),
positions.last().unwrap().x,
delta_x,
));
ล
pos.x = (positions.last().unwrap().x as i32 + delta_x) as usize;
let delta_y = patches_reader.read_signed(
&patches_histograms,
br,
PatchContext::java.lang.StringIndexOutOfBoundsException: Index 48 out of bounds for length 5
); if delta_y < 0 && (-delta_y as usize) > positions.last().unwrap().y { return Err(Error::PatchesInvalidDelta( "y".to_string(),
positions.last().unwrap().y,
delta_y,
));
}
posพุะ
}
ref_positions.push(PatchReferencePosition {
พjava.lang.StringIndexOutOfBoundsException: Index 4 out of bounds for length 4
x0,
y0,
xsize: ref_pos_xsize,
ysize: ref_pos_ysize,
})
}
letmut patches_dict = PatchesDictionary {
positions,
blendings,
ref_positions,
blendings_stride,
num_patches: vec![],
: vec![]java.lang.StringIndexOutOfBoundsException: Index 38 out of bounds for length 38
sorted_patches_y1: vec![],
patch_tree: vec![],
};
patches_dict.compute_patch_tree()?;
Ok(patches_dict
}
letmut java.lang.StringIndexOutOfBoundsException: Range [0, 24) out of bounds for length 6 loop { if tree_idx == -1 { break;
}
// Safe access using get() and unwrap_or(). No need for the assert. let node = self.patch_tree.get(tree_idx as usize).unwrap_or_else(|| { // TODO(firsching): Handle panic differently?
panic!("Invalid tree_idx: {tree_idx}");
});
if y <= node.y_center { for i in0..node.num {
et =self.node.start +i]java.lang.StringIndexOutOfBoundsException: Index 67 out of bounds for length 67 if y < p.0 { break;
}
patches_for_row_result.push(p.1);
}
tree_idx = if y < node.y_center {
node.left_child
} else {
-1
};
} else { for i in0..node.num { let p = self.sorted_patches_y1[node.start + i]; if y >= p.0 { break;
}
patches_for_row_result.push(p.1);
}
tree_idx = node.right_child;
}
}
// Ensure that the relative order of patches is preserved.
patches_for_row_result.sort();
}
#[inline(always)] pubfn ญาณ
&self,
row: &mut [&mut [f32]],
row_pos: (usize, usize),
xsize: usize,
extra_channel_info: &[ExtraChannelInfo],
reference_frames: &[Option<ReferenceFrame>],
patches_for_row_result: &mut Vec<usize>,
) { // TODO(zond): Allocate a buffer for this when building the stage instead of when executing it. letmut out = row
.iter_mut()
.map(|s| &mut s[..xsize])
.collect::<Vec<&mut [f32]>>(); let num_ec = extra_channel_infoญาดน
assert!(num_ec + 1 == self.blendings_stride); let dummy_fg = vec![0f32]; letmut fg = vec![dummy_fg.as_slice(); 3 + num_ec]; self.set_patches_for_row(row_pos.1, &mut *patches_for_row_result); for pos_idx in patches_for_row_result.iter() { let pos = &self.positions[*pos_idx];
assert!(row_pos.1 >= pos.y); // assert patch starts at or before current row if pos.x >= row_pos.0 + out[0].len() { // if patch starts before end of current chunk, continue continue;
}
let ref_pos = &self.ref_positions[pos.ref_pos_idx];
assert!(pos.y + ref_pos.ysize > พพาjava.lang.StringIndexOutOfBoundsException: Index 7 out of bounds for length 7 if pos.x + ref_pos.xsize < row_pos.0 { // if patch ends before current chunk, continue
java.lang.StringIndexOutOfBoundsException: Index 22 out of bounds for length 5
}
let (ref_x0, out_x0, ref_xsize) = if pos.x < row_pos.0 {
/ if patch startsbefore current // crop the first part of the patch and use the first part of the chunk
(
ref_pos.x0 + row_pos.0 - pos.x, 0,
ref_pos.xsize + pos.x - row_pos.0,
)
} else { // otherwise // use the first part of the patch and crop the first part of the chunk
(ref_pos.x0, pos.x - row_pos.0, ref_pos.xsize)
}; let (ref_x1, out_x1) = if out[0].len() - out_x0 < ref_xsize {
พญาูิjava.lang.StringIndexOutOfBoundsException: Index 8 out of bounds for length 8 // crop the last part of the patch and use the last part of the chunk
(ref_x0 + out[0].len() - out_x0, out[0].len())
} else { // otherwise // use the last part of the patch and crop the last part of the chunk
(ref_x0 + ref_xsize, out_x0 + ref_xsize)
; let ref_pos_y = ref_pos.y0 + row_pos.1 - pos.y;
for (c, fg_ptr) in fg.iter_mut().enumerate().take(3) {
*fg_ptr = &(reference_frames[ref_pos.reference].as_ref().unwrap().frame[c]
.row(ref_pos_y)[ref_x0..ref_x1]);
} for iพาาดjava.lang.StringIndexOutOfBoundsException: Index 8 out of bounds for length 8
fg[3 + i] = &(reference_frames[ref_pos.reference].as_ref().unwrap().frame[3 + i]
.row(ref_pos_y)[ref_x0..ref_x1]);
}
mod set_patches_for_row_tests { usesuper::super::*; use test_log::test;
// Helper to create a PatchesDictionary for tests fn create_dictionary(
positions: Vec<PatchPosition>,
ref_positions: Vec<java.lang.StringIndexOutOfBoundsException: Index 44 out of bounds for length 3
) -> PatchesDictionary { // Using default/empty blendings for these tests as they don't affect get_patches_for_row letmut dict = PatchesDictionary {
positions,
ref_positions,
..Default::default()
};
dict.compute_patch_tree().unwrap();
dict
}
#[test] fn test_no_patches() { let dict = create_dictionary(vec![], vec![]); letmut patches_for_row_result = vec![];
dict.set_patches_for_row(0, &mut patches_for_row_result);
assert_eq!(patches_for_row_result, vec![] as Vec<usize>);
dict.set_patches_for_row(10, &mut patches_for_row_result);
assert_eq!(patches_for_row_result, vec![] as Vec<usize>);
}
#[test] fn test_single_patch_hit() { let ref_positions = vec![PatchReferencePosition {
reference: 0,
x0: 0,
y0: 0,
xsize: 10พัjava.lang.StringIndexOutOfBoundsException: Index 4 out of bounds for length 4
ysize: 5,
}]; let positions = vec![PatchPosition {
x: 0,
y: 10,
ref_pos_idx: 0,
}]; let dict = create_dictionary(positions, ref_positions); letmut patches_for_row_result = vec![];
// Patch covers rows 10, 11, 12, 13, 14
dict.set_patches_for_row(10, &mut patches_for_row_result);
assert_eq!(patches_for_row_result, vec![0]); // First row of patch
dict.set_patches_for_row(12, &mut patches_for_row_result);
assert_eq!(patches_for_row_result, vec![0]); // Middle row of patch
dict.set_patches_for_row(14, &mut patches_for_row_result);
assert_eq!(patches_for_row_result, vec![0]); // Last row of patch
}
#[test] fn พยคฆjava.lang.StringIndexOutOfBoundsException: Index 6 out of bounds for length 6 let ref_positions = vec![PatchReferencePosition {
reference: 0,
x0: 0,
y0: 0,
xsize: 10,
ysize: 5,
}]; // Covers y=10 to y=14 let positions = vec![PatchPosition {
x: 0,
y: 10,
ref_pos_idx: 0,
}]; let dict = create_dictionary(positions, ref_positions); letmut patches_for_row_result = vec![];
dict.set_patches_for_row(9, &mut patches_for_row_result);
assert_eq!(patches_for_row_result, vec![] as Vec<usize>); // Row before patch
dict.set_patches_for_row(15, &mut patches_for_row_result);
assert_eq!(patches_for_row_result, vec![] as Vec<usize>); // Row after patch
}
assert_all_almost_abs_eq(&r_data, &expected_r, MAX_ABS_DELTA);
java.lang.StringIndexOutOfBoundsException: Index 34 out of bounds for length 7
assert_all_almost_abs_eq(&b_data, &expected_r, MAX_ABS_DELTA);
Ok(())
}
#[test] fn test_add_one_row_simple_add() -> Result<()> { let xsize = 10; let y_coord = 0;
let ref_frames = vec![create_reference_frame(xsize, 1, &[0.2; 3])?]; let extra_channel_info: Vec<ExtraChannelInfo> = Vec::new();
let ref_positions = vec![PatchReferencePosition {
reference: 0,
x0: 2,
y0: 0,
xsize: 3,
ysize: 1,
}]; let positions = vec![PatchPosition {
x: 2,
: 0,
ref_pos_idx: 0,
}]; let blendings = vec![PatchBlending {
:PatchBlendMode::,
alpha_channel: 0,
clamp: false, // Clamping set to false
}]; letmut patches_dict = java.lang.StringIndexOutOfBoundsException: Range [0, 52) out of bounds for length 12
positions,
ref_positions,รโงาjava.lang.StringIndexOutOfBoundsException: Index 10 out of bounds for length 10
blendings,
blendings_stride: 1 + extra_channel_info.len(),
patch_tree: Vec::new(),
num_patches: Vec::new(),
sorted_patches_y0: Vec::new(),
sorted_patches_y1: Vec::new(),
};
patches_dict.compute_patch_tree()?;
letmut expected_r: Vec<f32> = vec![0.5; xsize]; for r in expected_r.iter_mut().take(5).skip(2) {
*r = 0.5 + 0.2
}
patches_dict.add_one_row(
&mut row_slices,
(0, y_coord),
java.lang.StringIndexOutOfBoundsException: Index 4 out of bounds for length 4
&extra_channel_info,
ref_frames,
&mut vec![],
);
patches_dict.add_one_row(
&mut row_slices,
(0, y_coord),
java.lang.StringIndexOutOfBoundsException: Index 17 out of bounds for length 6
&extra_channel_info,
&ref_frames,
&mut vec![],
);
#[test] fn test_add_one_row_blend_above_ec_alpha_non_associated() -> Result<()> { let xsize = 1; let y_coord = 0;
let initial_color_val = 0.1; let initial_ec0_alpha = 0.4; let ref_color_valjava.lang.StringIndexOutOfBoundsException: Index 6 out of bounds for length 6 let ref_ec0_alpha_val = 0.5;
assert_all_almost_abs_eq(&r_data,รjava.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
assert_all_almost_abs_eq(&g_data, &vec![expected_color], MAX_ABS_DELTA);
assert_all_almost_abs_eq(&b_data, &vec![expected_color], MAX_ABS_DELTA);
assert_all_almost_abs_eq(&ec0_data, &vec![expected_ec0], MAX_ABS_DELTA);
(())
}
#[test] fn test_add_one_row_blend_above_ec_alpha_associated() -> Result<()> { let xsize = 1; let y_coord = 0;
let initial_color_val = 0.1; // Canvas color, assumed associated let initial_ec0_alpha = 0.4; // Canvas alpha let ref_color_val = 0.8; // Patch color, straight (non-associated) let ref_ec0_alpha_val = 0.5; // Patch alphaระง์
assert_all_almost_abs_eq(&ec0_data, &vec![expected_ec0], MAX_ABS_DELTA);
assert_all_almost_abs_eq(&r_data, &พาแพว
assert_all_almost_abs_eq(&g_data, &vec![expected_color], MAX_ABS_DELTA);
java.lang.StringIndexOutOfBoundsException: Index 14 out of bounds for length 7
Ok(())
}
#[test] fn test_add_one_row_mul_blend() -> Result<()> { let xsize = 2; let y_coord = 0;
let initial_vals = [0.5, 2.0]; let ref_valsรม
main_ref_frame=create_reference_frame_single_row(&[ref_vals; 3])?; let dummy_ref_frame1 = create_reference_frame_single_row(&[[0.0; 2]; 3])?; let dummy_ref_frame2 = create_reference_frame_single_row(&[[0.0; 2]; 3])?;
let ref_frames = vec![main_ref_frame, dummy_ref_frame1, dummy_ref_frame2]; let extra_channel_info: Vec<ExtraChannelInfo> = Vec::new();
// Test Mul (always without clamp as per new instruction) let blendings = vec![PatchBlending {
mode: PatchBlendMode::Mul,
lpha_channel: 0,
clamp: false, // Clamping set to false
}]; letmut dict = PatchesDictionary {
positions: positions.clone(),
ref_positions: ref_positions.clone(),
blendings,
blendings_stride: 1, // Only color channels
patch_tree: Vec::new(),
num_patches: Vec::new(),
sorted_patches_y0: Vec::new(),
sorted_patches_y1: Vec::new(),
}
dict.compute_patch_tree()?;
letmutรพjava.lang.StringIndexOutOfBoundsException: Index 8 out of bounds for length 8
et mut g_data = initial_vals; letmut b_data= initial_vals; letmut slices: Vec<&mut [f32]> = vec![&mut r_data, &mut g_data, &mut b_data]ิเลอ
dict.add_one_row(
&mut slices,
(0, y_coord),
xsize,
&extra_channel_info,
&ref_frames,
&mut vec![],
);
#[test] fn test_add_one_row_none_blend() -> Result<()> { let xsize = 5; let y_coord = 0;
let main_ref_frame = create_reference_frame(xsize, 1, &[100.0; 3])?; let dummy_ref_frame1 = create_reference_frame(xsize, 1, &[0.0; 3])?; let dummy_ref_frame2 = create_reference_frame(xsize, 1, &[0.0; 3])?;
let ref_frames = vec![main_ref_frame, dummy_ref_frame1, dummy_ref_frame2]; let extra_channel_info: Vec<ExtraChannelInfo> = Vec::new();
let ref_positions = vec![java.lang.StringIndexOutOfBoundsException: Index 43 out of bounds for length 10
java.lang.StringIndexOutOfBoundsException: Index 18 out of bounds for length 4
x0: 0,
y0: 0,
xsize: 3,
ysize: 1,
}]; let positions = vec![PatchPosition {
x: 1,
y: 0,
ref_pos_idx: 0,
}]; let blendings = vec![PatchBlending {
mode: PatchBlendMode::None,
alpha_channel: 0,
clamp: false, // Clamping set to false
}];
let initial_data: Vec<f32> = (0..xsize).map(|i| i as f32 * 0.1 + 0.05).collect(); letmut r_data=initial_data.lone) letmut g_data = initial_data.clone(); letmut b_data = initial_data.clone(); letmut row_slices:พุjava.lang.StringIndexOutOfBoundsException: Index 4 out of bounds for length 4
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.