;(function(burl) {
    var url = 'https://cdn.rawgit.com/anpylar/anpylar/1.1.3/anpylar.js'
    var s = document.createElement('script')
    s.type = 'text/javascript'
    s.async = true
    s.src = url
    var h = document.getElementsByTagName('head')[0]
    h.appendChild(s)
})();
###############################################################################
# Copyright 2018 The AnPyLar Team. All Rights Reserved.
# Use of this source code is governed by an MIT-style license that
# can be found in the LICENSE file at http://anpylar.com/mit-license
###############################################################################
from .app_module import AppModule
/* AppComponent's private CSS styles */
h1 {
  font-size: 1.2em;
  color: #999;
  margin-bottom: 0;
}
h2 {
  font-size: 2em;
  margin-top: 0;
  padding-top: 0;
}
nav a {
  padding: 5px 10px;
  text-decoration: none;
  margin-top: 10px;
  display: inline-block;
  background-color: #eee;
  border-radius: 4px;
}
nav a:visited, a:link {
  color: #607D8B;
}
nav a:hover {
  color: #039be5;
  background-color: #CFD8DC;
}
nav a.active {
  color: #039be5;
}


/*
Copyright 2017 Google Inc. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at http://angular.io/license
*/
<h1 {title}=title>{title}</h1>
<nav>
  <a routerLink="/dashboard" routerLinkActive="active">Dashboard</a>
  <a routerLink="/pyroes" routerLinkActive="active">Pyroes</a>
</nav>
<router-outlet></router-outlet>

<!--
Copyright 2017 Google Inc. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at http://angular.io/license
-->

<!--
Copyright 2018 The AnPyLar Team
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at http://anpylar.com/mit-license
-->
###############################################################################
# Copyright 2018 The AnPyLar Team. All Rights Reserved.
# Use of this source code is governed by an MIT-style license that
# can be found in the LICENSE file at http://anpylar.com/mit-license
###############################################################################
from anpylar import Component, html


class AppComponent(Component):

    title = 'Tour of Pyroes'

    bindings = {
        'pyroes': [],
    }

    def __init__(self):
        self.pyro_service.get_pyroes().subscribe(self.pyroes_)
###############################################################################
# Copyright 2018 The AnPyLar Team. All Rights Reserved.
# Use of this source code is governed by an MIT-style license that
# can be found in the LICENSE file at http://anpylar.com/mit-license
###############################################################################
from anpylar import Module, Http

from .app_component import AppComponent
from .app_routing import AppRouting
from .pyro_service import PyroService
from .pyro_search import PyroSearchComponent
from .pyro_search_service import PyroSearchService


if True:
    from .mock_pyroes import Pyroes
    Http.serve(Pyroes, index='pyd', url='api/pyroes/')


class AppModule(Module):

    components = AppComponent

    bindings = {}

    services = {
        'pyro_service': PyroService,
        'pyro_search': PyroSearchService,
    }

    routes = AppRouting

    def __init__(self):
        pass
###############################################################################
# Copyright 2018 The AnPyLar Team. All Rights Reserved.
# Use of this source code is governed by an MIT-style license that
# can be found in the LICENSE file at http://anpylar.com/mit-license
###############################################################################
from .dashboard import DashboardComponent
from .pyro_detail import PyroDetailComponent
from .pyroes import PyroesComponent


AppRouting = [
    {
        'path': '',
        'redirect_to': '/dashboard',
        'path_match': 'full'
    },
    {
        'path': 'dashboard',
        'component': DashboardComponent
    },
    {
        'path': 'pyroes',
        'component': PyroesComponent
    },
    {
        'path': 'detail',
        'component': PyroDetailComponent,
        'params': {'pyd': int},  # param transformation function
    },
]
#!/usr/bin/env python
# -*- coding: utf-8; py-indent-offset:4 -*-
###############################################################################
from .dashboard_component import DashboardComponent
/* DashboardComponent's private CSS styles */
[class*='col-'] {
  float: left;
  padding-right: 20px;
  padding-bottom: 20px;
}
[class*='col-']:last-of-type {
  padding-right: 0;
}
a {
  text-decoration: none;
}
*, *:after, *:before {
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
}
h3 {
  text-align: center; margin-bottom: 0;
}
h4 {
  position: relative;
}
.grid {
  margin: 0;
}
.col-1-4 {
  width: 25%;
}
.module {
  padding: 20px;
  text-align: center;
  color: #eee;
  max-height: 120px;
  min-width: 120px;
  background-color: #607D8B;
  border-radius: 2px;
}
.module:hover {
  background-color: #EEE;
  cursor: pointer;
  color: #607d8b;
}
.grid-pad {
  padding: 10px 0;
}
.grid-pad > [class*='col-']:last-of-type {
  padding-right: 20px;
}
@media (max-width: 600px) {
  .module {
    font-size: 10px;
    max-height: 75px; }
}
@media (max-width: 1024px) {
  .grid {
    margin: 0;
  }
  .module {
    min-width: 60px;
  }
}


