├── .gitignore ├── .idea ├── $CACHE_FILE$ ├── .gitignore ├── dataSources.xml ├── dictionaries │ └── mkennedy.xml ├── inspectionProfiles │ └── profiles_settings.xml ├── misc.xml ├── modules.xml ├── ten-tips-python-web-devs.iml ├── vagrant.xml └── vcs.xml ├── LICENSE ├── README.md ├── code ├── data │ └── pypi-top-100 │ │ ├── amqp.json │ │ ├── appdirs.json │ │ ├── argparse.json │ │ ├── asn1crypto.json │ │ ├── awscli-cwlogs.json │ │ ├── awscli.json │ │ ├── babel.json │ │ ├── beautifulsoup4.json │ │ ├── boto.json │ │ ├── boto3.json │ │ ├── botocore.json │ │ ├── certifi.json │ │ ├── cffi.json │ │ ├── chardet.json │ │ ├── click.json │ │ ├── colorama.json │ │ ├── coverage.json │ │ ├── cryptography.json │ │ ├── cython.json │ │ ├── decorator.json │ │ ├── django.json │ │ ├── docopt.json │ │ ├── docutils.json │ │ ├── elasticsearch.json │ │ ├── enum34.json │ │ ├── flake8.json │ │ ├── flask.json │ │ ├── funcsigs.json │ │ ├── functools32.json │ │ ├── future.json │ │ ├── futures.json │ │ ├── gevent.json │ │ ├── greenlet.json │ │ ├── gunicorn.json │ │ ├── httplib2.json │ │ ├── idna.json │ │ ├── ipaddress.json │ │ ├── ipython.json │ │ ├── itsdangerous.json │ │ ├── jinja2.json │ │ ├── jmespath.json │ │ ├── jsonschema.json │ │ ├── kombu.json │ │ ├── lxml.json │ │ ├── markupsafe.json │ │ ├── mccabe.json │ │ ├── mock.json │ │ ├── nose.json │ │ ├── numpy.json │ │ ├── oauth2client.json │ │ ├── packaging.json │ │ ├── pandas.json │ │ ├── paramiko.json │ │ ├── pbr.json │ │ ├── pep8.json │ │ ├── pexpect.json │ │ ├── pillow.json │ │ ├── pip.json │ │ ├── protobuf.json │ │ ├── psutil.json │ │ ├── psycopg2.json │ │ ├── ptyprocess.json │ │ ├── py.json │ │ ├── pyasn1-modules.json │ │ ├── pyasn1.json │ │ ├── pycodestyle.json │ │ ├── pycparser.json │ │ ├── pycrypto.json │ │ ├── pyflakes.json │ │ ├── pygments.json │ │ ├── pyopenssl.json │ │ ├── pyparsing.json │ │ ├── pytest-runner.json │ │ ├── pytest.json │ │ ├── python-dateutil.json │ │ ├── pytz.json │ │ ├── pyyaml.json │ │ ├── redis.json │ │ ├── requests.json │ │ ├── rsa.json │ │ ├── s3transfer.json │ │ ├── scipy.json │ │ ├── selenium.json │ │ ├── setuptools.json │ │ ├── simplejson.json │ │ ├── singledispatch.json │ │ ├── six.json │ │ ├── sqlalchemy.json │ │ ├── tornado.json │ │ ├── urllib3.json │ │ ├── vcversioner.json │ │ ├── virtualenv.json │ │ ├── websocket-client.json │ │ ├── werkzeug.json │ │ ├── wheel.json │ │ └── wrapt.json ├── ex01_html_forms │ ├── extras │ │ ├── form.css │ │ ├── form_hook.js │ │ └── site.css │ └── index.html ├── ex02_ngrok │ └── pypi_org │ │ ├── app.py │ │ ├── data │ │ ├── __all_models.py │ │ ├── __init__.py │ │ ├── auditing.py │ │ ├── db_session.py │ │ ├── downloads.py │ │ ├── languages.py │ │ ├── licenses.py │ │ ├── maintainers.py │ │ ├── modelbase.py │ │ ├── package.py │ │ ├── packages.py │ │ ├── releases.py │ │ └── users.py │ │ ├── db │ │ ├── placeholder.txt │ │ └── pypi.sqlite │ │ ├── infrastructure │ │ └── view_modifiers.py │ │ ├── services │ │ ├── cms_service.py │ │ └── package_service.py │ │ ├── static │ │ ├── css │ │ │ ├── nav.css │ │ │ └── site.css │ │ └── img │ │ │ ├── blue-cube.svg │ │ │ ├── favicon.png │ │ │ ├── pypi-logo.svg │ │ │ └── white-cube.svg │ │ ├── templates │ │ ├── cms │ │ │ └── page.html │ │ ├── home │ │ │ ├── about.html │ │ │ └── index.html │ │ ├── packages │ │ │ └── details.html │ │ └── shared │ │ │ └── _layout.html │ │ └── views │ │ ├── account_views.py │ │ ├── cms_views.py │ │ ├── home_views.py │ │ └── package_views.py ├── ex03_async_core │ └── program.py ├── ex04_async_web │ ├── app.py │ ├── config │ │ ├── dev.json │ │ ├── prod.json │ │ └── settings.py │ ├── services │ │ ├── event_service.py │ │ ├── location_service.py │ │ ├── sun_service.py │ │ └── weather_service.py │ └── views │ │ ├── city_api.py │ │ └── home.py ├── ex05_migrations │ ├── alembic.ini │ ├── alembic │ │ ├── README │ │ ├── env.py │ │ └── script.py.mako │ ├── pypi_org │ │ ├── __init__.py │ │ ├── app.py │ │ ├── data │ │ │ ├── __all_models.py │ │ │ ├── __init__.py │ │ │ ├── db_session.py │ │ │ ├── downloads.py │ │ │ ├── languages.py │ │ │ ├── licenses.py │ │ │ ├── maintainers.py │ │ │ ├── modelbase.py │ │ │ ├── package.py │ │ │ ├── releases.py │ │ │ └── users.py │ │ ├── db │ │ │ ├── __init__.py │ │ │ ├── placeholder.txt │ │ │ └── pypi.sqlite │ │ ├── infrastructure │ │ │ ├── __init__.py │ │ │ └── view_modifiers.py │ │ ├── services │ │ │ ├── __init__.py │ │ │ ├── cms_service.py │ │ │ ├── package_service.py │ │ │ └── user_service.py │ │ ├── static │ │ │ ├── css │ │ │ │ ├── nav.css │ │ │ │ └── site.css │ │ │ └── img │ │ │ │ ├── blue-cube.svg │ │ │ │ ├── favicon.png │ │ │ │ ├── pypi-logo.svg │ │ │ │ └── white-cube.svg │ │ ├── templates │ │ │ ├── cms │ │ │ │ └── page.html │ │ │ ├── home │ │ │ │ ├── about.html │ │ │ │ └── index.html │ │ │ ├── packages │ │ │ │ └── details.html │ │ │ └── shared │ │ │ │ └── _layout.html │ │ └── views │ │ │ ├── __init__.py │ │ │ ├── account_views.py │ │ │ ├── cms_views.py │ │ │ ├── home_views.py │ │ │ └── package_views.py │ └── setup.py ├── ex06_vue │ └── movie_exploder │ │ ├── css │ │ ├── bootstrap │ │ │ ├── css │ │ │ │ ├── bootstrap-grid.css │ │ │ │ ├── bootstrap-grid.min.css │ │ │ │ ├── bootstrap-reboot.css │ │ │ │ ├── bootstrap-reboot.min.css │ │ │ │ ├── bootstrap.css │ │ │ │ └── bootstrap.min.css │ │ │ └── js │ │ │ │ ├── bootstrap.bundle.js │ │ │ │ ├── bootstrap.bundle.min.js │ │ │ │ ├── bootstrap.js │ │ │ │ └── bootstrap.min.js │ │ ├── dropdown.css │ │ └── site.css │ │ ├── js │ │ ├── dropdown.js │ │ ├── fake_data.js │ │ ├── site.js │ │ └── vue │ │ │ ├── README.md │ │ │ ├── vue.common.dev.js │ │ │ ├── vue.common.js │ │ │ ├── vue.common.prod.js │ │ │ ├── vue.esm.browser.js │ │ │ ├── vue.esm.browser.min.js │ │ │ ├── vue.esm.js │ │ │ ├── vue.js │ │ │ ├── vue.min.js │ │ │ ├── vue.runtime.common.dev.js │ │ │ ├── vue.runtime.common.js │ │ │ ├── vue.runtime.common.prod.js │ │ │ ├── vue.runtime.esm.js │ │ │ ├── vue.runtime.js │ │ │ └── vue.runtime.min.js │ │ ├── node_modules │ │ └── vue │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── package.json │ │ │ ├── src │ │ │ ├── compiler │ │ │ │ ├── codeframe.js │ │ │ │ ├── codegen │ │ │ │ │ ├── events.js │ │ │ │ │ └── index.js │ │ │ │ ├── create-compiler.js │ │ │ │ ├── directives │ │ │ │ │ ├── bind.js │ │ │ │ │ ├── index.js │ │ │ │ │ ├── model.js │ │ │ │ │ └── on.js │ │ │ │ ├── error-detector.js │ │ │ │ ├── helpers.js │ │ │ │ ├── index.js │ │ │ │ ├── optimizer.js │ │ │ │ ├── parser │ │ │ │ │ ├── entity-decoder.js │ │ │ │ │ ├── filter-parser.js │ │ │ │ │ ├── html-parser.js │ │ │ │ │ ├── index.js │ │ │ │ │ └── text-parser.js │ │ │ │ └── to-function.js │ │ │ ├── core │ │ │ │ ├── components │ │ │ │ │ ├── index.js │ │ │ │ │ └── keep-alive.js │ │ │ │ ├── config.js │ │ │ │ ├── global-api │ │ │ │ │ ├── assets.js │ │ │ │ │ ├── extend.js │ │ │ │ │ ├── index.js │ │ │ │ │ ├── mixin.js │ │ │ │ │ └── use.js │ │ │ │ ├── index.js │ │ │ │ ├── observer │ │ │ │ │ ├── array.js │ │ │ │ │ ├── dep.js │ │ │ │ │ ├── index.js │ │ │ │ │ ├── scheduler.js │ │ │ │ │ ├── traverse.js │ │ │ │ │ └── watcher.js │ │ │ │ ├── util │ │ │ │ │ ├── debug.js │ │ │ │ │ ├── env.js │ │ │ │ │ ├── error.js │ │ │ │ │ ├── index.js │ │ │ │ │ ├── lang.js │ │ │ │ │ ├── next-tick.js │ │ │ │ │ ├── options.js │ │ │ │ │ ├── perf.js │ │ │ │ │ └── props.js │ │ │ │ └── vdom │ │ │ │ │ ├── create-component.js │ │ │ │ │ ├── create-element.js │ │ │ │ │ ├── create-functional-component.js │ │ │ │ │ ├── helpers │ │ │ │ │ ├── extract-props.js │ │ │ │ │ ├── get-first-component-child.js │ │ │ │ │ ├── index.js │ │ │ │ │ ├── is-async-placeholder.js │ │ │ │ │ ├── merge-hook.js │ │ │ │ │ ├── normalize-children.js │ │ │ │ │ ├── normalize-scoped-slots.js │ │ │ │ │ ├── resolve-async-component.js │ │ │ │ │ └── update-listeners.js │ │ │ │ │ ├── modules │ │ │ │ │ ├── directives.js │ │ │ │ │ ├── index.js │ │ │ │ │ └── ref.js │ │ │ │ │ ├── patch.js │ │ │ │ │ └── vnode.js │ │ │ ├── platforms │ │ │ │ ├── web │ │ │ │ │ ├── compiler │ │ │ │ │ │ ├── directives │ │ │ │ │ │ │ ├── html.js │ │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ │ ├── model.js │ │ │ │ │ │ │ └── text.js │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── modules │ │ │ │ │ │ │ ├── class.js │ │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ │ ├── model.js │ │ │ │ │ │ │ └── style.js │ │ │ │ │ │ ├── options.js │ │ │ │ │ │ └── util.js │ │ │ │ │ ├── entry-compiler.js │ │ │ │ │ ├── entry-runtime-with-compiler.js │ │ │ │ │ ├── entry-runtime.js │ │ │ │ │ ├── entry-server-basic-renderer.js │ │ │ │ │ ├── entry-server-renderer.js │ │ │ │ │ ├── runtime │ │ │ │ │ │ ├── class-util.js │ │ │ │ │ │ ├── components │ │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ │ ├── transition-group.js │ │ │ │ │ │ │ └── transition.js │ │ │ │ │ │ ├── directives │ │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ │ ├── model.js │ │ │ │ │ │ │ └── show.js │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── modules │ │ │ │ │ │ │ ├── attrs.js │ │ │ │ │ │ │ ├── class.js │ │ │ │ │ │ │ ├── dom-props.js │ │ │ │ │ │ │ ├── events.js │ │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ │ ├── style.js │ │ │ │ │ │ │ └── transition.js │ │ │ │ │ │ ├── node-ops.js │ │ │ │ │ │ ├── patch.js │ │ │ │ │ │ └── transition-util.js │ │ │ │ │ ├── server │ │ │ │ │ │ ├── compiler.js │ │ │ │ │ │ ├── directives │ │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ │ ├── model.js │ │ │ │ │ │ │ └── show.js │ │ │ │ │ │ ├── modules │ │ │ │ │ │ │ ├── attrs.js │ │ │ │ │ │ │ ├── class.js │ │ │ │ │ │ │ ├── dom-props.js │ │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ │ └── style.js │ │ │ │ │ │ └── util.js │ │ │ │ │ └── util │ │ │ │ │ │ ├── attrs.js │ │ │ │ │ │ ├── class.js │ │ │ │ │ │ ├── compat.js │ │ │ │ │ │ ├── element.js │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ └── style.js │ │ │ │ └── weex │ │ │ │ │ ├── compiler │ │ │ │ │ ├── directives │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ └── model.js │ │ │ │ │ ├── index.js │ │ │ │ │ └── modules │ │ │ │ │ │ ├── append.js │ │ │ │ │ │ ├── class.js │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── props.js │ │ │ │ │ │ ├── recycle-list │ │ │ │ │ │ ├── component-root.js │ │ │ │ │ │ ├── component.js │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── recycle-list.js │ │ │ │ │ │ ├── text.js │ │ │ │ │ │ ├── v-bind.js │ │ │ │ │ │ ├── v-for.js │ │ │ │ │ │ ├── v-if.js │ │ │ │ │ │ ├── v-on.js │ │ │ │ │ │ └── v-once.js │ │ │ │ │ │ └── style.js │ │ │ │ │ ├── entry-compiler.js │ │ │ │ │ ├── entry-framework.js │ │ │ │ │ ├── entry-runtime-factory.js │ │ │ │ │ ├── runtime │ │ │ │ │ ├── components │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── richtext.js │ │ │ │ │ │ ├── transition-group.js │ │ │ │ │ │ └── transition.js │ │ │ │ │ ├── directives │ │ │ │ │ │ └── index.js │ │ │ │ │ ├── index.js │ │ │ │ │ ├── modules │ │ │ │ │ │ ├── attrs.js │ │ │ │ │ │ ├── class.js │ │ │ │ │ │ ├── events.js │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── style.js │ │ │ │ │ │ └── transition.js │ │ │ │ │ ├── node-ops.js │ │ │ │ │ ├── patch.js │ │ │ │ │ ├── recycle-list │ │ │ │ │ │ ├── render-component-template.js │ │ │ │ │ │ └── virtual-component.js │ │ │ │ │ └── text-node.js │ │ │ │ │ └── util │ │ │ │ │ ├── element.js │ │ │ │ │ ├── index.js │ │ │ │ │ └── parser.js │ │ │ ├── server │ │ │ │ ├── bundle-renderer │ │ │ │ │ ├── create-bundle-renderer.js │ │ │ │ │ ├── create-bundle-runner.js │ │ │ │ │ └── source-map-support.js │ │ │ │ ├── create-basic-renderer.js │ │ │ │ ├── create-renderer.js │ │ │ │ ├── optimizing-compiler │ │ │ │ │ ├── codegen.js │ │ │ │ │ ├── index.js │ │ │ │ │ ├── modules.js │ │ │ │ │ ├── optimizer.js │ │ │ │ │ └── runtime-helpers.js │ │ │ │ ├── render-context.js │ │ │ │ ├── render-stream.js │ │ │ │ ├── render.js │ │ │ │ ├── template-renderer │ │ │ │ │ ├── create-async-file-mapper.js │ │ │ │ │ ├── index.js │ │ │ │ │ ├── parse-template.js │ │ │ │ │ └── template-stream.js │ │ │ │ ├── util.js │ │ │ │ ├── webpack-plugin │ │ │ │ │ ├── client.js │ │ │ │ │ ├── server.js │ │ │ │ │ └── util.js │ │ │ │ └── write.js │ │ │ ├── sfc │ │ │ │ └── parser.js │ │ │ └── shared │ │ │ │ ├── constants.js │ │ │ │ └── util.js │ │ │ └── types │ │ │ ├── index.d.ts │ │ │ ├── options.d.ts │ │ │ ├── plugin.d.ts │ │ │ ├── vnode.d.ts │ │ │ └── vue.d.ts │ │ ├── package-lock.json │ │ ├── package.json │ │ └── views │ │ └── index.html ├── ex07_viewmodels │ ├── alembic.ini │ ├── pypi_vm │ │ ├── __init__.py │ │ ├── app.py │ │ ├── config.py │ │ ├── data │ │ │ ├── __all_models.py │ │ │ ├── __init__.py │ │ │ ├── auditing.py │ │ │ ├── db_session.py │ │ │ ├── downloads.py │ │ │ ├── languages.py │ │ │ ├── maintainers.py │ │ │ ├── modelbase.py │ │ │ ├── packages.py │ │ │ ├── releases.py │ │ │ └── users.py │ │ ├── db │ │ │ └── pypi.sqlite │ │ ├── infrastructure │ │ │ ├── __init__.py │ │ │ ├── cookie_auth.py │ │ │ ├── number_utils.py │ │ │ ├── request_dict.py │ │ │ └── view_modifiers.py │ │ ├── services │ │ │ ├── __init__.py │ │ │ ├── package_service.py │ │ │ └── user_service.py │ │ ├── static │ │ │ ├── css │ │ │ │ ├── account.css │ │ │ │ ├── home.css │ │ │ │ ├── site.css │ │ │ │ ├── theme-overrides.css │ │ │ │ └── theme.css │ │ │ └── img │ │ │ │ ├── blue-cube.svg │ │ │ │ ├── favicon.png │ │ │ │ ├── pypi-logo.svg │ │ │ │ └── white-cube.svg │ │ ├── templates │ │ │ ├── account │ │ │ │ ├── index.html │ │ │ │ ├── login.html │ │ │ │ └── register.html │ │ │ ├── cms │ │ │ │ └── page.html │ │ │ ├── home │ │ │ │ └── index.html │ │ │ ├── packages │ │ │ │ ├── details.html │ │ │ │ └── popular.html │ │ │ ├── seo │ │ │ │ ├── robots.txt │ │ │ │ └── sitemap.html │ │ │ └── shared │ │ │ │ └── _layout.html │ │ ├── viewmodels │ │ │ ├── __init__.py │ │ │ ├── account │ │ │ │ ├── account_home_viewmodel.py │ │ │ │ ├── login_viewmodel.py │ │ │ │ └── register_viewmodel.py │ │ │ ├── cms │ │ │ │ └── page_viewmodel.py │ │ │ ├── home │ │ │ │ └── home_index_viewmodel.py │ │ │ ├── packages │ │ │ │ ├── package_details_viewmodel.py │ │ │ │ └── popular_viewmodel.py │ │ │ ├── shared │ │ │ │ └── viewmodel_base.py │ │ │ └── utils │ │ │ │ └── sitemap_viewmodel.py │ │ └── views │ │ │ ├── __init__.py │ │ │ ├── account_view.py │ │ │ ├── cms_view.py │ │ │ ├── home_view.py │ │ │ ├── packages_view.py │ │ │ └── seo_view.py │ ├── server │ │ ├── pypi.nginx │ │ ├── pypi.service │ │ └── server_setup.sh │ ├── setup.py │ └── tests │ │ ├── _all_tests.py │ │ ├── account_tests.py │ │ ├── commands.txt │ │ ├── home_tests.py │ │ ├── package_tests.py │ │ ├── sitemap_tests.py │ │ └── test_client.py ├── ex08_docker │ ├── base_server │ │ └── dockerfile │ ├── docker-compose.yml │ ├── frontend │ │ ├── dockerfile │ │ ├── movie_exploder │ │ │ ├── css │ │ │ │ ├── bootstrap │ │ │ │ │ ├── css │ │ │ │ │ │ ├── bootstrap-grid.css │ │ │ │ │ │ ├── bootstrap-grid.min.css │ │ │ │ │ │ ├── bootstrap-reboot.css │ │ │ │ │ │ ├── bootstrap-reboot.min.css │ │ │ │ │ │ ├── bootstrap.css │ │ │ │ │ │ └── bootstrap.min.css │ │ │ │ │ └── js │ │ │ │ │ │ ├── bootstrap.bundle.js │ │ │ │ │ │ ├── bootstrap.bundle.min.js │ │ │ │ │ │ ├── bootstrap.js │ │ │ │ │ │ └── bootstrap.min.js │ │ │ │ ├── dropdown.css │ │ │ │ └── site.css │ │ │ ├── js │ │ │ │ ├── dropdown.js │ │ │ │ ├── fake_data.js │ │ │ │ ├── site.js │ │ │ │ └── vue │ │ │ │ │ ├── README.md │ │ │ │ │ ├── vue.common.dev.js │ │ │ │ │ ├── vue.common.js │ │ │ │ │ ├── vue.common.prod.js │ │ │ │ │ ├── vue.esm.browser.js │ │ │ │ │ ├── vue.esm.browser.min.js │ │ │ │ │ ├── vue.esm.js │ │ │ │ │ ├── vue.js │ │ │ │ │ ├── vue.min.js │ │ │ │ │ ├── vue.runtime.common.dev.js │ │ │ │ │ ├── vue.runtime.common.js │ │ │ │ │ ├── vue.runtime.common.prod.js │ │ │ │ │ ├── vue.runtime.esm.js │ │ │ │ │ ├── vue.runtime.js │ │ │ │ │ └── vue.runtime.min.js │ │ │ ├── node_modules │ │ │ │ └── vue │ │ │ │ │ ├── LICENSE │ │ │ │ │ ├── README.md │ │ │ │ │ ├── package.json │ │ │ │ │ ├── src │ │ │ │ │ ├── compiler │ │ │ │ │ │ ├── codeframe.js │ │ │ │ │ │ ├── codegen │ │ │ │ │ │ │ ├── events.js │ │ │ │ │ │ │ └── index.js │ │ │ │ │ │ ├── create-compiler.js │ │ │ │ │ │ ├── directives │ │ │ │ │ │ │ ├── bind.js │ │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ │ ├── model.js │ │ │ │ │ │ │ └── on.js │ │ │ │ │ │ ├── error-detector.js │ │ │ │ │ │ ├── helpers.js │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── optimizer.js │ │ │ │ │ │ ├── parser │ │ │ │ │ │ │ ├── entity-decoder.js │ │ │ │ │ │ │ ├── filter-parser.js │ │ │ │ │ │ │ ├── html-parser.js │ │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ │ └── text-parser.js │ │ │ │ │ │ └── to-function.js │ │ │ │ │ ├── core │ │ │ │ │ │ ├── components │ │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ │ └── keep-alive.js │ │ │ │ │ │ ├── config.js │ │ │ │ │ │ ├── global-api │ │ │ │ │ │ │ ├── assets.js │ │ │ │ │ │ │ ├── extend.js │ │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ │ ├── mixin.js │ │ │ │ │ │ │ └── use.js │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── observer │ │ │ │ │ │ │ ├── array.js │ │ │ │ │ │ │ ├── dep.js │ │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ │ ├── scheduler.js │ │ │ │ │ │ │ ├── traverse.js │ │ │ │ │ │ │ └── watcher.js │ │ │ │ │ │ ├── util │ │ │ │ │ │ │ ├── debug.js │ │ │ │ │ │ │ ├── env.js │ │ │ │ │ │ │ ├── error.js │ │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ │ ├── lang.js │ │ │ │ │ │ │ ├── next-tick.js │ │ │ │ │ │ │ ├── options.js │ │ │ │ │ │ │ ├── perf.js │ │ │ │ │ │ │ └── props.js │ │ │ │ │ │ └── vdom │ │ │ │ │ │ │ ├── create-component.js │ │ │ │ │ │ │ ├── create-element.js │ │ │ │ │ │ │ ├── create-functional-component.js │ │ │ │ │ │ │ ├── helpers │ │ │ │ │ │ │ ├── extract-props.js │ │ │ │ │ │ │ ├── get-first-component-child.js │ │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ │ ├── is-async-placeholder.js │ │ │ │ │ │ │ ├── merge-hook.js │ │ │ │ │ │ │ ├── normalize-children.js │ │ │ │ │ │ │ ├── normalize-scoped-slots.js │ │ │ │ │ │ │ ├── resolve-async-component.js │ │ │ │ │ │ │ └── update-listeners.js │ │ │ │ │ │ │ ├── modules │ │ │ │ │ │ │ ├── directives.js │ │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ │ └── ref.js │ │ │ │ │ │ │ ├── patch.js │ │ │ │ │ │ │ └── vnode.js │ │ │ │ │ ├── platforms │ │ │ │ │ │ ├── web │ │ │ │ │ │ │ ├── compiler │ │ │ │ │ │ │ │ ├── directives │ │ │ │ │ │ │ │ │ ├── html.js │ │ │ │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ │ │ │ ├── model.js │ │ │ │ │ │ │ │ │ └── text.js │ │ │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ │ │ ├── modules │ │ │ │ │ │ │ │ │ ├── class.js │ │ │ │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ │ │ │ ├── model.js │ │ │ │ │ │ │ │ │ └── style.js │ │ │ │ │ │ │ │ ├── options.js │ │ │ │ │ │ │ │ └── util.js │ │ │ │ │ │ │ ├── entry-compiler.js │ │ │ │ │ │ │ ├── entry-runtime-with-compiler.js │ │ │ │ │ │ │ ├── entry-runtime.js │ │ │ │ │ │ │ ├── entry-server-basic-renderer.js │ │ │ │ │ │ │ ├── entry-server-renderer.js │ │ │ │ │ │ │ ├── runtime │ │ │ │ │ │ │ │ ├── class-util.js │ │ │ │ │ │ │ │ ├── components │ │ │ │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ │ │ │ ├── transition-group.js │ │ │ │ │ │ │ │ │ └── transition.js │ │ │ │ │ │ │ │ ├── directives │ │ │ │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ │ │ │ ├── model.js │ │ │ │ │ │ │ │ │ └── show.js │ │ │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ │ │ ├── modules │ │ │ │ │ │ │ │ │ ├── attrs.js │ │ │ │ │ │ │ │ │ ├── class.js │ │ │ │ │ │ │ │ │ ├── dom-props.js │ │ │ │ │ │ │ │ │ ├── events.js │ │ │ │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ │ │ │ ├── style.js │ │ │ │ │ │ │ │ │ └── transition.js │ │ │ │ │ │ │ │ ├── node-ops.js │ │ │ │ │ │ │ │ ├── patch.js │ │ │ │ │ │ │ │ └── transition-util.js │ │ │ │ │ │ │ ├── server │ │ │ │ │ │ │ │ ├── compiler.js │ │ │ │ │ │ │ │ ├── directives │ │ │ │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ │ │ │ ├── model.js │ │ │ │ │ │ │ │ │ └── show.js │ │ │ │ │ │ │ │ ├── modules │ │ │ │ │ │ │ │ │ ├── attrs.js │ │ │ │ │ │ │ │ │ ├── class.js │ │ │ │ │ │ │ │ │ ├── dom-props.js │ │ │ │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ │ │ │ └── style.js │ │ │ │ │ │ │ │ └── util.js │ │ │ │ │ │ │ └── util │ │ │ │ │ │ │ │ ├── attrs.js │ │ │ │ │ │ │ │ ├── class.js │ │ │ │ │ │ │ │ ├── compat.js │ │ │ │ │ │ │ │ ├── element.js │ │ │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ │ │ └── style.js │ │ │ │ │ │ └── weex │ │ │ │ │ │ │ ├── compiler │ │ │ │ │ │ │ ├── directives │ │ │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ │ │ └── model.js │ │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ │ └── modules │ │ │ │ │ │ │ │ ├── append.js │ │ │ │ │ │ │ │ ├── class.js │ │ │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ │ │ ├── props.js │ │ │ │ │ │ │ │ ├── recycle-list │ │ │ │ │ │ │ │ ├── component-root.js │ │ │ │ │ │ │ │ ├── component.js │ │ │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ │ │ ├── recycle-list.js │ │ │ │ │ │ │ │ ├── text.js │ │ │ │ │ │ │ │ ├── v-bind.js │ │ │ │ │ │ │ │ ├── v-for.js │ │ │ │ │ │ │ │ ├── v-if.js │ │ │ │ │ │ │ │ ├── v-on.js │ │ │ │ │ │ │ │ └── v-once.js │ │ │ │ │ │ │ │ └── style.js │ │ │ │ │ │ │ ├── entry-compiler.js │ │ │ │ │ │ │ ├── entry-framework.js │ │ │ │ │ │ │ ├── entry-runtime-factory.js │ │ │ │ │ │ │ ├── runtime │ │ │ │ │ │ │ ├── components │ │ │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ │ │ ├── richtext.js │ │ │ │ │ │ │ │ ├── transition-group.js │ │ │ │ │ │ │ │ └── transition.js │ │ │ │ │ │ │ ├── directives │ │ │ │ │ │ │ │ └── index.js │ │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ │ ├── modules │ │ │ │ │ │ │ │ ├── attrs.js │ │ │ │ │ │ │ │ ├── class.js │ │ │ │ │ │ │ │ ├── events.js │ │ │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ │ │ ├── style.js │ │ │ │ │ │ │ │ └── transition.js │ │ │ │ │ │ │ ├── node-ops.js │ │ │ │ │ │ │ ├── patch.js │ │ │ │ │ │ │ ├── recycle-list │ │ │ │ │ │ │ │ ├── render-component-template.js │ │ │ │ │ │ │ │ └── virtual-component.js │ │ │ │ │ │ │ └── text-node.js │ │ │ │ │ │ │ └── util │ │ │ │ │ │ │ ├── element.js │ │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ │ └── parser.js │ │ │ │ │ ├── server │ │ │ │ │ │ ├── bundle-renderer │ │ │ │ │ │ │ ├── create-bundle-renderer.js │ │ │ │ │ │ │ ├── create-bundle-runner.js │ │ │ │ │ │ │ └── source-map-support.js │ │ │ │ │ │ ├── create-basic-renderer.js │ │ │ │ │ │ ├── create-renderer.js │ │ │ │ │ │ ├── optimizing-compiler │ │ │ │ │ │ │ ├── codegen.js │ │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ │ ├── modules.js │ │ │ │ │ │ │ ├── optimizer.js │ │ │ │ │ │ │ └── runtime-helpers.js │ │ │ │ │ │ ├── render-context.js │ │ │ │ │ │ ├── render-stream.js │ │ │ │ │ │ ├── render.js │ │ │ │ │ │ ├── template-renderer │ │ │ │ │ │ │ ├── create-async-file-mapper.js │ │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ │ ├── parse-template.js │ │ │ │ │ │ │ └── template-stream.js │ │ │ │ │ │ ├── util.js │ │ │ │ │ │ ├── webpack-plugin │ │ │ │ │ │ │ ├── client.js │ │ │ │ │ │ │ ├── server.js │ │ │ │ │ │ │ └── util.js │ │ │ │ │ │ └── write.js │ │ │ │ │ ├── sfc │ │ │ │ │ │ └── parser.js │ │ │ │ │ └── shared │ │ │ │ │ │ ├── constants.js │ │ │ │ │ │ └── util.js │ │ │ │ │ └── types │ │ │ │ │ ├── index.d.ts │ │ │ │ │ ├── options.d.ts │ │ │ │ │ ├── plugin.d.ts │ │ │ │ │ ├── vnode.d.ts │ │ │ │ │ └── vue.d.ts │ │ │ ├── package-lock.json │ │ │ ├── package.json │ │ │ └── views │ │ │ │ └── index.html │ │ └── site.nginx │ └── services │ │ ├── dockerfile │ │ └── movie_svc │ │ ├── app.py │ │ ├── app_instance.py │ │ ├── data │ │ ├── db.py │ │ └── movies.csv │ │ ├── requirements.txt │ │ ├── routes.py │ │ ├── static │ │ └── css │ │ │ ├── docs.css │ │ │ └── theme.css │ │ ├── templates │ │ ├── home │ │ │ └── index.html │ │ └── shared │ │ │ └── _layout.html │ │ └── views │ │ ├── api_views.py │ │ └── home.py ├── ex09_lets_encrypt │ ├── make_secure.sh │ └── server_setup.sh ├── ex10_securepy │ ├── pypi_secure │ │ ├── __init__.py │ │ ├── app.py │ │ ├── data │ │ │ ├── __all_models.py │ │ │ ├── __init__.py │ │ │ ├── db_session.py │ │ │ ├── downloads.py │ │ │ ├── languages.py │ │ │ ├── licenses.py │ │ │ ├── maintainers.py │ │ │ ├── modelbase.py │ │ │ ├── package.py │ │ │ ├── releases.py │ │ │ └── users.py │ │ ├── db │ │ │ ├── __init__.py │ │ │ ├── placeholder.txt │ │ │ └── pypi.sqlite │ │ ├── infrastructure │ │ │ ├── __init__.py │ │ │ └── view_modifiers.py │ │ ├── services │ │ │ ├── __init__.py │ │ │ ├── cms_service.py │ │ │ ├── package_service.py │ │ │ └── user_service.py │ │ ├── static │ │ │ ├── css │ │ │ │ ├── nav.css │ │ │ │ └── site.css │ │ │ └── img │ │ │ │ ├── blue-cube.svg │ │ │ │ ├── favicon.png │ │ │ │ ├── pypi-logo.svg │ │ │ │ └── white-cube.svg │ │ ├── templates │ │ │ ├── cms │ │ │ │ └── page.html │ │ │ ├── home │ │ │ │ ├── about.html │ │ │ │ └── index.html │ │ │ ├── packages │ │ │ │ └── details.html │ │ │ └── shared │ │ │ │ └── _layout.html │ │ └── views │ │ │ ├── __init__.py │ │ │ ├── account_views.py │ │ │ ├── cms_views.py │ │ │ ├── home_views.py │ │ │ └── package_views.py │ └── setup.py ├── node_modules │ └── vue │ │ ├── LICENSE │ │ ├── README.md │ │ ├── package.json │ │ ├── src │ │ ├── compiler │ │ │ ├── codeframe.js │ │ │ ├── codegen │ │ │ │ ├── events.js │ │ │ │ └── index.js │ │ │ ├── create-compiler.js │ │ │ ├── directives │ │ │ │ ├── bind.js │ │ │ │ ├── index.js │ │ │ │ ├── model.js │ │ │ │ └── on.js │ │ │ ├── error-detector.js │ │ │ ├── helpers.js │ │ │ ├── index.js │ │ │ ├── optimizer.js │ │ │ ├── parser │ │ │ │ ├── entity-decoder.js │ │ │ │ ├── filter-parser.js │ │ │ │ ├── html-parser.js │ │ │ │ ├── index.js │ │ │ │ └── text-parser.js │ │ │ └── to-function.js │ │ ├── core │ │ │ ├── components │ │ │ │ ├── index.js │ │ │ │ └── keep-alive.js │ │ │ ├── config.js │ │ │ ├── global-api │ │ │ │ ├── assets.js │ │ │ │ ├── extend.js │ │ │ │ ├── index.js │ │ │ │ ├── mixin.js │ │ │ │ └── use.js │ │ │ ├── index.js │ │ │ ├── observer │ │ │ │ ├── array.js │ │ │ │ ├── dep.js │ │ │ │ ├── index.js │ │ │ │ ├── scheduler.js │ │ │ │ ├── traverse.js │ │ │ │ └── watcher.js │ │ │ ├── util │ │ │ │ ├── debug.js │ │ │ │ ├── env.js │ │ │ │ ├── error.js │ │ │ │ ├── index.js │ │ │ │ ├── lang.js │ │ │ │ ├── next-tick.js │ │ │ │ ├── options.js │ │ │ │ ├── perf.js │ │ │ │ └── props.js │ │ │ └── vdom │ │ │ │ ├── create-component.js │ │ │ │ ├── create-element.js │ │ │ │ ├── create-functional-component.js │ │ │ │ ├── helpers │ │ │ │ ├── extract-props.js │ │ │ │ ├── get-first-component-child.js │ │ │ │ ├── index.js │ │ │ │ ├── is-async-placeholder.js │ │ │ │ ├── merge-hook.js │ │ │ │ ├── normalize-children.js │ │ │ │ ├── normalize-scoped-slots.js │ │ │ │ ├── resolve-async-component.js │ │ │ │ └── update-listeners.js │ │ │ │ ├── modules │ │ │ │ ├── directives.js │ │ │ │ ├── index.js │ │ │ │ └── ref.js │ │ │ │ ├── patch.js │ │ │ │ └── vnode.js │ │ ├── platforms │ │ │ ├── web │ │ │ │ ├── compiler │ │ │ │ │ ├── directives │ │ │ │ │ │ ├── html.js │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── model.js │ │ │ │ │ │ └── text.js │ │ │ │ │ ├── index.js │ │ │ │ │ ├── modules │ │ │ │ │ │ ├── class.js │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── model.js │ │ │ │ │ │ └── style.js │ │ │ │ │ ├── options.js │ │ │ │ │ └── util.js │ │ │ │ ├── entry-compiler.js │ │ │ │ ├── entry-runtime-with-compiler.js │ │ │ │ ├── entry-runtime.js │ │ │ │ ├── entry-server-basic-renderer.js │ │ │ │ ├── entry-server-renderer.js │ │ │ │ ├── runtime │ │ │ │ │ ├── class-util.js │ │ │ │ │ ├── components │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── transition-group.js │ │ │ │ │ │ └── transition.js │ │ │ │ │ ├── directives │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── model.js │ │ │ │ │ │ └── show.js │ │ │ │ │ ├── index.js │ │ │ │ │ ├── modules │ │ │ │ │ │ ├── attrs.js │ │ │ │ │ │ ├── class.js │ │ │ │ │ │ ├── dom-props.js │ │ │ │ │ │ ├── events.js │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── style.js │ │ │ │ │ │ └── transition.js │ │ │ │ │ ├── node-ops.js │ │ │ │ │ ├── patch.js │ │ │ │ │ └── transition-util.js │ │ │ │ ├── server │ │ │ │ │ ├── compiler.js │ │ │ │ │ ├── directives │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── model.js │ │ │ │ │ │ └── show.js │ │ │ │ │ ├── modules │ │ │ │ │ │ ├── attrs.js │ │ │ │ │ │ ├── class.js │ │ │ │ │ │ ├── dom-props.js │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ └── style.js │ │ │ │ │ └── util.js │ │ │ │ └── util │ │ │ │ │ ├── attrs.js │ │ │ │ │ ├── class.js │ │ │ │ │ ├── compat.js │ │ │ │ │ ├── element.js │ │ │ │ │ ├── index.js │ │ │ │ │ └── style.js │ │ │ └── weex │ │ │ │ ├── compiler │ │ │ │ ├── directives │ │ │ │ │ ├── index.js │ │ │ │ │ └── model.js │ │ │ │ ├── index.js │ │ │ │ └── modules │ │ │ │ │ ├── append.js │ │ │ │ │ ├── class.js │ │ │ │ │ ├── index.js │ │ │ │ │ ├── props.js │ │ │ │ │ ├── recycle-list │ │ │ │ │ ├── component-root.js │ │ │ │ │ ├── component.js │ │ │ │ │ ├── index.js │ │ │ │ │ ├── recycle-list.js │ │ │ │ │ ├── text.js │ │ │ │ │ ├── v-bind.js │ │ │ │ │ ├── v-for.js │ │ │ │ │ ├── v-if.js │ │ │ │ │ ├── v-on.js │ │ │ │ │ └── v-once.js │ │ │ │ │ └── style.js │ │ │ │ ├── entry-compiler.js │ │ │ │ ├── entry-framework.js │ │ │ │ ├── entry-runtime-factory.js │ │ │ │ ├── runtime │ │ │ │ ├── components │ │ │ │ │ ├── index.js │ │ │ │ │ ├── richtext.js │ │ │ │ │ ├── transition-group.js │ │ │ │ │ └── transition.js │ │ │ │ ├── directives │ │ │ │ │ └── index.js │ │ │ │ ├── index.js │ │ │ │ ├── modules │ │ │ │ │ ├── attrs.js │ │ │ │ │ ├── class.js │ │ │ │ │ ├── events.js │ │ │ │ │ ├── index.js │ │ │ │ │ ├── style.js │ │ │ │ │ └── transition.js │ │ │ │ ├── node-ops.js │ │ │ │ ├── patch.js │ │ │ │ ├── recycle-list │ │ │ │ │ ├── render-component-template.js │ │ │ │ │ └── virtual-component.js │ │ │ │ └── text-node.js │ │ │ │ └── util │ │ │ │ ├── element.js │ │ │ │ ├── index.js │ │ │ │ └── parser.js │ │ ├── server │ │ │ ├── bundle-renderer │ │ │ │ ├── create-bundle-renderer.js │ │ │ │ ├── create-bundle-runner.js │ │ │ │ └── source-map-support.js │ │ │ ├── create-basic-renderer.js │ │ │ ├── create-renderer.js │ │ │ ├── optimizing-compiler │ │ │ │ ├── codegen.js │ │ │ │ ├── index.js │ │ │ │ ├── modules.js │ │ │ │ ├── optimizer.js │ │ │ │ └── runtime-helpers.js │ │ │ ├── render-context.js │ │ │ ├── render-stream.js │ │ │ ├── render.js │ │ │ ├── template-renderer │ │ │ │ ├── create-async-file-mapper.js │ │ │ │ ├── index.js │ │ │ │ ├── parse-template.js │ │ │ │ └── template-stream.js │ │ │ ├── util.js │ │ │ ├── webpack-plugin │ │ │ │ ├── client.js │ │ │ │ ├── server.js │ │ │ │ └── util.js │ │ │ └── write.js │ │ ├── sfc │ │ │ └── parser.js │ │ └── shared │ │ │ ├── constants.js │ │ │ └── util.js │ │ └── types │ │ ├── index.d.ts │ │ ├── options.d.ts │ │ ├── plugin.d.ts │ │ ├── vnode.d.ts │ │ └── vue.d.ts ├── package-lock.json ├── package.json └── requirements.txt ├── node_modules └── vue │ ├── LICENSE │ ├── README.md │ ├── package.json │ ├── src │ ├── compiler │ │ ├── codeframe.js │ │ ├── codegen │ │ │ ├── events.js │ │ │ └── index.js │ │ ├── create-compiler.js │ │ ├── directives │ │ │ ├── bind.js │ │ │ ├── index.js │ │ │ ├── model.js │ │ │ └── on.js │ │ ├── error-detector.js │ │ ├── helpers.js │ │ ├── index.js │ │ ├── optimizer.js │ │ ├── parser │ │ │ ├── entity-decoder.js │ │ │ ├── filter-parser.js │ │ │ ├── html-parser.js │ │ │ ├── index.js │ │ │ └── text-parser.js │ │ └── to-function.js │ ├── core │ │ ├── components │ │ │ ├── index.js │ │ │ └── keep-alive.js │ │ ├── config.js │ │ ├── global-api │ │ │ ├── assets.js │ │ │ ├── extend.js │ │ │ ├── index.js │ │ │ ├── mixin.js │ │ │ └── use.js │ │ ├── index.js │ │ ├── observer │ │ │ ├── array.js │ │ │ ├── dep.js │ │ │ ├── index.js │ │ │ ├── scheduler.js │ │ │ ├── traverse.js │ │ │ └── watcher.js │ │ ├── util │ │ │ ├── debug.js │ │ │ ├── env.js │ │ │ ├── error.js │ │ │ ├── index.js │ │ │ ├── lang.js │ │ │ ├── next-tick.js │ │ │ ├── options.js │ │ │ ├── perf.js │ │ │ └── props.js │ │ └── vdom │ │ │ ├── create-component.js │ │ │ ├── create-element.js │ │ │ ├── create-functional-component.js │ │ │ ├── helpers │ │ │ ├── extract-props.js │ │ │ ├── get-first-component-child.js │ │ │ ├── index.js │ │ │ ├── is-async-placeholder.js │ │ │ ├── merge-hook.js │ │ │ ├── normalize-children.js │ │ │ ├── normalize-scoped-slots.js │ │ │ ├── resolve-async-component.js │ │ │ └── update-listeners.js │ │ │ ├── modules │ │ │ ├── directives.js │ │ │ ├── index.js │ │ │ └── ref.js │ │ │ ├── patch.js │ │ │ └── vnode.js │ ├── platforms │ │ ├── web │ │ │ ├── compiler │ │ │ │ ├── directives │ │ │ │ │ ├── html.js │ │ │ │ │ ├── index.js │ │ │ │ │ ├── model.js │ │ │ │ │ └── text.js │ │ │ │ ├── index.js │ │ │ │ ├── modules │ │ │ │ │ ├── class.js │ │ │ │ │ ├── index.js │ │ │ │ │ ├── model.js │ │ │ │ │ └── style.js │ │ │ │ ├── options.js │ │ │ │ └── util.js │ │ │ ├── entry-compiler.js │ │ │ ├── entry-runtime-with-compiler.js │ │ │ ├── entry-runtime.js │ │ │ ├── entry-server-basic-renderer.js │ │ │ ├── entry-server-renderer.js │ │ │ ├── runtime │ │ │ │ ├── class-util.js │ │ │ │ ├── components │ │ │ │ │ ├── index.js │ │ │ │ │ ├── transition-group.js │ │ │ │ │ └── transition.js │ │ │ │ ├── directives │ │ │ │ │ ├── index.js │ │ │ │ │ ├── model.js │ │ │ │ │ └── show.js │ │ │ │ ├── index.js │ │ │ │ ├── modules │ │ │ │ │ ├── attrs.js │ │ │ │ │ ├── class.js │ │ │ │ │ ├── dom-props.js │ │ │ │ │ ├── events.js │ │ │ │ │ ├── index.js │ │ │ │ │ ├── style.js │ │ │ │ │ └── transition.js │ │ │ │ ├── node-ops.js │ │ │ │ ├── patch.js │ │ │ │ └── transition-util.js │ │ │ ├── server │ │ │ │ ├── compiler.js │ │ │ │ ├── directives │ │ │ │ │ ├── index.js │ │ │ │ │ ├── model.js │ │ │ │ │ └── show.js │ │ │ │ ├── modules │ │ │ │ │ ├── attrs.js │ │ │ │ │ ├── class.js │ │ │ │ │ ├── dom-props.js │ │ │ │ │ ├── index.js │ │ │ │ │ └── style.js │ │ │ │ └── util.js │ │ │ └── util │ │ │ │ ├── attrs.js │ │ │ │ ├── class.js │ │ │ │ ├── compat.js │ │ │ │ ├── element.js │ │ │ │ ├── index.js │ │ │ │ └── style.js │ │ └── weex │ │ │ ├── compiler │ │ │ ├── directives │ │ │ │ ├── index.js │ │ │ │ └── model.js │ │ │ ├── index.js │ │ │ └── modules │ │ │ │ ├── append.js │ │ │ │ ├── class.js │ │ │ │ ├── index.js │ │ │ │ ├── props.js │ │ │ │ ├── recycle-list │ │ │ │ ├── component-root.js │ │ │ │ ├── component.js │ │ │ │ ├── index.js │ │ │ │ ├── recycle-list.js │ │ │ │ ├── text.js │ │ │ │ ├── v-bind.js │ │ │ │ ├── v-for.js │ │ │ │ ├── v-if.js │ │ │ │ ├── v-on.js │ │ │ │ └── v-once.js │ │ │ │ └── style.js │ │ │ ├── entry-compiler.js │ │ │ ├── entry-framework.js │ │ │ ├── entry-runtime-factory.js │ │ │ ├── runtime │ │ │ ├── components │ │ │ │ ├── index.js │ │ │ │ ├── richtext.js │ │ │ │ ├── transition-group.js │ │ │ │ └── transition.js │ │ │ ├── directives │ │ │ │ └── index.js │ │ │ ├── index.js │ │ │ ├── modules │ │ │ │ ├── attrs.js │ │ │ │ ├── class.js │ │ │ │ ├── events.js │ │ │ │ ├── index.js │ │ │ │ ├── style.js │ │ │ │ └── transition.js │ │ │ ├── node-ops.js │ │ │ ├── patch.js │ │ │ ├── recycle-list │ │ │ │ ├── render-component-template.js │ │ │ │ └── virtual-component.js │ │ │ └── text-node.js │ │ │ └── util │ │ │ ├── element.js │ │ │ ├── index.js │ │ │ └── parser.js │ ├── server │ │ ├── bundle-renderer │ │ │ ├── create-bundle-renderer.js │ │ │ ├── create-bundle-runner.js │ │ │ └── source-map-support.js │ │ ├── create-basic-renderer.js │ │ ├── create-renderer.js │ │ ├── optimizing-compiler │ │ │ ├── codegen.js │ │ │ ├── index.js │ │ │ ├── modules.js │ │ │ ├── optimizer.js │ │ │ └── runtime-helpers.js │ │ ├── render-context.js │ │ ├── render-stream.js │ │ ├── render.js │ │ ├── template-renderer │ │ │ ├── create-async-file-mapper.js │ │ │ ├── index.js │ │ │ ├── parse-template.js │ │ │ └── template-stream.js │ │ ├── util.js │ │ ├── webpack-plugin │ │ │ ├── client.js │ │ │ ├── server.js │ │ │ └── util.js │ │ └── write.js │ ├── sfc │ │ └── parser.js │ └── shared │ │ ├── constants.js │ │ └── util.js │ └── types │ ├── index.d.ts │ ├── options.d.ts │ ├── plugin.d.ts │ ├── vnode.d.ts │ └── vue.d.ts ├── package-lock.json ├── package.json └── tools-and-techniques-web.pdf /.idea/$CACHE_FILE$: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | DeprecationUnit files (systemd) 13 | 14 | 15 | General 16 | 17 | 18 | Python 19 | 20 | 21 | Unit files (systemd) 22 | 23 | 24 | 25 | 26 | Angular 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /workspace.xml 3 | # Datasource local storage ignored files 4 | /dataSources/ 5 | /dataSources.local.xml -------------------------------------------------------------------------------- /.idea/dictionaries/mkennedy.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | aiodns 5 | aiohttp 6 | asyncio 7 | billtrackerprodemo 8 | cchardet 9 | colorama 10 | httpx 11 | nginx 12 | ngrok 13 | passlib 14 | podcast 15 | pytest 16 | sqlalchemy 17 | subcontrols 18 | tablename 19 | uwsgi 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/vagrant.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ten-tips-python-web-devs -------------------------------------------------------------------------------- /code/ex01_html_forms/extras/form_hook.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function () { 2 | 3 | $("form").submit(function (e) { 4 | e.preventDefault() 5 | 6 | const $inputs = $('form :input'); 7 | 8 | let values = {} 9 | $inputs.each(function () { 10 | if (this.name) { 11 | values[this.name] = $(this).val(); 12 | } 13 | }) 14 | 15 | alert(JSON.stringify(values, null, 2)) 16 | 17 | return false 18 | }) 19 | }) 20 | -------------------------------------------------------------------------------- /code/ex01_html_forms/extras/site.css: -------------------------------------------------------------------------------- 1 | 2 | form { 3 | margin-left: auto; 4 | margin-right: auto; 5 | max-width: 350px; 6 | background-color: white; 7 | padding: 20px; 8 | padding-right: 30px; 9 | border-radius: 10px; 10 | } 11 | 12 | form > * { 13 | margin: 10px; 14 | } 15 | 16 | form > div { 17 | text-align: right; 18 | margin-right: -10px; 19 | } 20 | 21 | body { 22 | background-color: #84cbff; 23 | } 24 | 25 | h1 { 26 | color: white; 27 | text-align: center; 28 | margin-top: 50px; 29 | margin-bottom: 50px; 30 | font-size: 64px; 31 | font-weight: lighter; 32 | } -------------------------------------------------------------------------------- /code/ex02_ngrok/pypi_org/app.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | import flask 4 | import pypi_org.data.db_session as db_session 5 | 6 | app = flask.Flask(__name__) 7 | 8 | 9 | def main(): 10 | register_blueprints() 11 | setup_db() 12 | app.run(debug=True) 13 | 14 | 15 | def setup_db(): 16 | db_file = os.path.join( 17 | os.path.dirname(__file__), 18 | 'db', 19 | 'pypi.sqlite') 20 | 21 | db_session.global_init(db_file) 22 | 23 | 24 | def register_blueprints(): 25 | from pypi_org.views import home_views 26 | from pypi_org.views import package_views 27 | from pypi_org.views import cms_views 28 | 29 | app.register_blueprint(package_views.blueprint) 30 | app.register_blueprint(home_views.blueprint) 31 | app.register_blueprint(cms_views.blueprint) 32 | 33 | 34 | if __name__ == '__main__': 35 | main() 36 | -------------------------------------------------------------------------------- /code/ex02_ngrok/pypi_org/data/__all_models.py: -------------------------------------------------------------------------------- 1 | # Add all your SQLAlchemy models here. 2 | # This allows us to import just this file when 3 | # we need to preload the models and ensure they 4 | # are all loaded. 5 | 6 | # noinspection PyUnresolvedReferences 7 | import pypi_vm.data.auditing 8 | # noinspection PyUnresolvedReferences 9 | import pypi_vm.data.downloads 10 | # noinspection PyUnresolvedReferences 11 | import pypi_vm.data.languages 12 | # noinspection PyUnresolvedReferences 13 | import pypi_vm.data.maintainers 14 | # noinspection PyUnresolvedReferences 15 | import pypi_vm.data.packages 16 | # noinspection PyUnresolvedReferences 17 | import pypi_vm.data.releases 18 | # noinspection PyUnresolvedReferences 19 | import pypi_vm.data.users 20 | -------------------------------------------------------------------------------- /code/ex02_ngrok/pypi_org/data/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikeckennedy/ten-tips-python-web-devs/e2406853a3d2e1d02ca5b00f68ae510993d4ad19/code/ex02_ngrok/pypi_org/data/__init__.py -------------------------------------------------------------------------------- /code/ex02_ngrok/pypi_org/data/auditing.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import sqlalchemy 3 | from pypi_vm.data.modelbase import SqlAlchemyBase 4 | 5 | 6 | class Auditing(SqlAlchemyBase): 7 | __tablename__ = 'auditing' 8 | 9 | id = sqlalchemy.Column(sqlalchemy.String, primary_key=True) 10 | created_date = sqlalchemy.Column(sqlalchemy.DateTime, default=datetime.datetime.now, index=True) 11 | description = sqlalchemy.Column(sqlalchemy.String) 12 | -------------------------------------------------------------------------------- /code/ex02_ngrok/pypi_org/data/db_session.py: -------------------------------------------------------------------------------- 1 | import sqlalchemy 2 | import sqlalchemy.orm 3 | from pypi_vm.data.modelbase import SqlAlchemyBase 4 | # noinspection PyUnresolvedReferences 5 | import pypi_vm.data.__all_models 6 | 7 | 8 | class DbSession: 9 | factory = None 10 | engine = None 11 | 12 | @staticmethod 13 | def global_init(db_file: str): 14 | if DbSession.factory: 15 | return 16 | 17 | if not db_file or not db_file.strip(): 18 | raise Exception("You must specify a data file.") 19 | 20 | conn_str = 'sqlite:///' + db_file 21 | print("Connecting to DB at: {}".format(conn_str)) 22 | 23 | engine = sqlalchemy.create_engine(conn_str, echo=False, connect_args={'check_same_thread': False}) 24 | DbSession.engine = engine 25 | DbSession.factory = sqlalchemy.orm.sessionmaker(bind=engine) 26 | 27 | SqlAlchemyBase.metadata.create_all(engine) 28 | 29 | -------------------------------------------------------------------------------- /code/ex02_ngrok/pypi_org/data/downloads.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import sqlalchemy 3 | from pypi_vm.data.modelbase import SqlAlchemyBase 4 | 5 | 6 | class Download(SqlAlchemyBase): 7 | __tablename__ = 'downloads' 8 | 9 | id = sqlalchemy.Column(sqlalchemy.BigInteger, primary_key=True, autoincrement=True) 10 | created_date = sqlalchemy.Column(sqlalchemy.DateTime, default=datetime.datetime.now, index=True) 11 | 12 | package_id = sqlalchemy.Column(sqlalchemy.String, index=True) 13 | release_id = sqlalchemy.Column(sqlalchemy.BigInteger, index=True) 14 | 15 | ip_address = sqlalchemy.Column(sqlalchemy.String) 16 | user_agent = sqlalchemy.Column(sqlalchemy.String) 17 | -------------------------------------------------------------------------------- /code/ex02_ngrok/pypi_org/data/languages.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import sqlalchemy 3 | from pypi_vm.data.modelbase import SqlAlchemyBase 4 | 5 | 6 | class ProgrammingLanguage(SqlAlchemyBase): 7 | __tablename__ = 'languages' 8 | 9 | id = sqlalchemy.Column(sqlalchemy.String, primary_key=True) 10 | created_date = sqlalchemy.Column(sqlalchemy.DateTime, default=datetime.datetime.now, index=True) 11 | description = sqlalchemy.Column(sqlalchemy.String) 12 | -------------------------------------------------------------------------------- /code/ex02_ngrok/pypi_org/data/licenses.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import sqlalchemy 3 | from pypi_org.data.modelbase import SqlAlchemyBase 4 | 5 | 6 | class License(SqlAlchemyBase): 7 | __tablename__ = 'licenses' 8 | 9 | id = sqlalchemy.Column(sqlalchemy.String, primary_key=True) 10 | created_date = sqlalchemy.Column(sqlalchemy.DateTime, default=datetime.datetime.now, index=True) 11 | description = sqlalchemy.Column(sqlalchemy.String) 12 | -------------------------------------------------------------------------------- /code/ex02_ngrok/pypi_org/data/maintainers.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | 3 | import sqlalchemy 4 | from pypi_vm.data.modelbase import SqlAlchemyBase 5 | 6 | 7 | class Maintainer(SqlAlchemyBase): 8 | __tablename__ = 'maintainers' 9 | 10 | user_id = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True) 11 | package_id = sqlalchemy.Column(sqlalchemy.String, primary_key=True) 12 | # date_added = sqlalchemy.Column(sqlalchemy.DateTime, default=datetime.datetime.now) 13 | -------------------------------------------------------------------------------- /code/ex02_ngrok/pypi_org/data/modelbase.py: -------------------------------------------------------------------------------- 1 | import sqlalchemy.ext.declarative as dec 2 | 3 | SqlAlchemyBase = dec.declarative_base() 4 | -------------------------------------------------------------------------------- /code/ex02_ngrok/pypi_org/data/users.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import sqlalchemy 3 | from pypi_vm.data.modelbase import SqlAlchemyBase 4 | 5 | 6 | class User(SqlAlchemyBase): 7 | __tablename__ = 'users' 8 | 9 | id = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True, autoincrement=True) 10 | name = sqlalchemy.Column(sqlalchemy.String, nullable=True) 11 | email = sqlalchemy.Column(sqlalchemy.String, index=True, nullable=True) 12 | hashed_password = sqlalchemy.Column(sqlalchemy.String, nullable=True, index=True) 13 | created_date = sqlalchemy.Column(sqlalchemy.DateTime, default=datetime.datetime.now, index=True) 14 | profile_image_url = sqlalchemy.Column(sqlalchemy.String) 15 | last_login = sqlalchemy.Column(sqlalchemy.DateTime, default=datetime.datetime.now, index=True) 16 | -------------------------------------------------------------------------------- /code/ex02_ngrok/pypi_org/db/placeholder.txt: -------------------------------------------------------------------------------- 1 | Just here so git will create this folder. -------------------------------------------------------------------------------- /code/ex02_ngrok/pypi_org/db/pypi.sqlite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikeckennedy/ten-tips-python-web-devs/e2406853a3d2e1d02ca5b00f68ae510993d4ad19/code/ex02_ngrok/pypi_org/db/pypi.sqlite -------------------------------------------------------------------------------- /code/ex02_ngrok/pypi_org/services/cms_service.py: -------------------------------------------------------------------------------- 1 | fake_db = { 2 | '/company/history': { 3 | 'page_title': 'Company history', 4 | 'page_details': 'Details about company history...', 5 | }, 6 | '/company/employees': { 7 | 'page_title': 'Our team', 8 | 'page_details': 'Details about company employees ...', 9 | }, 10 | } 11 | 12 | 13 | def get_page(url: str) -> dict: 14 | if not url: 15 | return {} 16 | 17 | url = url.strip().lower() 18 | url = '/' + url.lstrip('/') 19 | 20 | page = fake_db.get(url, {}) 21 | return page 22 | -------------------------------------------------------------------------------- /code/ex02_ngrok/pypi_org/services/package_service.py: -------------------------------------------------------------------------------- 1 | def get_latest_packages(): 2 | return [ 3 | {'name': 'flask', 'version': '1.2.3'}, 4 | {'name': 'sqlalchemy', 'version': '2.2.0'}, 5 | {'name': 'passlib', 'version': '3.0.0'}, 6 | ] 7 | -------------------------------------------------------------------------------- /code/ex02_ngrok/pypi_org/static/img/blue-cube.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /code/ex02_ngrok/pypi_org/static/img/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikeckennedy/ten-tips-python-web-devs/e2406853a3d2e1d02ca5b00f68ae510993d4ad19/code/ex02_ngrok/pypi_org/static/img/favicon.png -------------------------------------------------------------------------------- /code/ex02_ngrok/pypi_org/static/img/white-cube.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /code/ex02_ngrok/pypi_org/templates/cms/page.html: -------------------------------------------------------------------------------- 1 | {% extends "shared/_layout.html" %} 2 | {% block title %}About PyPI Demo{% endblock %} 3 | 4 | {% block main_content %} 5 |

