forked from mirrors/gstreamer-rs
fix typos in comments
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1246>
This commit is contained in:
parent
3cb2454fd3
commit
e75391139c
22 changed files with 31 additions and 31 deletions
|
@ -91,7 +91,7 @@ fn create_pipeline() -> Result<gst::Pipeline, Error> {
|
||||||
element_error!(
|
element_error!(
|
||||||
appsink,
|
appsink,
|
||||||
gst::ResourceError::Failed,
|
gst::ResourceError::Failed,
|
||||||
("Failed to interprete buffer as S16 PCM")
|
("Failed to interpret buffer as S16 PCM")
|
||||||
);
|
);
|
||||||
|
|
||||||
gst::FlowError::Error
|
gst::FlowError::Error
|
||||||
|
|
|
@ -53,7 +53,7 @@ mod cairo_compositor {
|
||||||
|
|
||||||
// Implementation of glib::Object virtual methods.
|
// Implementation of glib::Object virtual methods.
|
||||||
impl ObjectImpl for CairoCompositor {
|
impl ObjectImpl for CairoCompositor {
|
||||||
// Specfication of the compositor properties.
|
// Specification of the compositor properties.
|
||||||
// In this case a single property for configuring the background color of the
|
// In this case a single property for configuring the background color of the
|
||||||
// composition.
|
// composition.
|
||||||
fn properties() -> &'static [glib::ParamSpec] {
|
fn properties() -> &'static [glib::ParamSpec] {
|
||||||
|
@ -453,7 +453,7 @@ mod cairo_compositor {
|
||||||
|
|
||||||
// Implementation of glib::Object virtual methods.
|
// Implementation of glib::Object virtual methods.
|
||||||
impl ObjectImpl for CairoCompositorPad {
|
impl ObjectImpl for CairoCompositorPad {
|
||||||
// Specfication of the compositor pad properties.
|
// Specification of the compositor pad properties.
|
||||||
// In this case there are various properties for defining the position and otherwise
|
// In this case there are various properties for defining the position and otherwise
|
||||||
// the appearance of the stream corresponding to this pad.
|
// the appearance of the stream corresponding to this pad.
|
||||||
fn properties() -> &'static [glib::ParamSpec] {
|
fn properties() -> &'static [glib::ParamSpec] {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// This example demonstrates the use of the d3d11videosink's "present"
|
// This example demonstrates the use of the d3d11videosink's "present"
|
||||||
// signal and the use of Direct2D/DirectWrite APIs in Rust.
|
// signal and the use of Direct2D/DirectWrite APIs in Rust.
|
||||||
//
|
//
|
||||||
// Application can perform various hardware-acceleated 2D graphics operation
|
// Application can perform various hardware-accelerated 2D graphics operation
|
||||||
// (e.g., like cairo can support) and text rendering via the Windows APIs.
|
// (e.g., like cairo can support) and text rendering via the Windows APIs.
|
||||||
// In this example, 2D graphics operation and text rendering will happen
|
// In this example, 2D graphics operation and text rendering will happen
|
||||||
// directly to the on the DXGI swapchain's backbuffer via Windows API in
|
// directly to the on the DXGI swapchain's backbuffer via Windows API in
|
||||||
|
@ -129,7 +129,7 @@ fn main() -> Result<()> {
|
||||||
// APIs are marked as unsafe, except for cast.
|
// APIs are marked as unsafe, except for cast.
|
||||||
//
|
//
|
||||||
// In theory, all the Direct3D/Direct2D APIs could fail for
|
// In theory, all the Direct3D/Direct2D APIs could fail for
|
||||||
// some reasons (it's hardware!), but in pratice, it's very unexpected
|
// some reasons (it's hardware!), but in practice, it's very unexpected
|
||||||
// situation and any of failure below would mean we are doing
|
// situation and any of failure below would mean we are doing
|
||||||
// something in wrong way or driver bug or so.
|
// something in wrong way or driver bug or so.
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// This example demonstrates another type of combination of gtk and gstreamer,
|
// This example demonstrates another type of combination of gtk and gstreamer,
|
||||||
// in comparision to the gtksink example.
|
// in comparison to the gtksink example.
|
||||||
// This example uses regions that are managed by the window system, and uses
|
// This example uses regions that are managed by the window system, and uses
|
||||||
// the window system's api to insert a videostream into these regions.
|
// the window system's api to insert a videostream into these regions.
|
||||||
// So essentially, the window system of the system overlays our gui with
|
// So essentially, the window system of the system overlays our gui with
|
||||||
|
@ -107,7 +107,7 @@ fn create_ui(app: >k::Application) {
|
||||||
src.link(&sink).unwrap();
|
src.link(&sink).unwrap();
|
||||||
|
|
||||||
// First, we create our gtk window - which will contain a region where
|
// First, we create our gtk window - which will contain a region where
|
||||||
// our overlayed video will be displayed in.
|
// our overlaid video will be displayed in.
|
||||||
let window = gtk::Window::new(gtk::WindowType::Toplevel);
|
let window = gtk::Window::new(gtk::WindowType::Toplevel);
|
||||||
window.set_default_size(320, 240);
|
window.set_default_size(320, 240);
|
||||||
|
|
||||||
|
@ -130,7 +130,7 @@ fn create_ui(app: >k::Application) {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.downgrade();
|
.downgrade();
|
||||||
// Connect to this widget's realize signal, which will be emitted
|
// Connect to this widget's realize signal, which will be emitted
|
||||||
// after its display has been initialized. This is neccessary, because
|
// after its display has been initialized. This is necessary, because
|
||||||
// the window system doesn't know about our region until it was initialized.
|
// the window system doesn't know about our region until it was initialized.
|
||||||
video_window.connect_realize(move |video_window| {
|
video_window.connect_realize(move |video_window| {
|
||||||
// Here we temporarily retrieve a strong reference on the video-overlay from the
|
// Here we temporarily retrieve a strong reference on the video-overlay from the
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// This example demonstrates how to use GStreamer's iteration APIs.
|
// This example demonstrates how to use GStreamer's iteration APIs.
|
||||||
// This is used at multiple occassions - for example to iterate an
|
// This is used at multiple occasions - for example to iterate an
|
||||||
// element's pads.
|
// element's pads.
|
||||||
|
|
||||||
use gst::prelude::*;
|
use gst::prelude::*;
|
||||||
|
|
|
@ -17,7 +17,7 @@ fn example_main() {
|
||||||
gst::init().unwrap();
|
gst::init().unwrap();
|
||||||
|
|
||||||
// Let GStreamer create a pipeline from the parsed launch syntax on the cli.
|
// Let GStreamer create a pipeline from the parsed launch syntax on the cli.
|
||||||
// In comparision to the launch_glib_main example, this is using the advanced launch syntax
|
// In comparison to the launch_glib_main example, this is using the advanced launch syntax
|
||||||
// parsing API of GStreamer. The function returns a Result, handing us the pipeline if
|
// parsing API of GStreamer. The function returns a Result, handing us the pipeline if
|
||||||
// parsing and creating succeeded, and hands us detailed error information if something
|
// parsing and creating succeeded, and hands us detailed error information if something
|
||||||
// went wrong. The error is passed as gst::ParseError. In this example, we separately
|
// went wrong. The error is passed as gst::ParseError. In this example, we separately
|
||||||
|
|
|
@ -250,7 +250,7 @@ fn create_pipeline() -> Result<gst::Pipeline, Error> {
|
||||||
// will then change its caps and we use the notification about this change to
|
// will then change its caps and we use the notification about this change to
|
||||||
// resize our canvas's size.
|
// resize our canvas's size.
|
||||||
// Another possibility for when this might happen is, when our video is a network
|
// Another possibility for when this might happen is, when our video is a network
|
||||||
// stream that dynamically changes resolution when enough bandwith is available.
|
// stream that dynamically changes resolution when enough bandwidth is available.
|
||||||
overlay.connect_closure(
|
overlay.connect_closure(
|
||||||
"caps-changed",
|
"caps-changed",
|
||||||
false,
|
false,
|
||||||
|
|
|
@ -150,7 +150,7 @@ fn create_pipeline() -> Result<gst::Pipeline, Error> {
|
||||||
|
|
||||||
// The image we draw (the text) will be static, but we will change the
|
// The image we draw (the text) will be static, but we will change the
|
||||||
// transformation on the drawing context, which rotates and shifts everything
|
// transformation on the drawing context, which rotates and shifts everything
|
||||||
// that we draw afterwards. Like this, we have no complicated calulations
|
// that we draw afterwards. Like this, we have no complicated calculations
|
||||||
// in the actual drawing below.
|
// in the actual drawing below.
|
||||||
// Calling multiple transformation methods after each other will apply the
|
// Calling multiple transformation methods after each other will apply the
|
||||||
// new transformation on top. If you repeat the cr.rotate(angle) line below
|
// new transformation on top. If you repeat the cr.rotate(angle) line below
|
||||||
|
@ -179,7 +179,7 @@ fn create_pipeline() -> Result<gst::Pipeline, Error> {
|
||||||
// to end up as a 200x100 rectangle would now be 100x200.
|
// to end up as a 200x100 rectangle would now be 100x200.
|
||||||
pangocairo::functions::update_layout(&cr, layout);
|
pangocairo::functions::update_layout(&cr, layout);
|
||||||
let (width, _height) = layout.size();
|
let (width, _height) = layout.size();
|
||||||
// Using width and height of the text, we can properly possition it within
|
// Using width and height of the text, we can properly position it within
|
||||||
// our canvas.
|
// our canvas.
|
||||||
cr.move_to(
|
cr.move_to(
|
||||||
-(f64::from(width) / f64::from(pango::SCALE)) / 2.0,
|
-(f64::from(width) / f64::from(pango::SCALE)) / 2.0,
|
||||||
|
@ -241,7 +241,7 @@ fn create_pipeline() -> Result<gst::Pipeline, Error> {
|
||||||
// will then change its caps and we use the notification about this change to
|
// will then change its caps and we use the notification about this change to
|
||||||
// resize our canvas's size.
|
// resize our canvas's size.
|
||||||
// Another possibility for when this might happen is, when our video is a network
|
// Another possibility for when this might happen is, when our video is a network
|
||||||
// stream that dynamically changes resolution when enough bandwith is available.
|
// stream that dynamically changes resolution when enough bandwidth is available.
|
||||||
overlay.connect_closure(
|
overlay.connect_closure(
|
||||||
"caps-changed",
|
"caps-changed",
|
||||||
false,
|
false,
|
||||||
|
|
|
@ -134,7 +134,7 @@ fn create_pipeline() -> Result<gst::Pipeline, Error> {
|
||||||
|
|
||||||
// The image we draw (the text) will be static, but we will change the
|
// The image we draw (the text) will be static, but we will change the
|
||||||
// transformation on the drawing context, which rotates and shifts everything
|
// transformation on the drawing context, which rotates and shifts everything
|
||||||
// that we draw afterwards. Like this, we have no complicated calulations
|
// that we draw afterwards. Like this, we have no complicated calculations
|
||||||
// in the actual drawing below.
|
// in the actual drawing below.
|
||||||
// Calling multiple transformation methods after each other will apply the
|
// Calling multiple transformation methods after each other will apply the
|
||||||
// new transformation on top. If you repeat the cr.rotate(angle) line below
|
// new transformation on top. If you repeat the cr.rotate(angle) line below
|
||||||
|
@ -163,7 +163,7 @@ fn create_pipeline() -> Result<gst::Pipeline, Error> {
|
||||||
// to end up as a 200x100 rectangle would now be 100x200.
|
// to end up as a 200x100 rectangle would now be 100x200.
|
||||||
pangocairo::functions::update_layout(&cr, layout);
|
pangocairo::functions::update_layout(&cr, layout);
|
||||||
let (width, _height) = layout.size();
|
let (width, _height) = layout.size();
|
||||||
// Using width and height of the text, we can properly possition it within
|
// Using width and height of the text, we can properly position it within
|
||||||
// our canvas.
|
// our canvas.
|
||||||
cr.move_to(
|
cr.move_to(
|
||||||
-(f64::from(width) / f64::from(pango::SCALE)) / 2.0,
|
-(f64::from(width) / f64::from(pango::SCALE)) / 2.0,
|
||||||
|
@ -187,7 +187,7 @@ fn create_pipeline() -> Result<gst::Pipeline, Error> {
|
||||||
// will then change its caps and we use the notification about this change to
|
// will then change its caps and we use the notification about this change to
|
||||||
// resize our canvas's size.
|
// resize our canvas's size.
|
||||||
// Another possibility for when this might happen is, when our video is a network
|
// Another possibility for when this might happen is, when our video is a network
|
||||||
// stream that dynamically changes resolution when enough bandwith is available.
|
// stream that dynamically changes resolution when enough bandwidth is available.
|
||||||
overlay.connect("caps-changed", false, move |args| {
|
overlay.connect("caps-changed", false, move |args| {
|
||||||
let _overlay = args[0].get::<gst::Element>().unwrap();
|
let _overlay = args[0].get::<gst::Element>().unwrap();
|
||||||
let caps = args[1].get::<gst::Caps>().unwrap();
|
let caps = args[1].get::<gst::Caps>().unwrap();
|
||||||
|
|
|
@ -59,7 +59,7 @@ fn example_main() {
|
||||||
let playbin = values[0]
|
let playbin = values[0]
|
||||||
.get::<glib::Object>()
|
.get::<glib::Object>()
|
||||||
.expect("playbin \"audio-tags-changed\" signal values[1]");
|
.expect("playbin \"audio-tags-changed\" signal values[1]");
|
||||||
// This gets the index of the stream that changed. This is neccessary, since
|
// This gets the index of the stream that changed. This is necessary, since
|
||||||
// there could e.g. be multiple audio streams (english, spanish, ...).
|
// there could e.g. be multiple audio streams (english, spanish, ...).
|
||||||
let idx = values[1]
|
let idx = values[1]
|
||||||
.get::<i32>()
|
.get::<i32>()
|
||||||
|
|
|
@ -50,7 +50,7 @@ fn main_loop() -> Result<(), Error> {
|
||||||
&"user",
|
&"user",
|
||||||
)]);
|
)]);
|
||||||
let basic = gst_rtsp_server::RTSPAuth::make_basic("user", "password");
|
let basic = gst_rtsp_server::RTSPAuth::make_basic("user", "password");
|
||||||
// For propery authentication, we want to use encryption. And there's no
|
// For proper authentication, we want to use encryption. And there's no
|
||||||
// encryption without a certificate!
|
// encryption without a certificate!
|
||||||
let cert = gio::TlsCertificate::from_pem(
|
let cert = gio::TlsCertificate::from_pem(
|
||||||
"-----BEGIN CERTIFICATE-----\
|
"-----BEGIN CERTIFICATE-----\
|
||||||
|
|
|
@ -60,7 +60,7 @@ mod fir_filter {
|
||||||
// Implementation of gst::Element virtual methods
|
// Implementation of gst::Element virtual methods
|
||||||
impl ElementImpl for FirFilter {
|
impl ElementImpl for FirFilter {
|
||||||
// The element specific metadata. This information is what is visible from
|
// The element specific metadata. This information is what is visible from
|
||||||
// gst-inspect-1.0 and can also be programatically retrieved from the gst::Registry
|
// gst-inspect-1.0 and can also be programmatically retrieved from the gst::Registry
|
||||||
// after initial registration without having to load the plugin in memory.
|
// after initial registration without having to load the plugin in memory.
|
||||||
fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
|
fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
|
||||||
static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
|
static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
|
||||||
|
|
|
@ -191,7 +191,7 @@ status = "generate"
|
||||||
name = "is_missing_plugin_message"
|
name = "is_missing_plugin_message"
|
||||||
ignore = true
|
ignore = true
|
||||||
|
|
||||||
# Initialization is handled implicitely
|
# Initialization is handled implicitly
|
||||||
[[object.function]]
|
[[object.function]]
|
||||||
name = "pb_utils_init"
|
name = "pb_utils_init"
|
||||||
ignore = true
|
ignore = true
|
||||||
|
|
|
@ -400,7 +400,7 @@ impl Ord for VideoFormatInfo {
|
||||||
.then_with(|| self.h_sub().cmp(other.h_sub()).reverse())
|
.then_with(|| self.h_sub().cmp(other.h_sub()).reverse())
|
||||||
.then_with(|| self.n_planes().cmp(&other.n_planes()))
|
.then_with(|| self.n_planes().cmp(&other.n_planes()))
|
||||||
.then_with(|| {
|
.then_with(|| {
|
||||||
// Format using native endianess is considered as bigger
|
// Format using native endianness is considered as bigger
|
||||||
match (
|
match (
|
||||||
self.flags().contains(crate::VideoFormatFlags::LE),
|
self.flags().contains(crate::VideoFormatFlags::LE),
|
||||||
other.flags().contains(crate::VideoFormatFlags::LE),
|
other.flags().contains(crate::VideoFormatFlags::LE),
|
||||||
|
|
|
@ -9,7 +9,7 @@ use serde_bytes::{ByteBuf, Bytes};
|
||||||
|
|
||||||
use crate::{Buffer, BufferFlags, BufferRef, ClockTime};
|
use crate::{Buffer, BufferFlags, BufferRef, ClockTime};
|
||||||
|
|
||||||
// TODO: try `Either<ByteBuf, Bytes>` to merge the base reprensentations for ser and de
|
// TODO: try `Either<ByteBuf, Bytes>` to merge the base representations for ser and de
|
||||||
// while avoiding unneeded copy
|
// while avoiding unneeded copy
|
||||||
|
|
||||||
impl Serialize for BufferRef {
|
impl Serialize for BufferRef {
|
||||||
|
|
|
@ -302,7 +302,7 @@ impl DateTime {
|
||||||
.and_then(|d| d.to_utc())
|
.and_then(|d| d.to_utc())
|
||||||
.map(|d| d.into())
|
.map(|d| d.into())
|
||||||
} else {
|
} else {
|
||||||
// It would be cheaper to build a `glib::DateTime` direcly, unfortunetaly
|
// It would be cheaper to build a `glib::DateTime` directly, unfortunetaly
|
||||||
// this would require using `glib::TimeZone::new_offset` which is feature-gated
|
// this would require using `glib::TimeZone::new_offset` which is feature-gated
|
||||||
// to `glib/v2_58`. So we need to build a new `gst::DateTime` with `0f64`
|
// to `glib/v2_58`. So we need to build a new `gst::DateTime` with `0f64`
|
||||||
// and then discard seconds again
|
// and then discard seconds again
|
||||||
|
|
|
@ -88,13 +88,13 @@ pub trait CompatibleFormattedValue<V: FormattedValue> {
|
||||||
/// Returns `Ok(self)` with its type restored if it is compatible with the format of `V`.
|
/// Returns `Ok(self)` with its type restored if it is compatible with the format of `V`.
|
||||||
///
|
///
|
||||||
/// When possible, prefer using [`Self::try_into_checked`] which
|
/// When possible, prefer using [`Self::try_into_checked`] which
|
||||||
/// reduces the risk of missuse.
|
/// reduces the risk of misuse.
|
||||||
///
|
///
|
||||||
/// When used with compatible [`SpecificFormattedValue`]s, checks
|
/// When used with compatible [`SpecificFormattedValue`]s, checks
|
||||||
/// are enforced by the type system, no runtime checks are performed.
|
/// are enforced by the type system, no runtime checks are performed.
|
||||||
///
|
///
|
||||||
/// When used with [`SpecificFormattedValue`] as a parameter and
|
/// When used with [`SpecificFormattedValue`] as a parameter and
|
||||||
/// a [`GenericFormattedValue`] as `Self`, a runtime check is perfomed
|
/// a [`GenericFormattedValue`] as `Self`, a runtime check is performed
|
||||||
/// against the default format of the parameter. If the check fails,
|
/// against the default format of the parameter. If the check fails,
|
||||||
/// `Err(FormattedValueError)` is returned.
|
/// `Err(FormattedValueError)` is returned.
|
||||||
///
|
///
|
||||||
|
|
|
@ -110,7 +110,7 @@
|
||||||
//! assert_eq!(*(8.mebibytes()), 8 * 1024 * 1024);
|
//! assert_eq!(*(8.mebibytes()), 8 * 1024 * 1024);
|
||||||
//! assert_eq!(*(4.gibibytes()), 4 * 1024 * 1024 * 1024);
|
//! assert_eq!(*(4.gibibytes()), 4 * 1024 * 1024 * 1024);
|
||||||
//!
|
//!
|
||||||
//! // ... and the macthing constants:
|
//! // ... and the matching constants:
|
||||||
//! assert_eq!(512 * Bytes::KiB, 512.kibibytes());
|
//! assert_eq!(512 * Bytes::KiB, 512.kibibytes());
|
||||||
//!
|
//!
|
||||||
//! // `Percent` can be built from a percent integer value:
|
//! // `Percent` can be built from a percent integer value:
|
||||||
|
|
|
@ -9,7 +9,7 @@ use crate::utils::Displayable;
|
||||||
/// A signed wrapper.
|
/// A signed wrapper.
|
||||||
///
|
///
|
||||||
/// This wrapper allows representing a signed value from a type
|
/// This wrapper allows representing a signed value from a type
|
||||||
/// which is originaly unsigned. In C APIs, this is represented
|
/// which is originally unsigned. In C APIs, this is represented
|
||||||
/// by a tuple with a signed integer positive or negative and
|
/// by a tuple with a signed integer positive or negative and
|
||||||
/// the absolute value.
|
/// the absolute value.
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
|
||||||
|
|
|
@ -38,7 +38,7 @@ macro_rules! ser_opt_tag (
|
||||||
);
|
);
|
||||||
);
|
);
|
||||||
|
|
||||||
// Note: unlike `Value`s, `Tag`s with optional `Type` `String` & `Date` values are guarenteed
|
// Note: unlike `Value`s, `Tag`s with optional `Type` `String` & `Date` values are guaranteed
|
||||||
// to be Non-null and non-empty in the C API. See:
|
// to be Non-null and non-empty in the C API. See:
|
||||||
// https://gitlab.freedesktop.org/gstreamer/gstreamer/blob/d90d771a9a512381315f7694c3a50b152035f3cb/gst/gststructure.c#L810-853
|
// https://gitlab.freedesktop.org/gstreamer/gstreamer/blob/d90d771a9a512381315f7694c3a50b152035f3cb/gst/gststructure.c#L810-853
|
||||||
|
|
||||||
|
|
|
@ -198,7 +198,7 @@ fn main() {
|
||||||
let mut samples = buffer.map_writable().unwrap();
|
let mut samples = buffer.map_writable().unwrap();
|
||||||
let samples = samples.as_mut_slice_of::<i16>().unwrap();
|
let samples = samples.as_mut_slice_of::<i16>().unwrap();
|
||||||
|
|
||||||
// Generate some psychodelic waveforms
|
// Generate some psychedelic waveforms
|
||||||
data.c += data.d;
|
data.c += data.d;
|
||||||
data.d -= data.c / 1000.0;
|
data.d -= data.c / 1000.0;
|
||||||
let freq = 1100.0 + 1000.0 * data.d;
|
let freq = 1100.0 + 1000.0 * data.d;
|
||||||
|
|
|
@ -107,7 +107,7 @@ fn tutorial_main() -> Result<(), Error> {
|
||||||
let mut samples = buffer.map_writable().unwrap();
|
let mut samples = buffer.map_writable().unwrap();
|
||||||
let samples = samples.as_mut_slice_of::<i16>().unwrap();
|
let samples = samples.as_mut_slice_of::<i16>().unwrap();
|
||||||
|
|
||||||
// Generate some psychodelic waveforms
|
// Generate some psychedelic waveforms
|
||||||
data.c += data.d;
|
data.c += data.d;
|
||||||
data.d -= data.c / 1000.0;
|
data.d -= data.c / 1000.0;
|
||||||
let freq = 1100.0 + 1000.0 * data.d;
|
let freq = 1100.0 + 1000.0 * data.d;
|
||||||
|
|
Loading…
Reference in a new issue