/*
Copyright 2017 Google Inc. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at http://angular.io/license
*/
<h3>Top Pyroes</h3>
<div class="grid grid-pad">
</div>

<pyro-search></pyro-search>

<!--
Copyright 2017 Google Inc. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at http://angular.io/license
-->

<!--
Copyright 2018 The AnPyLar Team
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at http://anpylar.com/mit-license
-->
#!/usr/bin/env python
# -*- coding: utf-8; py-indent-offset:4 -*-
###############################################################################
from anpylar import Component, html


class DashboardComponent(Component):

    def loading(self):
        self.pyro_service.get_pyroes().subscribe(self.pyroes_)

    def unloading(self):
        self.pyroes_ = []

    def render(self, node):
        with node.select('div') as d:
            d._render(self.render_top_pyroes, self.pyroes_)

    def render_top_pyroes(self, pyroes):
        for p in pyroes[:4]:
            with html.a(Class='col-1-4',
                        routerlink=('/detail', {'pyd': p.pyd})):

                with html.div(Class='module pyro'):
                    html.h4('{name}')._fmt(name=p.name_)
###############################################################################
# Copyright 2018 The AnPyLar Team. All Rights Reserved.
# Use of this source code is governed by an MIT-style license that
# can be found in the LICENSE file at http://anpylar.com/mit-license
###############################################################################

Pyroes = [
    {'pyd': 11, 'name': 'Pyro Nakamura'},
    {'pyd': 12, 'name': 'Mopynder Shuresh'},
    {'pyd': 13, 'name': 'Pyter Pytrelli'},
    {'pyd': 14, 'name': 'Angela Pytrelli'},
    {'pyd': 15, 'name': 'Claire Pynnet'},
    {'pyd': 16, 'name': 'Noah Pynnet'},
    {'pyd': 17, 'name': 'Pysaac Mendez'},
    {'pyd': 18, 'name': 'Pyki Sanders'},
    {'pyd': 19, 'name': 'The Pytian'},
    {'pyd': 20, 'name': 'Pylar'},
]
###############################################################################
# Copyright 2018 The AnPyLar Team. All Rights Reserved.
# Use of this source code is governed by an MIT-style license that
# can be found in the LICENSE file at http://anpylar.com/mit-license
###############################################################################
from .pyro_detail_component import PyroDetailComponent
/* PyroDetailComponent's private CSS styles */
label {
  display: inline-block;
  width: 3em;
  margin: .5em 0;
  color: #607D8B;
  font-weight: bold;
}
input {
  height: 2em;
  font-size: 1em;
  padding-left: .4em;
}
button {
  margin-top: 20px;
  font-family: Arial;
  background-color: #eee;
  border: none;
  padding: 5px 10px;
  border-radius: 4px;
  cursor: pointer; cursor: hand;
}
button:hover {
  background-color: #cfd8dc;
}
button:disabled {
  background-color: #eee;
  color: #ccc;
  cursor: auto;
}


/*
Copyright 2017 Google Inc. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at http://angular.io/license
*/

/*
Copyright 2018 The AnPyLar Team
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at http://anpylar.com/mit-license
*/
<div *_display=pyro_.pyd_>
  <h2 {name}="pyro_.name_.map(lambda x: x.upper())">{name} Details</h2>
  <div><span>pyd: </span><txt [pyro_.pyd_]>{}</txt></div>
  <div>
      <label>name:
        <input *_fmtvalue=pyro_.name_ placeholder="name"/>
      </label>
  </div>
  <button (click)="router.back()", name="cancel">Go back</button>
  <button (click)="save()", name="save">Save</button>
</div>

<!--
Copyright 2017 Google Inc. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at http://angular.io/license
-->

<!--
Copyright 2018 The AnPyLar Team
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at http://anpylar.com/mit-license
-->
###############################################################################
# Copyright 2018 The AnPyLar Team. All Rights Reserved.
# Use of this source code is governed by an MIT-style license that
# can be found in the LICENSE file at http://anpylar.com/mit-license
###############################################################################
from anpylar import Component, html