{{ page_title }}

6 | 7 |
8 | {{ page_details }} 9 |
10 | {% endblock %} 11 | -------------------------------------------------------------------------------- /code/ex02_ngrok/pypi_org/templates/home/about.html: -------------------------------------------------------------------------------- 1 | {% extends "shared/_layout.html" %} 2 | {% block title %}About PyPI Demo{% endblock %} 3 | 4 | {% block main_content %} 5 |

About Python Package Index

6 | 7 |
8 | This is our demo app for our Flask course. 9 |
10 | {% endblock %} 11 | 12 | {% block additional_css %} 13 | 14 | {% endblock %} -------------------------------------------------------------------------------- /code/ex02_ngrok/pypi_org/templates/packages/details.html: -------------------------------------------------------------------------------- 1 | {% extends "shared/_layout.html" %} 2 | {% block main_content %} 3 | 4 |

Python Package Index

5 | 6 |

Packages

7 | 8 | {% for p in packages %} 9 | 10 |
11 | 12 | {{ p.name.upper() }} 13 | 14 | 15 | {{ p.version }} 16 | 17 |
18 | 19 | {% endfor %} 20 | {% endblock %} -------------------------------------------------------------------------------- /code/ex02_ngrok/pypi_org/views/cms_views.py: -------------------------------------------------------------------------------- 1 | import flask 2 | 3 | from pypi_org.infrastructure.view_modifiers import response 4 | import pypi_org.services.cms_service as cms_service 5 | 6 | blueprint = flask.Blueprint('cms', __name__, template_folder='templates') 7 | 8 | 9 | @blueprint.route('/') 10 | @response(template_file='cms/page.html') 11 | def cms_page(full_url: str): 12 | print("Getting CMS page for {}".format(full_url)) 13 | 14 | page = cms_service.get_page(full_url) 15 | if not page: 16 | return flask.abort(404) 17 | 18 | return page 19 | -------------------------------------------------------------------------------- /code/ex02_ngrok/pypi_org/views/home_views.py: -------------------------------------------------------------------------------- 1 | import flask 2 | 3 | from pypi_org.infrastructure.view_modifiers import response 4 | import pypi_org.services.package_service as package_service 5 | 6 | blueprint = flask.Blueprint('home', __name__, template_folder='templates') 7 | 8 | 9 | @blueprint.route('/') 10 | @response(template_file='home/index.html') 11 | def index(): 12 | test_packages = package_service.get_latest_packages() 13 | return {'packages': test_packages} 14 | # return flask.render_template('home/index.html', packages=test_packages) 15 | 16 | 17 | @blueprint.route('/about') 18 | @response(template_file='home/about.html') 19 | def about(): 20 | return {} 21 | -------------------------------------------------------------------------------- /code/ex02_ngrok/pypi_org/views/package_views.py: -------------------------------------------------------------------------------- 1 | import flask 2 | 3 | from pypi_org.infrastructure.view_modifiers import response 4 | import pypi_org.services.package_service as package_service 5 | 6 | blueprint = flask.Blueprint('packages', __name__, template_folder='templates') 7 | 8 | 9 | @blueprint.route('/project/') 10 | # @response(template_file='packages/details.html') 11 | def package_details(package_name: str): 12 | return "Package details for {}".format(package_name) 13 | 14 | 15 | @blueprint.route('/') 16 | def popular(rank: int): 17 | print(type(rank), rank) 18 | return "The details for the {}th most popular package".format(rank) 19 | -------------------------------------------------------------------------------- /code/ex04_async_web/config/dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "dev": true, 3 | "use_cached_data": false, 4 | "weather_key": "684e93644281bf1398569ccf91aca62d" 5 | } -------------------------------------------------------------------------------- /code/ex04_async_web/config/prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "dev": false, 3 | "use_cached_data": false, 4 | "weather_key": "684e93644281bf1398569ccf91aca62d" 5 | } -------------------------------------------------------------------------------- /code/ex04_async_web/config/settings.py: -------------------------------------------------------------------------------- 1 | import os 2 | import json 3 | 4 | 5 | def load(mode='dev') -> dict: 6 | file = os.path.join(os.path.dirname(__file__), f"{mode}.json") 7 | if not os.path.exists(file): 8 | raise Exception(f"Config not found for {mode}.") 9 | 10 | with open(file, 'r', encoding='utf-8') as fin: 11 | return json.load(fin) 12 | -------------------------------------------------------------------------------- /code/ex04_async_web/services/event_service.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikeckennedy/ten-tips-python-web-devs/e2406853a3d2e1d02ca5b00f68ae510993d4ad19/code/ex04_async_web/services/event_service.py -------------------------------------------------------------------------------- /code/ex04_async_web/services/weather_service.py: -------------------------------------------------------------------------------- 1 | import aiohttp 2 | 3 | __api_key = '' 4 | 5 | 6 | def global_init(api_key: str): 7 | global __api_key 8 | __api_key = api_key 9 | 10 | 11 | async def get_current(zip_code: str, country_code: str) -> dict: 12 | url = f'https://api.openweathermap.org/data/2.5/weather?zip={zip_code},{country_code}&appid={__api_key}' 13 | async with aiohttp.ClientSession() as session: 14 | async with session.get(url) as resp: 15 | resp.raise_for_status() 16 | 17 | return await resp.json() 18 | -------------------------------------------------------------------------------- /code/ex04_async_web/views/city_api.py: -------------------------------------------------------------------------------- 1 | import quart 2 | from services import weather_service, sun_service, location_service 3 | 4 | blueprint = quart.blueprints.Blueprint(__name__, __name__) 5 | 6 | 7 | @blueprint.route('/api/weather//', methods=['GET']) 8 | async def weather(zip_code: str, country: str): 9 | weather_data = await weather_service.get_current(zip_code, country) 10 | if not weather_data: 11 | quart.abort(404) 12 | return quart.jsonify(weather_data) 13 | 14 | 15 | @blueprint.route('/api/sun//', methods=['GET']) 16 | async def sun(zip_code: str, country: str): 17 | lat, long = await location_service.get_lat_long(zip_code, country) 18 | sun_data = await sun_service.for_today(lat, long) 19 | if not sun_data: 20 | quart.abort(404) 21 | return quart.jsonify(sun_data) 22 | -------------------------------------------------------------------------------- /code/ex04_async_web/views/home.py: -------------------------------------------------------------------------------- 1 | import quart 2 | 3 | blueprint = quart.blueprints.Blueprint(__name__, __name__) 4 | 5 | 6 | @blueprint.route('/') 7 | def index(): 8 | return "Welcome to the city_scape API. " \ 9 | "Use /api/sun/[zipcode]/[country code (e.g. us)] and" \ 10 | "/api/weather/[zipcode]/[country code (e.g. us)] for API calls." 11 | 12 | 13 | @blueprint.errorhandler(404) 14 | def not_found(_): 15 | return quart.Response("The page was not found.", status=404) 16 | -------------------------------------------------------------------------------- /code/ex05_migrations/alembic/README: -------------------------------------------------------------------------------- 1 | Generic single-database configuration. -------------------------------------------------------------------------------- /code/ex05_migrations/alembic/script.py.mako: -------------------------------------------------------------------------------- 1 | """${message} 2 | 3 | Revision ID: ${up_revision} 4 | Revises: ${down_revision | comma,n} 5 | Create Date: ${create_date} 6 | 7 | """ 8 | from alembic import op 9 | import sqlalchemy as sa 10 | ${imports if imports else ""} 11 | 12 | # revision identifiers, used by Alembic. 13 | revision = ${repr(up_revision)} 14 | down_revision = ${repr(down_revision)} 15 | branch_labels = ${repr(branch_labels)} 16 | depends_on = ${repr(depends_on)} 17 | 18 | 19 | def upgrade(): 20 | ${upgrades if upgrades else "pass"} 21 | 22 | 23 | def downgrade(): 24 | ${downgrades if downgrades else "pass"} 25 | -------------------------------------------------------------------------------- /code/ex05_migrations/pypi_org/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikeckennedy/ten-tips-python-web-devs/e2406853a3d2e1d02ca5b00f68ae510993d4ad19/code/ex05_migrations/pypi_org/__init__.py -------------------------------------------------------------------------------- /code/ex05_migrations/pypi_org/app.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | import flask 4 | import pypi_org.data.db_session as db_session 5 | 6 | app = flask.Flask(__name__) 7 | 8 | 9 | def main(): 10 | register_blueprints() 11 | setup_db() 12 | app.run(debug=True) 13 | 14 | 15 | def setup_db(): 16 | db_file = os.path.join( 17 | os.path.dirname(__file__), 18 | 'db', 19 | 'pypi.sqlite') 20 | 21 | db_session.global_init(db_file) 22 | 23 | 24 | def register_blueprints(): 25 | from pypi_org.views import home_views 26 | from pypi_org.views import package_views 27 | from pypi_org.views import cms_views 28 | 29 | app.register_blueprint(package_views.blueprint) 30 | app.register_blueprint(home_views.blueprint) 31 | app.register_blueprint(cms_views.blueprint) 32 | 33 | 34 | if __name__ == '__main__': 35 | main() 36 | -------------------------------------------------------------------------------- /code/ex05_migrations/pypi_org/data/__all_models.py: -------------------------------------------------------------------------------- 1 | # Add all your SQLAlchemy models here. 2 | # This allows us to import just this file when 3 | # we need to preload the models and ensure they 4 | # are all loaded. 5 | 6 | # noinspection PyUnresolvedReferences 7 | import pypi_org.data.downloads 8 | # noinspection PyUnresolvedReferences 9 | import pypi_org.data.languages 10 | # noinspection PyUnresolvedReferences 11 | import pypi_org.data.licenses 12 | # noinspection PyUnresolvedReferences 13 | import pypi_org.data.maintainers 14 | # noinspection PyUnresolvedReferences 15 | import pypi_org.data.package 16 | # noinspection PyUnresolvedReferences 17 | import pypi_org.data.releases 18 | # noinspection PyUnresolvedReferences 19 | import pypi_org.data.users 20 | -------------------------------------------------------------------------------- /code/ex05_migrations/pypi_org/data/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikeckennedy/ten-tips-python-web-devs/e2406853a3d2e1d02ca5b00f68ae510993d4ad19/code/ex05_migrations/pypi_org/data/__init__.py -------------------------------------------------------------------------------- /code/ex05_migrations/pypi_org/data/db_session.py: -------------------------------------------------------------------------------- 1 | import sqlalchemy as sa 2 | import sqlalchemy.orm as orm 3 | from sqlalchemy.orm import Session 4 | 5 | from pypi_org.data.modelbase import SqlAlchemyBase 6 | 7 | __factory = None 8 | 9 | 10 | def global_init(db_file: str): 11 | global __factory 12 | 13 | if __factory: 14 | return 15 | 16 | if not db_file or not db_file.strip(): 17 | raise Exception("You must specify a db file.") 18 | 19 | conn_str = 'sqlite:///' + db_file.strip() 20 | print("Connecting to DB with {}".format(conn_str)) 21 | 22 | engine = sa.create_engine(conn_str, echo=False) 23 | __factory = orm.sessionmaker(bind=engine) 24 | 25 | # noinspection PyUnresolvedReferences 26 | import pypi_org.data.__all_models 27 | 28 | SqlAlchemyBase.metadata.create_all(engine) 29 | 30 | 31 | def create_session() -> Session: 32 | global __factory 33 | return __factory() 34 | -------------------------------------------------------------------------------- /code/ex05_migrations/pypi_org/data/downloads.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import sqlalchemy 3 | from pypi_org.data.modelbase import SqlAlchemyBase 4 | 5 | 6 | class Download(SqlAlchemyBase): 7 | __tablename__ = 'downloads' 8 | 9 | id: int = sqlalchemy.Column(sqlalchemy.BigInteger, primary_key=True, autoincrement=True) 10 | created_date: datetime.datetime = sqlalchemy.Column( 11 | sqlalchemy.DateTime, default=datetime.datetime.now, index=True) 12 | 13 | package_id: str = sqlalchemy.Column(sqlalchemy.String, index=True) 14 | release_id: int = sqlalchemy.Column(sqlalchemy.BigInteger, index=True) 15 | 16 | ip_address: str = sqlalchemy.Column(sqlalchemy.String) 17 | user_agent: str = sqlalchemy.Column(sqlalchemy.String) 18 | -------------------------------------------------------------------------------- /code/ex05_migrations/pypi_org/data/languages.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import sqlalchemy 3 | from pypi_org.data.modelbase import SqlAlchemyBase 4 | 5 | 6 | class ProgrammingLanguage(SqlAlchemyBase): 7 | __tablename__ = 'languages' 8 | 9 | id: str = sqlalchemy.Column(sqlalchemy.String, primary_key=True) 10 | created_date: datetime.datetime = sqlalchemy.Column( 11 | sqlalchemy.DateTime, default=datetime.datetime.now, index=True) 12 | description: str = sqlalchemy.Column(sqlalchemy.String) 13 | -------------------------------------------------------------------------------- /code/ex05_migrations/pypi_org/data/licenses.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import sqlalchemy 3 | from pypi_org.data.modelbase import SqlAlchemyBase 4 | 5 | 6 | class License(SqlAlchemyBase): 7 | __tablename__ = 'licenses' 8 | 9 | id: str = sqlalchemy.Column(sqlalchemy.String, primary_key=True) 10 | created_date: datetime.datetime = sqlalchemy.Column(sqlalchemy.DateTime, default=datetime.datetime.now, index=True) 11 | description: str = sqlalchemy.Column(sqlalchemy.String) 12 | -------------------------------------------------------------------------------- /code/ex05_migrations/pypi_org/data/maintainers.py: -------------------------------------------------------------------------------- 1 | import sqlalchemy 2 | from pypi_org.data.modelbase import SqlAlchemyBase 3 | 4 | 5 | class Maintainer(SqlAlchemyBase): 6 | __tablename__ = 'maintainers' 7 | 8 | user_id: int = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True) 9 | package_id: str = sqlalchemy.Column(sqlalchemy.String, primary_key=True) 10 | -------------------------------------------------------------------------------- /code/ex05_migrations/pypi_org/data/modelbase.py: -------------------------------------------------------------------------------- 1 | import sqlalchemy.ext.declarative as dec 2 | 3 | SqlAlchemyBase = dec.declarative_base() 4 | -------------------------------------------------------------------------------- /code/ex05_migrations/pypi_org/data/users.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import sqlalchemy 3 | from pypi_org.data.modelbase import SqlAlchemyBase 4 | 5 | 6 | class User(SqlAlchemyBase): 7 | __tablename__ = 'users' 8 | 9 | id = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True, autoincrement=True) 10 | name = sqlalchemy.Column(sqlalchemy.String, nullable=True) 11 | email = sqlalchemy.Column(sqlalchemy.String, index=True, unique=True, nullable=True) 12 | hashed_password = sqlalchemy.Column(sqlalchemy.String, nullable=True, index=True) 13 | created_date = sqlalchemy.Column(sqlalchemy.DateTime, default=datetime.datetime.now, index=True) 14 | profile_image_url = sqlalchemy.Column(sqlalchemy.String) 15 | last_login = sqlalchemy.Column(sqlalchemy.DateTime, default=datetime.datetime.now, index=True) 16 | -------------------------------------------------------------------------------- /code/ex05_migrations/pypi_org/db/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikeckennedy/ten-tips-python-web-devs/e2406853a3d2e1d02ca5b00f68ae510993d4ad19/code/ex05_migrations/pypi_org/db/__init__.py -------------------------------------------------------------------------------- /code/ex05_migrations/pypi_org/db/placeholder.txt: -------------------------------------------------------------------------------- 1 | Just here so git will create this folder. -------------------------------------------------------------------------------- /code/ex05_migrations/pypi_org/db/pypi.sqlite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikeckennedy/ten-tips-python-web-devs/e2406853a3d2e1d02ca5b00f68ae510993d4ad19/code/ex05_migrations/pypi_org/db/pypi.sqlite -------------------------------------------------------------------------------- /code/ex05_migrations/pypi_org/infrastructure/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikeckennedy/ten-tips-python-web-devs/e2406853a3d2e1d02ca5b00f68ae510993d4ad19/code/ex05_migrations/pypi_org/infrastructure/__init__.py -------------------------------------------------------------------------------- /code/ex05_migrations/pypi_org/services/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikeckennedy/ten-tips-python-web-devs/e2406853a3d2e1d02ca5b00f68ae510993d4ad19/code/ex05_migrations/pypi_org/services/__init__.py -------------------------------------------------------------------------------- /code/ex05_migrations/pypi_org/services/cms_service.py: -------------------------------------------------------------------------------- 1 | fake_db = { 2 | '/company/history': { 3 | 'page_title': 'Company history', 4 | 'page_details': 'Details about company history...', 5 | }, 6 | '/company/employees': { 7 | 'page_title': 'Our team', 8 | 'page_details': 'Details about company employees ...', 9 | }, 10 | } 11 | 12 | 13 | def get_page(url: str) -> dict: 14 | if not url: 15 | return {} 16 | 17 | url = url.strip().lower() 18 | url = '/' + url.lstrip('/') 19 | 20 | page = fake_db.get(url, {}) 21 | return page 22 | -------------------------------------------------------------------------------- /code/ex05_migrations/pypi_org/services/user_service.py: -------------------------------------------------------------------------------- 1 | import pypi_org.data.db_session as db_session 2 | from pypi_org.data.users import User 3 | 4 | 5 | def get_user_count() -> int: 6 | session = db_session.create_session() 7 | return session.query(User).count() 8 | -------------------------------------------------------------------------------- /code/ex05_migrations/pypi_org/static/img/blue-cube.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /code/ex05_migrations/pypi_org/static/img/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikeckennedy/ten-tips-python-web-devs/e2406853a3d2e1d02ca5b00f68ae510993d4ad19/code/ex05_migrations/pypi_org/static/img/favicon.png -------------------------------------------------------------------------------- /code/ex05_migrations/pypi_org/static/img/white-cube.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /code/ex05_migrations/pypi_org/templates/cms/page.html: -------------------------------------------------------------------------------- 1 | {% extends "shared/_layout.html" %} 2 | {% block title %}About PyPI Demo{% endblock %} 3 | 4 | {% block main_content %} 5 |

