Sophie

Sophie

distrib > Mageia > 6 > x86_64 > media > core-updates > by-pkgid > cb677c027f0cc5c56853dd08d65bfb88 > files > 487

rust-doc-1.27.1-1.1.mga6.x86_64.rpm

<!DOCTYPE HTML>
<html lang="en" class="sidebar-visible no-js">
    <head>
        <!-- Book generated using mdBook -->
        <meta charset="UTF-8">
        <title>Procedural Macros (and custom derive) - The Rust Programming Language</title>
        <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
        <meta name="description" content="">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <meta name="theme-color" content="#ffffff" />

        <base href="">

        <link rel="stylesheet" href="book.css">
        <link href="https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800" rel="stylesheet" type="text/css">
        <link href="https://fonts.googleapis.com/css?family=Source+Code+Pro:500" rel="stylesheet" type="text/css">

        <link rel="shortcut icon" href="favicon.png">

        <!-- Font Awesome -->
        <link rel="stylesheet" href="_FontAwesome/css/font-awesome.css">

        <link rel="stylesheet" href="highlight.css">
        <link rel="stylesheet" href="tomorrow-night.css">
        <link rel="stylesheet" href="ayu-highlight.css">

        <!-- Custom theme stylesheets -->
        
        <link rel="stylesheet" href="src/theme/first-edition.css">
        

        

    </head>
    <body class="light">
        <!-- Work around some values being stored in localStorage wrapped in quotes -->
        <script type="text/javascript">
            try {
                var theme = localStorage.getItem('mdbook-theme');
                var sidebar = localStorage.getItem('mdbook-sidebar');

                if (theme.startsWith('"') && theme.endsWith('"')) {
                    localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
                }

                if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
                    localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
                }
            } catch (e) { }
        </script>

        <!-- Set the theme before any content is loaded, prevents flash -->
        <script type="text/javascript">
            var theme;
            try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { } 
            if (theme === null || theme === undefined) { theme = 'light'; }
            document.body.className = theme;
            document.querySelector('html').className = theme + ' js';
        </script>

        <!-- Hide / unhide sidebar before it is displayed -->
        <script type="text/javascript">
            var html = document.querySelector('html');
            var sidebar = 'hidden';
            if (document.body.clientWidth >= 1080) {
                try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
                sidebar = sidebar || 'visible';
            }
            html.classList.remove('sidebar-visible');
            html.classList.add("sidebar-" + sidebar);
        </script>

        <nav id="sidebar" class="sidebar" aria-label="Table of contents">
            <ol class="chapter"><li class="affix"><a href="README.html">Introduction</a></li><li><a href="getting-started.html"><strong aria-hidden="true">1.</strong> Getting Started</a></li><li><a href="guessing-game.html"><strong aria-hidden="true">2.</strong> Tutorial: Guessing Game</a></li><li><a href="syntax-and-semantics.html"><strong aria-hidden="true">3.</strong> Syntax and Semantics</a></li><li><ol class="section"><li><a href="variable-bindings.html"><strong aria-hidden="true">3.1.</strong> Variable Bindings</a></li><li><a href="functions.html"><strong aria-hidden="true">3.2.</strong> Functions</a></li><li><a href="primitive-types.html"><strong aria-hidden="true">3.3.</strong> Primitive Types</a></li><li><a href="comments.html"><strong aria-hidden="true">3.4.</strong> Comments</a></li><li><a href="if.html"><strong aria-hidden="true">3.5.</strong> if</a></li><li><a href="loops.html"><strong aria-hidden="true">3.6.</strong> Loops</a></li><li><a href="vectors.html"><strong aria-hidden="true">3.7.</strong> Vectors</a></li><li><a href="ownership.html"><strong aria-hidden="true">3.8.</strong> Ownership</a></li><li><a href="references-and-borrowing.html"><strong aria-hidden="true">3.9.</strong> References and Borrowing</a></li><li><a href="lifetimes.html"><strong aria-hidden="true">3.10.</strong> Lifetimes</a></li><li><a href="mutability.html"><strong aria-hidden="true">3.11.</strong> Mutability</a></li><li><a href="structs.html"><strong aria-hidden="true">3.12.</strong> Structs</a></li><li><a href="enums.html"><strong aria-hidden="true">3.13.</strong> Enums</a></li><li><a href="match.html"><strong aria-hidden="true">3.14.</strong> Match</a></li><li><a href="patterns.html"><strong aria-hidden="true">3.15.</strong> Patterns</a></li><li><a href="method-syntax.html"><strong aria-hidden="true">3.16.</strong> Method Syntax</a></li><li><a href="strings.html"><strong aria-hidden="true">3.17.</strong> Strings</a></li><li><a href="generics.html"><strong aria-hidden="true">3.18.</strong> Generics</a></li><li><a href="traits.html"><strong aria-hidden="true">3.19.</strong> Traits</a></li><li><a href="drop.html"><strong aria-hidden="true">3.20.</strong> Drop</a></li><li><a href="if-let.html"><strong aria-hidden="true">3.21.</strong> if let</a></li><li><a href="trait-objects.html"><strong aria-hidden="true">3.22.</strong> Trait Objects</a></li><li><a href="closures.html"><strong aria-hidden="true">3.23.</strong> Closures</a></li><li><a href="ufcs.html"><strong aria-hidden="true">3.24.</strong> Universal Function Call Syntax</a></li><li><a href="crates-and-modules.html"><strong aria-hidden="true">3.25.</strong> Crates and Modules</a></li><li><a href="const-and-static.html"><strong aria-hidden="true">3.26.</strong> const and static</a></li><li><a href="attributes.html"><strong aria-hidden="true">3.27.</strong> Attributes</a></li><li><a href="type-aliases.html"><strong aria-hidden="true">3.28.</strong> type aliases</a></li><li><a href="casting-between-types.html"><strong aria-hidden="true">3.29.</strong> Casting between types</a></li><li><a href="associated-types.html"><strong aria-hidden="true">3.30.</strong> Associated Types</a></li><li><a href="unsized-types.html"><strong aria-hidden="true">3.31.</strong> Unsized Types</a></li><li><a href="operators-and-overloading.html"><strong aria-hidden="true">3.32.</strong> Operators and Overloading</a></li><li><a href="deref-coercions.html"><strong aria-hidden="true">3.33.</strong> Deref coercions</a></li><li><a href="macros.html"><strong aria-hidden="true">3.34.</strong> Macros</a></li><li><a href="raw-pointers.html"><strong aria-hidden="true">3.35.</strong> Raw Pointers</a></li><li><a href="unsafe.html"><strong aria-hidden="true">3.36.</strong> unsafe</a></li></ol></li><li><a href="effective-rust.html"><strong aria-hidden="true">4.</strong> Effective Rust</a></li><li><ol class="section"><li><a href="the-stack-and-the-heap.html"><strong aria-hidden="true">4.1.</strong> The Stack and the Heap</a></li><li><a href="testing.html"><strong aria-hidden="true">4.2.</strong> Testing</a></li><li><a href="conditional-compilation.html"><strong aria-hidden="true">4.3.</strong> Conditional Compilation</a></li><li><a href="documentation.html"><strong aria-hidden="true">4.4.</strong> Documentation</a></li><li><a href="iterators.html"><strong aria-hidden="true">4.5.</strong> Iterators</a></li><li><a href="concurrency.html"><strong aria-hidden="true">4.6.</strong> Concurrency</a></li><li><a href="error-handling.html"><strong aria-hidden="true">4.7.</strong> Error Handling</a></li><li><a href="choosing-your-guarantees.html"><strong aria-hidden="true">4.8.</strong> Choosing your Guarantees</a></li><li><a href="ffi.html"><strong aria-hidden="true">4.9.</strong> FFI</a></li><li><a href="borrow-and-asref.html"><strong aria-hidden="true">4.10.</strong> Borrow and AsRef</a></li><li><a href="release-channels.html"><strong aria-hidden="true">4.11.</strong> Release Channels</a></li><li><a href="using-rust-without-the-standard-library.html"><strong aria-hidden="true">4.12.</strong> Using Rust without the standard library</a></li><li><a href="procedural-macros.html" class="active"><strong aria-hidden="true">4.13.</strong> Procedural Macros (and custom derive)</a></li></ol></li><li><a href="glossary.html"><strong aria-hidden="true">5.</strong> Glossary</a></li><li><a href="syntax-index.html"><strong aria-hidden="true">6.</strong> Syntax Index</a></li><li><a href="bibliography.html"><strong aria-hidden="true">7.</strong> Bibliography</a></li></ol>
        </nav>

        <div id="page-wrapper" class="page-wrapper">

            <div class="page">
                <div id="draft-warning" class="warning">
    <span class="message">You are reading an <strong>outdated</strong> edition of TRPL. For more, go <a href="../index.html">here</a>.</span>
    <button type="button" id="hide-draft-warning" title="Hide draft warning" class="button">
        <i class="fa fa-times"></i>
    </button>
