open pdf and draw c# : Add a link to a pdf control application platform web page azure winforms web browser %5BO%60Reilly%5D%20-%20JavaScript.%20The%20Definitive%20Guide,%206th%20ed.%20-%20%5BFlanagan%5D63-part1596

CHAPTER 21
Scripted Media and Graphics
This chapter describes how to use JavaScript to manipulate images, control audio and
video streams, and draw graphics. §21.1 explains traditional JavaScript techniques for
visual effects such as image rollovers in which one static image is replaced by another
when  the  mouse  pointer  moves  over  it. §21.2  covers  the  HTML5 
<audio>
and
<video>
elements and their JavaScript APIs.
After these first two sections on images, audio and video, the chapter moves on to cover
two powerful technologies for drawing client-side graphics. The ability to dynamically
generate sophisticated graphics in the browser is important for several reasons:
• The code used to produce graphics on the client side is typically much smaller than
the images themselves, creating a substantial bandwidth savings.
• Dynamically generating graphics from real-time data uses a lot of CPU cycles. Off-
loading this task to the client reduces the load on the server, potentially saving on
hardware costs.
• Generating graphics on the client is consistent with modern web application ar-
chitecture in which servers provide data and clients manage the presentation of
that data.
§21.3 explains Scalable Vector Graphics, or SVG. SVG is an XML-based language for
describing graphics, and SVG drawings can be created and scripted using JavaScript
and the DOM. Finally, §21.4 covers the HTML5 
<canvas>
element and its full-featured
JavaScript API for client-side drawing. The 
<canvas>
element is a revolutionary tech-
nology, and this chapter covers it in detail.
21.1  Scripting Images
Web pages include images using the HTML 
<img>
element. Like all HTML elements,
an 
<img>
element can be scripted: setting the 
src
property to a new URL causes the
browser to load (if necessary) and display a new image. (You can also script the width
613
Add a link to a pdf - insert, remove PDF links in C#.net, ASP.NET, MVC, Ajax, WinForms, WPF
Free C# example code is offered for users to edit PDF document hyperlink (url), like inserting and deleting
convert doc to pdf with hyperlinks; pdf hyperlink
Add a link to a pdf - VB.NET PDF url edit library: insert, remove PDF links in vb.net, ASP.NET, MVC, Ajax, WinForms, WPF
Help to Insert a Hyperlink to Specified PDF Document Page
adding hyperlinks to a pdf; pdf link to specific page
and height of an image, which will make the browser shrink or enlarge the image, but
that technique is not demonstrated here.)
The ability to dynamically replace one image with another in an HTML document
opens the door to a number of special effects. One common use for image replacement
is to implement image rollovers, in which an image changes when the mouse pointer
moves over it. When you make images clickable by placing them inside your hyperlinks,
rollover effects are a powerful way to invite the user to click on the image. (Similar
effects can be achieved without scripting using the CSS 
:hover
pseudoclass to alter the
background image of an element.) The following HTML fragment is a simple example:
it creates an image that changes when the mouse moves over it:
<img src="images/help.gif"
onmouseover="this.src='images/help_rollover.gif'"
onmouseout="this.src='images/help.gif'">
The event handlers of the 
<img>
element set the 
src
property when the mouse moves
over or out of the image. Image rollovers are strongly associated with clickability, so
this 
<img>
element should still be enclosed in an 
<a>
element or given an 
onclick
event
handler.
In order to be useful, image rollovers (and similar effects) need to be responsive. This
means that you need some way to ensure that the necessary images are “prefetched”
into the browser’s cache. Client-side JavaScript defines a special-purpose API for this
purpose: to force an image to be cached, create an offscreen Image object using the
Image()
constructor. Next, load an image into it by setting the 
src
property of this object
to the desired URL. This image is not added to the document, so it does not become
visible, but the browser nevertheless loads and caches the image data. Later, when the
same URL is used for an onscreen image, it can be quickly loaded from the browser’s
cache, rather than slowly loaded over the network.
The image-rollover code fragment shown in the previous section did not prefetch the
rollover image it used, so the user might notice a delay in the rollover effect the first
time she moves the mouse over the image. To fix this problem, modify the code as
follows:
<script>(new Image()).src = "images/help_rollover.gif";</script>
<img src="images/help.gif"
onmouseover="this.src='images/help_rollover.gif'"
onmouseout="this.src='images/help.gif'">
21.1.1  Unobtrusive Image Rollovers
The image rollover code just shown requires one 
<script>
element and two JavaScript
event-handler attributes to implement a single rollover effect. This is a perfect example
of obtrusive JavaScript: the amount of JavaScript code is so large that it effectively
obscures the HTML. Example 21-1 shows an unobtrusive alternative that allows you
to create image rollovers by simply specifying a 
data-rollover
attribute (see §15.4.3)
on any 
<img>
element. Note that this example uses the 
onLoad()
function of Exam-
614 | Chapter 21: Scripted Media and Graphics
RasterEdge .NET Document Imaging Trial Package Download Link.
Extract; C# Read: PDF Image Extract; C# Write: Insert text into PDF; C# Write: Add Image to PDF; C# Protect: Add Password to PDF; C#
pdf link open in new window; pdf hyperlinks
C# PDF Library SDK to view, edit, convert, process PDF file for C#
editing PDF document hyperlink (url) and quick navigation link in PDF bookmark. C#.NET: Edit PDF Metadata. PDF SDK for .NET allows you to read, add, edit, update
add hyperlinks to pdf; adding links to pdf
ple 13-5. It also uses the 
document.images[]
array (see §15.2.3) to find all 
<img>
elements
in the document.
Example 21-1. Unobtrusive Image Rollovers
/**
* rollover.js: unobtrusive image rollovers.
* To create image rollovers, include this module in your HTML file and
* use the data-rollover attribute on any <img> element to specify the URL of
* the rollover image. For example:
*   <img src="normal_image.png" data-rollover="rollover_image.png">
* Note that this module requires onLoad.js
*/
onLoad(function() { // Everything in one anonymous function: no symbols defined
// Loop through all images, looking for the data-rollover attribute
for(var i = 0; i < document.images.length; i++) {
var img = document.images[i]; 
var rollover = img.getAttribute("data-rollover"); 
if (!rollover) continue;  // Skip images without data-rollover
// Ensure that the rollover image is in the cache
(new Image()).src = rollover;
// Define an attribute to remember the default image URL
img.setAttribute("data-rollout", img.src);
// Register the event handlers that create the rollover effect
img.onmouseover = function() {
this.src = this.getAttribute("data-rollover");
};
img.onmouseout = function() {
this.src = this.getAttribute("data-rollout");
};
}
});
21.2  Scripting Audio and Video
HTML5 introduces 
<audio>
and 
<video>
elements that are, in theory, as easy to use as
the 
<img>
element. In HTML5-enabled browsers, you no longer need to use plug-ins
(like Flash) to embed sounds and movies in your HTML documents:
<audio src="background_music.mp3"/>
<video src="news.mov" width=320 height=240/>
In practice, the use of these elements is trickier than this, since browser vendors have
not been able to agree on a standard audio and video codec that all will support, so you
typically end up using 
<source>
elements to specify multiple media sources in different
formats:
21.2  Scripting Audio and Video | 615
Client-Side
JavaScript
C# PDF insert image Library: insert images into PDF in C#.net, ASP
C#.NET PDF SDK - Add Image to PDF Page in C#.NET. How to Insert & Add Image, Picture or Logo on PDF Page Using C#.NET. Add Image to PDF Page Using C#.NET.
add a link to a pdf in acrobat; adding hyperlinks to pdf
VB.NET PDF insert image library: insert images into PDF in vb.net
VB.NET PDF - Add Image to PDF Page in VB.NET. Guide VB.NET Programmers How to Add Images in PDF Document Using XDoc.PDF SDK for VB.NET.
pdf hyperlink; add links pdf document
<audio id="music">
<source src="music.mp3" type="audio/mpeg">  
<source src="music.ogg" type='audio/ogg; codec="vorbis"'>
</audio>
Note that 
<source>
elements have no content: there is no closing 
</source>
tag, and
you do not need to end them with 
/>
Browsers that support 
<audio>
and 
<video>
elements will not render these element’s
content. But browsers that do not support them do render their content, so you can
put fallback content (such as an 
<object>
element that invokes the Flash plug-in) inside:
<video id="news" width=640 height=480 controls preload>
<!-- WebM format for Firefox and Chrome -->
<source src="news.webm" type='video/webm; codecs="vp8, vorbis"'>
<!-- H.264 format for IE and Safari -->
<source src="news.mp4" type='video/mp4; codecs="avc1.42E01E, mp4a.40.2"'>
<!-- Fall back on the Flash plugin -->
<object width=640 height=480 type="application/x-shockwave-flash"
data="flash_movie_player.swf">
<!-- Param elements here configure the Flash movie player you're using -->
<!-- Text is the ultimate fallback content -->
<div>video element not supported and Flash plugin not installed.</div>
</object>
</video>
<audio>
and 
<video>
elements support a 
controls
attribute. If present (or if the corre-
sponding JavaScript property is set to 
true
), they display a set of playback controls that
includes play and pause buttons, a volume control, and so on. In addition, however,
the 
<audio>
and 
<video>
elements expose an API that gives scripts the power to control
media playback, and you can use this API to add simple sound effects to your web
application or to create your own custom control panels for sound and video. Although
their visual appearance is very different, the 
<audio>
and 
<video>
elements share es-
sentially the same API (the only real difference between them is that the 
<video>
element
has 
width
and 
height
properties) and almost everything that follows in this section
applies to both elements.
The Audio() constructor
<audio>
elements don’t have any visual appearance in the document unless you set the
controls
attribute. And just as you can create an offscreen image with the 
Image()
constructor, the HTML5 media API allows you to create an offscreen audio element
with the 
Audio()
constructor, passing a source URL as the argument:
new Audio("chime.wav").play();  // Load and play a sound effect
616 | Chapter 21: Scripted Media and Graphics
VB.NET PDF Password Library: add, remove, edit PDF file password
VB: Add Password to PDF with Permission Settings Applied. This VB.NET example shows how to add PDF file password with access permission setting.
pdf link to attached file; add a link to a pdf file
C# PDF Password Library: add, remove, edit PDF file password in C#
C# Sample Code: Add Password to PDF with Permission Settings Applied in C#.NET. This example shows how to add PDF file password with access permission setting.
add links to pdf in preview; change link in pdf file
The return value of the 
Audio()
constructor is the same kind of object you’d get when
querying  an 
<audio>
element  from  the  document,  or  creating  a  new  one  with
document.createElement("audio")
. Note that this is an audio-only feature of the media
API: there is no corresponding 
Video()
constructor.
Despite the frustrating requirement to define media in multiple file formats, the ability
to play audio and video natively in the browser, without the use of plug-ins, is a pow-
erful new feature in HTML5. Note that the problem of media codecs and browser
compatibility is beyond the scope of this book. The subsections that follow focus only
on the JavaScript API for working with audio and video streams.
21.2.1  Type Selection and Loading
If you want to test whether a media element can play a particular type of media, pass
the media MIME type (possibly including a 
codec
parameter) to the 
canPlayType()
method. The element returns the empty string (a falsy value) if it cannot play that media
type. Otherwise, it returns the string “maybe” or “probably”. Because of the compli-
cated nature of audio and video codecs, a player cannot in general be more certain than
“probably” that it can play a particular media type without actually downloading the
media and trying:
var a = new Audio();
if (a.canPlayType("audio/wav")) {
a.src = "soundeffect.wav";
a.play();
}
When you set the 
src
property of a media element, it begins the process of loading that
media. (That process won’t go very far unless 
preload
is “auto”.) Setting 
src
when some
other media is loading or playing will abort the loading or playing of the old media. If
you add 
<source>
elements to a media element instead of setting the 
src
attribute, the
element cannot know when you have inserted a complete set of elements, and it will
not begin choosing among the 
<source>
elements and loading data until you explicitly
call the 
load()
method.
21.2.2  Controlling Media Playback
The most important methods of the 
<audio>
and 
<video>
elements are 
play()
and
pause()
, which start and stop playback of the media:
// When the document has loaded, start playing some background music
window.addEventListener("load", function() { 
document.getElementById("music").play();
}, false);
In addition to starting and stopping sound and video, you can skip (or “seek”) to a
desired location within the media by setting the 
currentTime
property. This property
specifies the time in seconds to which the player should skip, and it can be set while
21.2  Scripting Audio and Video | 617
Client-Side
JavaScript
How to C#: Basic SDK Concept of XDoc.PDF for .NET
You may add PDF document protection functionality into your C# of PDF document, including editing PDF url links and quick navigation link in bookmark
add a link to a pdf; add links to pdf acrobat
VB.NET PDF: Basic SDK Concept of XDoc.PDF
You may add PDF document protection functionality into your VB.NET of PDF document, including editing PDF url links and quick navigation link in bookmark
clickable links in pdf files; add page number to pdf hyperlink
the media is playing or while it is paused. (The 
initialTime
and 
duration
properties
give the legal range of values for 
currentTime
; more about those properties follows.)
The 
volume
property specifies playback volume as a number between 0 (silent) and 1
(maximum volume). The 
muted
property can be set to 
true
to mute playback or set to
false
to resume playing sound at the specified 
volume
level.
The 
playbackRate
property specifies the speed at which the media is played. A value of
1.0 is the normal speed. Values greater than 1 are “fast forward” and values between 0
and 1 are “slow motion.” Negative values are supposed to play the sound or video
backward, but browsers do not support  that feature  at  the time of this writing.
<audio>
and 
<video>
elements also have a 
defaultPlaybackRate
property. Whenever the
play()
method is invoked, the 
playbackRate
property is set to 
defaultPlaybackRate
.
Note that the 
currentTime
volume
muted
, and 
playbackRate
properties are not only for
controlling media playback. If an 
<audio>
or 
<video>
element has the 
controls
attribute,
it displays player controls, giving the user control over playback. In that case, a script
might query properties like 
muted
and 
currentTime
to discover how the media is being
played.
The HTML attributes 
controls
loop
preload
, and 
autoplay
affect audio and video
playback and can also be set and queried as JavaScript properties. 
controls
specifies
whether playback controls are displayed in the browser. Set this property to 
true
to
display controls or 
false
to hide controls. The 
loop
property is a boolean that specifies
whether the media should play in a loop (
true
) or stop when it reaches the end
(
false
). The 
preload
property specifies whether (or how much) media content should
be preloaded before the user starts playing the media. The value “none” means no data
should be preloaded. The value “metadata” means that metadata such as duration,
bitrate, and frame size should be loaded, but not media data itself. Browsers typically
load metadata if you do not specify a 
preload
attribute. The 
preload
value “auto” means
that the browser should preload as much of the media as it deems appropriate. Finally,
the 
autoplay
property specifies whether the media should begin to play automatically
when a sufficient amount has been buffered. Setting 
autoplay
to 
true
obviously implies
that the browser should preload media data.
21.2.3  Querying Media Status
<audio>
and 
<video>
elements have a number of read-only properties that describe the
current state of the media and of the player. 
paused
is 
true
if the player is paused.
seeking
is 
true
if the player is skipping to a new playback position. 
ended
is 
true
if the
player has reached the end of the media and has stopped. (
ended
never becomes 
true
if 
loop
is true.)
The 
duration
property specifies the duration of the media in seconds. If you query this
property before the media metadata has been loaded, it returns 
NaN
. For streaming
media,  such as Internet  radio, with an indefinite  duration, this  property  returns
Infinity
.
618 | Chapter 21: Scripted Media and Graphics
The 
initialTime
property specifies the start time of the media, in seconds. For media
clips of fixed duration, this is usually 0. For streaming media, this property gives the
earliest time for which data is still buffered and which it is possible to seek back to.
currentTime
can never be set to less than 
initialTime
.
Three other properties provide a finer-grained view of the media timeline and its play-
back and buffering status. The 
played
property returns the time range or ranges that
have been played. The 
buffered
property returns the time range or ranges that are
currently buffered, and the 
seekable
property returns the time range or ranges that the
player can currently seek to. (You might use these properties to implement a progress
bar that illustrates the 
currentTime
and 
duration
along with how much of the media
has played and how much is buffered.)
played
buffered
, and 
seekable
are 
TimeRanges
objects. Each object has a 
length
prop-
erty that specifies the number of ranges it represents and 
start()
and 
end()
methods
that return the start and end times (in seconds) of a numbered range. In the most
common case of a single contiguous range of times, you’d use 
start(0)
and 
end(0)
.
Assuming that no seeking has happened and media is buffered from the beginning, for
example, you might use code like this to determine what percentage of a resource was
buffered:
var percent_loaded = Math.floor(song.buffered.end(0) / song.duration * 100);
Finally, three more properties, 
readyState
networkState
, and 
error
, give low-level sta-
tus details about 
<audio>
and 
<video>
elements. Each of the properties has a numeric
value, and constants are defined for each of the legal values. Note that these constants
are defined on the media object (or the error object) itself. You might use one in code
like this:
if (song.readyState === song.HAVE_ENOUGH_DATA) song.play();
readyState
specifies how much media data has been loaded, and therefore, how ready
the element is to begin playing that data. The values for this property and their meanings
are as follows:
Constant
Value
Description
HAVE_NOTHING
0
No media data or metadata has been loaded.
HAVE_METADATA
1
The media metadata has been loaded, but no data for the current playback position
has been loaded. This means that you can query the 
duration
of the media or the
dimensions of a video and you can seek by setting 
currentTime
, but the browser
cannot currently play the media at 
currentTime
.
HAVE_CURRENT_DATA
2
Media data for 
currentTime
has been loaded, but not enough data has been
loaded to allow the media to play. For video, this typically means that the current
frame has loaded, but the next one has not. This state occurs at the end of a sound
or movie.
HAVE_FUTURE_DATA
3
Enough media data has been loaded to begin playing, but it is likely not enough to
play to the end of the media without pausing to download more data.
21.2  Scripting Audio and Video | 619
Client-Side
JavaScript
Constant
Value
Description
HAVE_ENOUGH_DATA
4
Enough media data has been loaded that the browser is likely to be able to play to
the end without pausing.
The 
networkState
property specifies whether (or why not) a media element is using the
network:
Constant
Value
Description
NETWORK_EMPTY
0
The element has not started using the network. This would be the state before the
src
attribute was set, for example.
NETWORK_IDLE
1
The element is not currently loading data from the network. It might have loaded
the complete resource, or might have buffered all the data it currently needs. Or it
might have 
preload
set to “none” and not yet have been asked to load or play the
media.
NETWORK_LOADING
2
The element is currently using the network to load media data.
NETWORK_NO_SOURCE
3
The element was not able to find a media source that it is able to play.
When an error occurs in media loading or playback, the browser sets the 
error
property
of the 
<audio>
or 
<video>
element. If no error has occurred, 
error
is 
null
. Otherwise,
it is an object with a numeric 
code
property that describes the error. The error object
also defines constants that describe the possible error codes:
Constant
Value
Description
MEDIA_ERR_ABORTED
1
The user asked the browser to stop loading the media
MEDIA_ERR_NETWORK
2
The media is of the right type, but a network error prevented it from
being loaded.
MEDIA_ERR_DECODE
3
The media is of the right type, but an encoding error prevented it from
being decoded and played.
MEDIA_ERR_SRC_NOT_SUPPORTED
4
The media specified by the 
src
attribute is not a type that the browser
can play.
You might use the 
error
property with code like this:
if (song.error.code == song.error.MEDIA_ERR_DECODE)
alert("Can't play song: corrupt audio data.");
21.2.4  Media Events
<audio>
and 
<video>
are fairly complex elements—they must respond to user interac-
tion with their playback controls, to network activity, and even, during playback, to
the simple passage of time—and we’ve just seen that these elements have quite a few
properties that define their current state. Like most HTML elements, 
<audio>
and
<video>
fire events whenever their state changes. Because these elements have such a
complicated state, they can fire quite a few events.
620 | Chapter 21: Scripted Media and Graphics
Download from Wow! eBook <www.wowebook.com>
The table below summarizes the 22 media events, loosely in the order in which they
are likely to occur. There are no event registration properties for these events. Use the
addEventListener()
method of the 
<audio>
or 
<video>
element to register handler
functions.
Event Type
Description
loadstart
Triggered when the element begins requesting media data. 
networkState
is
NETWORK_LOADING
.
progress
Network activity is continuing to load media data. 
networkState
is 
NETWORK_LOADING
. Typ-
ically fired between 2 and 8 times per second.
loadedmetadata
The media metadata has been loaded, and the duration and dimensions of the media are ready.
readyState
has changed to 
HAVE_METADATA
for the first time.
loadeddata
Data for the current playback position has loaded for the first time, and 
readyState
has changed
to 
HAVE_CURRENT_DATA
.
canplay
Enough media data has loaded that playback can begin, but additional buffering is likely to be
required. 
readyState
is 
HAVE_FUTURE_DATA
.
canplaythrough
Enough media data has loaded that the media can probably be played all the way through without
pausing to buffer more data. 
readyState
is 
HAVE_ENOUGH_DATA
.
suspend
The element has buffered enough data and has temporarily stopped downloading. 
network
State
has changed to 
NETWORK_IDLE
.
stalled
The element is trying to load data, but no data is arriving. 
networkState
remains at
NETWORK_LOADING
.
play
The 
play()
method has been invoked, or the 
autoplay
attribute has caused the equivalent. If
sufficient data has loaded, this event will be followed by a playing event. Otherwise a waiting event
will follow.
waiting
Playback cannot begin, or playback has stopped, because there is not enough data buffered. A playing
event will follow when enough data is ready.
playing
The media has begun to play.
timeupdate
The 
currentTime
property has changed. During normal playback, this event is fired between 4
and 60 times per second, possibly depending on system load and how long the event handlers are
taking to complete.
pause
The 
pause()
method was called and playback has been paused.
seeking
The script or user has requested that playback skip to an unbuffered portion of the media and playback
has stopped while data loads. The 
seeking
property is 
true
.
seeked
The 
seeking
property has changed back to 
false
.
ended
Playback has stopped because the end of the media has been reached.
durationchange
The 
duration
property has changed
volumechange
The 
volume
or 
muted
property has changed.
ratechange
The 
playbackRate
or 
defaultPlaybackRate
has changed.
abort
The element has stopped loading data, typically at the user’s request. 
error.code
is
MEDIA_ERR_ABORTED
.
21.2  Scripting Audio and Video | 621
Client-Side
JavaScript
Event Type
Description
error
A network or other error prevented media data from being loaded. 
error.code
is a value other
than 
MEDIA_ERR_ABORTED
.
emptied
An error or abort has caused the 
networkState
to return to 
NETWORK_EMPTY
.
21.3  SVG: Scalable Vector Graphics
SVG is an XML grammar for graphics. The word “vector” in its name indicates that it
is fundamentally different from raster image formats, such as GIF, JPEG, and PNG,
that specify a matrix of pixel values. Instead, an SVG “image” is a precise, resolution-
independent (hence “scalable”) description of the steps necessary to draw the desired
graphic. Here is what a simple SVG file looks like:
<!-- Begin an SVG figure and declare our namespace -->
<svg xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 1000 1000">  <!-- Coordinate system for figure -->
<defs>                       <!-- Set up some definitions we'll use -->
<linearGradient id="fade"> <!-- a color gradient named "fade" -->
<stop offset="0%" stop-color="#008"/>    <!-- Start a dark blue -->
<stop offset="100%" stop-color="#ccf"/>  <!-- Fade to light blue -->
</linearGradient>
</defs>
<!-- Draw a rectangle with a thick black border and fill it with the fade -->
<rect x="100" y="200" width="800" height="600"
stroke="black" stroke-width="25" fill="url(#fade)"/>
</svg>
Figure 21-1 shows what this SVG file looks like when rendered graphically.
SVG is a large and moderately complex grammar. In addition to simple shape-drawing
primitives, it includes support for arbitrary curves, text, and animation. SVG graphics
can even incorporate JavaScript scripts and CSS stylesheets to add behavior and pre-
sentation information. This section shows how client-side JavaScript code (embedded
in HTML, not in SVG) can dynamically draw graphics using SVG. It includes examples
of SVG drawing but can only scratch the surface of what is possible with SVG. Full
details about SVG are available in the comprehensive, but quite readable, specification.
The specification is maintained by the W3C at http://www.w3.org/TR/SVG/. Note that
the specification includes a complete Document Object Model for SVG documents.
This section manipulates SVG graphics using the standard XML DOM and does not
use the SVG DOM at all.
At the time of this writing, all current browsers except IE support SVG (and IE9 will
support it). In the latest browsers, you can display SVG images using an ordinary
<img>
element. Some slightly older browsers (such as Firefox 3.6) do not support this
and require the use of an 
<object>
element:
<object data="sample.svg" type="image/svg+xml" width="100" height="100"/>
622 | Chapter 21: Scripted Media and Graphics
Documents you may be interested
Documents you may be interested