{{ page_title }}

6 | 7 |
8 | {{ page_details }} 9 |
10 | {% endblock %} 11 | -------------------------------------------------------------------------------- /code/ex05_migrations/pypi_org/templates/home/about.html: -------------------------------------------------------------------------------- 1 | {% extends "shared/_layout.html" %} 2 | {% block title %}About PyPI Demo{% endblock %} 3 | 4 | {% block main_content %} 5 |

About Python Package Index

6 | 7 |
8 | This is our demo app for our Flask course. 9 |
10 | {% endblock %} 11 | 12 | {% block additional_css %} 13 | 14 | {% endblock %} -------------------------------------------------------------------------------- /code/ex05_migrations/pypi_org/views/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikeckennedy/ten-tips-python-web-devs/e2406853a3d2e1d02ca5b00f68ae510993d4ad19/code/ex05_migrations/pypi_org/views/__init__.py -------------------------------------------------------------------------------- /code/ex05_migrations/pypi_org/views/cms_views.py: -------------------------------------------------------------------------------- 1 | import flask 2 | 3 | from pypi_org.infrastructure.view_modifiers import response 4 | import pypi_org.services.cms_service as cms_service 5 | 6 | blueprint = flask.Blueprint('cms', __name__, template_folder='templates') 7 | 8 | 9 | @blueprint.route('/') 10 | @response(template_file='cms/page.html') 11 | def cms_page(full_url: str): 12 | print("Getting CMS page for {}".format(full_url)) 13 | 14 | page = cms_service.get_page(full_url) 15 | if not page: 16 | return flask.abort(404) 17 | 18 | return page 19 | -------------------------------------------------------------------------------- /code/ex05_migrations/pypi_org/views/home_views.py: -------------------------------------------------------------------------------- 1 | import flask 2 | 3 | from pypi_org.infrastructure.view_modifiers import response 4 | import pypi_org.services.package_service as package_service 5 | import pypi_org.services.user_service as user_service 6 | 7 | blueprint = flask.Blueprint('home', __name__, template_folder='templates') 8 | 9 | 10 | @blueprint.route('/') 11 | @response(template_file='home/index.html') 12 | def index(): 13 | return { 14 | 'releases': package_service.get_latest_releases(), 15 | 'package_count': package_service.get_package_count(), 16 | 'release_count': package_service.get_release_count(), 17 | 'user_count': user_service.get_user_count(), 18 | } 19 | 20 | 21 | @blueprint.route('/about') 22 | @response(template_file='home/about.html') 23 | def about(): 24 | return {} 25 | -------------------------------------------------------------------------------- /code/ex05_migrations/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | setup( 4 | name='pypi_org', 5 | version='', 6 | packages=['pypi_org', 'pypi_org.db', 'pypi_org.data', 'pypi_org.views', 'pypi_org.services', 7 | 'pypi_org.infrastructure'], 8 | package_dir={'': '.'}, 9 | url='', 10 | license='', 11 | author='Michael Kennedy', 12 | author_email='', 13 | description='' 14 | ) 15 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/js/dropdown.js: -------------------------------------------------------------------------------- 1 | /* https://freefrontend.com/css-select-boxes/ */ 2 | 3 | let el = {}; 4 | 5 | $('.placeholder').on('click', function (ev) { 6 | $('.placeholder').css('opacity', '0'); 7 | $('.list__ul').toggle(); 8 | }); 9 | 10 | $('.list__ul a').on('click', function (ev) { 11 | ev.preventDefault(); 12 | var index = $(this).parent().index(); 13 | 14 | $('.placeholder').text($(this).text()).css('opacity', '1'); 15 | 16 | console.log($('.list__ul').find('li').eq(index).html()); 17 | 18 | $('.list__ul').find('li').eq(index).prependTo('.list__ul'); 19 | $('.list__ul').toggle(); 20 | 21 | }); 22 | 23 | 24 | $('select').on('change', function (e) { 25 | 26 | // Set text on placeholder hidden element 27 | $('.placeholder').text(this.value); 28 | 29 | // Animate select width as placeholder 30 | $(this).animate({width: $('.placeholder').width() + 'px'}); 31 | 32 | }); 33 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/js/vue/vue.common.js: -------------------------------------------------------------------------------- 1 | if (process.env.NODE_ENV === 'production') { 2 | module.exports = require('./vue.common.prod.js') 3 | } else { 4 | module.exports = require('./vue.common.dev.js') 5 | } 6 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/js/vue/vue.runtime.common.js: -------------------------------------------------------------------------------- 1 | if (process.env.NODE_ENV === 'production') { 2 | module.exports = require('./vue.runtime.common.prod.js') 3 | } else { 4 | module.exports = require('./vue.runtime.common.dev.js') 5 | } 6 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/node_modules/vue/src/compiler/directives/bind.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | export default function bind (el: ASTElement, dir: ASTDirective) { 4 | el.wrapData = (code: string) => { 5 | return `_b(${code},'${el.tag}',${dir.value},${ 6 | dir.modifiers && dir.modifiers.prop ? 'true' : 'false' 7 | }${ 8 | dir.modifiers && dir.modifiers.sync ? ',true' : '' 9 | })` 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/node_modules/vue/src/compiler/directives/index.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import on from './on' 4 | import bind from './bind' 5 | import { noop } from 'shared/util' 6 | 7 | export default { 8 | on, 9 | bind, 10 | cloak: noop 11 | } 12 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/node_modules/vue/src/compiler/directives/on.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { warn } from 'core/util/index' 4 | 5 | export default function on (el: ASTElement, dir: ASTDirective) { 6 | if (process.env.NODE_ENV !== 'production' && dir.modifiers) { 7 | warn(`v-on without argument does not support modifiers.`) 8 | } 9 | el.wrapListeners = (code: string) => `_g(${code},${dir.value})` 10 | } 11 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/node_modules/vue/src/compiler/index.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { parse } from './parser/index' 4 | import { optimize } from './optimizer' 5 | import { generate } from './codegen/index' 6 | import { createCompilerCreator } from './create-compiler' 7 | 8 | // `createCompilerCreator` allows creating compilers that use alternative 9 | // parser/optimizer/codegen, e.g the SSR optimizing compiler. 10 | // Here we just export a default compiler using the default parts. 11 | export const createCompiler = createCompilerCreator(function baseCompile ( 12 | template: string, 13 | options: CompilerOptions 14 | ): CompiledResult { 15 | const ast = parse(template.trim(), options) 16 | if (options.optimize !== false) { 17 | optimize(ast, options) 18 | } 19 | const code = generate(ast, options) 20 | return { 21 | ast, 22 | render: code.render, 23 | staticRenderFns: code.staticRenderFns 24 | } 25 | }) 26 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/node_modules/vue/src/compiler/parser/entity-decoder.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | let decoder 4 | 5 | export default { 6 | decode (html: string): string { 7 | decoder = decoder || document.createElement('div') 8 | decoder.innerHTML = html 9 | return decoder.textContent 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/node_modules/vue/src/core/components/index.js: -------------------------------------------------------------------------------- 1 | import KeepAlive from './keep-alive' 2 | 3 | export default { 4 | KeepAlive 5 | } 6 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/node_modules/vue/src/core/global-api/mixin.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { mergeOptions } from '../util/index' 4 | 5 | export function initMixin (Vue: GlobalAPI) { 6 | Vue.mixin = function (mixin: Object) { 7 | this.options = mergeOptions(this.options, mixin) 8 | return this 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/node_modules/vue/src/core/global-api/use.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { toArray } from '../util/index' 4 | 5 | export function initUse (Vue: GlobalAPI) { 6 | Vue.use = function (plugin: Function | Object) { 7 | const installedPlugins = (this._installedPlugins || (this._installedPlugins = [])) 8 | if (installedPlugins.indexOf(plugin) > -1) { 9 | return this 10 | } 11 | 12 | // additional parameters 13 | const args = toArray(arguments, 1) 14 | args.unshift(this) 15 | if (typeof plugin.install === 'function') { 16 | plugin.install.apply(plugin, args) 17 | } else if (typeof plugin === 'function') { 18 | plugin.apply(null, args) 19 | } 20 | installedPlugins.push(plugin) 21 | return this 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/node_modules/vue/src/core/index.js: -------------------------------------------------------------------------------- 1 | import Vue from './instance/index' 2 | import { initGlobalAPI } from './global-api/index' 3 | import { isServerRendering } from 'core/util/env' 4 | import { FunctionalRenderContext } from 'core/vdom/create-functional-component' 5 | 6 | initGlobalAPI(Vue) 7 | 8 | Object.defineProperty(Vue.prototype, '$isServer', { 9 | get: isServerRendering 10 | }) 11 | 12 | Object.defineProperty(Vue.prototype, '$ssrContext', { 13 | get () { 14 | /* istanbul ignore next */ 15 | return this.$vnode && this.$vnode.ssrContext 16 | } 17 | }) 18 | 19 | // expose FunctionalRenderContext for ssr runtime helper installation 20 | Object.defineProperty(Vue, 'FunctionalRenderContext', { 21 | value: FunctionalRenderContext 22 | }) 23 | 24 | Vue.version = '__VERSION__' 25 | 26 | export default Vue 27 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/node_modules/vue/src/core/util/index.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | export * from 'shared/util' 4 | export * from './lang' 5 | export * from './env' 6 | export * from './options' 7 | export * from './debug' 8 | export * from './props' 9 | export * from './error' 10 | export * from './next-tick' 11 | export { defineReactive } from '../observer/index' 12 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/node_modules/vue/src/core/util/perf.js: -------------------------------------------------------------------------------- 1 | import { inBrowser } from './env' 2 | 3 | export let mark 4 | export let measure 5 | 6 | if (process.env.NODE_ENV !== 'production') { 7 | const perf = inBrowser && window.performance 8 | /* istanbul ignore if */ 9 | if ( 10 | perf && 11 | perf.mark && 12 | perf.measure && 13 | perf.clearMarks && 14 | perf.clearMeasures 15 | ) { 16 | mark = tag => perf.mark(tag) 17 | measure = (name, startTag, endTag) => { 18 | perf.measure(name, startTag, endTag) 19 | perf.clearMarks(startTag) 20 | perf.clearMarks(endTag) 21 | // perf.clearMeasures(name) 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/node_modules/vue/src/core/vdom/helpers/get-first-component-child.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { isDef } from 'shared/util' 4 | import { isAsyncPlaceholder } from './is-async-placeholder' 5 | 6 | export function getFirstComponentChild (children: ?Array): ?VNode { 7 | if (Array.isArray(children)) { 8 | for (let i = 0; i < children.length; i++) { 9 | const c = children[i] 10 | if (isDef(c) && (isDef(c.componentOptions) || isAsyncPlaceholder(c))) { 11 | return c 12 | } 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/node_modules/vue/src/core/vdom/helpers/index.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | export * from './merge-hook' 4 | export * from './extract-props' 5 | export * from './update-listeners' 6 | export * from './normalize-children' 7 | export * from './resolve-async-component' 8 | export * from './get-first-component-child' 9 | export * from './is-async-placeholder' 10 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/node_modules/vue/src/core/vdom/helpers/is-async-placeholder.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | export function isAsyncPlaceholder (node: VNode): boolean { 4 | return node.isComment && node.asyncFactory 5 | } 6 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/node_modules/vue/src/core/vdom/modules/index.js: -------------------------------------------------------------------------------- 1 | import directives from './directives' 2 | import ref from './ref' 3 | 4 | export default [ 5 | ref, 6 | directives 7 | ] 8 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/node_modules/vue/src/platforms/web/compiler/directives/html.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { addProp } from 'compiler/helpers' 4 | 5 | export default function html (el: ASTElement, dir: ASTDirective) { 6 | if (dir.value) { 7 | addProp(el, 'innerHTML', `_s(${dir.value})`, dir) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/node_modules/vue/src/platforms/web/compiler/directives/index.js: -------------------------------------------------------------------------------- 1 | import model from './model' 2 | import text from './text' 3 | import html from './html' 4 | 5 | export default { 6 | model, 7 | text, 8 | html 9 | } 10 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/node_modules/vue/src/platforms/web/compiler/directives/text.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { addProp } from 'compiler/helpers' 4 | 5 | export default function text (el: ASTElement, dir: ASTDirective) { 6 | if (dir.value) { 7 | addProp(el, 'textContent', `_s(${dir.value})`, dir) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/node_modules/vue/src/platforms/web/compiler/index.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { baseOptions } from './options' 4 | import { createCompiler } from 'compiler/index' 5 | 6 | const { compile, compileToFunctions } = createCompiler(baseOptions) 7 | 8 | export { compile, compileToFunctions } 9 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/node_modules/vue/src/platforms/web/compiler/modules/index.js: -------------------------------------------------------------------------------- 1 | import klass from './class' 2 | import style from './style' 3 | import model from './model' 4 | 5 | export default [ 6 | klass, 7 | style, 8 | model 9 | ] 10 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/node_modules/vue/src/platforms/web/compiler/options.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { 4 | isPreTag, 5 | mustUseProp, 6 | isReservedTag, 7 | getTagNamespace 8 | } from '../util/index' 9 | 10 | import modules from './modules/index' 11 | import directives from './directives/index' 12 | import { genStaticKeys } from 'shared/util' 13 | import { isUnaryTag, canBeLeftOpenTag } from './util' 14 | 15 | export const baseOptions: CompilerOptions = { 16 | expectHTML: true, 17 | modules, 18 | directives, 19 | isPreTag, 20 | isUnaryTag, 21 | mustUseProp, 22 | canBeLeftOpenTag, 23 | isReservedTag, 24 | getTagNamespace, 25 | staticKeys: genStaticKeys(modules) 26 | } 27 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/node_modules/vue/src/platforms/web/entry-compiler.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | export { parseComponent } from 'sfc/parser' 4 | export { compile, compileToFunctions } from './compiler/index' 5 | export { ssrCompile, ssrCompileToFunctions } from './server/compiler' 6 | export { generateCodeFrame } from 'compiler/codeframe' 7 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/node_modules/vue/src/platforms/web/entry-runtime.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import Vue from './runtime/index' 4 | 5 | export default Vue 6 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/node_modules/vue/src/platforms/web/entry-server-basic-renderer.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import modules from './server/modules/index' 4 | import directives from './server/directives/index' 5 | import { isUnaryTag, canBeLeftOpenTag } from './compiler/util' 6 | import { createBasicRenderer } from 'server/create-basic-renderer' 7 | 8 | export default createBasicRenderer({ 9 | modules, 10 | directives, 11 | isUnaryTag, 12 | canBeLeftOpenTag 13 | }) 14 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/node_modules/vue/src/platforms/web/runtime/components/index.js: -------------------------------------------------------------------------------- 1 | import Transition from './transition' 2 | import TransitionGroup from './transition-group' 3 | 4 | export default { 5 | Transition, 6 | TransitionGroup 7 | } 8 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/node_modules/vue/src/platforms/web/runtime/directives/index.js: -------------------------------------------------------------------------------- 1 | import model from './model' 2 | import show from './show' 3 | 4 | export default { 5 | model, 6 | show 7 | } 8 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/node_modules/vue/src/platforms/web/runtime/modules/index.js: -------------------------------------------------------------------------------- 1 | import attrs from './attrs' 2 | import klass from './class' 3 | import events from './events' 4 | import domProps from './dom-props' 5 | import style from './style' 6 | import transition from './transition' 7 | 8 | export default [ 9 | attrs, 10 | klass, 11 | events, 12 | domProps, 13 | style, 14 | transition 15 | ] 16 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/node_modules/vue/src/platforms/web/runtime/patch.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import * as nodeOps from 'web/runtime/node-ops' 4 | import { createPatchFunction } from 'core/vdom/patch' 5 | import baseModules from 'core/vdom/modules/index' 6 | import platformModules from 'web/runtime/modules/index' 7 | 8 | // the directive module should be applied last, after all 9 | // built-in modules have been applied. 10 | const modules = platformModules.concat(baseModules) 11 | 12 | export const patch: Function = createPatchFunction({ nodeOps, modules }) 13 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/node_modules/vue/src/platforms/web/server/compiler.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { baseOptions } from '../compiler/options' 4 | import { createCompiler } from 'server/optimizing-compiler/index' 5 | 6 | const { compile, compileToFunctions } = createCompiler(baseOptions) 7 | 8 | export { 9 | compile as ssrCompile, 10 | compileToFunctions as ssrCompileToFunctions 11 | } 12 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/node_modules/vue/src/platforms/web/server/directives/index.js: -------------------------------------------------------------------------------- 1 | import show from './show' 2 | import model from './model' 3 | 4 | export default { 5 | show, 6 | model 7 | } 8 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/node_modules/vue/src/platforms/web/server/directives/show.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | export default function show (node: VNodeWithData, dir: VNodeDirective) { 4 | if (!dir.value) { 5 | const style: any = node.data.style || (node.data.style = {}) 6 | if (Array.isArray(style)) { 7 | style.push({ display: 'none' }) 8 | } else { 9 | style.display = 'none' 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/node_modules/vue/src/platforms/web/server/modules/class.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { escape } from '../util' 4 | import { genClassForVnode } from 'web/util/index' 5 | 6 | export default function renderClass (node: VNodeWithData): ?string { 7 | const classList = genClassForVnode(node) 8 | if (classList !== '') { 9 | return ` class="${escape(classList)}"` 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/node_modules/vue/src/platforms/web/server/modules/index.js: -------------------------------------------------------------------------------- 1 | import attrs from './attrs' 2 | import domProps from './dom-props' 3 | import klass from './class' 4 | import style from './style' 5 | 6 | export default [ 7 | attrs, 8 | domProps, 9 | klass, 10 | style 11 | ] 12 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/node_modules/vue/src/platforms/web/util/compat.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { inBrowser } from 'core/util/index' 4 | 5 | // check whether current browser encodes a char inside attribute values 6 | let div 7 | function getShouldDecode (href: boolean): boolean { 8 | div = div || document.createElement('div') 9 | div.innerHTML = href ? `` : `
` 10 | return div.innerHTML.indexOf(' ') > 0 11 | } 12 | 13 | // #3663: IE encodes newlines inside attribute values while other browsers don't 14 | export const shouldDecodeNewlines = inBrowser ? getShouldDecode(false) : false 15 | // #6828: chrome encodes content in a[href] 16 | export const shouldDecodeNewlinesForHref = inBrowser ? getShouldDecode(true) : false 17 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/node_modules/vue/src/platforms/web/util/index.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { warn } from 'core/util/index' 4 | 5 | export * from './attrs' 6 | export * from './class' 7 | export * from './element' 8 | 9 | /** 10 | * Query an element selector if it's not an element already. 11 | */ 12 | export function query (el: string | Element): Element { 13 | if (typeof el === 'string') { 14 | const selected = document.querySelector(el) 15 | if (!selected) { 16 | process.env.NODE_ENV !== 'production' && warn( 17 | 'Cannot find element: ' + el 18 | ) 19 | return document.createElement('div') 20 | } 21 | return selected 22 | } else { 23 | return el 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/node_modules/vue/src/platforms/weex/compiler/directives/index.js: -------------------------------------------------------------------------------- 1 | import model from './model' 2 | 3 | export default { 4 | model 5 | } 6 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/node_modules/vue/src/platforms/weex/compiler/modules/append.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { makeMap } from 'shared/util' 4 | 5 | // The "unitary tag" means that the tag node and its children 6 | // must be sent to the native together. 7 | const isUnitaryTag = makeMap('cell,header,cell-slot,recycle-list', true) 8 | 9 | function preTransformNode (el: ASTElement) { 10 | if (isUnitaryTag(el.tag) && !el.attrsList.some(item => item.name === 'append')) { 11 | el.attrsMap.append = 'tree' 12 | el.attrsList.push({ name: 'append', value: 'tree' }) 13 | } 14 | if (el.attrsMap.append === 'tree') { 15 | el.appendAsTree = true 16 | } 17 | } 18 | 19 | function genData (el: ASTElement): string { 20 | return el.appendAsTree ? `appendAsTree:true,` : '' 21 | } 22 | 23 | export default { 24 | staticKeys: ['appendAsTree'], 25 | preTransformNode, 26 | genData 27 | } 28 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/node_modules/vue/src/platforms/weex/compiler/modules/index.js: -------------------------------------------------------------------------------- 1 | import klass from './class' 2 | import style from './style' 3 | import props from './props' 4 | import append from './append' 5 | import recycleList from './recycle-list/index' 6 | 7 | export default [ 8 | recycleList, 9 | klass, 10 | style, 11 | props, 12 | append 13 | ] 14 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/node_modules/vue/src/platforms/weex/compiler/modules/recycle-list/component-root.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { addAttr } from 'compiler/helpers' 4 | 5 | // mark component root nodes as 6 | export function postTransformComponentRoot (el: ASTElement) { 7 | if (!el.parent) { 8 | // component root 9 | addAttr(el, '@isComponentRoot', 'true') 10 | addAttr(el, '@templateId', '_uid') 11 | addAttr(el, '@componentProps', '$props || {}') 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/node_modules/vue/src/platforms/weex/compiler/modules/recycle-list/component.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { addAttr } from 'compiler/helpers' 4 | import { RECYCLE_LIST_MARKER } from 'weex/util/index' 5 | 6 | // mark components as inside recycle-list so that we know we need to invoke 7 | // their special @render function instead of render in create-component.js 8 | export function postTransformComponent ( 9 | el: ASTElement, 10 | options: WeexCompilerOptions 11 | ) { 12 | // $flow-disable-line (we know isReservedTag is there) 13 | if (!options.isReservedTag(el.tag) && el.tag !== 'cell-slot') { 14 | addAttr(el, RECYCLE_LIST_MARKER, 'true') 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/node_modules/vue/src/platforms/weex/compiler/modules/recycle-list/text.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { addAttr } from 'compiler/helpers' 4 | 5 | function genText (node: ASTNode) { 6 | const value = node.type === 3 7 | ? node.text 8 | : node.type === 2 9 | ? node.tokens.length === 1 10 | ? node.tokens[0] 11 | : node.tokens 12 | : '' 13 | return JSON.stringify(value) 14 | } 15 | 16 | export function postTransformText (el: ASTElement) { 17 | // weex can only contain text, so the parser 18 | // always generates a single child. 19 | if (el.children.length) { 20 | addAttr(el, 'value', genText(el.children[0])) 21 | el.children = [] 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/node_modules/vue/src/platforms/weex/compiler/modules/recycle-list/v-bind.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { camelize } from 'shared/util' 4 | import { generateBinding } from 'weex/util/parser' 5 | import { bindRE } from 'compiler/parser/index' 6 | import { getAndRemoveAttr, addRawAttr } from 'compiler/helpers' 7 | 8 | function parseAttrName (name: string): string { 9 | return camelize(name.replace(bindRE, '')) 10 | } 11 | 12 | export function preTransformVBind (el: ASTElement) { 13 | for (const attr in el.attrsMap) { 14 | if (bindRE.test(attr)) { 15 | const name: string = parseAttrName(attr) 16 | const value = generateBinding(getAndRemoveAttr(el, attr)) 17 | delete el.attrsMap[attr] 18 | addRawAttr(el, name, value) 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/node_modules/vue/src/platforms/weex/compiler/modules/recycle-list/v-on.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | const inlineStatementRE = /^\s*([A-Za-z_$0-9\['\."\]]+)*\s*\(\s*(([A-Za-z_$0-9\['\."\]]+)?(\s*,\s*([A-Za-z_$0-9\['\."\]]+))*)\s*\)$/ 4 | 5 | function parseHandlerParams (handler: ASTElementHandler) { 6 | const res = inlineStatementRE.exec(handler.value) 7 | if (res && res[2]) { 8 | handler.params = res[2].split(/\s*,\s*/) 9 | } 10 | } 11 | 12 | export function postTransformVOn (el: ASTElement) { 13 | const events: ASTElementHandlers | void = el.events 14 | if (!events) { 15 | return 16 | } 17 | for (const name in events) { 18 | const handler: ASTElementHandler | Array = events[name] 19 | if (Array.isArray(handler)) { 20 | handler.map(fn => parseHandlerParams(fn)) 21 | } else { 22 | parseHandlerParams(handler) 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/node_modules/vue/src/platforms/weex/compiler/modules/recycle-list/v-once.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { getAndRemoveAttr, addRawAttr } from 'compiler/helpers' 4 | 5 | function containVOnce (el: ASTElement): boolean { 6 | for (const attr in el.attrsMap) { 7 | if (/^v\-once$/i.test(attr)) { 8 | return true 9 | } 10 | } 11 | return false 12 | } 13 | 14 | export function preTransformVOnce (el: ASTElement) { 15 | if (containVOnce(el)) { 16 | getAndRemoveAttr(el, 'v-once', true) 17 | addRawAttr(el, '[[once]]', true) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/node_modules/vue/src/platforms/weex/entry-compiler.js: -------------------------------------------------------------------------------- 1 | export { compile } from 'weex/compiler/index' 2 | export { generateCodeFrame } from 'compiler/codeframe' 3 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/node_modules/vue/src/platforms/weex/entry-runtime-factory.js: -------------------------------------------------------------------------------- 1 | // this entry is built and wrapped with a factory function 2 | // used to generate a fresh copy of Vue for every Weex instance. 3 | 4 | import Vue from './runtime/index' 5 | 6 | exports.Vue = Vue 7 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/node_modules/vue/src/platforms/weex/runtime/components/index.js: -------------------------------------------------------------------------------- 1 | import Richtext from './richtext' 2 | import Transition from './transition' 3 | import TransitionGroup from './transition-group' 4 | 5 | export default { 6 | Richtext, 7 | Transition, 8 | TransitionGroup 9 | } 10 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/node_modules/vue/src/platforms/weex/runtime/components/transition.js: -------------------------------------------------------------------------------- 1 | // reuse same transition component logic from web 2 | export { 3 | transitionProps, 4 | extractTransitionData 5 | } from 'web/runtime/components/transition' 6 | 7 | import Transition from 'web/runtime/components/transition' 8 | 9 | export default Transition 10 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/node_modules/vue/src/platforms/weex/runtime/directives/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | } 3 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/node_modules/vue/src/platforms/weex/runtime/modules/index.js: -------------------------------------------------------------------------------- 1 | import attrs from './attrs' 2 | import klass from './class' 3 | import events from './events' 4 | import style from './style' 5 | import transition from './transition' 6 | 7 | export default [ 8 | attrs, 9 | klass, 10 | events, 11 | style, 12 | transition 13 | ] 14 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/node_modules/vue/src/platforms/weex/runtime/patch.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import * as nodeOps from 'weex/runtime/node-ops' 4 | import { createPatchFunction } from 'core/vdom/patch' 5 | import baseModules from 'core/vdom/modules/index' 6 | import platformModules from 'weex/runtime/modules/index' 7 | 8 | // the directive module should be applied last, after all 9 | // built-in modules have been applied. 10 | const modules = platformModules.concat(baseModules) 11 | 12 | export const patch: Function = createPatchFunction({ 13 | nodeOps, 14 | modules, 15 | LONG_LIST_THRESHOLD: 10 16 | }) 17 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/node_modules/vue/src/platforms/weex/runtime/text-node.js: -------------------------------------------------------------------------------- 1 | let latestNodeId = 1 2 | 3 | export default function TextNode (text) { 4 | this.instanceId = '' 5 | this.nodeId = latestNodeId++ 6 | this.parentNode = null 7 | this.nodeType = 3 8 | this.text = text 9 | } 10 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/node_modules/vue/src/server/optimizing-compiler/index.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { parse } from 'compiler/parser/index' 4 | import { generate } from './codegen' 5 | import { optimize } from './optimizer' 6 | import { createCompilerCreator } from 'compiler/create-compiler' 7 | 8 | export const createCompiler = createCompilerCreator(function baseCompile ( 9 | template: string, 10 | options: CompilerOptions 11 | ): CompiledResult { 12 | const ast = parse(template.trim(), options) 13 | optimize(ast, options) 14 | const code = generate(ast, options) 15 | return { 16 | ast, 17 | render: code.render, 18 | staticRenderFns: code.staticRenderFns 19 | } 20 | }) 21 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/node_modules/vue/src/server/util.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | export const isJS = (file: string): boolean => /\.js(\?[^.]+)?$/.test(file) 4 | 5 | export const isCSS = (file: string): boolean => /\.css(\?[^.]+)?$/.test(file) 6 | 7 | export function createPromiseCallback () { 8 | let resolve, reject 9 | const promise: Promise = new Promise((_resolve, _reject) => { 10 | resolve = _resolve 11 | reject = _reject 12 | }) 13 | const cb = (err: Error, res?: string) => { 14 | if (err) return reject(err) 15 | resolve(res || '') 16 | } 17 | return { promise, cb } 18 | } 19 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/node_modules/vue/src/shared/constants.js: -------------------------------------------------------------------------------- 1 | export const SSR_ATTR = 'data-server-rendered' 2 | 3 | export const ASSET_TYPES = [ 4 | 'component', 5 | 'directive', 6 | 'filter' 7 | ] 8 | 9 | export const LIFECYCLE_HOOKS = [ 10 | 'beforeCreate', 11 | 'created', 12 | 'beforeMount', 13 | 'mounted', 14 | 'beforeUpdate', 15 | 'updated', 16 | 'beforeDestroy', 17 | 'destroyed', 18 | 'activated', 19 | 'deactivated', 20 | 'errorCaptured', 21 | 'serverPrefetch' 22 | ] 23 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/node_modules/vue/types/index.d.ts: -------------------------------------------------------------------------------- 1 | import { Vue } from "./vue"; 2 | 3 | export default Vue; 4 | 5 | export as namespace Vue; 6 | 7 | export { 8 | CreateElement, 9 | VueConstructor 10 | } from "./vue"; 11 | 12 | export { 13 | Component, 14 | AsyncComponent, 15 | ComponentOptions, 16 | FunctionalComponentOptions, 17 | RenderContext, 18 | PropType, 19 | PropOptions, 20 | ComputedOptions, 21 | WatchHandler, 22 | WatchOptions, 23 | WatchOptionsWithHandler, 24 | DirectiveFunction, 25 | DirectiveOptions 26 | } from "./options"; 27 | 28 | export { 29 | PluginFunction, 30 | PluginObject 31 | } from "./plugin"; 32 | 33 | export { 34 | VNodeChildren, 35 | VNodeChildrenArrayContents, 36 | VNode, 37 | VNodeComponentOptions, 38 | VNodeData, 39 | VNodeDirective 40 | } from "./vnode"; 41 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/node_modules/vue/types/plugin.d.ts: -------------------------------------------------------------------------------- 1 | import { Vue as _Vue } from "./vue"; 2 | 3 | export type PluginFunction = (Vue: typeof _Vue, options?: T) => void; 4 | 5 | export interface PluginObject { 6 | install: PluginFunction; 7 | [key: string]: any; 8 | } 9 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "movie_exploder", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "vue": { 8 | "version": "2.6.3", 9 | "resolved": "https://registry.npmjs.org/vue/-/vue-2.6.3.tgz", 10 | "integrity": "sha512-yftjtahz4UTAtOlXXuw7UaYD86fWrMDAAzqTdqJJx2FIBqcPmBN6kPBHiBJFGaQELVblb5ijbFMXsx0i0F7q3g==" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /code/ex06_vue/movie_exploder/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "movie_exploder", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "vue": "^2.6.3" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /code/ex07_viewmodels/pypi_vm/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikeckennedy/ten-tips-python-web-devs/e2406853a3d2e1d02ca5b00f68ae510993d4ad19/code/ex07_viewmodels/pypi_vm/__init__.py -------------------------------------------------------------------------------- /code/ex07_viewmodels/pypi_vm/config.py: -------------------------------------------------------------------------------- 1 | class Config: 2 | DEBUG = False 3 | TESTING = False 4 | DATABASE_URI = 'sqlite://:memory:' 5 | ENV = 'development' 6 | 7 | 8 | class ProductionConfig(Config): 9 | DATABASE_URI = 'mysql://user@localhost/foo' 10 | ENV = 'production' 11 | 12 | 13 | class DevelopmentConfig(Config): 14 | DEBUG = True 15 | 16 | 17 | class TestingConfig(Config): 18 | TESTING = True 19 | -------------------------------------------------------------------------------- /code/ex07_viewmodels/pypi_vm/data/__all_models.py: -------------------------------------------------------------------------------- 1 | # Add all your SQLAlchemy models here. 2 | # This allows us to import just this file when 3 | # we need to preload the models and ensure they 4 | # are all loaded. 5 | 6 | # noinspection PyUnresolvedReferences 7 | import pypi_vm.data.auditing 8 | # noinspection PyUnresolvedReferences 9 | import pypi_vm.data.downloads 10 | # noinspection PyUnresolvedReferences 11 | import pypi_vm.data.languages 12 | # noinspection PyUnresolvedReferences 13 | import pypi_vm.data.maintainers 14 | # noinspection PyUnresolvedReferences 15 | import pypi_vm.data.packages 16 | # noinspection PyUnresolvedReferences 17 | import pypi_vm.data.releases 18 | # noinspection PyUnresolvedReferences 19 | import pypi_vm.data.users 20 | -------------------------------------------------------------------------------- /code/ex07_viewmodels/pypi_vm/data/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikeckennedy/ten-tips-python-web-devs/e2406853a3d2e1d02ca5b00f68ae510993d4ad19/code/ex07_viewmodels/pypi_vm/data/__init__.py -------------------------------------------------------------------------------- /code/ex07_viewmodels/pypi_vm/data/auditing.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import sqlalchemy 3 | from pypi_vm.data.modelbase import SqlAlchemyBase 4 | 5 | 6 | class Auditing(SqlAlchemyBase): 7 | __tablename__ = 'auditing' 8 | 9 | id = sqlalchemy.Column(sqlalchemy.String, primary_key=True) 10 | created_date = sqlalchemy.Column(sqlalchemy.DateTime, default=datetime.datetime.now, index=True) 11 | description = sqlalchemy.Column(sqlalchemy.String) 12 | -------------------------------------------------------------------------------- /code/ex07_viewmodels/pypi_vm/data/db_session.py: -------------------------------------------------------------------------------- 1 | import sqlalchemy 2 | import sqlalchemy.orm 3 | from pypi_vm.data.modelbase import SqlAlchemyBase 4 | # noinspection PyUnresolvedReferences 5 | import pypi_vm.data.__all_models 6 | 7 | 8 | class DbSession: 9 | factory = None 10 | engine = None 11 | 12 | @staticmethod 13 | def global_init(db_file: str): 14 | if DbSession.factory: 15 | return 16 | 17 | if not db_file or not db_file.strip(): 18 | raise Exception("You must specify a data file.") 19 | 20 | conn_str = 'sqlite:///' + db_file 21 | print("Connecting to DB at: {}".format(conn_str)) 22 | 23 | engine = sqlalchemy.create_engine(conn_str, echo=False, connect_args={'check_same_thread': False}) 24 | DbSession.engine = engine 25 | DbSession.factory = sqlalchemy.orm.sessionmaker(bind=engine) 26 | 27 | SqlAlchemyBase.metadata.create_all(engine) 28 | 29 | -------------------------------------------------------------------------------- /code/ex07_viewmodels/pypi_vm/data/downloads.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import sqlalchemy 3 | from pypi_vm.data.modelbase import SqlAlchemyBase 4 | 5 | 6 | class Download(SqlAlchemyBase): 7 | __tablename__ = 'downloads' 8 | 9 | id = sqlalchemy.Column(sqlalchemy.BigInteger, primary_key=True, autoincrement=True) 10 | created_date = sqlalchemy.Column(sqlalchemy.DateTime, default=datetime.datetime.now, index=True) 11 | 12 | package_id = sqlalchemy.Column(sqlalchemy.String, index=True) 13 | release_id = sqlalchemy.Column(sqlalchemy.BigInteger, index=True) 14 | 15 | ip_address = sqlalchemy.Column(sqlalchemy.String) 16 | user_agent = sqlalchemy.Column(sqlalchemy.String) 17 | -------------------------------------------------------------------------------- /code/ex07_viewmodels/pypi_vm/data/languages.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import sqlalchemy 3 | from pypi_vm.data.modelbase import SqlAlchemyBase 4 | 5 | 6 | class ProgrammingLanguage(SqlAlchemyBase): 7 | __tablename__ = 'languages' 8 | 9 | id = sqlalchemy.Column(sqlalchemy.String, primary_key=True) 10 | created_date = sqlalchemy.Column(sqlalchemy.DateTime, default=datetime.datetime.now, index=True) 11 | description = sqlalchemy.Column(sqlalchemy.String) 12 | -------------------------------------------------------------------------------- /code/ex07_viewmodels/pypi_vm/data/maintainers.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | 3 | import sqlalchemy 4 | from pypi_vm.data.modelbase import SqlAlchemyBase 5 | 6 | 7 | class Maintainer(SqlAlchemyBase): 8 | __tablename__ = 'maintainers' 9 | 10 | user_id = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True) 11 | package_id = sqlalchemy.Column(sqlalchemy.String, primary_key=True) 12 | # date_added = sqlalchemy.Column(sqlalchemy.DateTime, default=datetime.datetime.now) 13 | -------------------------------------------------------------------------------- /code/ex07_viewmodels/pypi_vm/data/modelbase.py: -------------------------------------------------------------------------------- 1 | import sqlalchemy.ext.declarative as dec 2 | 3 | SqlAlchemyBase = dec.declarative_base() 4 | -------------------------------------------------------------------------------- /code/ex07_viewmodels/pypi_vm/data/users.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import sqlalchemy 3 | from pypi_vm.data.modelbase import SqlAlchemyBase 4 | 5 | 6 | class User(SqlAlchemyBase): 7 | __tablename__ = 'users' 8 | 9 | id = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True, autoincrement=True) 10 | name = sqlalchemy.Column(sqlalchemy.String, nullable=True) 11 | email = sqlalchemy.Column(sqlalchemy.String, index=True, nullable=True) 12 | hashed_password = sqlalchemy.Column(sqlalchemy.String, nullable=True, index=True) 13 | created_date = sqlalchemy.Column(sqlalchemy.DateTime, default=datetime.datetime.now, index=True) 14 | profile_image_url = sqlalchemy.Column(sqlalchemy.String) 15 | last_login = sqlalchemy.Column(sqlalchemy.DateTime, default=datetime.datetime.now, index=True) 16 | -------------------------------------------------------------------------------- /code/ex07_viewmodels/pypi_vm/db/pypi.sqlite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikeckennedy/ten-tips-python-web-devs/e2406853a3d2e1d02ca5b00f68ae510993d4ad19/code/ex07_viewmodels/pypi_vm/db/pypi.sqlite -------------------------------------------------------------------------------- /code/ex07_viewmodels/pypi_vm/infrastructure/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikeckennedy/ten-tips-python-web-devs/e2406853a3d2e1d02ca5b00f68ae510993d4ad19/code/ex07_viewmodels/pypi_vm/infrastructure/__init__.py -------------------------------------------------------------------------------- /code/ex07_viewmodels/pypi_vm/infrastructure/number_utils.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | 4 | def try_int(text: str) -> Optional[int]: 5 | try: 6 | return int(text) 7 | except: 8 | return None 9 | -------------------------------------------------------------------------------- /code/ex07_viewmodels/pypi_vm/infrastructure/request_dict.py: -------------------------------------------------------------------------------- 1 | from flask import Request 2 | 3 | 4 | class RequestDictionary(dict): 5 | def __getattr__(self, key): 6 | return self.get(key) 7 | 8 | 9 | def create(request: Request, **route_args) -> RequestDictionary: 10 | data = { 11 | **request.args, # The key/value pairs in the URL query string 12 | **request.headers, # Header values 13 | **request.form, # The key/value pairs in the body, from a HTML post form 14 | **route_args # And additional arguments the method access, if they want them merged. 15 | } 16 | 17 | return RequestDictionary(data) 18 | -------------------------------------------------------------------------------- /code/ex07_viewmodels/pypi_vm/services/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikeckennedy/ten-tips-python-web-devs/e2406853a3d2e1d02ca5b00f68ae510993d4ad19/code/ex07_viewmodels/pypi_vm/services/__init__.py -------------------------------------------------------------------------------- /code/ex07_viewmodels/pypi_vm/static/css/account.css: -------------------------------------------------------------------------------- 1 | 2 | form.account-form { 3 | margin-top: 50px; 4 | margin-left: auto; 5 | margin-right: auto; 6 | width: 500px; 7 | background-color: #ddd; 8 | color: #222; 9 | border: 1px solid gray; 10 | border-radius: 5px; 11 | text-align: center; 12 | } 13 | 14 | form.account-form h1 { 15 | text-align: center; 16 | } 17 | 18 | form.account-form > * { 19 | margin-top: 5px; 20 | margin-bottom: 5px; 21 | } 22 | 23 | form.account-form input.form-control { 24 | max-width: 95%; 25 | display: inline-block; 26 | } 27 | 28 | form.account-form button { 29 | margin-left: 350px; 30 | 31 | } 32 | 33 | .starter-template .content.account-home { 34 | margin-left: auto; 35 | margin-right: auto; 36 | max-width: 80%; 37 | } 38 | 39 | -------------------------------------------------------------------------------- /code/ex07_viewmodels/pypi_vm/static/css/home.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikeckennedy/ten-tips-python-web-devs/e2406853a3d2e1d02ca5b00f68ae510993d4ad19/code/ex07_viewmodels/pypi_vm/static/css/home.css -------------------------------------------------------------------------------- /code/ex07_viewmodels/pypi_vm/static/img/blue-cube.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /code/ex07_viewmodels/pypi_vm/static/img/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikeckennedy/ten-tips-python-web-devs/e2406853a3d2e1d02ca5b00f68ae510993d4ad19/code/ex07_viewmodels/pypi_vm/static/img/favicon.png -------------------------------------------------------------------------------- /code/ex07_viewmodels/pypi_vm/static/img/white-cube.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /code/ex07_viewmodels/pypi_vm/templates/account/index.html: -------------------------------------------------------------------------------- 1 | {% extends "shared/_layout.html" %} 2 | {% block content %} 3 | 4 | 10 | 11 | {% endblock %} 12 | 13 | 14 | {% block additional_css %} 15 | 16 | {% endblock %} -------------------------------------------------------------------------------- /code/ex07_viewmodels/pypi_vm/templates/cms/page.html: -------------------------------------------------------------------------------- 1 | {% extends "shared/_layout.html" %} 2 | {% block content %} 3 |
4 |

{{ page.page_title }}

5 |
6 | {{ page.page_details }} 7 |
8 |
9 | 10 | {% endblock %} -------------------------------------------------------------------------------- /code/ex07_viewmodels/pypi_vm/templates/packages/popular.html: -------------------------------------------------------------------------------- 1 | {% extends "shared/_layout.html" %} 2 | {% block content %} 3 | 4 |
5 | 6 |
7 |
8 |
9 |
10 |

11 | {{ package_name }} 12 |

13 | 14 |
15 |
16 | 17 |
18 | 19 | 20 |
21 | 22 | {% endblock %} 23 | -------------------------------------------------------------------------------- /code/ex07_viewmodels/pypi_vm/templates/seo/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: 3 | -------------------------------------------------------------------------------- /code/ex07_viewmodels/pypi_vm/viewmodels/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikeckennedy/ten-tips-python-web-devs/e2406853a3d2e1d02ca5b00f68ae510993d4ad19/code/ex07_viewmodels/pypi_vm/viewmodels/__init__.py -------------------------------------------------------------------------------- /code/ex07_viewmodels/pypi_vm/viewmodels/account/account_home_viewmodel.py: -------------------------------------------------------------------------------- 1 | from pypi_vm.services import user_service 2 | from pypi_vm.viewmodels.shared.viewmodel_base import ViewModelBase 3 | 4 | 5 | class AccountHomeViewModel(ViewModelBase): 6 | def __init__(self): 7 | super().__init__() 8 | 9 | self.user = user_service.find_user_by_id(self.user_id) 10 | -------------------------------------------------------------------------------- /code/ex07_viewmodels/pypi_vm/viewmodels/cms/page_viewmodel.py: -------------------------------------------------------------------------------- 1 | from pypi_vm.viewmodels.shared.viewmodel_base import ViewModelBase 2 | 3 | fake_db = { 4 | '/company/history': { 5 | 'page_title': 'Company history', 6 | 'page_details': 'Details about company history...', 7 | }, 8 | '/company/employees': { 9 | 'page_title': 'Our team', 10 | 'page_details': 'Details about company employees ...', 11 | }, 12 | } 13 | 14 | 15 | class PageViewModel(ViewModelBase): 16 | def __init__(self, sub_path: str): 17 | super().__init__() 18 | 19 | self.sub_path = sub_path 20 | self.sub_url = None 21 | if self.sub_path: 22 | self.sub_url = '/' + self.sub_path.lstrip('/') 23 | 24 | self.page = fake_db.get(self.sub_url) 25 | -------------------------------------------------------------------------------- /code/ex07_viewmodels/pypi_vm/viewmodels/home/home_index_viewmodel.py: -------------------------------------------------------------------------------- 1 | from pypi_vm.services import user_service, package_service 2 | from pypi_vm.viewmodels.shared.viewmodel_base import ViewModelBase 3 | 4 | 5 | class HomeIndexViewModel(ViewModelBase): 6 | def __init__(self): 7 | super().__init__() 8 | 9 | self.packages = package_service.latest_releases() 10 | self.package_count = package_service.package_count() 11 | self.release_count = package_service.release_count() 12 | self.user_count = user_service.user_count() 13 | -------------------------------------------------------------------------------- /code/ex07_viewmodels/pypi_vm/viewmodels/packages/popular_viewmodel.py: -------------------------------------------------------------------------------- 1 | from pypi_vm.viewmodels.shared.viewmodel_base import ViewModelBase 2 | 3 | 4 | class PopularPackageViewModel(ViewModelBase): 5 | def __init__(self, num: int): 6 | super().__init__() 7 | self.num = num 8 | self.package_name = "The {}th most popular package".format(self.num) 9 | -------------------------------------------------------------------------------- /code/ex07_viewmodels/pypi_vm/viewmodels/shared/viewmodel_base.py: -------------------------------------------------------------------------------- 1 | from typing import Optional, Any 2 | 3 | import flask 4 | from flask import Request 5 | 6 | from pypi_vm.infrastructure import request_dict, cookie_auth 7 | 8 | 9 | class ViewModelBase: 10 | def __init__(self): 11 | self.request: Request = flask.request 12 | self.request_dict = request_dict.create(self.request) 13 | self.error: Optional[str] = None 14 | self.user_id: int = cookie_auth.get_user_id_via_auth_cookie(self.request) 15 | self.name = "VM Name" 16 | self.stringify = self.stringify_func 17 | 18 | def to_dict(self): 19 | return self.__dict__ 20 | 21 | @staticmethod 22 | def stringify_func(item: Optional[Any]) -> str: 23 | if not item: 24 | return '' 25 | 26 | return str(item) 27 | -------------------------------------------------------------------------------- /code/ex07_viewmodels/pypi_vm/viewmodels/utils/sitemap_viewmodel.py: -------------------------------------------------------------------------------- 1 | import flask 2 | 3 | from pypi_vm.services import package_service 4 | from pypi_vm.viewmodels.shared.viewmodel_base import ViewModelBase 5 | 6 | 7 | class SiteMapViewModel(ViewModelBase): 8 | def __init__(self, limit: int): 9 | super().__init__() 10 | self.packages = package_service.all_packages(limit) 11 | self.last_updated_text = "2018-07-15" 12 | self.site = "{}://{}".format(flask.request.scheme, flask.request.host) 13 | -------------------------------------------------------------------------------- /code/ex07_viewmodels/pypi_vm/views/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikeckennedy/ten-tips-python-web-devs/e2406853a3d2e1d02ca5b00f68ae510993d4ad19/code/ex07_viewmodels/pypi_vm/views/__init__.py -------------------------------------------------------------------------------- /code/ex07_viewmodels/pypi_vm/views/cms_view.py: -------------------------------------------------------------------------------- 1 | import flask 2 | 3 | from pypi_vm.infrastructure.view_modifiers import response 4 | from pypi_vm.viewmodels.cms.page_viewmodel import PageViewModel 5 | 6 | blueprint = flask.Blueprint('cms', __name__, template_folder='templates') 7 | 8 | 9 | @blueprint.route('/') 10 | @response(template_file='cms/page.html') 11 | def cms_page(full_url: str): 12 | vm = PageViewModel(full_url) 13 | if not vm.page: 14 | flask.abort(status=404) 15 | 16 | return vm.to_dict() 17 | -------------------------------------------------------------------------------- /code/ex07_viewmodels/pypi_vm/views/home_view.py: -------------------------------------------------------------------------------- 1 | import flask 2 | 3 | from pypi_vm.infrastructure.view_modifiers import response 4 | from pypi_vm.viewmodels.home.home_index_viewmodel import HomeIndexViewModel 5 | 6 | blueprint = flask.Blueprint('home', __name__, template_folder='templates') 7 | 8 | 9 | @blueprint.route('/') 10 | @response(template_file='home/index.html') 11 | def index(): 12 | vm = HomeIndexViewModel() 13 | return vm.to_dict() 14 | -------------------------------------------------------------------------------- /code/ex07_viewmodels/pypi_vm/views/seo_view.py: -------------------------------------------------------------------------------- 1 | import flask 2 | 3 | from pypi_vm.infrastructure.view_modifiers import response 4 | from pypi_vm.viewmodels.utils.sitemap_viewmodel import SiteMapViewModel 5 | 6 | blueprint = flask.Blueprint('seo', __name__, template_folder='templates') 7 | 8 | 9 | # ################### Sitemap ################################# 10 | 11 | 12 | @blueprint.route('/sitemap.xml') 13 | @response(mimetype='application/xml', template_file='seo/sitemap.html') 14 | def sitemap(): 15 | vm = SiteMapViewModel(1000) 16 | return vm.to_dict() 17 | 18 | 19 | # ################### Robots ################################# 20 | 21 | @blueprint.route('/robots.txt') 22 | @response(mimetype='text/plain', template_file='seo/robots.txt') 23 | def robots(): 24 | return {} 25 | -------------------------------------------------------------------------------- /code/ex07_viewmodels/server/pypi.nginx: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | server_name fake_pypi.com 4 | server_tokens off; 5 | charset utf-8; 6 | client_max_body_size 150M; 7 | 8 | location /static { 9 | gzip on; 10 | gzip_buffers 8 256k; 11 | uwsgi_buffers 8 256k; 12 | 13 | alias /apps/appcode/demo_apps/pypi/pypi_org/static; 14 | expires 365d; 15 | } 16 | location / { 17 | try_files $uri @yourapplication; 18 | } 19 | location @yourapplication { 20 | include uwsgi_params; 21 | 22 | gzip on; 23 | gzip_buffers 8 256k; 24 | uwsgi_buffers 8 256k; 25 | uwsgi_read_timeout 300; 26 | 27 | proxy_pass http://127.0.0.1:5000; 28 | proxy_set_header Host $host; 29 | proxy_set_header X-Real-IP $remote_addr; 30 | proxy_set_header X-Forwarded-Protocol $scheme; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /code/ex07_viewmodels/server/pypi.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=uWSGI PyPI server instance 3 | After=syslog.target 4 | 5 | [Service] 6 | ExecStart=/apps/venv/bin/uwsgi -H /apps/venv --master --processes 4 --threads 2 --http :5000 --manage-script-name --mount /pypi_org=pypi_org.app:app 7 | RuntimeDirectory=/apps/appcode/demo_apps/pypi/pypi_org/ 8 | Restart=always 9 | KillSignal=SIGQUIT 10 | Type=notify 11 | StandardError=syslog 12 | NotifyAccess=all 13 | 14 | [Install] 15 | WantedBy=multi-user.target -------------------------------------------------------------------------------- /code/ex07_viewmodels/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | setup( 4 | name='pypi_vm', 5 | version='1.0.0.0', 6 | package_dir={'pypi_vm': 'pypi_vm'}, 7 | url='', 8 | license='', 9 | author='Michael Kennedy', 10 | author_email='', 11 | description='' 12 | ) 13 | -------------------------------------------------------------------------------- /code/ex07_viewmodels/tests/_all_tests.py: -------------------------------------------------------------------------------- 1 | # noinspection PyUnresolvedReferences 2 | from account_tests import * 3 | # noinspection PyUnresolvedReferences 4 | from package_tests import * 5 | # noinspection PyUnresolvedReferences 6 | from sitemap_tests import * 7 | # noinspection PyUnresolvedReferences 8 | from home_tests import * 9 | -------------------------------------------------------------------------------- /code/ex07_viewmodels/tests/commands.txt: -------------------------------------------------------------------------------- 1 | Run without warnings: 2 | 3 | -p no:warnings 4 | 5 | 6 | 7 | pytest /Users/mkennedy/github/talk-python/courses/data-driven-web/flask-materials/demo_apps/pypi/tests/_all_tests.py -p no:warnings 8 | pytest tests/_all_tests.py -p no:warnings -------------------------------------------------------------------------------- /code/ex07_viewmodels/tests/home_tests.py: -------------------------------------------------------------------------------- 1 | from flask import Response 2 | 3 | from test_client import client, flask_app 4 | from views import home_view 5 | 6 | 7 | def test_homepage(client): 8 | r: Response = client.get('/') 9 | assert r.status_code == 200 10 | assert b'Find, install and publish Python packages' in r.data 11 | 12 | 13 | def test_homepage_directly(): 14 | with flask_app.app.test_request_context(path='/'): 15 | r: Response = home_view.index() 16 | 17 | assert r.status_code == 200 18 | # noinspection PyUnresolvedReferences 19 | assert len(r.model.get('packages')) > 0 20 | -------------------------------------------------------------------------------- /code/ex07_viewmodels/tests/test_client.py: -------------------------------------------------------------------------------- 1 | # noinspection PyPackageRequirements 2 | import pytest 3 | 4 | import sys 5 | import os 6 | 7 | container_folder = os.path.abspath(os.path.join( 8 | os.path.dirname(__file__), '..' 9 | )) 10 | sys.path.append(container_folder) 11 | 12 | from pypi_vm import app as flask_app 13 | 14 | 15 | @pytest.fixture 16 | def client(): 17 | flask_app.app.config['TESTING'] = True 18 | client = flask_app.app.test_client() 19 | 20 | flask_app.register_blueprints() 21 | flask_app.init_db() 22 | client.post() 23 | 24 | yield client 25 | -------------------------------------------------------------------------------- /code/ex08_docker/base_server/dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:latest 2 | 3 | RUN apt-get update && apt-get upgrade -y 4 | ENV TZ=America/Los_Angeles 5 | RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone 6 | RUN apt-get install -y -q sudo 7 | RUN apt-get install -y -q fail2ban 8 | RUN apt-get install -y -q httpie 9 | RUN apt-get install -y -q glances 10 | -------------------------------------------------------------------------------- /code/ex08_docker/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | services: 3 | base_server: 4 | build: ./base_server/ 5 | image: base_server:latest 6 | frontend: 7 | build: ./frontend/ 8 | command: nginx -g "daemon off;" 9 | depends_on: 10 | - services 11 | - base_server 12 | ports: 13 | - "80:80" 14 | services: 15 | build: ./services/ 16 | command: /venv/bin/python /app/app.py 17 | depends_on: 18 | - base_server 19 | ports: 20 | - "7007:7007" 21 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/dockerfile: -------------------------------------------------------------------------------- 1 | FROM base_server:latest 2 | 3 | RUN apt-get install -y -q nginx 4 | RUN rm /etc/nginx/sites-enabled/default 5 | COPY site.nginx /etc/nginx/sites-enabled/site.nginx 6 | COPY movie_exploder /app 7 | 8 | ENTRYPOINT nginx -g "daemon off;" 9 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/js/dropdown.js: -------------------------------------------------------------------------------- 1 | /* https://freefrontend.com/css-select-boxes/ */ 2 | 3 | let el = {}; 4 | 5 | $('.placeholder').on('click', function (ev) { 6 | $('.placeholder').css('opacity', '0'); 7 | $('.list__ul').toggle(); 8 | }); 9 | 10 | $('.list__ul a').on('click', function (ev) { 11 | ev.preventDefault(); 12 | var index = $(this).parent().index(); 13 | 14 | $('.placeholder').text($(this).text()).css('opacity', '1'); 15 | 16 | console.log($('.list__ul').find('li').eq(index).html()); 17 | 18 | $('.list__ul').find('li').eq(index).prependTo('.list__ul'); 19 | $('.list__ul').toggle(); 20 | 21 | }); 22 | 23 | 24 | $('select').on('change', function (e) { 25 | 26 | // Set text on placeholder hidden element 27 | $('.placeholder').text(this.value); 28 | 29 | // Animate select width as placeholder 30 | $(this).animate({width: $('.placeholder').width() + 'px'}); 31 | 32 | }); 33 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/js/vue/vue.common.js: -------------------------------------------------------------------------------- 1 | if (process.env.NODE_ENV === 'production') { 2 | module.exports = require('./vue.common.prod.js') 3 | } else { 4 | module.exports = require('./vue.common.dev.js') 5 | } 6 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/js/vue/vue.runtime.common.js: -------------------------------------------------------------------------------- 1 | if (process.env.NODE_ENV === 'production') { 2 | module.exports = require('./vue.runtime.common.prod.js') 3 | } else { 4 | module.exports = require('./vue.runtime.common.dev.js') 5 | } 6 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/node_modules/vue/src/compiler/directives/bind.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | export default function bind (el: ASTElement, dir: ASTDirective) { 4 | el.wrapData = (code: string) => { 5 | return `_b(${code},'${el.tag}',${dir.value},${ 6 | dir.modifiers && dir.modifiers.prop ? 'true' : 'false' 7 | }${ 8 | dir.modifiers && dir.modifiers.sync ? ',true' : '' 9 | })` 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/node_modules/vue/src/compiler/directives/index.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import on from './on' 4 | import bind from './bind' 5 | import { noop } from 'shared/util' 6 | 7 | export default { 8 | on, 9 | bind, 10 | cloak: noop 11 | } 12 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/node_modules/vue/src/compiler/directives/on.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { warn } from 'core/util/index' 4 | 5 | export default function on (el: ASTElement, dir: ASTDirective) { 6 | if (process.env.NODE_ENV !== 'production' && dir.modifiers) { 7 | warn(`v-on without argument does not support modifiers.`) 8 | } 9 | el.wrapListeners = (code: string) => `_g(${code},${dir.value})` 10 | } 11 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/node_modules/vue/src/compiler/index.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { parse } from './parser/index' 4 | import { optimize } from './optimizer' 5 | import { generate } from './codegen/index' 6 | import { createCompilerCreator } from './create-compiler' 7 | 8 | // `createCompilerCreator` allows creating compilers that use alternative 9 | // parser/optimizer/codegen, e.g the SSR optimizing compiler. 10 | // Here we just export a default compiler using the default parts. 11 | export const createCompiler = createCompilerCreator(function baseCompile ( 12 | template: string, 13 | options: CompilerOptions 14 | ): CompiledResult { 15 | const ast = parse(template.trim(), options) 16 | if (options.optimize !== false) { 17 | optimize(ast, options) 18 | } 19 | const code = generate(ast, options) 20 | return { 21 | ast, 22 | render: code.render, 23 | staticRenderFns: code.staticRenderFns 24 | } 25 | }) 26 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/node_modules/vue/src/compiler/parser/entity-decoder.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | let decoder 4 | 5 | export default { 6 | decode (html: string): string { 7 | decoder = decoder || document.createElement('div') 8 | decoder.innerHTML = html 9 | return decoder.textContent 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/node_modules/vue/src/core/components/index.js: -------------------------------------------------------------------------------- 1 | import KeepAlive from './keep-alive' 2 | 3 | export default { 4 | KeepAlive 5 | } 6 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/node_modules/vue/src/core/global-api/mixin.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { mergeOptions } from '../util/index' 4 | 5 | export function initMixin (Vue: GlobalAPI) { 6 | Vue.mixin = function (mixin: Object) { 7 | this.options = mergeOptions(this.options, mixin) 8 | return this 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/node_modules/vue/src/core/global-api/use.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { toArray } from '../util/index' 4 | 5 | export function initUse (Vue: GlobalAPI) { 6 | Vue.use = function (plugin: Function | Object) { 7 | const installedPlugins = (this._installedPlugins || (this._installedPlugins = [])) 8 | if (installedPlugins.indexOf(plugin) > -1) { 9 | return this 10 | } 11 | 12 | // additional parameters 13 | const args = toArray(arguments, 1) 14 | args.unshift(this) 15 | if (typeof plugin.install === 'function') { 16 | plugin.install.apply(plugin, args) 17 | } else if (typeof plugin === 'function') { 18 | plugin.apply(null, args) 19 | } 20 | installedPlugins.push(plugin) 21 | return this 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/node_modules/vue/src/core/index.js: -------------------------------------------------------------------------------- 1 | import Vue from './instance/index' 2 | import { initGlobalAPI } from './global-api/index' 3 | import { isServerRendering } from 'core/util/env' 4 | import { FunctionalRenderContext } from 'core/vdom/create-functional-component' 5 | 6 | initGlobalAPI(Vue) 7 | 8 | Object.defineProperty(Vue.prototype, '$isServer', { 9 | get: isServerRendering 10 | }) 11 | 12 | Object.defineProperty(Vue.prototype, '$ssrContext', { 13 | get () { 14 | /* istanbul ignore next */ 15 | return this.$vnode && this.$vnode.ssrContext 16 | } 17 | }) 18 | 19 | // expose FunctionalRenderContext for ssr runtime helper installation 20 | Object.defineProperty(Vue, 'FunctionalRenderContext', { 21 | value: FunctionalRenderContext 22 | }) 23 | 24 | Vue.version = '__VERSION__' 25 | 26 | export default Vue 27 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/node_modules/vue/src/core/util/index.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | export * from 'shared/util' 4 | export * from './lang' 5 | export * from './env' 6 | export * from './options' 7 | export * from './debug' 8 | export * from './props' 9 | export * from './error' 10 | export * from './next-tick' 11 | export { defineReactive } from '../observer/index' 12 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/node_modules/vue/src/core/util/perf.js: -------------------------------------------------------------------------------- 1 | import { inBrowser } from './env' 2 | 3 | export let mark 4 | export let measure 5 | 6 | if (process.env.NODE_ENV !== 'production') { 7 | const perf = inBrowser && window.performance 8 | /* istanbul ignore if */ 9 | if ( 10 | perf && 11 | perf.mark && 12 | perf.measure && 13 | perf.clearMarks && 14 | perf.clearMeasures 15 | ) { 16 | mark = tag => perf.mark(tag) 17 | measure = (name, startTag, endTag) => { 18 | perf.measure(name, startTag, endTag) 19 | perf.clearMarks(startTag) 20 | perf.clearMarks(endTag) 21 | // perf.clearMeasures(name) 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/node_modules/vue/src/core/vdom/helpers/get-first-component-child.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { isDef } from 'shared/util' 4 | import { isAsyncPlaceholder } from './is-async-placeholder' 5 | 6 | export function getFirstComponentChild (children: ?Array): ?VNode { 7 | if (Array.isArray(children)) { 8 | for (let i = 0; i < children.length; i++) { 9 | const c = children[i] 10 | if (isDef(c) && (isDef(c.componentOptions) || isAsyncPlaceholder(c))) { 11 | return c 12 | } 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/node_modules/vue/src/core/vdom/helpers/index.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | export * from './merge-hook' 4 | export * from './extract-props' 5 | export * from './update-listeners' 6 | export * from './normalize-children' 7 | export * from './resolve-async-component' 8 | export * from './get-first-component-child' 9 | export * from './is-async-placeholder' 10 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/node_modules/vue/src/core/vdom/helpers/is-async-placeholder.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | export function isAsyncPlaceholder (node: VNode): boolean { 4 | return node.isComment && node.asyncFactory 5 | } 6 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/node_modules/vue/src/core/vdom/modules/index.js: -------------------------------------------------------------------------------- 1 | import directives from './directives' 2 | import ref from './ref' 3 | 4 | export default [ 5 | ref, 6 | directives 7 | ] 8 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/node_modules/vue/src/platforms/web/compiler/directives/html.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { addProp } from 'compiler/helpers' 4 | 5 | export default function html (el: ASTElement, dir: ASTDirective) { 6 | if (dir.value) { 7 | addProp(el, 'innerHTML', `_s(${dir.value})`, dir) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/node_modules/vue/src/platforms/web/compiler/directives/index.js: -------------------------------------------------------------------------------- 1 | import model from './model' 2 | import text from './text' 3 | import html from './html' 4 | 5 | export default { 6 | model, 7 | text, 8 | html 9 | } 10 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/node_modules/vue/src/platforms/web/compiler/directives/text.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { addProp } from 'compiler/helpers' 4 | 5 | export default function text (el: ASTElement, dir: ASTDirective) { 6 | if (dir.value) { 7 | addProp(el, 'textContent', `_s(${dir.value})`, dir) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/node_modules/vue/src/platforms/web/compiler/index.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { baseOptions } from './options' 4 | import { createCompiler } from 'compiler/index' 5 | 6 | const { compile, compileToFunctions } = createCompiler(baseOptions) 7 | 8 | export { compile, compileToFunctions } 9 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/node_modules/vue/src/platforms/web/compiler/modules/index.js: -------------------------------------------------------------------------------- 1 | import klass from './class' 2 | import style from './style' 3 | import model from './model' 4 | 5 | export default [ 6 | klass, 7 | style, 8 | model 9 | ] 10 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/node_modules/vue/src/platforms/web/compiler/options.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { 4 | isPreTag, 5 | mustUseProp, 6 | isReservedTag, 7 | getTagNamespace 8 | } from '../util/index' 9 | 10 | import modules from './modules/index' 11 | import directives from './directives/index' 12 | import { genStaticKeys } from 'shared/util' 13 | import { isUnaryTag, canBeLeftOpenTag } from './util' 14 | 15 | export const baseOptions: CompilerOptions = { 16 | expectHTML: true, 17 | modules, 18 | directives, 19 | isPreTag, 20 | isUnaryTag, 21 | mustUseProp, 22 | canBeLeftOpenTag, 23 | isReservedTag, 24 | getTagNamespace, 25 | staticKeys: genStaticKeys(modules) 26 | } 27 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/node_modules/vue/src/platforms/web/entry-compiler.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | export { parseComponent } from 'sfc/parser' 4 | export { compile, compileToFunctions } from './compiler/index' 5 | export { ssrCompile, ssrCompileToFunctions } from './server/compiler' 6 | export { generateCodeFrame } from 'compiler/codeframe' 7 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/node_modules/vue/src/platforms/web/entry-runtime.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import Vue from './runtime/index' 4 | 5 | export default Vue 6 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/node_modules/vue/src/platforms/web/entry-server-basic-renderer.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import modules from './server/modules/index' 4 | import directives from './server/directives/index' 5 | import { isUnaryTag, canBeLeftOpenTag } from './compiler/util' 6 | import { createBasicRenderer } from 'server/create-basic-renderer' 7 | 8 | export default createBasicRenderer({ 9 | modules, 10 | directives, 11 | isUnaryTag, 12 | canBeLeftOpenTag 13 | }) 14 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/node_modules/vue/src/platforms/web/runtime/components/index.js: -------------------------------------------------------------------------------- 1 | import Transition from './transition' 2 | import TransitionGroup from './transition-group' 3 | 4 | export default { 5 | Transition, 6 | TransitionGroup 7 | } 8 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/node_modules/vue/src/platforms/web/runtime/directives/index.js: -------------------------------------------------------------------------------- 1 | import model from './model' 2 | import show from './show' 3 | 4 | export default { 5 | model, 6 | show 7 | } 8 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/node_modules/vue/src/platforms/web/runtime/modules/index.js: -------------------------------------------------------------------------------- 1 | import attrs from './attrs' 2 | import klass from './class' 3 | import events from './events' 4 | import domProps from './dom-props' 5 | import style from './style' 6 | import transition from './transition' 7 | 8 | export default [ 9 | attrs, 10 | klass, 11 | events, 12 | domProps, 13 | style, 14 | transition 15 | ] 16 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/node_modules/vue/src/platforms/web/runtime/patch.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import * as nodeOps from 'web/runtime/node-ops' 4 | import { createPatchFunction } from 'core/vdom/patch' 5 | import baseModules from 'core/vdom/modules/index' 6 | import platformModules from 'web/runtime/modules/index' 7 | 8 | // the directive module should be applied last, after all 9 | // built-in modules have been applied. 10 | const modules = platformModules.concat(baseModules) 11 | 12 | export const patch: Function = createPatchFunction({ nodeOps, modules }) 13 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/node_modules/vue/src/platforms/web/server/compiler.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { baseOptions } from '../compiler/options' 4 | import { createCompiler } from 'server/optimizing-compiler/index' 5 | 6 | const { compile, compileToFunctions } = createCompiler(baseOptions) 7 | 8 | export { 9 | compile as ssrCompile, 10 | compileToFunctions as ssrCompileToFunctions 11 | } 12 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/node_modules/vue/src/platforms/web/server/directives/index.js: -------------------------------------------------------------------------------- 1 | import show from './show' 2 | import model from './model' 3 | 4 | export default { 5 | show, 6 | model 7 | } 8 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/node_modules/vue/src/platforms/web/server/directives/show.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | export default function show (node: VNodeWithData, dir: VNodeDirective) { 4 | if (!dir.value) { 5 | const style: any = node.data.style || (node.data.style = {}) 6 | if (Array.isArray(style)) { 7 | style.push({ display: 'none' }) 8 | } else { 9 | style.display = 'none' 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/node_modules/vue/src/platforms/web/server/modules/class.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { escape } from '../util' 4 | import { genClassForVnode } from 'web/util/index' 5 | 6 | export default function renderClass (node: VNodeWithData): ?string { 7 | const classList = genClassForVnode(node) 8 | if (classList !== '') { 9 | return ` class="${escape(classList)}"` 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/node_modules/vue/src/platforms/web/server/modules/index.js: -------------------------------------------------------------------------------- 1 | import attrs from './attrs' 2 | import domProps from './dom-props' 3 | import klass from './class' 4 | import style from './style' 5 | 6 | export default [ 7 | attrs, 8 | domProps, 9 | klass, 10 | style 11 | ] 12 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/node_modules/vue/src/platforms/web/util/compat.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { inBrowser } from 'core/util/index' 4 | 5 | // check whether current browser encodes a char inside attribute values 6 | let div 7 | function getShouldDecode (href: boolean): boolean { 8 | div = div || document.createElement('div') 9 | div.innerHTML = href ? `
` : `
` 10 | return div.innerHTML.indexOf(' ') > 0 11 | } 12 | 13 | // #3663: IE encodes newlines inside attribute values while other browsers don't 14 | export const shouldDecodeNewlines = inBrowser ? getShouldDecode(false) : false 15 | // #6828: chrome encodes content in a[href] 16 | export const shouldDecodeNewlinesForHref = inBrowser ? getShouldDecode(true) : false 17 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/node_modules/vue/src/platforms/web/util/index.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { warn } from 'core/util/index' 4 | 5 | export * from './attrs' 6 | export * from './class' 7 | export * from './element' 8 | 9 | /** 10 | * Query an element selector if it's not an element already. 11 | */ 12 | export function query (el: string | Element): Element { 13 | if (typeof el === 'string') { 14 | const selected = document.querySelector(el) 15 | if (!selected) { 16 | process.env.NODE_ENV !== 'production' && warn( 17 | 'Cannot find element: ' + el 18 | ) 19 | return document.createElement('div') 20 | } 21 | return selected 22 | } else { 23 | return el 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/node_modules/vue/src/platforms/weex/compiler/directives/index.js: -------------------------------------------------------------------------------- 1 | import model from './model' 2 | 3 | export default { 4 | model 5 | } 6 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/node_modules/vue/src/platforms/weex/compiler/modules/append.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { makeMap } from 'shared/util' 4 | 5 | // The "unitary tag" means that the tag node and its children 6 | // must be sent to the native together. 7 | const isUnitaryTag = makeMap('cell,header,cell-slot,recycle-list', true) 8 | 9 | function preTransformNode (el: ASTElement) { 10 | if (isUnitaryTag(el.tag) && !el.attrsList.some(item => item.name === 'append')) { 11 | el.attrsMap.append = 'tree' 12 | el.attrsList.push({ name: 'append', value: 'tree' }) 13 | } 14 | if (el.attrsMap.append === 'tree') { 15 | el.appendAsTree = true 16 | } 17 | } 18 | 19 | function genData (el: ASTElement): string { 20 | return el.appendAsTree ? `appendAsTree:true,` : '' 21 | } 22 | 23 | export default { 24 | staticKeys: ['appendAsTree'], 25 | preTransformNode, 26 | genData 27 | } 28 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/node_modules/vue/src/platforms/weex/compiler/modules/index.js: -------------------------------------------------------------------------------- 1 | import klass from './class' 2 | import style from './style' 3 | import props from './props' 4 | import append from './append' 5 | import recycleList from './recycle-list/index' 6 | 7 | export default [ 8 | recycleList, 9 | klass, 10 | style, 11 | props, 12 | append 13 | ] 14 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/node_modules/vue/src/platforms/weex/compiler/modules/recycle-list/component-root.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { addAttr } from 'compiler/helpers' 4 | 5 | // mark component root nodes as 6 | export function postTransformComponentRoot (el: ASTElement) { 7 | if (!el.parent) { 8 | // component root 9 | addAttr(el, '@isComponentRoot', 'true') 10 | addAttr(el, '@templateId', '_uid') 11 | addAttr(el, '@componentProps', '$props || {}') 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/node_modules/vue/src/platforms/weex/compiler/modules/recycle-list/component.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { addAttr } from 'compiler/helpers' 4 | import { RECYCLE_LIST_MARKER } from 'weex/util/index' 5 | 6 | // mark components as inside recycle-list so that we know we need to invoke 7 | // their special @render function instead of render in create-component.js 8 | export function postTransformComponent ( 9 | el: ASTElement, 10 | options: WeexCompilerOptions 11 | ) { 12 | // $flow-disable-line (we know isReservedTag is there) 13 | if (!options.isReservedTag(el.tag) && el.tag !== 'cell-slot') { 14 | addAttr(el, RECYCLE_LIST_MARKER, 'true') 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/node_modules/vue/src/platforms/weex/compiler/modules/recycle-list/text.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { addAttr } from 'compiler/helpers' 4 | 5 | function genText (node: ASTNode) { 6 | const value = node.type === 3 7 | ? node.text 8 | : node.type === 2 9 | ? node.tokens.length === 1 10 | ? node.tokens[0] 11 | : node.tokens 12 | : '' 13 | return JSON.stringify(value) 14 | } 15 | 16 | export function postTransformText (el: ASTElement) { 17 | // weex can only contain text, so the parser 18 | // always generates a single child. 19 | if (el.children.length) { 20 | addAttr(el, 'value', genText(el.children[0])) 21 | el.children = [] 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/node_modules/vue/src/platforms/weex/compiler/modules/recycle-list/v-bind.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { camelize } from 'shared/util' 4 | import { generateBinding } from 'weex/util/parser' 5 | import { bindRE } from 'compiler/parser/index' 6 | import { getAndRemoveAttr, addRawAttr } from 'compiler/helpers' 7 | 8 | function parseAttrName (name: string): string { 9 | return camelize(name.replace(bindRE, '')) 10 | } 11 | 12 | export function preTransformVBind (el: ASTElement) { 13 | for (const attr in el.attrsMap) { 14 | if (bindRE.test(attr)) { 15 | const name: string = parseAttrName(attr) 16 | const value = generateBinding(getAndRemoveAttr(el, attr)) 17 | delete el.attrsMap[attr] 18 | addRawAttr(el, name, value) 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/node_modules/vue/src/platforms/weex/compiler/modules/recycle-list/v-on.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | const inlineStatementRE = /^\s*([A-Za-z_$0-9\['\."\]]+)*\s*\(\s*(([A-Za-z_$0-9\['\."\]]+)?(\s*,\s*([A-Za-z_$0-9\['\."\]]+))*)\s*\)$/ 4 | 5 | function parseHandlerParams (handler: ASTElementHandler) { 6 | const res = inlineStatementRE.exec(handler.value) 7 | if (res && res[2]) { 8 | handler.params = res[2].split(/\s*,\s*/) 9 | } 10 | } 11 | 12 | export function postTransformVOn (el: ASTElement) { 13 | const events: ASTElementHandlers | void = el.events 14 | if (!events) { 15 | return 16 | } 17 | for (const name in events) { 18 | const handler: ASTElementHandler | Array = events[name] 19 | if (Array.isArray(handler)) { 20 | handler.map(fn => parseHandlerParams(fn)) 21 | } else { 22 | parseHandlerParams(handler) 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/node_modules/vue/src/platforms/weex/compiler/modules/recycle-list/v-once.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { getAndRemoveAttr, addRawAttr } from 'compiler/helpers' 4 | 5 | function containVOnce (el: ASTElement): boolean { 6 | for (const attr in el.attrsMap) { 7 | if (/^v\-once$/i.test(attr)) { 8 | return true 9 | } 10 | } 11 | return false 12 | } 13 | 14 | export function preTransformVOnce (el: ASTElement) { 15 | if (containVOnce(el)) { 16 | getAndRemoveAttr(el, 'v-once', true) 17 | addRawAttr(el, '[[once]]', true) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/node_modules/vue/src/platforms/weex/entry-compiler.js: -------------------------------------------------------------------------------- 1 | export { compile } from 'weex/compiler/index' 2 | export { generateCodeFrame } from 'compiler/codeframe' 3 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/node_modules/vue/src/platforms/weex/entry-runtime-factory.js: -------------------------------------------------------------------------------- 1 | // this entry is built and wrapped with a factory function 2 | // used to generate a fresh copy of Vue for every Weex instance. 3 | 4 | import Vue from './runtime/index' 5 | 6 | exports.Vue = Vue 7 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/node_modules/vue/src/platforms/weex/runtime/components/index.js: -------------------------------------------------------------------------------- 1 | import Richtext from './richtext' 2 | import Transition from './transition' 3 | import TransitionGroup from './transition-group' 4 | 5 | export default { 6 | Richtext, 7 | Transition, 8 | TransitionGroup 9 | } 10 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/node_modules/vue/src/platforms/weex/runtime/components/transition.js: -------------------------------------------------------------------------------- 1 | // reuse same transition component logic from web 2 | export { 3 | transitionProps, 4 | extractTransitionData 5 | } from 'web/runtime/components/transition' 6 | 7 | import Transition from 'web/runtime/components/transition' 8 | 9 | export default Transition 10 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/node_modules/vue/src/platforms/weex/runtime/directives/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | } 3 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/node_modules/vue/src/platforms/weex/runtime/modules/index.js: -------------------------------------------------------------------------------- 1 | import attrs from './attrs' 2 | import klass from './class' 3 | import events from './events' 4 | import style from './style' 5 | import transition from './transition' 6 | 7 | export default [ 8 | attrs, 9 | klass, 10 | events, 11 | style, 12 | transition 13 | ] 14 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/node_modules/vue/src/platforms/weex/runtime/patch.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import * as nodeOps from 'weex/runtime/node-ops' 4 | import { createPatchFunction } from 'core/vdom/patch' 5 | import baseModules from 'core/vdom/modules/index' 6 | import platformModules from 'weex/runtime/modules/index' 7 | 8 | // the directive module should be applied last, after all 9 | // built-in modules have been applied. 10 | const modules = platformModules.concat(baseModules) 11 | 12 | export const patch: Function = createPatchFunction({ 13 | nodeOps, 14 | modules, 15 | LONG_LIST_THRESHOLD: 10 16 | }) 17 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/node_modules/vue/src/platforms/weex/runtime/text-node.js: -------------------------------------------------------------------------------- 1 | let latestNodeId = 1 2 | 3 | export default function TextNode (text) { 4 | this.instanceId = '' 5 | this.nodeId = latestNodeId++ 6 | this.parentNode = null 7 | this.nodeType = 3 8 | this.text = text 9 | } 10 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/node_modules/vue/src/server/optimizing-compiler/index.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { parse } from 'compiler/parser/index' 4 | import { generate } from './codegen' 5 | import { optimize } from './optimizer' 6 | import { createCompilerCreator } from 'compiler/create-compiler' 7 | 8 | export const createCompiler = createCompilerCreator(function baseCompile ( 9 | template: string, 10 | options: CompilerOptions 11 | ): CompiledResult { 12 | const ast = parse(template.trim(), options) 13 | optimize(ast, options) 14 | const code = generate(ast, options) 15 | return { 16 | ast, 17 | render: code.render, 18 | staticRenderFns: code.staticRenderFns 19 | } 20 | }) 21 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/node_modules/vue/src/server/util.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | export const isJS = (file: string): boolean => /\.js(\?[^.]+)?$/.test(file) 4 | 5 | export const isCSS = (file: string): boolean => /\.css(\?[^.]+)?$/.test(file) 6 | 7 | export function createPromiseCallback () { 8 | let resolve, reject 9 | const promise: Promise = new Promise((_resolve, _reject) => { 10 | resolve = _resolve 11 | reject = _reject 12 | }) 13 | const cb = (err: Error, res?: string) => { 14 | if (err) return reject(err) 15 | resolve(res || '') 16 | } 17 | return { promise, cb } 18 | } 19 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/node_modules/vue/src/shared/constants.js: -------------------------------------------------------------------------------- 1 | export const SSR_ATTR = 'data-server-rendered' 2 | 3 | export const ASSET_TYPES = [ 4 | 'component', 5 | 'directive', 6 | 'filter' 7 | ] 8 | 9 | export const LIFECYCLE_HOOKS = [ 10 | 'beforeCreate', 11 | 'created', 12 | 'beforeMount', 13 | 'mounted', 14 | 'beforeUpdate', 15 | 'updated', 16 | 'beforeDestroy', 17 | 'destroyed', 18 | 'activated', 19 | 'deactivated', 20 | 'errorCaptured', 21 | 'serverPrefetch' 22 | ] 23 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/node_modules/vue/types/index.d.ts: -------------------------------------------------------------------------------- 1 | import { Vue } from "./vue"; 2 | 3 | export default Vue; 4 | 5 | export as namespace Vue; 6 | 7 | export { 8 | CreateElement, 9 | VueConstructor 10 | } from "./vue"; 11 | 12 | export { 13 | Component, 14 | AsyncComponent, 15 | ComponentOptions, 16 | FunctionalComponentOptions, 17 | RenderContext, 18 | PropType, 19 | PropOptions, 20 | ComputedOptions, 21 | WatchHandler, 22 | WatchOptions, 23 | WatchOptionsWithHandler, 24 | DirectiveFunction, 25 | DirectiveOptions 26 | } from "./options"; 27 | 28 | export { 29 | PluginFunction, 30 | PluginObject 31 | } from "./plugin"; 32 | 33 | export { 34 | VNodeChildren, 35 | VNodeChildrenArrayContents, 36 | VNode, 37 | VNodeComponentOptions, 38 | VNodeData, 39 | VNodeDirective 40 | } from "./vnode"; 41 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/node_modules/vue/types/plugin.d.ts: -------------------------------------------------------------------------------- 1 | import { Vue as _Vue } from "./vue"; 2 | 3 | export type PluginFunction = (Vue: typeof _Vue, options?: T) => void; 4 | 5 | export interface PluginObject { 6 | install: PluginFunction; 7 | [key: string]: any; 8 | } 9 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "movie_exploder", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "vue": { 8 | "version": "2.6.3", 9 | "resolved": "https://registry.npmjs.org/vue/-/vue-2.6.3.tgz", 10 | "integrity": "sha512-yftjtahz4UTAtOlXXuw7UaYD86fWrMDAAzqTdqJJx2FIBqcPmBN6kPBHiBJFGaQELVblb5ijbFMXsx0i0F7q3g==" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/movie_exploder/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "movie_exploder", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "vue": "^2.6.3" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /code/ex08_docker/frontend/site.nginx: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | server_name movieexploder.com; 4 | server_tokens off; 5 | charset utf-8; 6 | client_max_body_size 150M; 7 | 8 | root /app; 9 | 10 | location /css { 11 | alias /app/css; 12 | # autoindex on; 13 | expires 365d; 14 | } 15 | 16 | location / { 17 | index /views/index.html; 18 | } 19 | 20 | location /js { 21 | alias /app/js; 22 | # autoindex on; 23 | expires 365d; 24 | } 25 | location /node_modules { 26 | alias /app/node_modules; 27 | # autoindex on; 28 | expires 365d; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /code/ex08_docker/services/dockerfile: -------------------------------------------------------------------------------- 1 | FROM base_server:latest 2 | 3 | RUN apt-get install -y -q build-essential git python3-pip python3-dev python3-venv 4 | RUN python3 -m venv /venv 5 | RUN /venv/bin/pip install -U pip setuptools 6 | RUN /venv/bin/pip install responder 7 | 8 | COPY movie_svc /app 9 | WORKDIR /app 10 | RUN /venv/bin/pip install -r /app/requirements.txt 11 | 12 | ENTRYPOINT /venv/bin/python /app/app.py 13 | -------------------------------------------------------------------------------- /code/ex08_docker/services/movie_svc/app.py: -------------------------------------------------------------------------------- 1 | # noinspection PyUnresolvedReferences 2 | from app_instance import api 3 | from routes import * 4 | from data import db 5 | 6 | db.global_init() 7 | 8 | 9 | api.run(port=7007, address="0.0.0.0") 10 | -------------------------------------------------------------------------------- /code/ex08_docker/services/movie_svc/app_instance.py: -------------------------------------------------------------------------------- 1 | import responder 2 | 3 | cors_params = { 4 | 'allow_origins': '*', 5 | 'allow_methods': '*', 6 | } 7 | 8 | api = responder.API(cors=True, cors_params=cors_params) 9 | -------------------------------------------------------------------------------- /code/ex08_docker/services/movie_svc/requirements.txt: -------------------------------------------------------------------------------- 1 | responder 2 | -------------------------------------------------------------------------------- /code/ex08_docker/services/movie_svc/routes.py: -------------------------------------------------------------------------------- 1 | # noinspection PyUnresolvedReferences 2 | from app_instance import api 3 | # noinspection PyUnresolvedReferences 4 | from views.api_views import * 5 | # noinspection PyUnresolvedReferences 6 | from views.home import * 7 | 8 | api.add_route("/static", static=True) 9 | -------------------------------------------------------------------------------- /code/ex08_docker/services/movie_svc/static/css/docs.css: -------------------------------------------------------------------------------- 1 | .request { 2 | font-family: Menlo, Monaco, Consolas, "Courier New", monospace; 3 | font-weight: bold; 4 | border: 1px solid gray; 5 | border-radius: 5px; 6 | padding: 10px; 7 | font-size: 24px; 8 | } 9 | 10 | .get { 11 | color: #2b542c; 12 | background-color: #beffbd; 13 | } 14 | 15 | .post { 16 | color: #ae5900; 17 | background-color: #ffc79d; 18 | } 19 | 20 | .response_formats span { 21 | font-weight: bold; 22 | color: darkred; 23 | font-family: Menlo, Monaco, Consolas, "Courier New", monospace; 24 | } 25 | 26 | pre { 27 | font-family: Menlo, Monaco, Consolas, "Courier New", monospace; 28 | } 29 | 30 | ul li { 31 | font-size: 18px; 32 | margin-bottom: 10px; 33 | } -------------------------------------------------------------------------------- /code/ex08_docker/services/movie_svc/views/home.py: -------------------------------------------------------------------------------- 1 | from app_instance import api 2 | 3 | 4 | @api.route("/") 5 | def index(req, resp): 6 | resp.content = api.template('home/index.html') 7 | -------------------------------------------------------------------------------- /code/ex09_lets_encrypt/make_secure.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Steps: 4 | # https://www.digitalocean.com/community/tutorials/how-to-secure-nginx-with-let-s-encrypt-on-ubuntu-18-04 5 | 6 | add-apt-repository ppa:certbot/certbot -y 7 | apt update 8 | apt install python-certbot-nginx -y 9 | 10 | certbot --nginx -d billssltest.talkpython.com 11 | 12 | service nginx restart -------------------------------------------------------------------------------- /code/ex10_securepy/pypi_secure/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikeckennedy/ten-tips-python-web-devs/e2406853a3d2e1d02ca5b00f68ae510993d4ad19/code/ex10_securepy/pypi_secure/__init__.py -------------------------------------------------------------------------------- /code/ex10_securepy/pypi_secure/data/__all_models.py: -------------------------------------------------------------------------------- 1 | # Add all your SQLAlchemy models here. 2 | # This allows us to import just this file when 3 | # we need to preload the models and ensure they 4 | # are all loaded. 5 | 6 | # noinspection PyUnresolvedReferences 7 | import pypi_secure.data.downloads 8 | # noinspection PyUnresolvedReferences 9 | import pypi_secure.data.languages 10 | # noinspection PyUnresolvedReferences 11 | import pypi_secure.data.licenses 12 | # noinspection PyUnresolvedReferences 13 | import pypi_secure.data.maintainers 14 | # noinspection PyUnresolvedReferences 15 | import pypi_secure.data.package 16 | # noinspection PyUnresolvedReferences 17 | import pypi_secure.data.releases 18 | # noinspection PyUnresolvedReferences 19 | import pypi_secure.data.users 20 | -------------------------------------------------------------------------------- /code/ex10_securepy/pypi_secure/data/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikeckennedy/ten-tips-python-web-devs/e2406853a3d2e1d02ca5b00f68ae510993d4ad19/code/ex10_securepy/pypi_secure/data/__init__.py -------------------------------------------------------------------------------- /code/ex10_securepy/pypi_secure/data/db_session.py: -------------------------------------------------------------------------------- 1 | import sqlalchemy as sa 2 | import sqlalchemy.orm as orm 3 | from sqlalchemy.orm import Session 4 | 5 | from pypi_secure.data.modelbase import SqlAlchemyBase 6 | 7 | __factory = None 8 | 9 | 10 | def global_init(db_file: str): 11 | global __factory 12 | 13 | if __factory: 14 | return 15 | 16 | if not db_file or not db_file.strip(): 17 | raise Exception("You must specify a db file.") 18 | 19 | conn_str = 'sqlite:///' + db_file.strip() 20 | print("Connecting to DB with {}".format(conn_str)) 21 | 22 | engine = sa.create_engine(conn_str, echo=False) 23 | __factory = orm.sessionmaker(bind=engine) 24 | 25 | # noinspection PyUnresolvedReferences 26 | import pypi_secure.data.__all_models 27 | 28 | SqlAlchemyBase.metadata.create_all(engine) 29 | 30 | 31 | def create_session() -> Session: 32 | global __factory 33 | return __factory() 34 | -------------------------------------------------------------------------------- /code/ex10_securepy/pypi_secure/data/downloads.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import sqlalchemy 3 | from pypi_secure.data.modelbase import SqlAlchemyBase 4 | 5 | 6 | class Download(SqlAlchemyBase): 7 | __tablename__ = 'downloads' 8 | 9 | id: int = sqlalchemy.Column(sqlalchemy.BigInteger, primary_key=True, autoincrement=True) 10 | created_date: datetime.datetime = sqlalchemy.Column( 11 | sqlalchemy.DateTime, default=datetime.datetime.now, index=True) 12 | 13 | package_id: str = sqlalchemy.Column(sqlalchemy.String, index=True) 14 | release_id: int = sqlalchemy.Column(sqlalchemy.BigInteger, index=True) 15 | 16 | ip_address: str = sqlalchemy.Column(sqlalchemy.String) 17 | user_agent: str = sqlalchemy.Column(sqlalchemy.String) 18 | -------------------------------------------------------------------------------- /code/ex10_securepy/pypi_secure/data/languages.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import sqlalchemy 3 | from pypi_secure.data.modelbase import SqlAlchemyBase 4 | 5 | 6 | class ProgrammingLanguage(SqlAlchemyBase): 7 | __tablename__ = 'languages' 8 | 9 | id: str = sqlalchemy.Column(sqlalchemy.String, primary_key=True) 10 | created_date: datetime.datetime = sqlalchemy.Column( 11 | sqlalchemy.DateTime, default=datetime.datetime.now, index=True) 12 | description: str = sqlalchemy.Column(sqlalchemy.String) 13 | -------------------------------------------------------------------------------- /code/ex10_securepy/pypi_secure/data/licenses.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import sqlalchemy 3 | from pypi_secure.data.modelbase import SqlAlchemyBase 4 | 5 | 6 | class License(SqlAlchemyBase): 7 | __tablename__ = 'licenses' 8 | 9 | id: str = sqlalchemy.Column(sqlalchemy.String, primary_key=True) 10 | created_date: datetime.datetime = sqlalchemy.Column(sqlalchemy.DateTime, default=datetime.datetime.now, index=True) 11 | description: str = sqlalchemy.Column(sqlalchemy.String) 12 | -------------------------------------------------------------------------------- /code/ex10_securepy/pypi_secure/data/maintainers.py: -------------------------------------------------------------------------------- 1 | import sqlalchemy 2 | from pypi_secure.data.modelbase import SqlAlchemyBase 3 | 4 | 5 | class Maintainer(SqlAlchemyBase): 6 | __tablename__ = 'maintainers' 7 | 8 | user_id: int = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True) 9 | package_id: str = sqlalchemy.Column(sqlalchemy.String, primary_key=True) 10 | -------------------------------------------------------------------------------- /code/ex10_securepy/pypi_secure/data/modelbase.py: -------------------------------------------------------------------------------- 1 | import sqlalchemy.ext.declarative as dec 2 | 3 | SqlAlchemyBase = dec.declarative_base() 4 | -------------------------------------------------------------------------------- /code/ex10_securepy/pypi_secure/data/users.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import sqlalchemy 3 | from pypi_secure.data.modelbase import SqlAlchemyBase 4 | 5 | 6 | class User(SqlAlchemyBase): 7 | __tablename__ = 'users' 8 | 9 | id = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True, autoincrement=True) 10 | name = sqlalchemy.Column(sqlalchemy.String, nullable=True) 11 | email = sqlalchemy.Column(sqlalchemy.String, index=True, unique=True, nullable=True) 12 | hashed_password = sqlalchemy.Column(sqlalchemy.String, nullable=True, index=True) 13 | created_date = sqlalchemy.Column(sqlalchemy.DateTime, default=datetime.datetime.now, index=True) 14 | profile_image_url = sqlalchemy.Column(sqlalchemy.String) 15 | last_login = sqlalchemy.Column(sqlalchemy.DateTime, default=datetime.datetime.now, index=True) 16 | -------------------------------------------------------------------------------- /code/ex10_securepy/pypi_secure/db/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikeckennedy/ten-tips-python-web-devs/e2406853a3d2e1d02ca5b00f68ae510993d4ad19/code/ex10_securepy/pypi_secure/db/__init__.py -------------------------------------------------------------------------------- /code/ex10_securepy/pypi_secure/db/placeholder.txt: -------------------------------------------------------------------------------- 1 | Just here so git will create this folder. -------------------------------------------------------------------------------- /code/ex10_securepy/pypi_secure/db/pypi.sqlite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikeckennedy/ten-tips-python-web-devs/e2406853a3d2e1d02ca5b00f68ae510993d4ad19/code/ex10_securepy/pypi_secure/db/pypi.sqlite -------------------------------------------------------------------------------- /code/ex10_securepy/pypi_secure/infrastructure/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikeckennedy/ten-tips-python-web-devs/e2406853a3d2e1d02ca5b00f68ae510993d4ad19/code/ex10_securepy/pypi_secure/infrastructure/__init__.py -------------------------------------------------------------------------------- /code/ex10_securepy/pypi_secure/services/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikeckennedy/ten-tips-python-web-devs/e2406853a3d2e1d02ca5b00f68ae510993d4ad19/code/ex10_securepy/pypi_secure/services/__init__.py -------------------------------------------------------------------------------- /code/ex10_securepy/pypi_secure/services/cms_service.py: -------------------------------------------------------------------------------- 1 | fake_db = { 2 | '/company/history': { 3 | 'page_title': 'Company history', 4 | 'page_details': 'Details about company history...', 5 | }, 6 | '/company/employees': { 7 | 'page_title': 'Our team', 8 | 'page_details': 'Details about company employees ...', 9 | }, 10 | } 11 | 12 | 13 | def get_page(url: str) -> dict: 14 | if not url: 15 | return {} 16 | 17 | url = url.strip().lower() 18 | url = '/' + url.lstrip('/') 19 | 20 | page = fake_db.get(url, {}) 21 | return page 22 | -------------------------------------------------------------------------------- /code/ex10_securepy/pypi_secure/services/user_service.py: -------------------------------------------------------------------------------- 1 | import pypi_secure.data.db_session as db_session 2 | from pypi_secure.data.users import User 3 | 4 | 5 | def get_user_count() -> int: 6 | session = db_session.create_session() 7 | return session.query(User).count() 8 | -------------------------------------------------------------------------------- /code/ex10_securepy/pypi_secure/static/img/blue-cube.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /code/ex10_securepy/pypi_secure/static/img/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikeckennedy/ten-tips-python-web-devs/e2406853a3d2e1d02ca5b00f68ae510993d4ad19/code/ex10_securepy/pypi_secure/static/img/favicon.png -------------------------------------------------------------------------------- /code/ex10_securepy/pypi_secure/static/img/white-cube.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /code/ex10_securepy/pypi_secure/templates/cms/page.html: -------------------------------------------------------------------------------- 1 | {% extends "shared/_layout.html" %} 2 | {% block title %}About PyPI Demo{% endblock %} 3 | 4 | {% block main_content %} 5 |

{{ page_title }}

6 | 7 |
8 | {{ page_details }} 9 |
10 | {% endblock %} 11 | -------------------------------------------------------------------------------- /code/ex10_securepy/pypi_secure/templates/home/about.html: -------------------------------------------------------------------------------- 1 | {% extends "shared/_layout.html" %} 2 | {% block title %}About PyPI Demo{% endblock %} 3 | 4 | {% block main_content %} 5 |

About Python Package Index

6 | 7 |
8 | This is our demo app for our Flask course. 9 |
10 | {% endblock %} 11 | 12 | {% block additional_css %} 13 | 14 | {% endblock %} -------------------------------------------------------------------------------- /code/ex10_securepy/pypi_secure/views/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikeckennedy/ten-tips-python-web-devs/e2406853a3d2e1d02ca5b00f68ae510993d4ad19/code/ex10_securepy/pypi_secure/views/__init__.py -------------------------------------------------------------------------------- /code/ex10_securepy/pypi_secure/views/cms_views.py: -------------------------------------------------------------------------------- 1 | import flask 2 | 3 | from pypi_secure.infrastructure.view_modifiers import response 4 | import pypi_secure.services.cms_service as cms_service 5 | 6 | blueprint = flask.Blueprint('cms', __name__, template_folder='templates') 7 | 8 | 9 | @blueprint.route('/') 10 | @response(template_file='cms/page.html') 11 | def cms_page(full_url: str): 12 | print("Getting CMS page for {}".format(full_url)) 13 | 14 | page = cms_service.get_page(full_url) 15 | if not page: 16 | return flask.abort(404) 17 | 18 | return page 19 | -------------------------------------------------------------------------------- /code/ex10_securepy/pypi_secure/views/home_views.py: -------------------------------------------------------------------------------- 1 | import flask 2 | 3 | from pypi_secure.infrastructure.view_modifiers import response 4 | import pypi_secure.services.package_service as package_service 5 | import pypi_secure.services.user_service as user_service 6 | 7 | blueprint = flask.Blueprint('home', __name__, template_folder='templates') 8 | 9 | 10 | @blueprint.route('/') 11 | @response(template_file='home/index.html') 12 | def index(): 13 | return { 14 | 'releases': package_service.get_latest_releases(), 15 | 'package_count': package_service.get_package_count(), 16 | 'release_count': package_service.get_release_count(), 17 | 'user_count': user_service.get_user_count(), 18 | } 19 | 20 | 21 | @blueprint.route('/about') 22 | @response(template_file='home/about.html') 23 | def about(): 24 | return {} 25 | -------------------------------------------------------------------------------- /code/ex10_securepy/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | setup( 4 | name='pypi_secure', 5 | version='', 6 | packages=['pypi_secure', 'pypi_secure.db', 'pypi_secure.data', 'pypi_secure.views', 'pypi_secure.services', 7 | 'pypi_secure.infrastructure'], 8 | package_dir={'': '.'}, 9 | url='', 10 | license='', 11 | author='Michael Kennedy', 12 | author_email='', 13 | description='' 14 | ) 15 | -------------------------------------------------------------------------------- /code/node_modules/vue/src/compiler/directives/bind.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | export default function bind (el: ASTElement, dir: ASTDirective) { 4 | el.wrapData = (code: string) => { 5 | return `_b(${code},'${el.tag}',${dir.value},${ 6 | dir.modifiers && dir.modifiers.prop ? 'true' : 'false' 7 | }${ 8 | dir.modifiers && dir.modifiers.sync ? ',true' : '' 9 | })` 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /code/node_modules/vue/src/compiler/directives/index.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import on from './on' 4 | import bind from './bind' 5 | import { noop } from 'shared/util' 6 | 7 | export default { 8 | on, 9 | bind, 10 | cloak: noop 11 | } 12 | -------------------------------------------------------------------------------- /code/node_modules/vue/src/compiler/directives/on.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { warn } from 'core/util/index' 4 | 5 | export default function on (el: ASTElement, dir: ASTDirective) { 6 | if (process.env.NODE_ENV !== 'production' && dir.modifiers) { 7 | warn(`v-on without argument does not support modifiers.`) 8 | } 9 | el.wrapListeners = (code: string) => `_g(${code},${dir.value})` 10 | } 11 | -------------------------------------------------------------------------------- /code/node_modules/vue/src/compiler/index.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { parse } from './parser/index' 4 | import { optimize } from './optimizer' 5 | import { generate } from './codegen/index' 6 | import { createCompilerCreator } from './create-compiler' 7 | 8 | // `createCompilerCreator` allows creating compilers that use alternative 9 | // parser/optimizer/codegen, e.g the SSR optimizing compiler. 10 | // Here we just export a default compiler using the default parts. 11 | export const createCompiler = createCompilerCreator(function baseCompile ( 12 | template: string, 13 | options: CompilerOptions 14 | ): CompiledResult { 15 | const ast = parse(template.trim(), options) 16 | if (options.optimize !== false) { 17 | optimize(ast, options) 18 | } 19 | const code = generate(ast, options) 20 | return { 21 | ast, 22 | render: code.render, 23 | staticRenderFns: code.staticRenderFns 24 | } 25 | }) 26 | -------------------------------------------------------------------------------- /code/node_modules/vue/src/compiler/parser/entity-decoder.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | let decoder 4 | 5 | export default { 6 | decode (html: string): string { 7 | decoder = decoder || document.createElement('div') 8 | decoder.innerHTML = html 9 | return decoder.textContent 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /code/node_modules/vue/src/core/components/index.js: -------------------------------------------------------------------------------- 1 | import KeepAlive from './keep-alive' 2 | 3 | export default { 4 | KeepAlive 5 | } 6 | -------------------------------------------------------------------------------- /code/node_modules/vue/src/core/global-api/mixin.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { mergeOptions } from '../util/index' 4 | 5 | export function initMixin (Vue: GlobalAPI) { 6 | Vue.mixin = function (mixin: Object) { 7 | this.options = mergeOptions(this.options, mixin) 8 | return this 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /code/node_modules/vue/src/core/global-api/use.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { toArray } from '../util/index' 4 | 5 | export function initUse (Vue: GlobalAPI) { 6 | Vue.use = function (plugin: Function | Object) { 7 | const installedPlugins = (this._installedPlugins || (this._installedPlugins = [])) 8 | if (installedPlugins.indexOf(plugin) > -1) { 9 | return this 10 | } 11 | 12 | // additional parameters 13 | const args = toArray(arguments, 1) 14 | args.unshift(this) 15 | if (typeof plugin.install === 'function') { 16 | plugin.install.apply(plugin, args) 17 | } else if (typeof plugin === 'function') { 18 | plugin.apply(null, args) 19 | } 20 | installedPlugins.push(plugin) 21 | return this 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /code/node_modules/vue/src/core/index.js: -------------------------------------------------------------------------------- 1 | import Vue from './instance/index' 2 | import { initGlobalAPI } from './global-api/index' 3 | import { isServerRendering } from 'core/util/env' 4 | import { FunctionalRenderContext } from 'core/vdom/create-functional-component' 5 | 6 | initGlobalAPI(Vue) 7 | 8 | Object.defineProperty(Vue.prototype, '$isServer', { 9 | get: isServerRendering 10 | }) 11 | 12 | Object.defineProperty(Vue.prototype, '$ssrContext', { 13 | get () { 14 | /* istanbul ignore next */ 15 | return this.$vnode && this.$vnode.ssrContext 16 | } 17 | }) 18 | 19 | // expose FunctionalRenderContext for ssr runtime helper installation 20 | Object.defineProperty(Vue, 'FunctionalRenderContext', { 21 | value: FunctionalRenderContext 22 | }) 23 | 24 | Vue.version = '__VERSION__' 25 | 26 | export default Vue 27 | -------------------------------------------------------------------------------- /code/node_modules/vue/src/core/util/index.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | export * from 'shared/util' 4 | export * from './lang' 5 | export * from './env' 6 | export * from './options' 7 | export * from './debug' 8 | export * from './props' 9 | export * from './error' 10 | export * from './next-tick' 11 | export { defineReactive } from '../observer/index' 12 | -------------------------------------------------------------------------------- /code/node_modules/vue/src/core/util/perf.js: -------------------------------------------------------------------------------- 1 | import { inBrowser } from './env' 2 | 3 | export let mark 4 | export let measure 5 | 6 | if (process.env.NODE_ENV !== 'production') { 7 | const perf = inBrowser && window.performance 8 | /* istanbul ignore if */ 9 | if ( 10 | perf && 11 | perf.mark && 12 | perf.measure && 13 | perf.clearMarks && 14 | perf.clearMeasures 15 | ) { 16 | mark = tag => perf.mark(tag) 17 | measure = (name, startTag, endTag) => { 18 | perf.measure(name, startTag, endTag) 19 | perf.clearMarks(startTag) 20 | perf.clearMarks(endTag) 21 | // perf.clearMeasures(name) 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /code/node_modules/vue/src/core/vdom/helpers/get-first-component-child.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { isDef } from 'shared/util' 4 | import { isAsyncPlaceholder } from './is-async-placeholder' 5 | 6 | export function getFirstComponentChild (children: ?Array): ?VNode { 7 | if (Array.isArray(children)) { 8 | for (let i = 0; i < children.length; i++) { 9 | const c = children[i] 10 | if (isDef(c) && (isDef(c.componentOptions) || isAsyncPlaceholder(c))) { 11 | return c 12 | } 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /code/node_modules/vue/src/core/vdom/helpers/index.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | export * from './merge-hook' 4 | export * from './extract-props' 5 | export * from './update-listeners' 6 | export * from './normalize-children' 7 | export * from './resolve-async-component' 8 | export * from './get-first-component-child' 9 | export * from './is-async-placeholder' 10 | -------------------------------------------------------------------------------- /code/node_modules/vue/src/core/vdom/helpers/is-async-placeholder.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | export function isAsyncPlaceholder (node: VNode): boolean { 4 | return node.isComment && node.asyncFactory 5 | } 6 | -------------------------------------------------------------------------------- /code/node_modules/vue/src/core/vdom/modules/index.js: -------------------------------------------------------------------------------- 1 | import directives from './directives' 2 | import ref from './ref' 3 | 4 | export default [ 5 | ref, 6 | directives 7 | ] 8 | -------------------------------------------------------------------------------- /code/node_modules/vue/src/platforms/web/compiler/directives/html.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { addProp } from 'compiler/helpers' 4 | 5 | export default function html (el: ASTElement, dir: ASTDirective) { 6 | if (dir.value) { 7 | addProp(el, 'innerHTML', `_s(${dir.value})`, dir) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /code/node_modules/vue/src/platforms/web/compiler/directives/index.js: -------------------------------------------------------------------------------- 1 | import model from './model' 2 | import text from './text' 3 | import html from './html' 4 | 5 | export default { 6 | model, 7 | text, 8 | html 9 | } 10 | -------------------------------------------------------------------------------- /code/node_modules/vue/src/platforms/web/compiler/directives/text.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { addProp } from 'compiler/helpers' 4 | 5 | export default function text (el: ASTElement, dir: ASTDirective) { 6 | if (dir.value) { 7 | addProp(el, 'textContent', `_s(${dir.value})`, dir) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /code/node_modules/vue/src/platforms/web/compiler/index.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { baseOptions } from './options' 4 | import { createCompiler } from 'compiler/index' 5 | 6 | const { compile, compileToFunctions } = createCompiler(baseOptions) 7 | 8 | export { compile, compileToFunctions } 9 | -------------------------------------------------------------------------------- /code/node_modules/vue/src/platforms/web/compiler/modules/index.js: -------------------------------------------------------------------------------- 1 | import klass from './class' 2 | import style from './style' 3 | import model from './model' 4 | 5 | export default [ 6 | klass, 7 | style, 8 | model 9 | ] 10 | -------------------------------------------------------------------------------- /code/node_modules/vue/src/platforms/web/compiler/options.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { 4 | isPreTag, 5 | mustUseProp, 6 | isReservedTag, 7 | getTagNamespace 8 | } from '../util/index' 9 | 10 | import modules from './modules/index' 11 | import directives from './directives/index' 12 | import { genStaticKeys } from 'shared/util' 13 | import { isUnaryTag, canBeLeftOpenTag } from './util' 14 | 15 | export const baseOptions: CompilerOptions = { 16 | expectHTML: true, 17 | modules, 18 | directives, 19 | isPreTag, 20 | isUnaryTag, 21 | mustUseProp, 22 | canBeLeftOpenTag, 23 | isReservedTag, 24 | getTagNamespace, 25 | staticKeys: genStaticKeys(modules) 26 | } 27 | -------------------------------------------------------------------------------- /code/node_modules/vue/src/platforms/web/entry-compiler.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | export { parseComponent } from 'sfc/parser' 4 | export { compile, compileToFunctions } from './compiler/index' 5 | export { ssrCompile, ssrCompileToFunctions } from './server/compiler' 6 | export { generateCodeFrame } from 'compiler/codeframe' 7 | -------------------------------------------------------------------------------- /code/node_modules/vue/src/platforms/web/entry-runtime.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import Vue from './runtime/index' 4 | 5 | export default Vue 6 | -------------------------------------------------------------------------------- /code/node_modules/vue/src/platforms/web/entry-server-basic-renderer.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import modules from './server/modules/index' 4 | import directives from './server/directives/index' 5 | import { isUnaryTag, canBeLeftOpenTag } from './compiler/util' 6 | import { createBasicRenderer } from 'server/create-basic-renderer' 7 | 8 | export default createBasicRenderer({ 9 | modules, 10 | directives, 11 | isUnaryTag, 12 | canBeLeftOpenTag 13 | }) 14 | -------------------------------------------------------------------------------- /code/node_modules/vue/src/platforms/web/runtime/components/index.js: -------------------------------------------------------------------------------- 1 | import Transition from './transition' 2 | import TransitionGroup from './transition-group' 3 | 4 | export default { 5 | Transition, 6 | TransitionGroup 7 | } 8 | -------------------------------------------------------------------------------- /code/node_modules/vue/src/platforms/web/runtime/directives/index.js: -------------------------------------------------------------------------------- 1 | import model from './model' 2 | import show from './show' 3 | 4 | export default { 5 | model, 6 | show 7 | } 8 | -------------------------------------------------------------------------------- /code/node_modules/vue/src/platforms/web/runtime/modules/index.js: -------------------------------------------------------------------------------- 1 | import attrs from './attrs' 2 | import klass from './class' 3 | import events from './events' 4 | import domProps from './dom-props' 5 | import style from './style' 6 | import transition from './transition' 7 | 8 | export default [ 9 | attrs, 10 | klass, 11 | events, 12 | domProps, 13 | style, 14 | transition 15 | ] 16 | -------------------------------------------------------------------------------- /code/node_modules/vue/src/platforms/web/runtime/patch.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import * as nodeOps from 'web/runtime/node-ops' 4 | import { createPatchFunction } from 'core/vdom/patch' 5 | import baseModules from 'core/vdom/modules/index' 6 | import platformModules from 'web/runtime/modules/index' 7 | 8 | // the directive module should be applied last, after all 9 | // built-in modules have been applied. 10 | const modules = platformModules.concat(baseModules) 11 | 12 | export const patch: Function = createPatchFunction({ nodeOps, modules }) 13 | -------------------------------------------------------------------------------- /code/node_modules/vue/src/platforms/web/server/compiler.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { baseOptions } from '../compiler/options' 4 | import { createCompiler } from 'server/optimizing-compiler/index' 5 | 6 | const { compile, compileToFunctions } = createCompiler(baseOptions) 7 | 8 | export { 9 | compile as ssrCompile, 10 | compileToFunctions as ssrCompileToFunctions 11 | } 12 | -------------------------------------------------------------------------------- /code/node_modules/vue/src/platforms/web/server/directives/index.js: -------------------------------------------------------------------------------- 1 | import show from './show' 2 | import model from './model' 3 | 4 | export default { 5 | show, 6 | model 7 | } 8 | -------------------------------------------------------------------------------- /code/node_modules/vue/src/platforms/web/server/directives/show.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | export default function show (node: VNodeWithData, dir: VNodeDirective) { 4 | if (!dir.value) { 5 | const style: any = node.data.style || (node.data.style = {}) 6 | if (Array.isArray(style)) { 7 | style.push({ display: 'none' }) 8 | } else { 9 | style.display = 'none' 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /code/node_modules/vue/src/platforms/web/server/modules/class.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { escape } from '../util' 4 | import { genClassForVnode } from 'web/util/index' 5 | 6 | export default function renderClass (node: VNodeWithData): ?string { 7 | const classList = genClassForVnode(node) 8 | if (classList !== '') { 9 | return ` class="${escape(classList)}"` 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /code/node_modules/vue/src/platforms/web/server/modules/index.js: -------------------------------------------------------------------------------- 1 | import attrs from './attrs' 2 | import domProps from './dom-props' 3 | import klass from './class' 4 | import style from './style' 5 | 6 | export default [ 7 | attrs, 8 | domProps, 9 | klass, 10 | style 11 | ] 12 | -------------------------------------------------------------------------------- /code/node_modules/vue/src/platforms/web/util/compat.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { inBrowser } from 'core/util/index' 4 | 5 | // check whether current browser encodes a char inside attribute values 6 | let div 7 | function getShouldDecode (href: boolean): boolean { 8 | div = div || document.createElement('div') 9 | div.innerHTML = href ? `
` : `
` 10 | return div.innerHTML.indexOf(' ') > 0 11 | } 12 | 13 | // #3663: IE encodes newlines inside attribute values while other browsers don't 14 | export const shouldDecodeNewlines = inBrowser ? getShouldDecode(false) : false 15 | // #6828: chrome encodes content in a[href] 16 | export const shouldDecodeNewlinesForHref = inBrowser ? getShouldDecode(true) : false 17 | -------------------------------------------------------------------------------- /code/node_modules/vue/src/platforms/web/util/index.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { warn } from 'core/util/index' 4 | 5 | export * from './attrs' 6 | export * from './class' 7 | export * from './element' 8 | 9 | /** 10 | * Query an element selector if it's not an element already. 11 | */ 12 | export function query (el: string | Element): Element { 13 | if (typeof el === 'string') { 14 | const selected = document.querySelector(el) 15 | if (!selected) { 16 | process.env.NODE_ENV !== 'production' && warn( 17 | 'Cannot find element: ' + el 18 | ) 19 | return document.createElement('div') 20 | } 21 | return selected 22 | } else { 23 | return el 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /code/node_modules/vue/src/platforms/weex/compiler/directives/index.js: -------------------------------------------------------------------------------- 1 | import model from './model' 2 | 3 | export default { 4 | model 5 | } 6 | -------------------------------------------------------------------------------- /code/node_modules/vue/src/platforms/weex/compiler/modules/append.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { makeMap } from 'shared/util' 4 | 5 | // The "unitary tag" means that the tag node and its children 6 | // must be sent to the native together. 7 | const isUnitaryTag = makeMap('cell,header,cell-slot,recycle-list', true) 8 | 9 | function preTransformNode (el: ASTElement) { 10 | if (isUnitaryTag(el.tag) && !el.attrsList.some(item => item.name === 'append')) { 11 | el.attrsMap.append = 'tree' 12 | el.attrsList.push({ name: 'append', value: 'tree' }) 13 | } 14 | if (el.attrsMap.append === 'tree') { 15 | el.appendAsTree = true 16 | } 17 | } 18 | 19 | function genData (el: ASTElement): string { 20 | return el.appendAsTree ? `appendAsTree:true,` : '' 21 | } 22 | 23 | export default { 24 | staticKeys: ['appendAsTree'], 25 | preTransformNode, 26 | genData 27 | } 28 | -------------------------------------------------------------------------------- /code/node_modules/vue/src/platforms/weex/compiler/modules/index.js: -------------------------------------------------------------------------------- 1 | import klass from './class' 2 | import style from './style' 3 | import props from './props' 4 | import append from './append' 5 | import recycleList from './recycle-list/index' 6 | 7 | export default [ 8 | recycleList, 9 | klass, 10 | style, 11 | props, 12 | append 13 | ] 14 | -------------------------------------------------------------------------------- /code/node_modules/vue/src/platforms/weex/compiler/modules/recycle-list/component-root.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { addAttr } from 'compiler/helpers' 4 | 5 | // mark component root nodes as 6 | export function postTransformComponentRoot (el: ASTElement) { 7 | if (!el.parent) { 8 | // component root 9 | addAttr(el, '@isComponentRoot', 'true') 10 | addAttr(el, '@templateId', '_uid') 11 | addAttr(el, '@componentProps', '$props || {}') 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /code/node_modules/vue/src/platforms/weex/compiler/modules/recycle-list/component.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { addAttr } from 'compiler/helpers' 4 | import { RECYCLE_LIST_MARKER } from 'weex/util/index' 5 | 6 | // mark components as inside recycle-list so that we know we need to invoke 7 | // their special @render function instead of render in create-component.js 8 | export function postTransformComponent ( 9 | el: ASTElement, 10 | options: WeexCompilerOptions 11 | ) { 12 | // $flow-disable-line (we know isReservedTag is there) 13 | if (!options.isReservedTag(el.tag) && el.tag !== 'cell-slot') { 14 | addAttr(el, RECYCLE_LIST_MARKER, 'true') 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /code/node_modules/vue/src/platforms/weex/compiler/modules/recycle-list/text.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { addAttr } from 'compiler/helpers' 4 | 5 | function genText (node: ASTNode) { 6 | const value = node.type === 3 7 | ? node.text 8 | : node.type === 2 9 | ? node.tokens.length === 1 10 | ? node.tokens[0] 11 | : node.tokens 12 | : '' 13 | return JSON.stringify(value) 14 | } 15 | 16 | export function postTransformText (el: ASTElement) { 17 | // weex can only contain text, so the parser 18 | // always generates a single child. 19 | if (el.children.length) { 20 | addAttr(el, 'value', genText(el.children[0])) 21 | el.children = [] 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /code/node_modules/vue/src/platforms/weex/compiler/modules/recycle-list/v-bind.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { camelize } from 'shared/util' 4 | import { generateBinding } from 'weex/util/parser' 5 | import { bindRE } from 'compiler/parser/index' 6 | import { getAndRemoveAttr, addRawAttr } from 'compiler/helpers' 7 | 8 | function parseAttrName (name: string): string { 9 | return camelize(name.replace(bindRE, '')) 10 | } 11 | 12 | export function preTransformVBind (el: ASTElement) { 13 | for (const attr in el.attrsMap) { 14 | if (bindRE.test(attr)) { 15 | const name: string = parseAttrName(attr) 16 | const value = generateBinding(getAndRemoveAttr(el, attr)) 17 | delete el.attrsMap[attr] 18 | addRawAttr(el, name, value) 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /code/node_modules/vue/src/platforms/weex/compiler/modules/recycle-list/v-on.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | const inlineStatementRE = /^\s*([A-Za-z_$0-9\['\."\]]+)*\s*\(\s*(([A-Za-z_$0-9\['\."\]]+)?(\s*,\s*([A-Za-z_$0-9\['\."\]]+))*)\s*\)$/ 4 | 5 | function parseHandlerParams (handler: ASTElementHandler) { 6 | const res = inlineStatementRE.exec(handler.value) 7 | if (res && res[2]) { 8 | handler.params = res[2].split(/\s*,\s*/) 9 | } 10 | } 11 | 12 | export function postTransformVOn (el: ASTElement) { 13 | const events: ASTElementHandlers | void = el.events 14 | if (!events) { 15 | return 16 | } 17 | for (const name in events) { 18 | const handler: ASTElementHandler | Array = events[name] 19 | if (Array.isArray(handler)) { 20 | handler.map(fn => parseHandlerParams(fn)) 21 | } else { 22 | parseHandlerParams(handler) 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /code/node_modules/vue/src/platforms/weex/compiler/modules/recycle-list/v-once.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { getAndRemoveAttr, addRawAttr } from 'compiler/helpers' 4 | 5 | function containVOnce (el: ASTElement): boolean { 6 | for (const attr in el.attrsMap) { 7 | if (/^v\-once$/i.test(attr)) { 8 | return true 9 | } 10 | } 11 | return false 12 | } 13 | 14 | export function preTransformVOnce (el: ASTElement) { 15 | if (containVOnce(el)) { 16 | getAndRemoveAttr(el, 'v-once', true) 17 | addRawAttr(el, '[[once]]', true) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /code/node_modules/vue/src/platforms/weex/entry-compiler.js: -------------------------------------------------------------------------------- 1 | export { compile } from 'weex/compiler/index' 2 | export { generateCodeFrame } from 'compiler/codeframe' 3 | -------------------------------------------------------------------------------- /code/node_modules/vue/src/platforms/weex/entry-runtime-factory.js: -------------------------------------------------------------------------------- 1 | // this entry is built and wrapped with a factory function 2 | // used to generate a fresh copy of Vue for every Weex instance. 3 | 4 | import Vue from './runtime/index' 5 | 6 | exports.Vue = Vue 7 | -------------------------------------------------------------------------------- /code/node_modules/vue/src/platforms/weex/runtime/components/index.js: -------------------------------------------------------------------------------- 1 | import Richtext from './richtext' 2 | import Transition from './transition' 3 | import TransitionGroup from './transition-group' 4 | 5 | export default { 6 | Richtext, 7 | Transition, 8 | TransitionGroup 9 | } 10 | -------------------------------------------------------------------------------- /code/node_modules/vue/src/platforms/weex/runtime/components/transition.js: -------------------------------------------------------------------------------- 1 | // reuse same transition component logic from web 2 | export { 3 | transitionProps, 4 | extractTransitionData 5 | } from 'web/runtime/components/transition' 6 | 7 | import Transition from 'web/runtime/components/transition' 8 | 9 | export default Transition 10 | -------------------------------------------------------------------------------- /code/node_modules/vue/src/platforms/weex/runtime/directives/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | } 3 | -------------------------------------------------------------------------------- /code/node_modules/vue/src/platforms/weex/runtime/modules/index.js: -------------------------------------------------------------------------------- 1 | import attrs from './attrs' 2 | import klass from './class' 3 | import events from './events' 4 | import style from './style' 5 | import transition from './transition' 6 | 7 | export default [ 8 | attrs, 9 | klass, 10 | events, 11 | style, 12 | transition 13 | ] 14 | -------------------------------------------------------------------------------- /code/node_modules/vue/src/platforms/weex/runtime/patch.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import * as nodeOps from 'weex/runtime/node-ops' 4 | import { createPatchFunction } from 'core/vdom/patch' 5 | import baseModules from 'core/vdom/modules/index' 6 | import platformModules from 'weex/runtime/modules/index' 7 | 8 | // the directive module should be applied last, after all 9 | // built-in modules have been applied. 10 | const modules = platformModules.concat(baseModules) 11 | 12 | export const patch: Function = createPatchFunction({ 13 | nodeOps, 14 | modules, 15 | LONG_LIST_THRESHOLD: 10 16 | }) 17 | -------------------------------------------------------------------------------- /code/node_modules/vue/src/platforms/weex/runtime/text-node.js: -------------------------------------------------------------------------------- 1 | let latestNodeId = 1 2 | 3 | export default function TextNode (text) { 4 | this.instanceId = '' 5 | this.nodeId = latestNodeId++ 6 | this.parentNode = null 7 | this.nodeType = 3 8 | this.text = text 9 | } 10 | -------------------------------------------------------------------------------- /code/node_modules/vue/src/server/optimizing-compiler/index.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { parse } from 'compiler/parser/index' 4 | import { generate } from './codegen' 5 | import { optimize } from './optimizer' 6 | import { createCompilerCreator } from 'compiler/create-compiler' 7 | 8 | export const createCompiler = createCompilerCreator(function baseCompile ( 9 | template: string, 10 | options: CompilerOptions 11 | ): CompiledResult { 12 | const ast = parse(template.trim(), options) 13 | optimize(ast, options) 14 | const code = generate(ast, options) 15 | return { 16 | ast, 17 | render: code.render, 18 | staticRenderFns: code.staticRenderFns 19 | } 20 | }) 21 | -------------------------------------------------------------------------------- /code/node_modules/vue/src/server/util.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | export const isJS = (file: string): boolean => /\.js(\?[^.]+)?$/.test(file) 4 | 5 | export const isCSS = (file: string): boolean => /\.css(\?[^.]+)?$/.test(file) 6 | 7 | export function createPromiseCallback () { 8 | let resolve, reject 9 | const promise: Promise = new Promise((_resolve, _reject) => { 10 | resolve = _resolve 11 | reject = _reject 12 | }) 13 | const cb = (err: Error, res?: string) => { 14 | if (err) return reject(err) 15 | resolve(res || '') 16 | } 17 | return { promise, cb } 18 | } 19 | -------------------------------------------------------------------------------- /code/node_modules/vue/src/shared/constants.js: -------------------------------------------------------------------------------- 1 | export const SSR_ATTR = 'data-server-rendered' 2 | 3 | export const ASSET_TYPES = [ 4 | 'component', 5 | 'directive', 6 | 'filter' 7 | ] 8 | 9 | export const LIFECYCLE_HOOKS = [ 10 | 'beforeCreate', 11 | 'created', 12 | 'beforeMount', 13 | 'mounted', 14 | 'beforeUpdate', 15 | 'updated', 16 | 'beforeDestroy', 17 | 'destroyed', 18 | 'activated', 19 | 'deactivated', 20 | 'errorCaptured', 21 | 'serverPrefetch' 22 | ] 23 | -------------------------------------------------------------------------------- /code/node_modules/vue/types/index.d.ts: -------------------------------------------------------------------------------- 1 | import { Vue } from "./vue"; 2 | 3 | export default Vue; 4 | 5 | export as namespace Vue; 6 | 7 | export { 8 | CreateElement, 9 | VueConstructor 10 | } from "./vue"; 11 | 12 | export { 13 | Component, 14 | AsyncComponent, 15 | ComponentOptions, 16 | FunctionalComponentOptions, 17 | RenderContext, 18 | PropType, 19 | PropOptions, 20 | ComputedOptions, 21 | WatchHandler, 22 | WatchOptions, 23 | WatchOptionsWithHandler, 24 | DirectiveFunction, 25 | DirectiveOptions 26 | } from "./options"; 27 | 28 | export { 29 | PluginFunction, 30 | PluginObject 31 | } from "./plugin"; 32 | 33 | export { 34 | VNodeChildren, 35 | VNodeChildrenArrayContents, 36 | VNode, 37 | VNodeComponentOptions, 38 | VNodeData, 39 | VNodeDirective 40 | } from "./vnode"; 41 | -------------------------------------------------------------------------------- /code/node_modules/vue/types/plugin.d.ts: -------------------------------------------------------------------------------- 1 | import { Vue as _Vue } from "./vue"; 2 | 3 | export type PluginFunction = (Vue: typeof _Vue, options?: T) => void; 4 | 5 | export interface PluginObject { 6 | install: PluginFunction; 7 | [key: string]: any; 8 | } 9 | -------------------------------------------------------------------------------- /code/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "top_10_web_explore", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "vue": { 8 | "version": "2.6.10", 9 | "resolved": "https://registry.npmjs.org/vue/-/vue-2.6.10.tgz", 10 | "integrity": "sha512-ImThpeNU9HbdZL3utgMCq0oiMzAkt1mcgy3/E6zWC/G6AaQoeuFdsl9nDhTDU3X1R6FK7nsIUuRACVcjI+A2GQ==" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /code/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "top_10_web_explore", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "vue": "^2.6.10" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /node_modules/vue/src/compiler/directives/bind.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | export default function bind (el: ASTElement, dir: ASTDirective) { 4 | el.wrapData = (code: string) => { 5 | return `_b(${code},'${el.tag}',${dir.value},${ 6 | dir.modifiers && dir.modifiers.prop ? 'true' : 'false' 7 | }${ 8 | dir.modifiers && dir.modifiers.sync ? ',true' : '' 9 | })` 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /node_modules/vue/src/compiler/directives/index.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import on from './on' 4 | import bind from './bind' 5 | import { noop } from 'shared/util' 6 | 7 | export default { 8 | on, 9 | bind, 10 | cloak: noop 11 | } 12 | -------------------------------------------------------------------------------- /node_modules/vue/src/compiler/directives/on.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { warn } from 'core/util/index' 4 | 5 | export default function on (el: ASTElement, dir: ASTDirective) { 6 | if (process.env.NODE_ENV !== 'production' && dir.modifiers) { 7 | warn(`v-on without argument does not support modifiers.`) 8 | } 9 | el.wrapListeners = (code: string) => `_g(${code},${dir.value})` 10 | } 11 | -------------------------------------------------------------------------------- /node_modules/vue/src/compiler/index.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { parse } from './parser/index' 4 | import { optimize } from './optimizer' 5 | import { generate } from './codegen/index' 6 | import { createCompilerCreator } from './create-compiler' 7 | 8 | // `createCompilerCreator` allows creating compilers that use alternative 9 | // parser/optimizer/codegen, e.g the SSR optimizing compiler. 10 | // Here we just export a default compiler using the default parts. 11 | export const createCompiler = createCompilerCreator(function baseCompile ( 12 | template: string, 13 | options: CompilerOptions 14 | ): CompiledResult { 15 | const ast = parse(template.trim(), options) 16 | if (options.optimize !== false) { 17 | optimize(ast, options) 18 | } 19 | const code = generate(ast, options) 20 | return { 21 | ast, 22 | render: code.render, 23 | staticRenderFns: code.staticRenderFns 24 | } 25 | }) 26 | -------------------------------------------------------------------------------- /node_modules/vue/src/compiler/parser/entity-decoder.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | let decoder 4 | 5 | export default { 6 | decode (html: string): string { 7 | decoder = decoder || document.createElement('div') 8 | decoder.innerHTML = html 9 | return decoder.textContent 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /node_modules/vue/src/core/components/index.js: -------------------------------------------------------------------------------- 1 | import KeepAlive from './keep-alive' 2 | 3 | export default { 4 | KeepAlive 5 | } 6 | -------------------------------------------------------------------------------- /node_modules/vue/src/core/global-api/mixin.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { mergeOptions } from '../util/index' 4 | 5 | export function initMixin (Vue: GlobalAPI) { 6 | Vue.mixin = function (mixin: Object) { 7 | this.options = mergeOptions(this.options, mixin) 8 | return this 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /node_modules/vue/src/core/global-api/use.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { toArray } from '../util/index' 4 | 5 | export function initUse (Vue: GlobalAPI) { 6 | Vue.use = function (plugin: Function | Object) { 7 | const installedPlugins = (this._installedPlugins || (this._installedPlugins = [])) 8 | if (installedPlugins.indexOf(plugin) > -1) { 9 | return this 10 | } 11 | 12 | // additional parameters 13 | const args = toArray(arguments, 1) 14 | args.unshift(this) 15 | if (typeof plugin.install === 'function') { 16 | plugin.install.apply(plugin, args) 17 | } else if (typeof plugin === 'function') { 18 | plugin.apply(null, args) 19 | } 20 | installedPlugins.push(plugin) 21 | return this 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /node_modules/vue/src/core/index.js: -------------------------------------------------------------------------------- 1 | import Vue from './instance/index' 2 | import { initGlobalAPI } from './global-api/index' 3 | import { isServerRendering } from 'core/util/env' 4 | import { FunctionalRenderContext } from 'core/vdom/create-functional-component' 5 | 6 | initGlobalAPI(Vue) 7 | 8 | Object.defineProperty(Vue.prototype, '$isServer', { 9 | get: isServerRendering 10 | }) 11 | 12 | Object.defineProperty(Vue.prototype, '$ssrContext', { 13 | get () { 14 | /* istanbul ignore next */ 15 | return this.$vnode && this.$vnode.ssrContext 16 | } 17 | }) 18 | 19 | // expose FunctionalRenderContext for ssr runtime helper installation 20 | Object.defineProperty(Vue, 'FunctionalRenderContext', { 21 | value: FunctionalRenderContext 22 | }) 23 | 24 | Vue.version = '__VERSION__' 25 | 26 | export default Vue 27 | -------------------------------------------------------------------------------- /node_modules/vue/src/core/util/index.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | export * from 'shared/util' 4 | export * from './lang' 5 | export * from './env' 6 | export * from './options' 7 | export * from './debug' 8 | export * from './props' 9 | export * from './error' 10 | export * from './next-tick' 11 | export { defineReactive } from '../observer/index' 12 | -------------------------------------------------------------------------------- /node_modules/vue/src/core/util/perf.js: -------------------------------------------------------------------------------- 1 | import { inBrowser } from './env' 2 | 3 | export let mark 4 | export let measure 5 | 6 | if (process.env.NODE_ENV !== 'production') { 7 | const perf = inBrowser && window.performance 8 | /* istanbul ignore if */ 9 | if ( 10 | perf && 11 | perf.mark && 12 | perf.measure && 13 | perf.clearMarks && 14 | perf.clearMeasures 15 | ) { 16 | mark = tag => perf.mark(tag) 17 | measure = (name, startTag, endTag) => { 18 | perf.measure(name, startTag, endTag) 19 | perf.clearMarks(startTag) 20 | perf.clearMarks(endTag) 21 | // perf.clearMeasures(name) 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /node_modules/vue/src/core/vdom/helpers/get-first-component-child.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { isDef } from 'shared/util' 4 | import { isAsyncPlaceholder } from './is-async-placeholder' 5 | 6 | export function getFirstComponentChild (children: ?Array): ?VNode { 7 | if (Array.isArray(children)) { 8 | for (let i = 0; i < children.length; i++) { 9 | const c = children[i] 10 | if (isDef(c) && (isDef(c.componentOptions) || isAsyncPlaceholder(c))) { 11 | return c 12 | } 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /node_modules/vue/src/core/vdom/helpers/index.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | export * from './merge-hook' 4 | export * from './extract-props' 5 | export * from './update-listeners' 6 | export * from './normalize-children' 7 | export * from './resolve-async-component' 8 | export * from './get-first-component-child' 9 | export * from './is-async-placeholder' 10 | -------------------------------------------------------------------------------- /node_modules/vue/src/core/vdom/helpers/is-async-placeholder.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | export function isAsyncPlaceholder (node: VNode): boolean { 4 | return node.isComment && node.asyncFactory 5 | } 6 | -------------------------------------------------------------------------------- /node_modules/vue/src/core/vdom/modules/index.js: -------------------------------------------------------------------------------- 1 | import directives from './directives' 2 | import ref from './ref' 3 | 4 | export default [ 5 | ref, 6 | directives 7 | ] 8 | -------------------------------------------------------------------------------- /node_modules/vue/src/platforms/web/compiler/directives/html.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { addProp } from 'compiler/helpers' 4 | 5 | export default function html (el: ASTElement, dir: ASTDirective) { 6 | if (dir.value) { 7 | addProp(el, 'innerHTML', `_s(${dir.value})`, dir) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /node_modules/vue/src/platforms/web/compiler/directives/index.js: -------------------------------------------------------------------------------- 1 | import model from './model' 2 | import text from './text' 3 | import html from './html' 4 | 5 | export default { 6 | model, 7 | text, 8 | html 9 | } 10 | -------------------------------------------------------------------------------- /node_modules/vue/src/platforms/web/compiler/directives/text.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { addProp } from 'compiler/helpers' 4 | 5 | export default function text (el: ASTElement, dir: ASTDirective) { 6 | if (dir.value) { 7 | addProp(el, 'textContent', `_s(${dir.value})`, dir) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /node_modules/vue/src/platforms/web/compiler/index.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { baseOptions } from './options' 4 | import { createCompiler } from 'compiler/index' 5 | 6 | const { compile, compileToFunctions } = createCompiler(baseOptions) 7 | 8 | export { compile, compileToFunctions } 9 | -------------------------------------------------------------------------------- /node_modules/vue/src/platforms/web/compiler/modules/index.js: -------------------------------------------------------------------------------- 1 | import klass from './class' 2 | import style from './style' 3 | import model from './model' 4 | 5 | export default [ 6 | klass, 7 | style, 8 | model 9 | ] 10 | -------------------------------------------------------------------------------- /node_modules/vue/src/platforms/web/compiler/options.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { 4 | isPreTag, 5 | mustUseProp, 6 | isReservedTag, 7 | getTagNamespace 8 | } from '../util/index' 9 | 10 | import modules from './modules/index' 11 | import directives from './directives/index' 12 | import { genStaticKeys } from 'shared/util' 13 | import { isUnaryTag, canBeLeftOpenTag } from './util' 14 | 15 | export const baseOptions: CompilerOptions = { 16 | expectHTML: true, 17 | modules, 18 | directives, 19 | isPreTag, 20 | isUnaryTag, 21 | mustUseProp, 22 | canBeLeftOpenTag, 23 | isReservedTag, 24 | getTagNamespace, 25 | staticKeys: genStaticKeys(modules) 26 | } 27 | -------------------------------------------------------------------------------- /node_modules/vue/src/platforms/web/entry-compiler.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | export { parseComponent } from 'sfc/parser' 4 | export { compile, compileToFunctions } from './compiler/index' 5 | export { ssrCompile, ssrCompileToFunctions } from './server/compiler' 6 | export { generateCodeFrame } from 'compiler/codeframe' 7 | -------------------------------------------------------------------------------- /node_modules/vue/src/platforms/web/entry-runtime.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import Vue from './runtime/index' 4 | 5 | export default Vue 6 | -------------------------------------------------------------------------------- /node_modules/vue/src/platforms/web/entry-server-basic-renderer.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import modules from './server/modules/index' 4 | import directives from './server/directives/index' 5 | import { isUnaryTag, canBeLeftOpenTag } from './compiler/util' 6 | import { createBasicRenderer } from 'server/create-basic-renderer' 7 | 8 | export default createBasicRenderer({ 9 | modules, 10 | directives, 11 | isUnaryTag, 12 | canBeLeftOpenTag 13 | }) 14 | -------------------------------------------------------------------------------- /node_modules/vue/src/platforms/web/runtime/components/index.js: -------------------------------------------------------------------------------- 1 | import Transition from './transition' 2 | import TransitionGroup from './transition-group' 3 | 4 | export default { 5 | Transition, 6 | TransitionGroup 7 | } 8 | -------------------------------------------------------------------------------- /node_modules/vue/src/platforms/web/runtime/directives/index.js: -------------------------------------------------------------------------------- 1 | import model from './model' 2 | import show from './show' 3 | 4 | export default { 5 | model, 6 | show 7 | } 8 | -------------------------------------------------------------------------------- /node_modules/vue/src/platforms/web/runtime/modules/index.js: -------------------------------------------------------------------------------- 1 | import attrs from './attrs' 2 | import klass from './class' 3 | import events from './events' 4 | import domProps from './dom-props' 5 | import style from './style' 6 | import transition from './transition' 7 | 8 | export default [ 9 | attrs, 10 | klass, 11 | events, 12 | domProps, 13 | style, 14 | transition 15 | ] 16 | -------------------------------------------------------------------------------- /node_modules/vue/src/platforms/web/runtime/patch.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import * as nodeOps from 'web/runtime/node-ops' 4 | import { createPatchFunction } from 'core/vdom/patch' 5 | import baseModules from 'core/vdom/modules/index' 6 | import platformModules from 'web/runtime/modules/index' 7 | 8 | // the directive module should be applied last, after all 9 | // built-in modules have been applied. 10 | const modules = platformModules.concat(baseModules) 11 | 12 | export const patch: Function = createPatchFunction({ nodeOps, modules }) 13 | -------------------------------------------------------------------------------- /node_modules/vue/src/platforms/web/server/compiler.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { baseOptions } from '../compiler/options' 4 | import { createCompiler } from 'server/optimizing-compiler/index' 5 | 6 | const { compile, compileToFunctions } = createCompiler(baseOptions) 7 | 8 | export { 9 | compile as ssrCompile, 10 | compileToFunctions as ssrCompileToFunctions 11 | } 12 | -------------------------------------------------------------------------------- /node_modules/vue/src/platforms/web/server/directives/index.js: -------------------------------------------------------------------------------- 1 | import show from './show' 2 | import model from './model' 3 | 4 | export default { 5 | show, 6 | model 7 | } 8 | -------------------------------------------------------------------------------- /node_modules/vue/src/platforms/web/server/directives/show.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | export default function show (node: VNodeWithData, dir: VNodeDirective) { 4 | if (!dir.value) { 5 | const style: any = node.data.style || (node.data.style = {}) 6 | if (Array.isArray(style)) { 7 | style.push({ display: 'none' }) 8 | } else { 9 | style.display = 'none' 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /node_modules/vue/src/platforms/web/server/modules/class.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { escape } from '../util' 4 | import { genClassForVnode } from 'web/util/index' 5 | 6 | export default function renderClass (node: VNodeWithData): ?string { 7 | const classList = genClassForVnode(node) 8 | if (classList !== '') { 9 | return ` class="${escape(classList)}"` 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /node_modules/vue/src/platforms/web/server/modules/index.js: -------------------------------------------------------------------------------- 1 | import attrs from './attrs' 2 | import domProps from './dom-props' 3 | import klass from './class' 4 | import style from './style' 5 | 6 | export default [ 7 | attrs, 8 | domProps, 9 | klass, 10 | style 11 | ] 12 | -------------------------------------------------------------------------------- /node_modules/vue/src/platforms/web/util/compat.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { inBrowser } from 'core/util/index' 4 | 5 | // check whether current browser encodes a char inside attribute values 6 | let div 7 | function getShouldDecode (href: boolean): boolean { 8 | div = div || document.createElement('div') 9 | div.innerHTML = href ? `` : `
` 10 | return div.innerHTML.indexOf(' ') > 0 11 | } 12 | 13 | // #3663: IE encodes newlines inside attribute values while other browsers don't 14 | export const shouldDecodeNewlines = inBrowser ? getShouldDecode(false) : false 15 | // #6828: chrome encodes content in a[href] 16 | export const shouldDecodeNewlinesForHref = inBrowser ? getShouldDecode(true) : false 17 | -------------------------------------------------------------------------------- /node_modules/vue/src/platforms/web/util/index.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { warn } from 'core/util/index' 4 | 5 | export * from './attrs' 6 | export * from './class' 7 | export * from './element' 8 | 9 | /** 10 | * Query an element selector if it's not an element already. 11 | */ 12 | export function query (el: string | Element): Element { 13 | if (typeof el === 'string') { 14 | const selected = document.querySelector(el) 15 | if (!selected) { 16 | process.env.NODE_ENV !== 'production' && warn( 17 | 'Cannot find element: ' + el 18 | ) 19 | return document.createElement('div') 20 | } 21 | return selected 22 | } else { 23 | return el 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /node_modules/vue/src/platforms/weex/compiler/directives/index.js: -------------------------------------------------------------------------------- 1 | import model from './model' 2 | 3 | export default { 4 | model 5 | } 6 | -------------------------------------------------------------------------------- /node_modules/vue/src/platforms/weex/compiler/modules/append.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { makeMap } from 'shared/util' 4 | 5 | // The "unitary tag" means that the tag node and its children 6 | // must be sent to the native together. 7 | const isUnitaryTag = makeMap('cell,header,cell-slot,recycle-list', true) 8 | 9 | function preTransformNode (el: ASTElement) { 10 | if (isUnitaryTag(el.tag) && !el.attrsList.some(item => item.name === 'append')) { 11 | el.attrsMap.append = 'tree' 12 | el.attrsList.push({ name: 'append', value: 'tree' }) 13 | } 14 | if (el.attrsMap.append === 'tree') { 15 | el.appendAsTree = true 16 | } 17 | } 18 | 19 | function genData (el: ASTElement): string { 20 | return el.appendAsTree ? `appendAsTree:true,` : '' 21 | } 22 | 23 | export default { 24 | staticKeys: ['appendAsTree'], 25 | preTransformNode, 26 | genData 27 | } 28 | -------------------------------------------------------------------------------- /node_modules/vue/src/platforms/weex/compiler/modules/index.js: -------------------------------------------------------------------------------- 1 | import klass from './class' 2 | import style from './style' 3 | import props from './props' 4 | import append from './append' 5 | import recycleList from './recycle-list/index' 6 | 7 | export default [ 8 | recycleList, 9 | klass, 10 | style, 11 | props, 12 | append 13 | ] 14 | -------------------------------------------------------------------------------- /node_modules/vue/src/platforms/weex/compiler/modules/recycle-list/component-root.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { addAttr } from 'compiler/helpers' 4 | 5 | // mark component root nodes as 6 | export function postTransformComponentRoot (el: ASTElement) { 7 | if (!el.parent) { 8 | // component root 9 | addAttr(el, '@isComponentRoot', 'true') 10 | addAttr(el, '@templateId', '_uid') 11 | addAttr(el, '@componentProps', '$props || {}') 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /node_modules/vue/src/platforms/weex/compiler/modules/recycle-list/component.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { addAttr } from 'compiler/helpers' 4 | import { RECYCLE_LIST_MARKER } from 'weex/util/index' 5 | 6 | // mark components as inside recycle-list so that we know we need to invoke 7 | // their special @render function instead of render in create-component.js 8 | export function postTransformComponent ( 9 | el: ASTElement, 10 | options: WeexCompilerOptions 11 | ) { 12 | // $flow-disable-line (we know isReservedTag is there) 13 | if (!options.isReservedTag(el.tag) && el.tag !== 'cell-slot') { 14 | addAttr(el, RECYCLE_LIST_MARKER, 'true') 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /node_modules/vue/src/platforms/weex/compiler/modules/recycle-list/text.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { addAttr } from 'compiler/helpers' 4 | 5 | function genText (node: ASTNode) { 6 | const value = node.type === 3 7 | ? node.text 8 | : node.type === 2 9 | ? node.tokens.length === 1 10 | ? node.tokens[0] 11 | : node.tokens 12 | : '' 13 | return JSON.stringify(value) 14 | } 15 | 16 | export function postTransformText (el: ASTElement) { 17 | // weex can only contain text, so the parser 18 | // always generates a single child. 19 | if (el.children.length) { 20 | addAttr(el, 'value', genText(el.children[0])) 21 | el.children = [] 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /node_modules/vue/src/platforms/weex/compiler/modules/recycle-list/v-bind.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { camelize } from 'shared/util' 4 | import { generateBinding } from 'weex/util/parser' 5 | import { bindRE } from 'compiler/parser/index' 6 | import { getAndRemoveAttr, addRawAttr } from 'compiler/helpers' 7 | 8 | function parseAttrName (name: string): string { 9 | return camelize(name.replace(bindRE, '')) 10 | } 11 | 12 | export function preTransformVBind (el: ASTElement) { 13 | for (const attr in el.attrsMap) { 14 | if (bindRE.test(attr)) { 15 | const name: string = parseAttrName(attr) 16 | const value = generateBinding(getAndRemoveAttr(el, attr)) 17 | delete el.attrsMap[attr] 18 | addRawAttr(el, name, value) 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /node_modules/vue/src/platforms/weex/compiler/modules/recycle-list/v-on.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | const inlineStatementRE = /^\s*([A-Za-z_$0-9\['\."\]]+)*\s*\(\s*(([A-Za-z_$0-9\['\."\]]+)?(\s*,\s*([A-Za-z_$0-9\['\."\]]+))*)\s*\)$/ 4 | 5 | function parseHandlerParams (handler: ASTElementHandler) { 6 | const res = inlineStatementRE.exec(handler.value) 7 | if (res && res[2]) { 8 | handler.params = res[2].split(/\s*,\s*/) 9 | } 10 | } 11 | 12 | export function postTransformVOn (el: ASTElement) { 13 | const events: ASTElementHandlers | void = el.events 14 | if (!events) { 15 | return 16 | } 17 | for (const name in events) { 18 | const handler: ASTElementHandler | Array = events[name] 19 | if (Array.isArray(handler)) { 20 | handler.map(fn => parseHandlerParams(fn)) 21 | } else { 22 | parseHandlerParams(handler) 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /node_modules/vue/src/platforms/weex/compiler/modules/recycle-list/v-once.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { getAndRemoveAttr, addRawAttr } from 'compiler/helpers' 4 | 5 | function containVOnce (el: ASTElement): boolean { 6 | for (const attr in el.attrsMap) { 7 | if (/^v\-once$/i.test(attr)) { 8 | return true 9 | } 10 | } 11 | return false 12 | } 13 | 14 | export function preTransformVOnce (el: ASTElement) { 15 | if (containVOnce(el)) { 16 | getAndRemoveAttr(el, 'v-once', true) 17 | addRawAttr(el, '[[once]]', true) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /node_modules/vue/src/platforms/weex/entry-compiler.js: -------------------------------------------------------------------------------- 1 | export { compile } from 'weex/compiler/index' 2 | export { generateCodeFrame } from 'compiler/codeframe' 3 | -------------------------------------------------------------------------------- /node_modules/vue/src/platforms/weex/entry-runtime-factory.js: -------------------------------------------------------------------------------- 1 | // this entry is built and wrapped with a factory function 2 | // used to generate a fresh copy of Vue for every Weex instance. 3 | 4 | import Vue from './runtime/index' 5 | 6 | exports.Vue = Vue 7 | -------------------------------------------------------------------------------- /node_modules/vue/src/platforms/weex/runtime/components/index.js: -------------------------------------------------------------------------------- 1 | import Richtext from './richtext' 2 | import Transition from './transition' 3 | import TransitionGroup from './transition-group' 4 | 5 | export default { 6 | Richtext, 7 | Transition, 8 | TransitionGroup 9 | } 10 | -------------------------------------------------------------------------------- /node_modules/vue/src/platforms/weex/runtime/components/transition.js: -------------------------------------------------------------------------------- 1 | // reuse same transition component logic from web 2 | export { 3 | transitionProps, 4 | extractTransitionData 5 | } from 'web/runtime/components/transition' 6 | 7 | import Transition from 'web/runtime/components/transition' 8 | 9 | export default Transition 10 | -------------------------------------------------------------------------------- /node_modules/vue/src/platforms/weex/runtime/directives/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | } 3 | -------------------------------------------------------------------------------- /node_modules/vue/src/platforms/weex/runtime/modules/index.js: -------------------------------------------------------------------------------- 1 | import attrs from './attrs' 2 | import klass from './class' 3 | import events from './events' 4 | import style from './style' 5 | import transition from './transition' 6 | 7 | export default [ 8 | attrs, 9 | klass, 10 | events, 11 | style, 12 | transition 13 | ] 14 | -------------------------------------------------------------------------------- /node_modules/vue/src/platforms/weex/runtime/patch.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import * as nodeOps from 'weex/runtime/node-ops' 4 | import { createPatchFunction } from 'core/vdom/patch' 5 | import baseModules from 'core/vdom/modules/index' 6 | import platformModules from 'weex/runtime/modules/index' 7 | 8 | // the directive module should be applied last, after all 9 | // built-in modules have been applied. 10 | const modules = platformModules.concat(baseModules) 11 | 12 | export const patch: Function = createPatchFunction({ 13 | nodeOps, 14 | modules, 15 | LONG_LIST_THRESHOLD: 10 16 | }) 17 | -------------------------------------------------------------------------------- /node_modules/vue/src/platforms/weex/runtime/text-node.js: -------------------------------------------------------------------------------- 1 | let latestNodeId = 1 2 | 3 | export default function TextNode (text) { 4 | this.instanceId = '' 5 | this.nodeId = latestNodeId++ 6 | this.parentNode = null 7 | this.nodeType = 3 8 | this.text = text 9 | } 10 | -------------------------------------------------------------------------------- /node_modules/vue/src/server/optimizing-compiler/index.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { parse } from 'compiler/parser/index' 4 | import { generate } from './codegen' 5 | import { optimize } from './optimizer' 6 | import { createCompilerCreator } from 'compiler/create-compiler' 7 | 8 | export const createCompiler = createCompilerCreator(function baseCompile ( 9 | template: string, 10 | options: CompilerOptions 11 | ): CompiledResult { 12 | const ast = parse(template.trim(), options) 13 | optimize(ast, options) 14 | const code = generate(ast, options) 15 | return { 16 | ast, 17 | render: code.render, 18 | staticRenderFns: code.staticRenderFns 19 | } 20 | }) 21 | -------------------------------------------------------------------------------- /node_modules/vue/src/server/util.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | export const isJS = (file: string): boolean => /\.js(\?[^.]+)?$/.test(file) 4 | 5 | export const isCSS = (file: string): boolean => /\.css(\?[^.]+)?$/.test(file) 6 | 7 | export function createPromiseCallback () { 8 | let resolve, reject 9 | const promise: Promise = new Promise((_resolve, _reject) => { 10 | resolve = _resolve 11 | reject = _reject 12 | }) 13 | const cb = (err: Error, res?: string) => { 14 | if (err) return reject(err) 15 | resolve(res || '') 16 | } 17 | return { promise, cb } 18 | } 19 | -------------------------------------------------------------------------------- /node_modules/vue/src/shared/constants.js: -------------------------------------------------------------------------------- 1 | export const SSR_ATTR = 'data-server-rendered' 2 | 3 | export const ASSET_TYPES = [ 4 | 'component', 5 | 'directive', 6 | 'filter' 7 | ] 8 | 9 | export const LIFECYCLE_HOOKS = [ 10 | 'beforeCreate', 11 | 'created', 12 | 'beforeMount', 13 | 'mounted', 14 | 'beforeUpdate', 15 | 'updated', 16 | 'beforeDestroy', 17 | 'destroyed', 18 | 'activated', 19 | 'deactivated', 20 | 'errorCaptured', 21 | 'serverPrefetch' 22 | ] 23 | -------------------------------------------------------------------------------- /node_modules/vue/types/index.d.ts: -------------------------------------------------------------------------------- 1 | import { Vue } from "./vue"; 2 | 3 | export default Vue; 4 | 5 | export as namespace Vue; 6 | 7 | export { 8 | CreateElement, 9 | VueConstructor 10 | } from "./vue"; 11 | 12 | export { 13 | Component, 14 | AsyncComponent, 15 | ComponentOptions, 16 | FunctionalComponentOptions, 17 | RenderContext, 18 | PropType, 19 | PropOptions, 20 | ComputedOptions, 21 | WatchHandler, 22 | WatchOptions, 23 | WatchOptionsWithHandler, 24 | DirectiveFunction, 25 | DirectiveOptions 26 | } from "./options"; 27 | 28 | export { 29 | PluginFunction, 30 | PluginObject 31 | } from "./plugin"; 32 | 33 | export { 34 | VNodeChildren, 35 | VNodeChildrenArrayContents, 36 | VNode, 37 | VNodeComponentOptions, 38 | VNodeData, 39 | VNodeDirective 40 | } from "./vnode"; 41 | -------------------------------------------------------------------------------- /node_modules/vue/types/plugin.d.ts: -------------------------------------------------------------------------------- 1 | import { Vue as _Vue } from "./vue"; 2 | 3 | export type PluginFunction = (Vue: typeof _Vue, options?: T) => void; 4 | 5 | export interface PluginObject { 6 | install: PluginFunction; 7 | [key: string]: any; 8 | } 9 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ten-tips-python-web-devs", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "vue": { 8 | "version": "2.6.10", 9 | "resolved": "https://registry.npmjs.org/vue/-/vue-2.6.10.tgz", 10 | "integrity": "sha512-ImThpeNU9HbdZL3utgMCq0oiMzAkt1mcgy3/E6zWC/G6AaQoeuFdsl9nDhTDU3X1R6FK7nsIUuRACVcjI+A2GQ==" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ten-tips-python-web-devs", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/mikeckennedy/ten-tips-python-web-devs.git" 12 | }, 13 | "author": "", 14 | "license": "ISC", 15 | "bugs": { 16 | "url": "https://github.com/mikeckennedy/ten-tips-python-web-devs/issues" 17 | }, 18 | "homepage": "https://github.com/mikeckennedy/ten-tips-python-web-devs#readme", 19 | "dependencies": { 20 | "vue": "^2.6.10" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tools-and-techniques-web.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikeckennedy/ten-tips-python-web-devs/e2406853a3d2e1d02ca5b00f68ae510993d4ad19/tools-and-techniques-web.pdf --------------------------------------------------------------------------------