</div>
<!-- Hide / unhide warning before it is displayed -->
<script type="text/javascript">
var warning = localStorage.getItem('trpl-first-edition-draft-warning');

if (warning === 'hidden') {
    Array
    .from(document.querySelectorAll('#page-wrapper'))
    .forEach(function(block) { block.classList.remove('has-warning'); });
    var elem = document.getElementById("draft-warning");
    elem.parentNode.removeChild(elem);
}

document.addEventListener("DOMContentLoaded", function(event) { 
    document.getElementById("hide-draft-warning").addEventListener("click", function(e) {
        var elem = document.getElementById("draft-warning");
        elem.parentNode.removeChild(elem);

        localStorage.setItem('trpl-first-edition-draft-warning', 'hidden');
    });
});
</script>

                <div id="menu-bar" class="menu-bar">
                    <div id="menu-bar-sticky-container">
                        <div class="left-buttons">
                            <button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
                                <i class="fa fa-bars"></i>
                            </button>
                            <button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
                                <i class="fa fa-paint-brush"></i>
                            </button>
                            <ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
                                <li role="none"><button role="menuitem" class="theme" id="light">Light <span class="default">(default)</span></button></li>
                                <li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
                                <li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
                                <li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
                                <li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
                            </ul>
                            
                            <button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
                                <i class="fa fa-search"></i>
                            </button>
                            
                        </div>

                        <h1 class="menu-title">The Rust Programming Language</h1> 

                        <div class="right-buttons">
                            <a href="print.html" title="Print this book" aria-label="Print this book">
                                <i id="print-button" class="fa fa-print"></i>
                            </a>
                        </div>
                    </div>
                </div>

                
                <div id="search-wrapper" class="hidden">
                    <form id="searchbar-outer" class="searchbar-outer">
                        <input type="search" name="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
                    </form>
                    <div id="searchresults-outer" class="searchresults-outer hidden">
                        <div id="searchresults-header" class="searchresults-header"></div>
                        <ul id="searchresults">
                        </ul>
                    </div>
                </div>
                

                <!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
                <script type="text/javascript">
                    document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
                    document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
                    Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
                        link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
                    });
                </script>

                <div id="content" class="content">
                    <main>
                        <a class="header" href="procedural-macros.html#procedural-macros-and-custom-derive" id="procedural-macros-and-custom-derive"><h1>Procedural Macros (and custom Derive)</h1></a>
