add support for image inputs
This commit is contained in:
parent
5ba6e33fa8
commit
29836d979a
@ -18,9 +18,6 @@ const CSS_PROPS_WITH_IMAGE_URLS: &[&str] = &[
|
|||||||
"mask-image",
|
"mask-image",
|
||||||
];
|
];
|
||||||
|
|
||||||
const TRANSPARENT_PIXEL: &str = "data:image/png;base64,\
|
|
||||||
iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=";
|
|
||||||
|
|
||||||
pub fn is_image_url_prop(prop_name: &str) -> bool {
|
pub fn is_image_url_prop(prop_name: &str) -> bool {
|
||||||
CSS_PROPS_WITH_IMAGE_URLS
|
CSS_PROPS_WITH_IMAGE_URLS
|
||||||
.iter()
|
.iter()
|
||||||
@ -185,7 +182,7 @@ pub fn process_css<'a>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if opt_no_images && is_image_url_prop(curr_prop.as_str()) {
|
if opt_no_images && is_image_url_prop(curr_prop.as_str()) {
|
||||||
result.push_str(enquote(str!(TRANSPARENT_PIXEL), false).as_str());
|
result.push_str(enquote(str!(empty_image!()), false).as_str());
|
||||||
} else {
|
} else {
|
||||||
let resolved_url = resolve_url(&parent_url, value).unwrap_or_default();
|
let resolved_url = resolve_url(&parent_url, value).unwrap_or_default();
|
||||||
let (data_url, _final_url) = retrieve_asset(
|
let (data_url, _final_url) = retrieve_asset(
|
||||||
@ -294,7 +291,7 @@ pub fn process_css<'a>(
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
if opt_no_images && is_image_url_prop(curr_prop.as_str()) {
|
if opt_no_images && is_image_url_prop(curr_prop.as_str()) {
|
||||||
result.push_str(enquote(str!(TRANSPARENT_PIXEL), false).as_str());
|
result.push_str(enquote(str!(empty_image!()), false).as_str());
|
||||||
} else {
|
} else {
|
||||||
let full_url = resolve_url(&parent_url, value).unwrap_or_default();
|
let full_url = resolve_url(&parent_url, value).unwrap_or_default();
|
||||||
let (data_url, _final_url) = retrieve_asset(
|
let (data_url, _final_url) = retrieve_asset(
|
||||||
|
59
src/html.rs
59
src/html.rs
@ -20,9 +20,6 @@ const ICON_VALUES: &[&str] = &[
|
|||||||
"fluid-icon",
|
"fluid-icon",
|
||||||
];
|
];
|
||||||
|
|
||||||
const TRANSPARENT_PIXEL: &str = "data:image/png;base64,\
|
|
||||||
iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=";
|
|
||||||
|
|
||||||
pub fn get_parent_node(node: &Handle) -> Handle {
|
pub fn get_parent_node(node: &Handle) -> Handle {
|
||||||
let parent = node.parent.take().clone();
|
let parent = node.parent.take().clone();
|
||||||
parent.and_then(|node| node.upgrade()).unwrap()
|
parent.and_then(|node| node.upgrade()).unwrap()
|
||||||
@ -270,7 +267,7 @@ pub fn walk_and_embed_assets(
|
|||||||
if opt_no_images {
|
if opt_no_images {
|
||||||
attrs_mut.push(Attribute {
|
attrs_mut.push(Attribute {
|
||||||
name: QualName::new(None, ns!(), local_name!("src")),
|
name: QualName::new(None, ns!(), local_name!("src")),
|
||||||
value: Tendril::from_slice(TRANSPARENT_PIXEL),
|
value: Tendril::from_slice(empty_image!()),
|
||||||
});
|
});
|
||||||
} else if let Some((data_url, _)) = found_datasrc
|
} else if let Some((data_url, _)) = found_datasrc
|
||||||
.iter()
|
.iter()
|
||||||
@ -297,6 +294,58 @@ pub fn walk_and_embed_assets(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
"input" => {
|
||||||
|
let mut is_image: bool = false;
|
||||||
|
for attr in attrs_mut.iter_mut() {
|
||||||
|
let attr_name: &str = &attr.name.local;
|
||||||
|
if attr_name == "type" {
|
||||||
|
is_image = attr.value.to_string().eq_ignore_ascii_case("image");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if is_image {
|
||||||
|
let mut found_src: Option<Attribute> = None;
|
||||||
|
let mut i = 0;
|
||||||
|
while i < attrs_mut.len() {
|
||||||
|
let attr_name = attrs_mut[i].name.local.as_ref();
|
||||||
|
if attr_name.eq_ignore_ascii_case("src") {
|
||||||
|
found_src = Some(attrs_mut.remove(i));
|
||||||
|
} else {
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If images are disabled, clear both sources
|
||||||
|
if opt_no_images {
|
||||||
|
attrs_mut.push(Attribute {
|
||||||
|
name: QualName::new(None, ns!(), local_name!("src")),
|
||||||
|
value: Tendril::from_slice(empty_image!()),
|
||||||
|
});
|
||||||
|
} else if let Some((data_url, _)) = found_src
|
||||||
|
.iter()
|
||||||
|
.map(|attr| attr.value.trim())
|
||||||
|
.filter(|src| !src.is_empty()) // Skip if empty
|
||||||
|
.next()
|
||||||
|
.and_then(|src| resolve_url(&url, src).ok()) // Make absolute
|
||||||
|
.and_then(|abs_src| // Download and convert to data_url
|
||||||
|
retrieve_asset(
|
||||||
|
cache,
|
||||||
|
client,
|
||||||
|
&url,
|
||||||
|
&abs_src,
|
||||||
|
true,
|
||||||
|
"",
|
||||||
|
opt_silent,
|
||||||
|
).ok())
|
||||||
|
{
|
||||||
|
// Add new data_url src attribute
|
||||||
|
attrs_mut.push(Attribute {
|
||||||
|
name: QualName::new(None, ns!(), local_name!("src")),
|
||||||
|
value: Tendril::from_slice(data_url.as_ref()),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
"source" => {
|
"source" => {
|
||||||
for attr in attrs_mut.iter_mut() {
|
for attr in attrs_mut.iter_mut() {
|
||||||
let attr_name: &str = &attr.name.local;
|
let attr_name: &str = &attr.name.local;
|
||||||
@ -310,7 +359,7 @@ pub fn walk_and_embed_assets(
|
|||||||
if get_node_name(&get_parent_node(&node)) == Some("picture") {
|
if get_node_name(&get_parent_node(&node)) == Some("picture") {
|
||||||
if opt_no_images {
|
if opt_no_images {
|
||||||
attr.value.clear();
|
attr.value.clear();
|
||||||
attr.value.push_slice(TRANSPARENT_PIXEL);
|
attr.value.push_slice(empty_image!());
|
||||||
} else {
|
} else {
|
||||||
let srcset_full_url =
|
let srcset_full_url =
|
||||||
resolve_url(&url, attr.value.trim()).unwrap_or_default();
|
resolve_url(&url, attr.value.trim()).unwrap_or_default();
|
||||||
|
@ -7,3 +7,11 @@ macro_rules! str {
|
|||||||
ToString::to_string(&$val)
|
ToString::to_string(&$val)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! empty_image {
|
||||||
|
() => {
|
||||||
|
"data:image/png;base64,\
|
||||||
|
iVBORw0KGgoAAAANSUhEUgAAAA0AAAANCAQAAADY4iz3AAAAEUlEQVR42mNkwAkYR6UolgIACvgADsuK6xYAAAAASUVORK5CYII="
|
||||||
|
};
|
||||||
|
}
|
||||||
|
@ -162,15 +162,18 @@ fn passing_remove_images_from_data_url() -> Result<(), Box<dyn std::error::Error
|
|||||||
// STDOUT should contain HTML with no images
|
// STDOUT should contain HTML with no images
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
std::str::from_utf8(&out.stdout).unwrap(),
|
std::str::from_utf8(&out.stdout).unwrap(),
|
||||||
"<html>\
|
format!(
|
||||||
|
"<html>\
|
||||||
<head>\
|
<head>\
|
||||||
<meta http-equiv=\"Content-Security-Policy\" content=\"img-src data:;\"></meta>\
|
<meta http-equiv=\"Content-Security-Policy\" content=\"img-src data:;\"></meta>\
|
||||||
</head>\
|
</head>\
|
||||||
<body>\
|
<body>\
|
||||||
<img src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=\">\
|
<img src=\"{empty_image}\">\
|
||||||
Hi\
|
Hi\
|
||||||
</body>\
|
</body>\
|
||||||
</html>\n"
|
</html>\n",
|
||||||
|
empty_image = empty_image!()
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
// STDERR should be empty
|
// STDERR should be empty
|
||||||
@ -229,7 +232,8 @@ fn passing_local_file_target_input() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
// STDOUT should contain HTML from the local file
|
// STDOUT should contain HTML from the local file
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
std::str::from_utf8(&out.stdout).unwrap(),
|
std::str::from_utf8(&out.stdout).unwrap(),
|
||||||
"<!DOCTYPE html><html lang=\"en\"><head>\n \
|
"\
|
||||||
|
<!DOCTYPE html><html lang=\"en\"><head>\n \
|
||||||
<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n \
|
<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n \
|
||||||
<title>Local HTML file</title>\n \
|
<title>Local HTML file</title>\n \
|
||||||
<link href=\"data:text/css;base64,Ym9keSB7CiAgICBiYWNrZ3JvdW5kLWNvbG9yOiAjMDAwOwogICAgY29sb3I6ICNmZmY7Cn0K\" rel=\"stylesheet\" type=\"text/css\">\n \
|
<link href=\"data:text/css;base64,Ym9keSB7CiAgICBiYWNrZ3JvdW5kLWNvbG9yOiAjMDAwOwogICAgY29sb3I6ICNmZmY7Cn0K\" rel=\"stylesheet\" type=\"text/css\">\n \
|
||||||
@ -238,16 +242,19 @@ fn passing_local_file_target_input() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
<a href=\"file://local-file.html/\">Tricky href</a>\n \
|
<a href=\"file://local-file.html/\">Tricky href</a>\n \
|
||||||
<a href=\"https://github.com/Y2Z/monolith\">Remote URL</a>\n \
|
<a href=\"https://github.com/Y2Z/monolith\">Remote URL</a>\n \
|
||||||
<script src=\"data:application/javascript;base64,ZG9jdW1lbnQuYm9keS5zdHlsZS5iYWNrZ3JvdW5kQ29sb3IgPSAiZ3JlZW4iOwpkb2N1bWVudC5ib2R5LnN0eWxlLmNvbG9yID0gInJlZCI7Cg==\"></script>\n\n\n\n\
|
<script src=\"data:application/javascript;base64,ZG9jdW1lbnQuYm9keS5zdHlsZS5iYWNrZ3JvdW5kQ29sb3IgPSAiZ3JlZW4iOwpkb2N1bWVudC5ib2R5LnN0eWxlLmNvbG9yID0gInJlZCI7Cg==\"></script>\n\n\n\n\
|
||||||
</body></html>\n"
|
</body></html>\n\
|
||||||
|
"
|
||||||
);
|
);
|
||||||
|
|
||||||
// STDERR should contain list of retrieved file URLs
|
// STDERR should contain list of retrieved file URLs
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
std::str::from_utf8(&out.stderr).unwrap(),
|
std::str::from_utf8(&out.stderr).unwrap(),
|
||||||
format!(
|
format!(
|
||||||
"{file}{cwd}/src/tests/data/local-file.html\n\
|
"\
|
||||||
|
{file}{cwd}/src/tests/data/local-file.html\n\
|
||||||
{file}{cwd}/src/tests/data/local-style.css\n\
|
{file}{cwd}/src/tests/data/local-style.css\n\
|
||||||
{file}{cwd}/src/tests/data/local-script.js\n",
|
{file}{cwd}/src/tests/data/local-script.js\n\
|
||||||
|
",
|
||||||
file = file_url_protocol,
|
file = file_url_protocol,
|
||||||
cwd = cwd_normalized
|
cwd = cwd_normalized
|
||||||
)
|
)
|
||||||
@ -286,17 +293,22 @@ fn passing_local_file_target_input_absolute_target_path() -> Result<(), Box<dyn
|
|||||||
// STDOUT should contain HTML from the local file
|
// STDOUT should contain HTML from the local file
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
std::str::from_utf8(&out.stdout).unwrap(),
|
std::str::from_utf8(&out.stdout).unwrap(),
|
||||||
"<!DOCTYPE html><html lang=\"en\"><head>\
|
format!(
|
||||||
|
"\
|
||||||
|
<!DOCTYPE html><html lang=\"en\"><head>\
|
||||||
<meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'unsafe-inline' data:; style-src 'none'; script-src 'none'; img-src data:;\"></meta>\n \
|
<meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'unsafe-inline' data:; style-src 'none'; script-src 'none'; img-src data:;\"></meta>\n \
|
||||||
<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n \
|
<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n \
|
||||||
<title>Local HTML file</title>\n \
|
<title>Local HTML file</title>\n \
|
||||||
<link href=\"\" rel=\"stylesheet\" type=\"text/css\">\n \
|
<link href=\"\" rel=\"stylesheet\" type=\"text/css\">\n \
|
||||||
<link href=\"\" rel=\"stylesheet\" type=\"text/css\">\n</head>\n\n<body>\n \
|
<link href=\"\" rel=\"stylesheet\" type=\"text/css\">\n</head>\n\n<body>\n \
|
||||||
<img alt=\"\" src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=\">\n \
|
<img alt=\"\" src=\"{empty_image}\">\n \
|
||||||
<a href=\"file://local-file.html/\">Tricky href</a>\n \
|
<a href=\"file://local-file.html/\">Tricky href</a>\n \
|
||||||
<a href=\"https://github.com/Y2Z/monolith\">Remote URL</a>\n \
|
<a href=\"https://github.com/Y2Z/monolith\">Remote URL</a>\n \
|
||||||
<script src=\"\"></script>\n\n\n\n\
|
<script src=\"\"></script>\n\n\n\n\
|
||||||
</body></html>\n"
|
</body></html>\n\
|
||||||
|
",
|
||||||
|
empty_image = empty_image!()
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
// STDERR should contain only the target file
|
// STDERR should contain only the target file
|
||||||
@ -342,17 +354,22 @@ fn passing_local_file_url_target_input() -> Result<(), Box<dyn std::error::Error
|
|||||||
// STDOUT should contain HTML from the local file
|
// STDOUT should contain HTML from the local file
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
std::str::from_utf8(&out.stdout).unwrap(),
|
std::str::from_utf8(&out.stdout).unwrap(),
|
||||||
"<!DOCTYPE html><html lang=\"en\"><head>\
|
format!(
|
||||||
|
"\
|
||||||
|
<!DOCTYPE html><html lang=\"en\"><head>\
|
||||||
<meta http-equiv=\"Content-Security-Policy\" content=\"style-src 'none'; script-src 'none'; img-src data:;\"></meta>\n \
|
<meta http-equiv=\"Content-Security-Policy\" content=\"style-src 'none'; script-src 'none'; img-src data:;\"></meta>\n \
|
||||||
<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n \
|
<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n \
|
||||||
<title>Local HTML file</title>\n \
|
<title>Local HTML file</title>\n \
|
||||||
<link href=\"\" rel=\"stylesheet\" type=\"text/css\">\n \
|
<link href=\"\" rel=\"stylesheet\" type=\"text/css\">\n \
|
||||||
<link href=\"\" rel=\"stylesheet\" type=\"text/css\">\n</head>\n\n<body>\n \
|
<link href=\"\" rel=\"stylesheet\" type=\"text/css\">\n</head>\n\n<body>\n \
|
||||||
<img alt=\"\" src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=\">\n \
|
<img alt=\"\" src=\"{empty_image}\">\n \
|
||||||
<a href=\"file://local-file.html/\">Tricky href</a>\n \
|
<a href=\"file://local-file.html/\">Tricky href</a>\n \
|
||||||
<a href=\"https://github.com/Y2Z/monolith\">Remote URL</a>\n \
|
<a href=\"https://github.com/Y2Z/monolith\">Remote URL</a>\n \
|
||||||
<script src=\"\"></script>\n\n\n\n\
|
<script src=\"\"></script>\n\n\n\n\
|
||||||
</body></html>\n"
|
</body></html>\n\
|
||||||
|
",
|
||||||
|
empty_image = empty_image!()
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
// STDERR should contain list of retrieved file URLs
|
// STDERR should contain list of retrieved file URLs
|
||||||
@ -458,7 +475,8 @@ fn passing_css_import_string() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
let mut file_html = NamedTempFile::new()?;
|
let mut file_html = NamedTempFile::new()?;
|
||||||
writeln!(
|
writeln!(
|
||||||
file_html,
|
file_html,
|
||||||
"<style>\n\
|
"\
|
||||||
|
<style>\n\
|
||||||
@charset 'UTF-8';\n\
|
@charset 'UTF-8';\n\
|
||||||
\n\
|
\n\
|
||||||
@import '{file}{css_path}';\n\
|
@import '{file}{css_path}';\n\
|
||||||
@ -466,7 +484,8 @@ fn passing_css_import_string() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
@import url({file}{css_path});\n\
|
@import url({file}{css_path});\n\
|
||||||
\n\
|
\n\
|
||||||
@import url('{file}{css_path}')\n\
|
@import url('{file}{css_path}')\n\
|
||||||
</style>\n",
|
</style>\n\
|
||||||
|
",
|
||||||
file = file_url_prefix,
|
file = file_url_prefix,
|
||||||
css_path = str!(file_css.path().to_str().unwrap()).replace("\\", "/"),
|
css_path = str!(file_css.path().to_str().unwrap()).replace("\\", "/"),
|
||||||
)?;
|
)?;
|
||||||
|
@ -40,13 +40,16 @@ height: calc(100vh - 10pt)";
|
|||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
"/* border: none;*/\
|
format!(
|
||||||
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII='); \
|
"/* border: none;*/\
|
||||||
list-style: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=');\
|
background-image: url('{empty_image}'); \
|
||||||
|
list-style: url('{empty_image}');\
|
||||||
width:99.998%; \
|
width:99.998%; \
|
||||||
margin-top: -20px; \
|
margin-top: -20px; \
|
||||||
line-height: -1; \
|
line-height: -1; \
|
||||||
height: calc(100vh - 10pt)"
|
height: calc(100vh - 10pt)",
|
||||||
|
empty_image = empty_image!()
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,21 +67,17 @@ line-height: -1; \
|
|||||||
height: calc(100vh - 10pt)";
|
height: calc(100vh - 10pt)";
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
css::embed_css(
|
css::embed_css(cache, &client, "", &STYLE, true, true,),
|
||||||
cache,
|
format!(
|
||||||
&client,
|
"/* border: none;*/\
|
||||||
"",
|
background-image: url('{empty_image}'); \
|
||||||
&STYLE,
|
list-style: url('{empty_image}');\
|
||||||
true,
|
|
||||||
true,
|
|
||||||
),
|
|
||||||
"/* border: none;*/\
|
|
||||||
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII='); \
|
|
||||||
list-style: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=');\
|
|
||||||
width:99.998%; \
|
width:99.998%; \
|
||||||
margin-top: -20px; \
|
margin-top: -20px; \
|
||||||
line-height: -1; \
|
line-height: -1; \
|
||||||
height: calc(100vh - 10pt)"
|
height: calc(100vh - 10pt)",
|
||||||
|
empty_image = empty_image!()
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,18 +197,19 @@ fn passing_no_images() {
|
|||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
buf.iter().map(|&c| c as char).collect::<String>(),
|
buf.iter().map(|&c| c as char).collect::<String>(),
|
||||||
"<html>\
|
format!(
|
||||||
|
"<html>\
|
||||||
<head>\
|
<head>\
|
||||||
<link rel=\"icon\" href=\"\">\
|
<link rel=\"icon\" href=\"\">\
|
||||||
</head>\
|
</head>\
|
||||||
<body>\
|
<body>\
|
||||||
<div>\
|
<div>\
|
||||||
<img src=\"data:image/png;base64,\
|
<img src=\"{empty_image}\">\
|
||||||
iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0\
|
|
||||||
lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=\">\
|
|
||||||
</div>\
|
</div>\
|
||||||
</body>\
|
</body>\
|
||||||
</html>"
|
</html>",
|
||||||
|
empty_image = empty_image!()
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user