from app.pyro import Pyro


class PyroDetailComponent(Component):
    bindings = {
        'pyro': Pyro(),
    }

    def loading(self):
        self.pyro_service \
            .get_pyro(self.params.get('pyd', 0)) \
            .subscribe(self.pyro_)  # fetch async and fire self.pyro_ when done

    def unloading(self):
        self.pyro = Pyro()  # clear the editor on unloading: set null Pyro

    def render(self, node):
        pass  # the entire work is done in the html rendering

    def save(self):
        self.pyro_service.update_pyro(self.pyro) \
            .subscribe(lambda x: self.router.back())
###############################################################################
# Copyright 2018 The AnPyLar Team. All Rights Reserved.
# Use of this source code is governed by an MIT-style license that
# can be found in the LICENSE file at http://anpylar.com/mit-license
###############################################################################
from anpylar import http, Observable

from .pyro import Pyro

import json


class PyroSearchService:
    def __init__(self):
        self.http = http.Http(
            url='api/pyroes/',
            headers={'Content-Type': 'application/json'},
        )

    def search(self, term):
        return self.http.get(data={'name': term}) \
            .map(lambda x: [Pyro(**p), for p in json.loads(x)])
#!/usr/bin/env python
# -*- coding: utf-8; py-indent-offset:4 -*-
###############################################################################
from .pyro_search_component import PyroSearchComponent
.search-result li {
  border-bottom: 1px solid gray;
  border-left: 1px solid gray;
  border-right: 1px solid gray;
  width:195px;
  height: 16px;
  padding: 5px;
  background-color: white;
  cursor: pointer;
  list-style-type: none;
}

.search-result li:hover {
  background-color: #607D8B;
}

.search-result li a {
  color: #888;
  display: block;
  text-decoration: none;
}

.search-result li a:hover {
  color: white;
}
.search-result li a:active {
  color: white;
}
#search-box {
  width: 200px;
  height: 20px;
}

ul.search-result {
  margin-top: 0;
  padding-left: 0;
}

/*
Copyright 2017 Google Inc. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at http://angular.io/license
*/
<div id="search-component">
  <h4>Pyro Search</h4>

  <input id="search-box" *_fmtvalue="searchterm_"/>

  <ul class="search-result">
  </ul>
</div>


<!--
Copyright 2017 Google Inc. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at http://angular.io/license
-->

<!--
Copyright 2018 The AnPyLar Team
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at http://anpylar.com/mit-license
-->
###############################################################################
# Copyright 2018 The AnPyLar Team. All Rights Reserved.
# Use of this source code is governed by an MIT-style license that
# can be found in the LICENSE file at http://anpylar.com/mit-license
###############################################################################
from anpylar import Component, html


class PyroSearchComponent(Component):
    selector = 'pyro-search'

    bindings = {
        'pyroes': [],
        'searchterm': '',
    }

    services = {}

    def __init__(self):
        # connect searchterm to the found pyroes to be displayed
        self.searchterm_ \
            .debounce(300) \
            .distinct_until_changed() \
            .switch_map(lambda x: self.pyro_search.search(x) if x else []) \
            .catch_exception(lambda e: print('search error:', e) or []) \
            .subscribe(self.pyroes_)

    def unloading(self):
        self.pyroes = []  # clear result
        self.searchterm = ''  # clear search box

    def render(self, node):

        def sought_pyroes(pyroes):
            for p in pyroes:
                with html.li() as li:  # per-pyro list item
                    # per-pyro anchor routing path with parameter pyd
                    html.a(p.name, routerlink=('/detail', {'pyd': p.pyd}))

        with node.select('ul') as ul:
            ul._render(sought_pyroes, self.pyroes_)
###############################################################################
# Copyright 2018 The AnPyLar Team. All Rights Reserved.
# Use of this source code is governed by an MIT-style license that
# can be found in the LICENSE file at http://anpylar.com/mit-license
###############################################################################
from anpylar import Observable, http

from .pyro import Pyro

import json