<p>As you've seen throughout the rest of the book, Rust provides a mechanism
called &quot;derive&quot; that lets you implement traits easily. For example,</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
#[derive(Debug)]
struct Point {
    x: i32,
    y: i32,
}
#}</code></pre></pre>
<p>is a lot simpler than</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
struct Point {
    x: i32,
    y: i32,
}

use std::fmt;

impl fmt::Debug for Point {
    fn fmt(&amp;self, f: &amp;mut fmt::Formatter) -&gt; fmt::Result {
        write!(f, &quot;Point {{ x: {}, y: {} }}&quot;, self.x, self.y)
    }
}
#}</code></pre></pre>
<p>Rust includes several traits that you can derive, but it also lets you define
your own. We can accomplish this task through a feature of Rust called
&quot;procedural macros.&quot; Eventually, procedural macros will allow for all sorts of
advanced metaprogramming in Rust, but today, they're only for custom derive.</p>
<p>Let's build a very simple trait, and derive it with custom derive.</p>
<a class="header" href="procedural-macros.html#hello-world" id="hello-world"><h2>Hello World</h2></a>
<p>So the first thing we need to do is start a new crate for our project.</p>
<pre><code class="language-bash">$ cargo new --bin hello-world
</code></pre>
<p>All we want is to be able to call <code>hello_world()</code> on a derived type. Something
like this:</p>
<pre><code class="language-rust ignore">#[derive(HelloWorld)]
struct Pancakes;

fn main() {
    Pancakes::hello_world();
}
</code></pre>
<p>With some kind of nice output, like <code>Hello, World! My name is Pancakes.</code>.</p>
<p>Let's go ahead and write up what we think our macro will look like from a user
perspective. In <code>src/main.rs</code> we write:</p>
<pre><code class="language-rust ignore">#[macro_use]
extern crate hello_world_derive;

trait HelloWorld {
    fn hello_world();
}

#[derive(HelloWorld)]
struct FrenchToast;

#[derive(HelloWorld)]
struct Waffles;

