blob: b73ae5d0f8cf246298691d3c02dbe11641b225b3 [file] [log] [blame]
<!doctype html>
<html lang="en" class="no-js">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<link rel="icon" href="../../assets/images/favicon.png">
<meta name="generator" content="mkdocs-1.1.2, mkdocs-material-7.1.5">
<title>Model Generation (EMG) - Epsilon</title>
<link rel="stylesheet" href="../../assets/stylesheets/main.bde7dde4.min.css">
<link rel="stylesheet" href="../../assets/stylesheets/palette.ef6f36e2.min.css">
<meta name="theme-color" content="#000000">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,400i,700%7CRoboto+Mono&display=fallback">
<style>:root{--md-text-font-family:"Roboto";--md-code-font-family:"Roboto Mono"}</style>
<link rel="stylesheet" href="../../assets/stylesheets/mermaid.css">
<link rel="stylesheet" href="../../assets/javascript/google-code-prettify/prettify.css">
<link rel="stylesheet" href="https://unpkg.com/mermaid@8.5.1/dist/mermaid.css">
<link rel="stylesheet" href="../../assets/stylesheets/slick.css">
<link rel="stylesheet" href="../../assets/stylesheets/slick-theme.css">
<link rel="stylesheet" href="../../assets/stylesheets/extra.css">
<script>
window.ga = window.ga || function() {
(ga.q = ga.q || []).push(arguments)
}
ga.l = +new Date
/* Setup integration and send page view */
ga("create", "UA-184785655-1", "auto")
ga("set", "anonymizeIp", true)
ga("send", "pageview")
/* Register handler to log search on blur */
document.addEventListener("DOMContentLoaded", () => {
if (document.forms.search) {
var query = document.forms.search.query
query.addEventListener("blur", function() {
if (this.value) {
var path = document.location.pathname;
ga("send", "pageview", path + "?q=" + this.value)
}
})
}
})
</script>
<script async src="https://www.google-analytics.com/analytics.js"></script>
</head>
<body dir="ltr" data-md-color-scheme="" data-md-color-primary="black" data-md-color-accent="orange">
<script>function __prefix(e){return new URL("../..",location).pathname+"."+e}function __get(e,t=localStorage){return JSON.parse(t.getItem(__prefix(e)))}</script>
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
<label class="md-overlay" for="__drawer"></label>
<div data-md-component="skip">
<a href="#the-epsilon-model-generation-language-emg" class="md-skip">
Skip to content
</a>
</div>
<div data-md-component="announce">
</div>
<header class="md-header" data-md-component="header">
<nav class="md-header__inner md-grid" aria-label="Header">
<a href="../.." title="Epsilon" class="md-header__button md-logo" aria-label="Epsilon" data-md-component="logo">
<img src="../../assets/images/epsilon-white-background.png" alt="logo">
</a>
<label class="md-header__button md-icon" for="__drawer">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 6h18v2H3V6m0 5h18v2H3v-2m0 5h18v2H3v-2z"/></svg>
</label>
<div class="md-header__title" data-md-component="header-title">
<div class="md-header__ellipsis">
<div class="md-header__topic">
<span class="md-ellipsis">
Epsilon
</span>
</div>
<div class="md-header__topic" data-md-component="header-topic">
<span class="md-ellipsis">
Model Generation (EMG)
</span>
</div>
</div>
</div>
<label class="md-header__button md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.516 6.516 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5z"/></svg>
</label>
<div class="md-search" data-md-component="search" role="dialog">
<label class="md-search__overlay" for="__search"></label>
<div class="md-search__inner" role="search">
<form class="md-search__form" name="search">
<input type="text" class="md-search__input" name="query" aria-label="Search" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="search-query" data-md-state="active" required>
<label class="md-search__icon md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.516 6.516 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5z"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11h12z"/></svg>
</label>
<button type="reset" class="md-search__icon md-icon" aria-label="Clear" tabindex="-1">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41z"/></svg>
</button>
</form>
<div class="md-search__output">
<div class="md-search__scrollwrap" data-md-scrollfix>
<div class="md-search-result" data-md-component="search-result">
<div class="md-search-result__meta">
Initializing search
</div>
<ol class="md-search-result__list"></ol>
</div>
</div>
</div>
</div>
</div>
<div class="md-header__source">
<a href="https://git.eclipse.org/c/epsilon/org.eclipse.epsilon.git/" title="Go to repository" class="md-source" data-md-component="source">
<div class="md-source__icon md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path d="M439.55 236.05 244 40.45a28.87 28.87 0 0 0-40.81 0l-40.66 40.63 51.52 51.52c27.06-9.14 52.68 16.77 43.39 43.68l49.66 49.66c34.23-11.8 61.18 31 35.47 56.69-26.49 26.49-70.21-2.87-56-37.34L240.22 199v121.85c25.3 12.54 22.26 41.85 9.08 55a34.34 34.34 0 0 1-48.55 0c-17.57-17.6-11.07-46.91 11.25-56v-123c-20.8-8.51-24.6-30.74-18.64-45L142.57 101 8.45 235.14a28.86 28.86 0 0 0 0 40.81l195.61 195.6a28.86 28.86 0 0 0 40.8 0l194.69-194.69a28.86 28.86 0 0 0 0-40.81z"/></svg>
</div>
<div class="md-source__repository">
Git repository @ Eclipse
</div>
</a>
</div>
</nav>
</header>
<div class="md-container" data-md-component="container">
<main class="md-main" data-md-component="main">
<div class="md-main__inner md-grid">
<div class="md-sidebar md-sidebar--primary" data-md-component="sidebar" data-md-type="navigation" >
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--primary" aria-label="Navigation" data-md-level="0">
<label class="md-nav__title" for="__drawer">
<a href="../.." title="Epsilon" class="md-nav__button md-logo" aria-label="Epsilon" data-md-component="logo">
<img src="../../assets/images/epsilon-white-background.png" alt="logo">
</a>
Epsilon
</label>
<div class="md-nav__source">
<a href="https://git.eclipse.org/c/epsilon/org.eclipse.epsilon.git/" title="Go to repository" class="md-source" data-md-component="source">
<div class="md-source__icon md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path d="M439.55 236.05 244 40.45a28.87 28.87 0 0 0-40.81 0l-40.66 40.63 51.52 51.52c27.06-9.14 52.68 16.77 43.39 43.68l49.66 49.66c34.23-11.8 61.18 31 35.47 56.69-26.49 26.49-70.21-2.87-56-37.34L240.22 199v121.85c25.3 12.54 22.26 41.85 9.08 55a34.34 34.34 0 0 1-48.55 0c-17.57-17.6-11.07-46.91 11.25-56v-123c-20.8-8.51-24.6-30.74-18.64-45L142.57 101 8.45 235.14a28.86 28.86 0 0 0 0 40.81l195.61 195.6a28.86 28.86 0 0 0 40.8 0l194.69-194.69a28.86 28.86 0 0 0 0-40.81z"/></svg>
</div>
<div class="md-source__repository">
Git repository @ Eclipse
</div>
</a>
</div>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../.." class="md-nav__link">
Home
</a>
</li>
<li class="md-nav__item">
<a href="../../download/" class="md-nav__link">
Download
</a>
</li>
<li class="md-nav__item">
<a href="../../getting-started/" class="md-nav__link">
Getting Started
</a>
</li>
<li class="md-nav__item">
<a href="../../live" class="md-nav__link">
Playground
</a>
</li>
<li class="md-nav__item md-nav__item--active md-nav__item--nested">
<input class="md-nav__toggle md-toggle" data-md-toggle="__nav_5" type="checkbox" id="__nav_5" checked>
<label class="md-nav__link" for="__nav_5">
Documentation
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" aria-label="Documentation" data-md-level="1">
<label class="md-nav__title" for="__nav_5">
<span class="md-nav__icon md-icon"></span>
Documentation
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../" class="md-nav__link">
Overview
</a>
</li>
<li class="md-nav__item">
<a href="../emc/" class="md-nav__link">
Model Connectivity
</a>
</li>
<li class="md-nav__item md-nav__item--active md-nav__item--nested">
<input class="md-nav__toggle md-toggle" data-md-toggle="__nav_5_3" type="checkbox" id="__nav_5_3" checked>
<label class="md-nav__link" for="__nav_5_3">
Languages
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" aria-label="Languages" data-md-level="2">
<label class="md-nav__title" for="__nav_5_3">
<span class="md-nav__icon md-icon"></span>
Languages
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../eol/" class="md-nav__link">
Object Language (EOL)
</a>
</li>
<li class="md-nav__item">
<a href="../egl/" class="md-nav__link">
Code Generation (EGL)
</a>
</li>
<li class="md-nav__item">
<a href="../evl/" class="md-nav__link">
Model Validation (EVL)
</a>
</li>
<li class="md-nav__item">
<a href="../etl/" class="md-nav__link">
Model Transformation (ETL)
</a>
</li>
<li class="md-nav__item">
<a href="../ecl/" class="md-nav__link">
Model Comparison (ECL)
</a>
</li>
<li class="md-nav__item">
<a href="../eml/" class="md-nav__link">
Model Merging (EML)
</a>
</li>
<li class="md-nav__item">
<a href="../epl/" class="md-nav__link">
Pattern Matching (EPL)
</a>
</li>
<li class="md-nav__item">
<a href="../flock/" class="md-nav__link">
Model Migration (Flock)
</a>
</li>
<li class="md-nav__item md-nav__item--active">
<input class="md-nav__toggle md-toggle" data-md-toggle="toc" type="checkbox" id="__toc">
<label class="md-nav__link md-nav__link--active" for="__toc">
Model Generation (EMG)
<span class="md-nav__icon md-icon"></span>
</label>
<a href="./" class="md-nav__link md-nav__link--active">
Model Generation (EMG)
</a>
<nav class="md-nav md-nav--secondary">
<label class="md-nav__title" for="__toc">Table of contents</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="#approaches-to-model-generation" class="md-nav__link">
Approaches to Model Generation
</a>
</li>
<li class="md-nav__item">
<a href="#syntax" class="md-nav__link">
Syntax
</a>
<nav class="md-nav" aria-label="Syntax">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#emg-predefined-operations" class="md-nav__link">
EMG predefined operations
</a>
<nav class="md-nav" aria-label="EMG predefined operations">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#character-sets-for-string-operations" class="md-nav__link">
Character Sets for String operations
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#creating-model-elements" class="md-nav__link">
Creating Model Elements
</a>
</li>
<li class="md-nav__item">
<a href="#creating-model-links" class="md-nav__link">
Creating Model Links
</a>
</li>
<li class="md-nav__item">
<a href="#meaningful-strings" class="md-nav__link">
Meaningful Strings
</a>
<nav class="md-nav" aria-label="Meaningful Strings">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#values-as-a-parameter" class="md-nav__link">
Values as a parameter
</a>
</li>
<li class="md-nav__item">
<a href="#values-as-a-model" class="md-nav__link">
Values as a model
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../eunit/" class="md-nav__link">
Unit Testing (EUnit)
</a>
</li>
<li class="md-nav__item">
<a href="../pinset/" class="md-nav__link">
Dataset Extraction (Pinset)
</a>
</li>
<li class="md-nav__item">
<a href="../ewl/" class="md-nav__link">
Wizard Language (EWL)
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle" data-md-toggle="__nav_5_4" type="checkbox" id="__nav_5_4" >
<label class="md-nav__link" for="__nav_5_4">
Tools
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" aria-label="Tools" data-md-level="2">
<label class="md-nav__title" for="__nav_5_4">
<span class="md-nav__icon md-icon"></span>
Tools
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../picto/" class="md-nav__link">
Picto
</a>
</li>
<li class="md-nav__item">
<a href="../flexmi/" class="md-nav__link">
Flexmi
</a>
</li>
<li class="md-nav__item">
<a href="../eugenia/" class="md-nav__link">
Eugenia
</a>
</li>
<li class="md-nav__item">
<a href="../exeed/" class="md-nav__link">
Exeed
</a>
</li>
<li class="md-nav__item">
<a href="../modelink/" class="md-nav__link">
Modelink
</a>
</li>
<li class="md-nav__item">
<a href="../hutn/" class="md-nav__link">
HUTN
</a>
</li>
<li class="md-nav__item">
<a href="../workflow/" class="md-nav__link">
Workflow (Ant tasks)
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../articles/" class="md-nav__link">
Articles
</a>
</li>
<li class="md-nav__item">
<a href="../../examples/" class="md-nav__link">
Examples
</a>
</li>
<li class="md-nav__item">
<a href="https://www.youtube.com/epsilondevs" class="md-nav__link">
Screencasts
</a>
</li>
<li class="md-nav__item">
<a href="https://www.youtube.com/playlist?list=PLRwHao6Ue0YUecg7vEUQTrtySIWwrd_mI" class="md-nav__link">
Lectures
</a>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle" data-md-toggle="__nav_5_9" type="checkbox" id="__nav_5_9" >
<label class="md-nav__link" for="__nav_5_9">
Javadoc
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" aria-label="Javadoc" data-md-level="2">
<label class="md-nav__title" for="__nav_5_9">
<span class="md-nav__icon md-icon"></span>
Javadoc
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="https://download.eclipse.org/epsilon/stable-javadoc/" class="md-nav__link">
Stable
</a>
</li>
<li class="md-nav__item">
<a href="https://download.eclipse.org/epsilon/interim-javadoc/" class="md-nav__link">
Interim
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle" data-md-toggle="__nav_6" type="checkbox" id="__nav_6" >
<label class="md-nav__link" for="__nav_6">
Issues
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" aria-label="Issues" data-md-level="1">
<label class="md-nav__title" for="__nav_6">
<span class="md-nav__icon md-icon"></span>
Issues
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="https://bugs.eclipse.org/bugs/enter_bug.cgi?product=epsilon" class="md-nav__link">
Report a new issue
</a>
</li>
<li class="md-nav__item">
<a href="https://bugs.eclipse.org/bugs/buglist.cgi?product=epsilon&cmdtype=doit&order=Reuse+same+sort+as+last+time&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&bug_severity=blocker&bug_severity=critical&bug_severity=major&bug_severity=normal&bug_severity=minor&bug_severity=trivial" class="md-nav__link">
View open bugs
</a>
</li>
<li class="md-nav__item">
<a href="https://bugs.eclipse.org/bugs/buglist.cgi?product=epsilon&cmdtype=doit&order=Reuse+same+sort+as+last+time&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&bug_severity=enhancement" class="md-nav__link">
View enhancement requests
</a>
</li>
<li class="md-nav__item">
<a href="https://bugs.eclipse.org/bugs/buglist.cgi?bug_status=RESOLVED&list_id=17694438&product=epsilon&query_format=advanced" class="md-nav__link">
View issues resolved since the last stable release
</a>
</li>
<li class="md-nav__item">
<a href="https://bugs.eclipse.org/bugs/buglist.cgi?product=epsilon&cmdtype=doit&order=Reuse+same+sort+as+last+time" class="md-nav__link">
View all issues
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle" data-md-toggle="__nav_7" type="checkbox" id="__nav_7" >
<label class="md-nav__link" for="__nav_7">
Community
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" aria-label="Community" data-md-level="1">
<label class="md-nav__title" for="__nav_7">
<span class="md-nav__icon md-icon"></span>
Community
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle" data-md-toggle="__nav_7_1" type="checkbox" id="__nav_7_1" >
<label class="md-nav__link" for="__nav_7_1">
Who is using Epsilon?
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" aria-label="Who is using Epsilon?" data-md-level="2">
<label class="md-nav__title" for="__nav_7_1">
<span class="md-nav__icon md-icon"></span>
Who is using Epsilon?
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../users/" class="md-nav__link">
Industry
</a>
</li>
<li class="md-nav__item">
<a href="../../users/education/" class="md-nav__link">
Education
</a>
</li>
<li class="md-nav__item">
<a href="../../users/open-source/" class="md-nav__link">
Open-source Projects
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="https://projects.eclipse.org/projects/modeling.epsilon/who" class="md-nav__link">
Who is developing Epsilon?
</a>
</li>
<li class="md-nav__item">
<a href="https://www.eclipse.org/forums/index.php/f/22/" class="md-nav__link">
Forum
</a>
</li>
<li class="md-nav__item">
<a href="../../professional-services" class="md-nav__link">
Professional Services
</a>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle" data-md-toggle="__nav_7_5" type="checkbox" id="__nav_7_5" >
<label class="md-nav__link" for="__nav_7_5">
Social Media
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" aria-label="Social Media" data-md-level="2">
<label class="md-nav__title" for="__nav_7_5">
<span class="md-nav__icon md-icon"></span>
Social Media
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="https://twitter.com/eclipseepsilon" class="md-nav__link">
Twitter
</a>
</li>
<li class="md-nav__item">
<a href="https://youtube.com/epsilondevs" class="md-nav__link">
YouTube
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../../labs/" class="md-nav__link">
Epsilon Labs
</a>
</li>
<li class="md-nav__item">
<a href="../../faq/" class="md-nav__link">
Frequently Asked Questions
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../../branding/" class="md-nav__link">
Branding
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-sidebar md-sidebar--secondary" data-md-component="sidebar" data-md-type="toc" >
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--secondary">
<label class="md-nav__title" for="__toc">Table of contents</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="#approaches-to-model-generation" class="md-nav__link">
Approaches to Model Generation
</a>
</li>
<li class="md-nav__item">
<a href="#syntax" class="md-nav__link">
Syntax
</a>
<nav class="md-nav" aria-label="Syntax">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#emg-predefined-operations" class="md-nav__link">
EMG predefined operations
</a>
<nav class="md-nav" aria-label="EMG predefined operations">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#character-sets-for-string-operations" class="md-nav__link">
Character Sets for String operations
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#creating-model-elements" class="md-nav__link">
Creating Model Elements
</a>
</li>
<li class="md-nav__item">
<a href="#creating-model-links" class="md-nav__link">
Creating Model Links
</a>
</li>
<li class="md-nav__item">
<a href="#meaningful-strings" class="md-nav__link">
Meaningful Strings
</a>
<nav class="md-nav" aria-label="Meaningful Strings">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#values-as-a-parameter" class="md-nav__link">
Values as a parameter
</a>
</li>
<li class="md-nav__item">
<a href="#values-as-a-model" class="md-nav__link">
Values as a model
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-content" data-md-component="content">
<article class="md-content__inner md-typeset">
<h1 id="the-epsilon-model-generation-language-emg">The Epsilon Model Generation Language (EMG)<a class="headerlink" href="#the-epsilon-model-generation-language-emg" title="Permanent link">&para;</a></h1>
<p>At some point, programs written in any of the Epsilon model management languages might need to be tested in order to find defects (bugs) and assert their correctness, or benchmarked in order to assess their performance. Both testing and benchmarking activities require appropriate test data, i.e. models that conform to specific metamodels and their constraints, satisfy additional requirements or characteristics (e.g. certain size), and/or contain data and provide a structure that exercises particular aspects of the program under test.</p>
<p>Manual assembly of test models is an error prone, time and labour consuming activity. This type of activities are perfect candidates for automation. Given that it is also a model management activity, it follows that the automation can be provided by a model generation engine that can execute model generation scripts. The scripts should be written in a model generation language that allows the user to generate models that conform to specific metamodels and its arbitrarily complex constraints (e.g constraints formulated in compound first-order OCL operations), satisfy particular characteristics, and contain specific data and exhibit particular structures. The model generation engine should exhibit characteristics such as randomness, repeatability, scalability and easy parametrization. The Epsilon Model Generation Language addresses the automated generation of complex models.</p>
<h3 id="approaches-to-model-generation">Approaches to Model Generation<a class="headerlink" href="#approaches-to-model-generation" title="Permanent link">&para;</a></h3>
<p>The model generation approaches found in literature provide fully-automated behaviour. In a fully-automated approach, the tool loads the metamodel (and in some cases its constraints) and generates models that conform to the metamodel (and satisfy the constraints, if constraints are supported). However, the existing solutions can generate invalid models and in the case where constraints are supported, only simple constraints are supported.</p>
<p>The Epsilon Model Generation follows a semi-automated generation approach. There are three main tasks in model generation:</p>
<ul>
<li>
<p>Create instances of types in the metamodel(s).</p>
</li>
<li>
<p>Assign values to the instance's attributes (properties typed by primitive types: String, Integer, etc.).</p>
</li>
<li>
<p>Create links between instances to assign values to references (properties typed by complex types: other types in the metamodel).</p>
</li>
</ul>
<p>In the semi-automated approach, all of these tasks can be configured to execute statically or dynamically (with randomness). Statically, the user must specify every single aspect of the generation. Dynamically, for example, the number of instances to create of a given type can be random, or the value of a given attribute can be set to random values, or the links between elements can be done between random pairs of elements. The combination of random and static definition of the generation tasks allows the user to generate models that can satisfy complex constraints, guarantee additional characteristics and exercise particular aspects of the program under test.</p>
<p>This chapter discusses the concrete syntax of EMG as well as its execution semantics. To aid understanding, the discussion of the syntax and the semantics of the language revolves around an exemplar generation which is developed incrementally throughout the chapter.</p>
<h2 id="syntax">Syntax<a class="headerlink" href="#syntax" title="Permanent link">&para;</a></h2>
<p>The EMG language does not provide additional syntax. Instead it provides a set of predefined annotations that can be added to EOL operations and EPL patterns in order to perform the model generation. The predefined EOL operation annotations are:</p>
<table>
<thead>
<tr>
<th>Name</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>instances</td>
<td>Defines the number of instances to create. This annotation accepts one parameter. The parameter can be an expression that resolves to an Integer (e.g. literal, variable name, etc.) or a sequence in the form <code>Sequence {min, max}</code>). An integer value statically defines how many instances are to be created. A sequence defines a range that is used by the engine to generates a random number <em>n</em> of instances, with <code>min &lt;= n &lt;= max</code>.</td>
</tr>
<tr>
<td>list</td>
<td>Defines an identifier (listID) for a placeholder list for the elements created. This annotation accepts one parameter. The parameter is the identifier (String) that can later be used in operations that accept it as an argument in order to access the elements created by the operation.</td>
</tr>
<tr>
<td>parameters</td>
<td>If the instantiated type accepts/needs arguments for instantiation, the parameters annotation can be used to provide them. This annotation accepts one parameter. The parameter must be a Sequence that contains the desired arguments in the order expected by the constructor.</td>
</tr>
</tbody>
</table>
<p>All three annotations are executable and hence must be prefixed with a $ symbol when used. Further, these annotations are only evaluated on <em>create</em> operations.</p>
<p>The EPL pattern annotations are:</p>
<table>
<thead>
<tr>
<th>Name</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>number</td>
<td>This limits the number of times the pattern is matched, to constraint the number of links created between elements. This annotation accepts one parameter. The parameter can be an expression that resolves to an Integer (e.g. literal, variable name, etc.) or a sequence in the form <code>Sequence {min, max}</code>). An integer value statically defines how many instances are to be created. A sequence defines a range that is used by the engine to generates a random number <em>n</em> of instances, with <code>min &lt;= n &lt;= max</code>.</td>
</tr>
<tr>
<td>probability</td>
<td>This defines the probability that the body of the pattern will be executed for a matching set of elements. The effect is that not all matching elements are linked. Effectively this also limits the number of times links are created.</td>
</tr>
<tr>
<td>noRepeat</td>
<td>This forbids previous matched elements to be re-linked.</td>
</tr>
</tbody>
</table>
<p>The first two annotations are executable and hence must be prefixed with a <code>$</code> symbol when used and the last one is a simple annotation and must be prefixed with <code>@</code>.</p>
<p>Additionally the EMG engine provides a set of predefined operations that provide support for generating random data that can be used to set the attributes and references of the generated model elements, to select random elements from collections, etc.</p>
<h3 id="emg-predefined-operations">EMG predefined operations<a class="headerlink" href="#emg-predefined-operations" title="Permanent link">&para;</a></h3>
<table>
<thead>
<tr>
<th>Signature</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>nextAddTo(n : Integer, m : Integer): Sequence(Integer)</td>
<td>Returns a sequence of n integers who's sum is equal to m.</td>
</tr>
<tr>
<td>nextBoolean()</td>
<td>Returns the next pseudorandom, uniformly distributed <code>boolean</code> value.</td>
</tr>
<tr>
<td>nextCamelCaseWords(charSet : String, length : Integer, minWordLength : Integer) : String</td>
<td>Generates a string of the given length formatted as CamelCase, with subwords of a minimum length of the minWordLength argument, using characters from the given charSet.</td>
</tr>
<tr>
<td>nextCapitalisedWord(charSet : String, length : Integer) : String</td>
<td>Generate a Capitalized string of the given length using characters from the given charSet.</td>
</tr>
<tr>
<td>nextFromCollection(c : Sequence) : Any</td>
<td>Returns the next <code>object</code> from the collection, selected pseudoramdomly using the uniform distribution. If the collection is empty, returns null.</td>
</tr>
<tr>
<td>nextFromList(listID : String) : Any</td>
<td>Returns the next <code>object</code> from the list, selected pseudoramdomly using the uniform distribution. If the list is empty, returns null. The <em>listID</em> can either be a name defined by the \@list annotation or a parameter name from the run configuration. In the latter case, the parameter value can be either a comma separated string or a file path. If it is a comma separated string, then a list is created by splitting the string, if the value is a path, then the file will be read and each line will be treated as a list element.</td>
</tr>
<tr>
<td>nextFromListAsSample(listID : String) : Any</td>
<td>Same as nextFromList, but in this case the list is treated as a sample without replacement, i.e. each call will return a unique member of the list.</td>
</tr>
<tr>
<td>nextHttpURI(addPort : Boolean, addPath : Boolean, addQuery : Boolean, addFragment : Boolean) : String</td>
<td>Generates a random URI that complies to http:[//host[:port]][/]path [?query][#fragment]. The path, query and fragment parts are optional and will be added if the respective argument is True.</td>
</tr>
<tr>
<td>nextInt() : Integer</td>
<td>Returns the next pseudorandom, uniformly distributed integer. All <code>2^32</code> possible integer values should be produced with (approximately) equal probability.</td>
</tr>
<tr>
<td>nextInt(upper : Integer) : Integer</td>
<td>Returns a pseudorandom, uniformly distributed integer value between 0 (inclusive) and <em>upper</em> (exclusive). The argument must be positive.</td>
</tr>
<tr>
<td>nextInt(lower: Integer, upper : Integer) : Integer</td>
<td>Returns a pseudorandom, uniformly distributed integer value between lower and upper (endpoints included). The arguments must be positive and <code>upper &gt;= lower</code>.</td>
</tr>
<tr>
<td>nextReal() : Real</td>
<td>Returns the next pseudorandom, uniformly distributed <code>real</code> value between <code>0.0</code> and <code>1.0</code>.</td>
</tr>
<tr>
<td>nextReal(upper : Real) : Real</td>
<td>Returns the next pseudorandom, uniformly distributed <code>real</code> value between <code>0.0</code> and <em>upper</em> (inclusive).</td>
</tr>
<tr>
<td>nextReal(lower: Real, upper : Real) : Real</td>
<td>Returns a pseudorandom, uniformly distributed <code>real</code> value between <em>lower</em> and <em>upper</em> (endpoints included).</td>
</tr>
<tr>
<td>nextSample(c : Sequence, k : Integer) : Sequence(Any)</td>
<td>Returns a Sequence of <code>k</code> objects selected randomly from the Sequence <code>c</code> using a uniform distribution. Sampling from <code>c</code> is without replacement; but if c contains identical objects, the sample may include repeats. If all elements of <code>c</code> are distinct, the resulting object collection represents a Simple Random Sample of size <code>k</code> from the elements of <code>c</code>.</td>
</tr>
<tr>
<td>nextSample(listID : String, k : Integer) : Sequence(Any)</td>
<td>Same as nextSample but the sequence is referenced by <em>listID</em>. The <em>listID</em> has the same meanings as for operation <em>nextFromList</em>.</td>
</tr>
<tr>
<td>nextString() : String</td>
<td>Returns the next string made up from characters of the <code>LETTER</code> character set, pseudorandomly selected with a uniform distribution. The length of the string is between 4 and 10 characters.</td>
</tr>
<tr>
<td>nextString(length : Integer) : String</td>
<td>Returns the next String made up from characters of the <code>LETTER</code> character set, pseudorandomly selected with a uniform distribution. The length of the String is equal to <em>length</em>.</td>
</tr>
<tr>
<td>nextString(charSet : String, length : Integer) : String</td>
<td>Returns the next String of the given <em>length</em> using the specified character set, pseudorandomly selected with a uniform distribution.</td>
</tr>
<tr>
<td>nextURI() : String</td>
<td>Generates a random URI that complies to: scheme:[//[user:password]host[:port]][/]path [?query][#fragment]. The port, path, query and fragment are added randomly. The scheme is randomly selected from: http, ssh and ftp. For ssh and ftp, a user and pasword are randomly generated. The host is generated from a random string and uses a top-level domain. The number of paths and queries are random between 1 and 4.</td>
</tr>
<tr>
<td>nextURI(addPort : Boolean, addPath : Boolean, addQuery : Boolean, addFragment : Boolean) : String</td>
<td>Same as nextURI, but the given arguments control what additional port, path, query and fragment information is added.</td>
</tr>
<tr>
<td>nextUUID() : String</td>
<td>Returns a type 4 (pseudo randomly generated) UUID. The UUID is generated using a cryptographically strong pseudo random number generator.</td>
</tr>
<tr>
<td>nextValue() : Real</td>
<td>Returns the next pseudorandom value, picked from the configured distribution (by default the uniform distribution is used).</td>
</tr>
<tr>
<td>nextValue(d : String, p : Sequence) : Real</td>
<td>Returns the next pseudorandom, from the provided distribution <code>d</code>. The parameters <code>p</code> are used to configure the distribution (if required). The supported distributions are: Binomial, Exponential and Uniform. For Binomial parameters are: numberOfTrials and probabilityOfSuccess. For Exponential the mean. For Uniform the lower and upper values (lower inclusive).</td>
</tr>
<tr>
<td>setNextValueDistribution(d : String, p : Sequence)</td>
<td>Define the distribution to use for calls to <em>nextValue()</em>. Parameters are the same as for nextValue(d, p).</td>
</tr>
</tbody>
</table>
<h4 id="character-sets-for-string-operations">Character Sets for String operations<a class="headerlink" href="#character-sets-for-string-operations" title="Permanent link">&para;</a></h4>
<p>For the operations that accept a character set, the supported sets are
defined as follows:</p>
<table>
<thead>
<tr>
<th>Name</th>
<th>Characters</th>
</tr>
</thead>
<tbody>
<tr>
<td>ID</td>
<td>abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ 1234567890</td>
</tr>
<tr>
<td>NUMERIC</td>
<td>1234567890</td>
</tr>
<tr>
<td>LETTER</td>
<td>abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ</td>
</tr>
<tr>
<td>LETTER_UPPER</td>
<td>ABCDEFGHIJKLMNOPQRSTUVWXYZ</td>
</tr>
<tr>
<td>LETTER_LOWER</td>
<td>abcdefghijklmnopqrstuvwxyz</td>
</tr>
<tr>
<td>UPPER_NUM</td>
<td>ABCDEFGHIJKLMNOPQRSTUVWXYZ 1234567890</td>
</tr>
<tr>
<td>LOWER_NUM</td>
<td>abcdefghijklmnopqrstuvwxyz 1234567890</td>
</tr>
<tr>
<td>ID_SYMBOL</td>
<td>abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ 1234567890 ~{}!@#\$%\^&amp;( ) _+-=[] \|;': \" \&lt; > ? , . /\</td>
</tr>
<tr>
<td>HEX_LOWER</td>
<td>abcdef1234567890</td>
</tr>
<tr>
<td>HEX_UPPER</td>
<td>ABCDEF1234567890</td>
</tr>
</tbody>
</table>
<h2 id="creating-model-elements">Creating Model Elements<a class="headerlink" href="#creating-model-elements" title="Permanent link">&para;</a></h2>
<p>The EMG engine will search for EOL operations that follow a particular signature in order to determine what elements to create in the generated model. The signature is: <code>create &lt;OutputType&gt; () { ... }</code>. That is, the operation must be named <em>create</em>, the operation's context type defines the type of the created instance and no parameters should be passed. By default the create operation only creates one instance. Hence, the provided annotations can be used to tailor the behaviour of the operation.</p>
<p>Consider the case of the PetriNet metamodel in the figure below. </p>
<div class="mermaid mermaid-100">classDiagram
class Element {
+name: String
}
class Place {
+outgoing: PlaceToTransArc[*]
+incoming: TransToPlaceArc[*]
}
class PetriNet {
+places: Place[*]
+transitions: Transition[*]
+arcs: Arc[*]
}
class Transition {
+incoming: PlaceToTransArc[*]
+outgoing: TransToPlaceArc[*]
}
class TransToPlaceArc {
+source: Transition
+target: Place
}
class PlaceToTransArc {
+target: Transition
+source: Place
}
Element &lt;|-- PetriNet
Element &lt;|-- Place
Transition --|&gt; Element
PetriNet *-- Arc
PetriNet *-- Place
PetriNet *-- Transition
Arc &lt;|-- TransToPlaceArc
Arc &lt;|-- PlaceToTransArc</div>
<p>The code excerpt displayed below creates a PetriNet and then adds some places and transitions to it. Note that the instances annotation is executable and hence you can use absolute values, variables or expressions. The <code>list</code> annotation in the PetriNet creation will result in all PetriNet instances to be stored in a sequence called <em>net</em>. The list name is then used in the Place and Transition create operations to add the places and transitions to a random (<em>nextFromList</em>) PetriNet. In this example there is only one, but we could easily create more PetriNet instances and hence have them contain random number of Places and Transitions. The name of the elements is generated using the random string generation facilities.</p>
<pre class="prettyprint lang-epl"><code>pre {
var num_p = 10
}
$instances 1
@list net
operation PetriNet create() {
self.name = nextCamelCaseWords("LETTER_LOWER", 15, 10);
}
$instances num_p
operation Place create() {
self.name = "P_" + nextString("LETTER_LOWER", 15);
nextFromList("net").transitions.add(self);
}
$instances num_p / 2
operation Transition create() {
self.name = "T_" + nextString("LETTER_LOWER", 15);
nextFromList("net").transitions.add(self);
}</code></pre>
<h2 id="creating-model-links">Creating Model Links<a class="headerlink" href="#creating-model-links" title="Permanent link">&para;</a></h2>
<p>In the previous section, the <em>places</em> and <em>transitions</em> references of the PetriNet were defined during the creation of the Place and Transition elements. For more complex reference patterns, EMG leverages the use of EPL patterns. For example, Arcs can have complex constraints in order to determine the source and target transition/place, and possibly even having separate rules for each type of Arc.</p>
<p>The EPL pattern in the listing below creates two arcs in order to connect a source and a target Place via a Transition. The pattern matches all transitions in a given PetriNet. The pattern body selects a random Place for the source and a random Place for the target (the while loops are used to pick places that have the lowest incoming/outgoing arcs possible). The weight of the arc is generated randomly from 0 to 10 (<em>nextInt(10)</em>). The pattern has been annotated with the \@probability annotation which will effectively only use 70% of the transitions to create arcs (i.e. of all the possible PetriNet-Transition matches, the code of the pattern will only be executed with a probability of 0.70).</p>
<pre class="prettyprint lang-epl"><code>@probability 0.7
pattern Transition
net:PetriNet,
tra:Transition
from: net.transitions {
onmatch {
var size = 0;
var freeSources = Place.all().select(s | s.incoming.size() == size);
while (freeSources.isEmpty()) {
size += 1;
freeSources = Place.all().select(s | s.incoming.size() == size);
}
size = 0;
var freeTarget = Place.all().select(s | s.outgoing.size() == size);
while (freeTarget.isEmpty()) {
size += 1;
freeTarget = Place.all().select(s | s.outgoing.size() == size);
}
var source = nextFromCollection(freeSources);
var target = nextFromCollection(freeTarget);
var a1:Arc = new PlaceToTransArc();
a1.weight = nextInt(10);
a1.source = source;
net.places.add(source);
a1.target = tra;
net.arcs.add(a1);
var a2:Arc = new TransToPlaceArc();
a1.weight = nextInt(10);
a2.source = tra;
a2.target = target;
net.places.add(target);
net.arcs.add(a2);
}
}</code></pre>
<h2 id="meaningful-strings">Meaningful Strings<a class="headerlink" href="#meaningful-strings" title="Permanent link">&para;</a></h2>
<p>In some scenarios having completely random Strings for some of the element fields might not be desirable. In this case EMG has an embedded mechanism to facilitate the use of meaningful attribute values (not only for Strings) and we show a second approach based on additional models.</p>
<h3 id="values-as-a-parameter">Values as a parameter<a class="headerlink" href="#values-as-a-parameter" title="Permanent link">&para;</a></h3>
<p>The <em>nextFromList()</em> operation will first look for a list with that name, if it can't find it will look for a parameter (from the run configuration) with that name. The value of the parameter can be either an absolute path to a file or a comma separated list of values.</p>
<p>If it is a comma separated list of values, then the individual values will be loaded as a Collection. For example, if we added the parameter <code>names: John, Rose, Juan, Xiang, Joe</code> to the run configuration, the listing below shows how to use that information to define the instance attributes.</p>
<pre class="prettyprint lang-eol"><code>$instances num_p
operation Place create() {
self.name = nextFromList("name");
nextFromList("net").transitions.add(self);
}</code></pre>
<p>If it is a file path, then each line of the file will be loaded as an item to the Collection. Note that the distinction between paths and comma separated values is the assumption that paths don't contain commas.</p>
<h3 id="values-as-a-model">Values as a model<a class="headerlink" href="#values-as-a-model" title="Permanent link">&para;</a></h3>
<p>A more powerful approach would be to use an existing model to serve as the source for attribute values. Given that there are several websites<sup id="fnref:1"><a class="footnote-ref" href="#fn:1">1</a></sup> to generate random data in the form of CSV files, we recommend the use of a CSV model to serve as an attribute value source. A CSV file with <em>name</em>, <em>lastName</em>, and <em>email</em> can be easily generated and loaded as a second model the the EMG script. Then, a Row of data can be picked randomly to set an element's attributes. The listing below shows this approach.</p>
<pre class="prettyprint lang-eol"><code>$instances num_p
operation Person create() {
var p = nextFromCollection(dataModel.Row.all());
self.name = p.name;
self.lastName = p.lastName;
self.email = p.email;
}</code></pre>
<p>Note that in this case, by using different rows for each value you can further randomize the data.</p>
<div class="footnote">
<hr />
<ol>
<li id="fn:1">
<p>https://www.mockaroo.com/, https://www.generatedata.com/,
www.freedatagenerator.com/, etc.&#160;<a class="footnote-backref" href="#fnref:1" title="Jump back to footnote 1 in the text">&#8617;</a></p>
</li>
</ol>
</div>
</article>
</div>
</div>
</main>
<footer class="md-footer">
<div class="md-footer-nav">
<nav class="md-footer-nav__inner md-grid">
<a href="../flock/" title="Model Migration (Flock)" class="md-flex md-footer-nav__link md-footer-nav__link--prev" rel="prev">
<div class="md-flex__cell md-flex__cell--shrink">
<i class="md-icon md-icon--arrow-back md-footer-nav__button"></i>
</div>
<div class="md-flex__cell md-flex__cell--stretch md-footer-nav__title">
<span class="md-flex__ellipsis">
<span class="md-footer-nav__direction">
Previous
</span>
Model Migration (Flock)
</span>
</div>
</a>
<a href="../eunit/" title="Unit Testing (EUnit)" class="md-flex md-footer-nav__link md-footer-nav__link--next" rel="next">
<div class="md-flex__cell md-flex__cell--stretch md-footer-nav__title">
<span class="md-flex__ellipsis">
<span class="md-footer-nav__direction">
Next
</span>
Unit Testing (EUnit)
</span>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<i class="md-icon md-icon--arrow-forward md-footer-nav__button"></i>
</div>
</a>
</nav>
</div>
<div class="md-footer-meta md-typeset">
<div class="md-footer-meta__inner md-grid">
<div class="md-footer-copyright">
<div class="md-footer-copyright__highlight">
Copyright © Eclipse Foundation, Inc. All Rights Reserved.
</div>
powered by
<a href="https://www.mkdocs.org">MkDocs</a>
and
<a href="https://squidfunk.github.io/mkdocs-material/">Material for MkDocs</a>
</div>
<div class="md-footer-copyright epsilon-eclipse-links">
<ul>
<li><a href="https://www.eclipse.org/legal/privacy.php">Privacy Policy</a></li>
<li><a href="https://www.eclipse.org/legal/termsofuse.php">Terms of Use</a></li>
<li><a href="https://www.eclipse.org/legal/copyright.php">Copyright Agent</a></li>
</ul>
</div>
<div class="md-footer-social">
<a href="https://twitter.com/eclipseepsilon" target="_blank" rel="noopener" title="twitter.com" class="md-footer-social__link">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M459.37 151.716c.325 4.548.325 9.097.325 13.645 0 138.72-105.583 298.558-298.558 298.558-59.452 0-114.68-17.219-161.137-47.106 8.447.974 16.568 1.299 25.34 1.299 49.055 0 94.213-16.568 130.274-44.832-46.132-.975-84.792-31.188-98.112-72.772 6.498.974 12.995 1.624 19.818 1.624 9.421 0 18.843-1.3 27.614-3.573-48.081-9.747-84.143-51.98-84.143-102.985v-1.299c13.969 7.797 30.214 12.67 47.431 13.319-28.264-18.843-46.781-51.005-46.781-87.391 0-19.492 5.197-37.36 14.294-52.954 51.655 63.675 129.3 105.258 216.365 109.807-1.624-7.797-2.599-15.918-2.599-24.04 0-57.828 46.782-104.934 104.934-104.934 30.213 0 57.502 12.67 76.67 33.137 23.715-4.548 46.456-13.32 66.599-25.34-7.798 24.366-24.366 44.833-46.132 57.827 21.117-2.273 41.584-8.122 60.426-16.243-14.292 20.791-32.161 39.308-52.628 54.253z"/></svg>
</a>
<a href="https://youtube.com/epsilondevs" target="_blank" rel="noopener" title="youtube.com" class="md-footer-social__link">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><path d="M549.655 124.083c-6.281-23.65-24.787-42.276-48.284-48.597C458.781 64 288 64 288 64S117.22 64 74.629 75.486c-23.497 6.322-42.003 24.947-48.284 48.597-11.412 42.867-11.412 132.305-11.412 132.305s0 89.438 11.412 132.305c6.281 23.65 24.787 41.5 48.284 47.821C117.22 448 288 448 288 448s170.78 0 213.371-11.486c23.497-6.321 42.003-24.171 48.284-47.821 11.412-42.867 11.412-132.305 11.412-132.305s0-89.438-11.412-132.305zm-317.51 213.508V175.185l142.739 81.205-142.739 81.201z"/></svg>
</a>
</div>
</div>
</div>
</footer>
</div>
<div class="md-dialog" data-md-component="dialog">
<div class="md-dialog__inner md-typeset"></div>
</div>
<script id="__config" type="application/json">{"base": "../..", "features": [], "translations": {"clipboard.copy": "Copy to clipboard", "clipboard.copied": "Copied to clipboard", "search.config.lang": "en", "search.config.pipeline": "trimmer, stopWordFilter", "search.config.separator": "[\\s\\-]+", "search.placeholder": "Search", "search.result.placeholder": "Type to start searching", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.term.missing": "Missing"}, "search": "../../assets/javascripts/workers/search.d351de03.min.js", "version": null}</script>
<script src="../../assets/javascripts/bundle.a1609d9a.min.js"></script>
<script src="https://unpkg.com/mermaid@8.5.1/dist/mermaid.min.js"></script>
<script src="../../assets/javascript/mermaid.js"></script>
<script src="../../assets/javascript/jquery.js"></script>
<script src="../../assets/javascript/slick.min.js"></script>
<script src="../../assets/javascript/google-code-prettify/prettify.js"></script>
<script src="../../assets/javascript/google-code-prettify/lang-emfatic.js"></script>
<script src="../../assets/javascript/google-code-prettify/lang-epsilon.js"></script>
<script src="../../assets/javascript/google-code-prettify/prettyprint.js"></script>
<script src="../../assets/javascript/extra.js"></script>
<script src="https://w.appzi.io/w.js?token=jlv6W"></script>
</body>
</html>