class PyroService:

    def __init__(self):
        self.http = http.Http(
            url='api/pyroes/',
            headers={'Content-Type': 'application/json'},
        )

    def handle_error(self, e, retval=False):
        print(e)
        return retval

    def get_pyroes(self):
        return self.http.get() \
            .map(lambda x: [Pyro(**p), for p in json.loads(x)]) \
            .catch_exception(lambda e: self.handle_error(e, []))

    def get_pyro(self, pyd):
        return self.http.get(url='{}'.format(pyd)) \
            .map(lambda x: Pyro(**json.loads(x))) \
            .catch_exception(lambda e: self.handle_error(e, Pyro()))

    def update_pyro(self, pyro):
        return self.http.put(url='{}'.format(pyro.pyd),
                             data=json.dumps({'name': pyro.name})) \
            .catch_exception(lambda e: self.handle_error(e))

    def delete_pyro(self, pyd):
        return self.http.delete(url='{}'.format(pyd)) \
            .catch_exception(lambda e: self.handle_error(e))

    def add_pyro(self, name):
        return self.http.post(data=json.dumps({'name': name})) \
            .map(lambda x: Pyro(**json.loads(x))) \
            .catch_exception(lambda e: self.handle_error(e))
###############################################################################
# Copyright 2018 The AnPyLar Team. All Rights Reserved.
# Use of this source code is governed by an MIT-style license that
# can be found in the LICENSE file at http://anpylar.com/mit-license
###############################################################################
from anpylar import Model


class Pyro(Model):
    bindings = {
        'pyd': 0,
        'name': '',
    }
###############################################################################
# Copyright 2018 The AnPyLar Team. All Rights Reserved.
# Use of this source code is governed by an MIT-style license that
# can be found in the LICENSE file at http://anpylar.com/mit-license
###############################################################################
from .pyroes_component import PyroesComponent
/* PyroesComponent's private CSS styles */
.pyroes {
  margin: 0 0 2em 0;
  list-style-type: none;
  padding: 0;
  width: 15em;
}
.pyroes li {
  position: relative;
  cursor: pointer;
  background-color: #EEE;
  margin: .5em;
  padding: .3em 0;
  height: 1.6em;
  border-radius: 4px;
}

.pyroes li:hover {
  color: #607D8B;
  background-color: #DDD;
  left: .1em;
}

.pyroes a {
  color: #888;
  text-decoration: none;
  position: relative;
  display: block;
  width: 250px;
}

.pyroes a:hover {
  color:#607D8B;
}

.pyroes .badge {
  display: inline-block;
  font-size: small;
  color: white;
  padding: 0.8em 0.7em 0 0.7em;
  background-color: #607D8B;
  line-height: 1em;
  position: relative;
  left: -1px;
  top: -4px;
  height: 1.8em;
  min-width: 16px;
  text-align: right;
  margin-right: .8em;
  border-radius: 4px 0 0 4px;
}

.button {
  background-color: #eee;
  border: none;
  padding: 5px 10px;
  border-radius: 4px;
  cursor: pointer;
  cursor: hand;
  font-family: Arial;
}

button:hover {
  background-color: #cfd8dc;
}

button.delete {
  position: relative;
  left: 194px;
  top: -32px;
  background-color: gray !important;
  color: white;
}

/*
Copyright 2017 Google Inc. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at http://angular.io/license
*/

/*
Copyright 2018 The AnPyLar Team
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at http://anpylar.com/mit-license
*/
<h2>My Pyroes</h2>
<div>
  <label>Pyro name:
    <input *_fmtvalue="pyro_name_" />  <!-- bidirectional binding to pyro_name_ -->
  </label>
  <!-- (click) passes input value to add() and then clears the input -->
  <button (click)="pyro_add()">  <!-- pyro_add uses the pyro_name_ binding -->
    Add
  </button>
</div>

<ul class="pyroes">
</ul>

<!--
Copyright 2017 Google Inc. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at http://angular.io/license
-->

<!--
Copyright 2018 The AnPyLar Team
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at http://anpylar.com/mit-license
-->
###############################################################################
# Copyright 2018 The AnPyLar Team. All Rights Reserved.
# Use of this source code is governed by an MIT-style license that
# can be found in the LICENSE file at http://anpylar.com/mit-license
###############################################################################
from anpylar import Component, html