fn main() {
    FrenchToast::hello_world();
    Waffles::hello_world();
}
</code></pre>
<p>Great. So now we just need to actually write the procedural macro. At the
moment, procedural macros need to be in their own crate. Eventually, this
restriction may be lifted, but for now, it's required. As such, there's a
convention; for a crate named <code>foo</code>, a custom derive procedural macro is called
<code>foo-derive</code>. Let's start a new crate called <code>hello-world-derive</code> inside our
<code>hello-world</code> project.</p>
<pre><code class="language-bash">$ cargo new hello-world-derive
</code></pre>
<p>To make sure that our <code>hello-world</code> crate is able to find this new crate we've
created, we'll add it to our toml:</p>
<pre><code class="language-toml">[dependencies]
hello-world-derive = { path = &quot;hello-world-derive&quot; }
</code></pre>
<p>As for the source of our <code>hello-world-derive</code> crate, here's an example:</p>
<pre><code class="language-rust ignore">extern crate proc_macro;
extern crate syn;
#[macro_use]
extern crate quote;

use proc_macro::TokenStream;

#[proc_macro_derive(HelloWorld)]
pub fn hello_world(input: TokenStream) -&gt; TokenStream {
    // Construct a string representation of the type definition
    let s = input.to_string();
    
    // Parse the string representation
    let ast = syn::parse_derive_input(&amp;s).unwrap();

    // Build the impl
    let gen = impl_hello_world(&amp;ast);
    
    // Return the generated impl
    gen.parse().unwrap()
}
</code></pre>
<p>So there is a lot going on here. We have introduced two new crates: <a href="https://crates.io/crates/syn"><code>syn</code></a> and
<a href="https://crates.io/crates/quote"><code>quote</code></a>. As you may have noticed, <code>input: TokenSteam</code> is immediately converted
to a <code>String</code>. This <code>String</code> is a string representation of the Rust code for which
we are deriving <code>HelloWorld</code>. At the moment, the only thing you can do with a
<code>TokenStream</code> is convert it to a string. A richer API will exist in the future.</p>
<p>So what we really need is to be able to <em>parse</em> Rust code into something
usable. This is where <code>syn</code> comes to play. <code>syn</code> is a crate for parsing Rust
code. The other crate we've introduced is <code>quote</code>. It's essentially the dual of
<code>syn</code> as it will make generating Rust code really easy. We could write this
stuff on our own, but it's much simpler to use these libraries. Writing a full
parser for Rust code is no simple task.</p>
<p>The comments seem to give us a pretty good idea of our overall strategy. We
are going to take a <code>String</code> of the Rust code for the type we are deriving, parse
it using <code>syn</code>, construct the implementation of <code>hello_world</code> (using <code>quote</code>),
then pass it back to Rust compiler.</p>
<p>One last note: you'll see some <code>unwrap()</code>s there. If you want to provide an
error for a procedural macro, then you should <code>panic!</code> with the error message.
In this case, we're keeping it as simple as possible.</p>
<p>Great, so let's write <code>impl_hello_world(&amp;ast)</code>.</p>
<pre><code class="language-rust ignore">fn impl_hello_world(ast: &amp;syn::DeriveInput) -&gt; quote::Tokens {
    let name = &amp;ast.ident;
    quote! {
        impl HelloWorld for #name {
            fn hello_world() {
                println!(&quot;Hello, World! My name is {}&quot;, stringify!(#name));
            }
        }
    }
}
</code></pre>
<p>So this is where quotes comes in. The <code>ast</code> argument is a struct that gives us
a representation of our type (which can be either a <code>struct</code> or an <code>enum</code>).
Check out the <a href="https://docs.rs/syn/0.11.11/syn/struct.DeriveInput.html">docs</a>,
there is some useful information there. We are able to get the name of the
type using <code>ast.ident</code>. The <code>quote!</code> macro lets us write up the Rust code
that we wish to return and convert it into <code>Tokens</code>. <code>quote!</code> lets us use some
really cool templating mechanics; we simply write <code>#name</code> and <code>quote!</code> will
replace it with the variable named <code>name</code>. You can even do some repetition
similar to regular macros work. You should check out the
<a href="https://docs.rs/quote">docs</a> for a good introduction.</p>
<p>So I think that's it. Oh, well, we do need to add dependencies for <code>syn</code> and
<code>quote</code> in the <code>Cargo.toml</code> for <code>hello-world-derive</code>.</p>
<pre><code class="language-toml">[dependencies]
syn = &quot;0.11.11&quot;
quote = &quot;0.3.15&quot;
</code></pre>
<p>That should be it. Let's try to compile <code>hello-world</code>.</p>
<pre><code class="language-bash">error: the `#[proc_macro_derive]` attribute is only usable with crates of the `proc-macro` crate type
 --&gt; hello-world-derive/src/lib.rs:8:3
  |
8 | #[proc_macro_derive(HelloWorld)]
  |   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
</code></pre>
<p>Oh, so it appears that we need to declare that our <code>hello-world-derive</code> crate is
a <code>proc-macro</code> crate type. How do we do this? Like this:</p>
<pre><code class="language-toml">[lib]
proc-macro = true
</code></pre>
<p>Ok so now, let's compile <code>hello-world</code>. Executing <code>cargo run</code> now yields:</p>
<pre><code class="language-bash">Hello, World! My name is FrenchToast
Hello, World! My name is Waffles
</code></pre>
<p>We've done it!</p>
<a class="header" href="procedural-macros.html#custom-attributes" id="custom-attributes"><h2>Custom Attributes</h2></a>
<p>In some cases it might make sense to allow users some kind of configuration.
For example, the user might want to overwrite the name that is printed in the <code>hello_world()</code> method.</p>
<p>This can be achieved with custom attributes:</p>
<pre><code class="language-rust ignore">#[derive(HelloWorld)]
#[HelloWorldName = &quot;the best Pancakes&quot;]
struct Pancakes;

fn main() {
    Pancakes::hello_world();
}
</code></pre>
<p>If we try to compile this though, the compiler will respond with an error:</p>
<pre><code class="language-bash">error: The attribute `HelloWorldName` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642)
</code></pre>
<p>The compiler needs to know that we're handling this attribute and to not respond with an error.
This is done in the <code>hello-world-derive</code> crate by adding <code>attributes</code> to the <code>proc_macro_derive</code> attribute:</p>
<pre><code class="language-rust ignore">#[proc_macro_derive(HelloWorld, attributes(HelloWorldName))]
pub fn hello_world(input: TokenStream) -&gt; TokenStream 
</code></pre>
<p>Multiple attributes can be specified that way.</p>
<a class="header" href="procedural-macros.html#raising-errors" id="raising-errors"><h2>Raising Errors</h2></a>
<p>Let's assume that we do not want to accept enums as input to our custom derive method.</p>
<p>This condition can be easily checked with the help of <code>syn</code>.
But how do we tell the user, that we do not accept enums?
The idiomatic way to report errors in procedural macros is to panic:</p>
<pre><code class="language-rust ignore">fn impl_hello_world(ast: &amp;syn::DeriveInput) -&gt; quote::Tokens {
    let name = &amp;ast.ident;
    // Check if derive(HelloWorld) was specified for a struct
    if let syn::Body::Struct(_) = ast.body {
        // Yes, this is a struct
        quote! {
            impl HelloWorld for #name {
                fn hello_world() {
                    println!(&quot;Hello, World! My name is {}&quot;, stringify!(#name));
                }
            }
        }
    } else {
        // Nope. This is an Enum. We cannot handle these!
        panic!(&quot;#[derive(HelloWorld)] is only defined for structs, not for enums!&quot;);
    }
}
</code></pre>
<p>If a user now tries to derive <code>HelloWorld</code> from an enum they will be greeted with following, hopefully helpful, error:</p>
<pre><code class="language-bash">error: custom derive attribute panicked
  --&gt; src/main.rs
   |
   | #[derive(HelloWorld)]
   |          ^^^^^^^^^^
   |
   = help: message: #[derive(HelloWorld)] is only defined for structs, not for enums!
</code></pre>

                    </main>

                    <nav class="nav-wrapper" aria-label="Page navigation">
                        <!-- Mobile navigation buttons -->
                        
                            <a rel="prev" href="using-rust-without-the-standard-library.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
                                <i class="fa fa-angle-left"></i>
                            </a>
                        

                        
                            <a rel="next" href="glossary.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
                                <i class="fa fa-angle-right"></i>
                            </a>
                        

                        <div style="clear: both"></div>
                    </nav>
                </div>
            </div>

            <nav class="nav-wide-wrapper" aria-label="Page navigation">
                
                    <a href="using-rust-without-the-standard-library.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
                        <i class="fa fa-angle-left"></i>
                    </a>
                

                
                    <a href="glossary.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
                        <i class="fa fa-angle-right"></i>
                    </a>
                
            </nav>

        </div>

        

        

        

        

        
        <script src="searchindex.js" type="text/javascript" charset="utf-8"></script>
        
        
        <script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
        <script src="mark.min.js" type="text/javascript" charset="utf-8"></script>
        <script src="searcher.js" type="text/javascript" charset="utf-8"></script>
        

        <script src="clipboard.min.js" type="text/javascript" charset="utf-8"></script>
        <script src="highlight.js" type="text/javascript" charset="utf-8"></script>
        <script src="book.js" type="text/javascript" charset="utf-8"></script>

        <!-- Custom JS scripts -->
        

    </body>
</html>