class PyroesComponent(Component):

    bindings = {
        'pyro_name': '',
    }

    def loading(self):
        self.pyro_service.get_pyroes().subscribe(self.pyroes_)

    def unloading(self):
        self.pyroes_ = []

    def render(self, node):
        # render under ul in render_pyroes when observable self.pyroes_ fires
        with node.select('ul') as ul:  # find node where to display the list
            ul._render(self.render_pyroes, self.pyroes_)

    def render_pyroes(self, pyroes):
        for pyro in pyroes:
            with html.li() as li:  # per-pyro list item
                # per-pyro anchor routing path with parameter pyd
                with html.a(routerlink=('/detail', {'pyd': pyro.pyd})):
                    html.span(pyro.pyd, Class='badge')  # show pyd as badge
                    html.txt(' {name}')._fmt(name=pyro.name_)  # obs name_

                with html.button('x', Class='delete') as b:
                    # def param avoids closure using last pyro.pyd
                    def pyro_delete(evt, pyd=pyro.pyd):
                        evt.stopPropagation()  # avoid evt clicking on "a"
                        self.pyro_delete(pyd)

                    b._bind.click(pyro_delete)  # use "bind" to get event

    def pyro_add(self):
        self.pyro_service.add_pyro(self.pyro_name).subscribe(
            lambda pyro: self.pyroes_(self.pyroes + [pyro])
        )

        self.pyro_name_ = ''

    def pyro_delete(self, pyd):
        self.pyro_service.delete_pyro(pyd) \
            .subscribe(
                lambda x: self.pyroes_([x for x in self.pyroes if x.pyd != pyd])
            )
<!DOCTYPE html>
<html>
<head>
  <title>Tour of Pyroes</title>

  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">

  <link rel="stylesheet" href="styles.css">
  <script src="anpylar_overlay.js"></script>
  <script src="anpylar.js"></script>

</head>
<body></body>
</html>

<!--
Copyright 2018 The AnPyLar Team
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at http://anpylar.com/mit-license
-->
{
    "packages": [
        "app"
    ],
    "app_name": "",
    "version": "",
    "author": "",
    "author_email": "",
    "license": "",
    "url": ""
}
/* Master Styles */
h1 {
  color: #369;
  font-family: Arial, Helvetica, sans-serif;
  font-size: 250%;
}
h2, h3 {
  color: #444;
  font-family: Arial, Helvetica, sans-serif;
  font-weight: lighter;
}
body {
  margin: 2em;
}
body, input[text], button {
  color: #888;
  font-family: Cambria, Georgia;
}
a {
  cursor: pointer;
  cursor: hand;
}
button {
  font-family: Arial;
  background-color: #eee;
  border: none;
  padding: 5px 10px;
  border-radius: 4px;
  cursor: pointer;
  cursor: hand;
}
button:hover {
  background-color: #cfd8dc;
}
button:disabled {
  background-color: #eee;
  color: #aaa;
  cursor: auto;
}

/* Navigation link styles */
nav a {
  padding: 5px 10px;
  text-decoration: none;
  margin-right: 10px;
  margin-top: 10px;
  display: inline-block;
  background-color: #eee;
  border-radius: 4px;
}
nav a:visited, a:link {
  color: #607D8B;
}
nav a:hover {
  color: #039be5;
  background-color: #CFD8DC;
}
nav a.active {
  color: #039be5;
}

/* everywhere else */
* {
  font-family: Arial, Helvetica, sans-serif;
}


/*
Copyright 2017 Google Inc. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at http://angular.io/license
*/
;(function(){
    function add_overlay() {

        var elem = document.createElement('div');
        elem.id = 'anpylar-loading-overlay'
        elem.style.cssText = 'position: fixed; width: 100%; height: 100%;' + 'min-height: 100%;' +
            'left: 0;top: 0;background: rgba(224,224,224,0.33); z-index: 100000;'
        document.body.appendChild(elem);

        var elem4 = document.createElement('div');
        elem4.innerHTML = '<h1 style="text-align:center;position:relative;top:46%;transform:translateY(-46%);">Loading ...</h1>'
        elem4.style.cssText = 'position: fixed; width: 100%; height: 100%;' +
            'left: 0;top: 0; z-index: 10002;'
        elem.appendChild(elem4)

        var keyframes = '\
#anpylar-loading-wheel {\
  position: fixed;\
  top: 50%;\
  left: 50%;\
  width: 150px;\
  height: 150px;\
  margin: -75px 0 0 -75px;\
  border: 16px solid #f3f3f3;\
  border-radius: 50%;\
  border-top: 16px solid #3498db;\
  width: 120px;\
  height: 120px;\
  animation: spin 2s linear infinite;\
  z-index: 10001;\
}\
\
@keyframes spin {\
  0% { transform: rotate(0deg); }\
  100% { transform: rotate(360deg); }\
}';

        var elem2 = document.createElement('style');
        elem2.style.type = 'text/css'
        elem2.id = 'anpylar-loading-overlay-style'
        elem2.innerHTML = keyframes
        document.head.appendChild(elem2)

        var elem3 = document.createElement('div')
        elem3.id = 'anpylar-loading-wheel'
        elem.appendChild(elem3)
    }
    window.addEventListener('DOMContentLoaded', add_overlay, true)
})();