├── .dockerignore ├── .eslintignore ├── .eslintrc.yml ├── .github └── dependabot.yml ├── .gitignore ├── .lgtm.yml ├── .node-version ├── .travis.yml ├── .vscode ├── launch.json └── settings.json ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── HISTORY.md ├── LICENSE ├── Makefile ├── README.md ├── SECURITY.md ├── apidoc.json ├── art ├── seq-seq-animation-clean-svg.svg └── seq-seq-animation.svg ├── browser ├── .eslintrc.yml ├── blog-editor.js ├── commandpedia.js ├── conversation.js ├── deps │ ├── codemirror-thingtalk.js │ ├── new-command.js │ ├── parserclient.js │ ├── persistent-set.js │ ├── reconstruct_canonical.js │ ├── recorder.js │ ├── search-or-infinite-scroll.js │ ├── thingpediaclient.js │ └── thingtalkutils.js ├── polyfill.js ├── thingpedia-device-create.js ├── thingpedia-device-translate.js └── thingpedia-portal.js ├── build ├── apply-db-migrations.sh ├── make-config-file-reference.js └── update-po.sh ├── cli ├── .gitignore ├── README.md ├── almond_cloud │ ├── __init__.py │ ├── cmd │ │ ├── __init__.py │ │ ├── deploy.py │ │ ├── image │ │ │ ├── __init__.py │ │ │ └── build.py │ │ ├── k8s │ │ │ ├── __init__.py │ │ │ ├── create.py │ │ │ ├── destroy.py │ │ │ ├── flip.py │ │ │ ├── nlp │ │ │ │ ├── __init__.py │ │ │ │ ├── create.py │ │ │ │ └── delete.py │ │ │ ├── repl.py │ │ │ ├── tail.py │ │ │ └── update.py │ │ ├── kust │ │ │ ├── __init__.py │ │ │ └── dump.py │ │ ├── target │ │ │ ├── __init__.py │ │ │ ├── get.py │ │ │ └── set.py │ │ └── thingpedia │ │ │ ├── __init__.py │ │ │ ├── configure.py │ │ │ └── upload.py │ ├── config.py │ ├── etc │ │ ├── coll.py │ │ └── path.py │ └── lib │ │ ├── k8s.py │ │ ├── kustard.py │ │ └── targets.py ├── bin │ └── almond-cloud ├── requirements.txt ├── setup.py └── share │ └── bash-completion.sh ├── data ├── icon.png ├── messaging │ ├── dataset.tt │ ├── manifest.tt │ └── metadata.yaml ├── org.thingpedia.builtin.bluetooth.generic │ ├── dataset.tt │ ├── icon.png │ ├── manifest.tt │ └── metadata.yaml ├── org.thingpedia.builtin.test ├── org.thingpedia.builtin.thingengine ├── org.thingpedia.builtin.thingengine.builtin ├── org.thingpedia.builtin.thingengine.gnome │ ├── dataset.tt │ └── manifest.tt ├── org.thingpedia.builtin.thingengine.phone │ ├── dataset.tt │ └── manifest.tt └── org.thingpedia.volume-control ├── dev ├── .gitignore ├── bin │ ├── almond-dev.configure.bash │ └── almond-dev.connect-mysql.bash ├── kind │ └── cluster.yaml └── macos │ └── Brewfile ├── docker ├── Dockerfile ├── hooks │ ├── build │ └── post_push └── start.sh ├── go ├── README.md ├── backend │ ├── backend_test.go │ └── main.go ├── config │ ├── config.go │ └── config_test.go ├── dbproxy │ ├── auth.go │ ├── dbproxy.go │ ├── local_table.go │ ├── sync_table.go │ └── util.go ├── go.mod ├── go.sum ├── k8s │ ├── api │ │ └── v1 │ │ │ ├── groupversion_info.go │ │ │ ├── user_types.go │ │ │ └── zz_generated.deepcopy.go │ ├── controllers │ │ ├── user_controller.go │ │ ├── utils.go │ │ └── utils_test.go │ └── manager │ │ └── manager.go ├── sql │ ├── local_table.go │ ├── local_table_test.go │ ├── model.go │ ├── mysql.go │ ├── mysql_test.go │ ├── sync_table.go │ ├── sync_table_test.go │ ├── user_app.go │ ├── user_channel.go │ ├── user_conversation.go │ ├── user_conversation_history.go │ ├── user_conversation_state.go │ ├── user_device.go │ ├── user_preference.go │ └── users.go └── tools │ ├── load-database │ └── main.go │ └── sign-jwt │ └── main.go ├── k8s ├── .gitignore ├── README.md ├── components │ ├── bootstrap │ │ ├── base │ │ │ ├── bootstrap.job.yaml │ │ │ ├── create-db.job.yaml │ │ │ └── kustomization.yaml │ │ ├── debug │ │ │ ├── bootstrap.job.yaml │ │ │ └── kustomization.yaml │ │ └── dev │ │ │ ├── bootstrap.job.yaml │ │ │ ├── create-db.job.yaml │ │ │ └── kustomization.yaml │ ├── config │ │ ├── base │ │ │ ├── kustomization.yaml │ │ │ └── sa.yaml │ │ └── dev │ │ │ ├── .gitignore │ │ │ ├── config.yaml │ │ │ ├── kustomization.yaml │ │ │ ├── manager-config │ │ │ ├── developer-deployment.json │ │ │ └── developer-service.json │ │ │ └── namespace.yaml │ ├── controller │ │ ├── crd │ │ │ ├── base │ │ │ │ ├── backend.almond.stanford.edu_users.yaml │ │ │ │ └── kustomization.yaml │ │ │ └── dev │ │ │ │ └── kustomization.yaml │ │ ├── manager │ │ │ ├── base │ │ │ │ ├── deployment.yaml │ │ │ │ └── kustomization.yaml │ │ │ └── dev │ │ │ │ ├── deployment.yaml │ │ │ │ └── kustomization.yaml │ │ └── rbac │ │ │ ├── base │ │ │ ├── auth_proxy_client_clusterrole.yaml │ │ │ ├── auth_proxy_role.yaml │ │ │ ├── auth_proxy_role_binding.yaml │ │ │ ├── auth_proxy_service.yaml │ │ │ ├── kustomization.yaml │ │ │ ├── leader_election_role.yaml │ │ │ ├── leader_election_role_binding.yaml │ │ │ ├── role.yaml │ │ │ ├── role_binding.yaml │ │ │ ├── service_account.yaml │ │ │ ├── user_editor_role.yaml │ │ │ ├── user_editor_role_binding.yaml │ │ │ └── user_viewer_role.yaml │ │ │ └── dev │ │ │ └── kustomization.yaml │ ├── dashboard │ │ └── dev │ │ │ ├── deployment.yaml │ │ │ └── kustomization.yaml │ ├── db │ │ ├── base │ │ │ ├── deployment.yaml │ │ │ ├── kustomization.yaml │ │ │ └── service.yaml │ │ └── dev │ │ │ ├── deployment.yaml │ │ │ └── kustomization.yaml │ ├── dbproxy │ │ ├── base │ │ │ ├── deployment.yaml │ │ │ ├── kustomization.yaml │ │ │ └── service.yaml │ │ └── dev │ │ │ ├── deployment.yaml │ │ │ └── kustomization.yaml │ ├── frontend │ │ ├── base │ │ │ ├── deployment.yaml │ │ │ ├── kustomization.yaml │ │ │ └── service.yaml │ │ ├── debug │ │ │ ├── deployment.yaml │ │ │ └── kustomization.yaml │ │ └── dev │ │ │ ├── deployment.yaml │ │ │ ├── ingress.yaml │ │ │ └── kustomization.yaml │ ├── ingress-nginx │ │ └── dev │ │ │ ├── kustomization.yaml │ │ │ └── service.yaml │ ├── nlp │ │ ├── README.md │ │ ├── base │ │ │ ├── cluster-role-binding.yaml │ │ │ ├── cluster-role.yaml │ │ │ ├── deployment.yaml │ │ │ ├── kustomization.yaml │ │ │ ├── service-account.yaml │ │ │ └── service.yaml │ │ ├── debug │ │ │ ├── deployment.yaml │ │ │ └── kustomization.yaml │ │ └── dev │ │ │ ├── deployment.yaml │ │ │ ├── ingress.yaml │ │ │ └── kustomization.yaml │ ├── redis │ │ ├── base │ │ │ ├── deployment.yaml │ │ │ ├── kustomization.yaml │ │ │ └── service.yaml │ │ └── dev │ │ │ └── kustomization.yaml │ └── shared-backend │ │ ├── base │ │ ├── kustomization.yaml │ │ ├── service.yaml │ │ └── stateful-set.yaml │ │ ├── debug │ │ ├── kustomization.yaml │ │ └── stateful-set.yaml │ │ └── dev │ │ ├── kustomization.yaml │ │ └── stateful-set.yaml ├── kustomizations │ ├── debug │ │ ├── bootstrap │ │ │ └── kustomization.yaml │ │ ├── core │ │ │ └── kustomization.yaml │ │ └── nlp │ │ │ └── kustomization.yaml │ └── dev │ │ ├── bootstrap │ │ └── kustomization.yaml │ │ ├── core │ │ └── kustomization.yaml │ │ └── nlp │ │ └── kustomization.yaml └── plugins │ ├── resolve-host-paths │ ├── README.md │ ├── resolve-host-paths.py │ └── transformer.yaml │ └── testy.py ├── model ├── migrations │ ├── 022a5a5-models_version.sql │ ├── 02f414e-device_class_tag.sql │ ├── 084e6e3-models_new_fields.sql │ ├── 145ed9e-training_jobs.sql │ ├── 15af11d-org_credit_updates.sql │ ├── 25a672b-email_verified.sql │ ├── 2704af0-oauth.sql │ ├── 29ea218-example_name.sql │ ├── 342392c-example_context.sql │ ├── 342dbfb-no_template_files.sql │ ├── 3b78ae3-org_credits.sql │ ├── 409ee66-models_trained_flag.sql │ ├── 4b93ac8-models_use_exact.sql │ ├── 4b96642-blog.sql │ ├── 4e67dec-user_conversation_state.sql │ ├── 58f74-user_tables.sql │ ├── 64a125f-dummy.sh │ ├── 64a125f-dummy.sql │ ├── 66131b0-replaced_example_utterances.sql │ ├── 6797316-homepage_links.sql │ ├── 6d555b8-mturk_validation.sql │ ├── 7254ac6-user_conversation.sql │ ├── 72ccf68-utterance_log_time.sql │ ├── 78f159b-new_roles_nlp_discourse_admin.sql │ ├── 7a10973-blog-images.sql │ ├── 7c832a4-entity_subtyping.sql │ ├── 871a27f-model_config.sql │ ├── 8b4218a-users_undo_developer_model.sql │ ├── 8ef5fbb-schema_extends.sql │ ├── 9256a08-blog_editor.sql │ ├── 96df512-github_login.sql │ ├── 9afc8bd-model_metrics.sql │ ├── a3f600e-users_developer_model.sql │ ├── a8dd900-model_contextual_flag.sql │ ├── aa91e09-conversation_state_history.sql │ ├── b6fafa8-org_invitations.sql │ ├── b77ba97-function_annotation_confirm.sql │ ├── bb1d2a9-admin_dev_status.sql │ ├── c6f6de7-totp.sql │ ├── c84c8c2-user_preference.sql │ ├── c953506-log_context.sql │ ├── cd30315-pkg_metadata.sql │ ├── db0f40b-models_redo_part1.sql │ ├── db0f40b-models_redo_part2.js │ ├── e1a71a4-user_phone.sql │ ├── e6ce32d-example_likes.sql │ ├── f931b89-mturk_batch_owner.sql │ ├── fa7aa77-alexa_models.sql │ └── fb205b8-trusted_dev_status.sql └── schema.sql ├── package-lock.json ├── package.json ├── po ├── .gitignore ├── POTFILES ├── POTFILES.jade ├── es.po ├── it.po └── zh_CN.po ├── public ├── fonts │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.svg │ ├── glyphicons-halflings-regular.ttf │ ├── glyphicons-halflings-regular.woff │ └── glyphicons-halflings-regular.woff2 ├── google1b619b92c63c82e6.html ├── images │ ├── .keep │ ├── almond-background.png │ ├── almond.png │ ├── almond_error.png │ ├── almond_mic_round_grey.svg │ ├── almond_mic_round_white.svg │ ├── almond_mic_white_round.svg │ ├── almond_music.jpg │ ├── bubble_almond.png │ ├── bubble_user.png │ ├── carousel-alexa.png │ ├── carousel-nasa.png │ ├── carousel-nest.png │ ├── carousel-nyt.png │ ├── carousel-teardrop.png │ ├── cheatsheet.png │ ├── docs │ │ ├── metadata_page.png │ │ ├── thingpedia_catalog.png │ │ └── train_almond_page.png │ ├── example-bitcoin.png │ ├── favicon.ico │ ├── home_assistant.png │ ├── icon-cloud.png │ ├── icon-compound.png │ ├── icon-email.png │ ├── icon-memory.png │ ├── icon-multi-user.png │ ├── icon-nn.png │ ├── icon-phone.svg │ ├── icon-spotify.png │ ├── icon-thingpedia.png │ ├── icon-tt.png │ ├── logo-discord.png │ ├── logo-email.png │ ├── logo-forum.png │ ├── logo-github.png │ ├── logo-rss.png │ ├── logo-slack.png │ ├── logo-twitter.png │ ├── logo.png │ ├── mmi.jpg │ ├── multi_user_almond.jpg │ ├── news-logo-hackaday.png │ ├── news-logo-hostingadvice.png │ ├── news-logo-nyt.png │ ├── news-logo-techhq.svg │ ├── sports_wikidata.jpg │ ├── stanford-logo.png │ ├── stanford-signature.png │ ├── symbolic-logo-community.svg │ ├── symbolic-logo-discord.svg │ ├── symbolic-logo-email.svg │ ├── symbolic-logo-github.svg │ ├── symbolic-logo-rss.svg │ ├── symbolic-logo-twitter.svg │ ├── thingengine-arch.svg │ ├── thingpedia-arch-diagram.svg │ ├── thingpedia-icon-cloud.png │ └── user-no-avatar.png ├── javascripts │ ├── .eslintrc.yml │ ├── .keep │ ├── 2fa_setup.js │ ├── ackee-min.js │ ├── admin.js │ ├── apps.js │ ├── device-selector.js │ ├── device.js │ ├── devices-create.js │ ├── get-involved.js │ ├── index.js │ ├── jsoneditor.min.js │ ├── jsonlint.js │ ├── jstz.min.js │ ├── mturk_check.js │ ├── profile.js │ ├── qrcode.js │ ├── register.js │ ├── shared.js │ ├── status.js │ └── validator.min.js └── stylesheets │ ├── admin.css │ ├── app.css │ ├── blog-editor.css │ ├── bootstrap.min.css │ ├── codemirror.css │ ├── conversation.css │ ├── dev_sidebar.css │ ├── docs.css │ ├── get-involved.css │ ├── glide.core.min.css │ ├── glide.theme.min.css │ ├── index.css │ ├── lint.css │ ├── luinet-dataset.css │ ├── mturk.css │ ├── my_stuff.css │ ├── oauth2.css │ ├── profiles.css │ ├── spinner.css │ ├── status.css │ ├── style.css │ ├── thingpedia-cheatsheet.css │ ├── thingpedia-device-create.css │ ├── thingpedia-devices.css │ └── thingpedia.css ├── sandbox ├── .gitignore ├── Makefile └── sandbox.c ├── src ├── almond │ ├── engine.ts │ ├── enginemanager.ts │ ├── enginemanagerclient.ts │ ├── enginemanagerclient_k8s.ts │ ├── graphics.ts │ ├── master.ts │ ├── platform.ts │ ├── preferences.ts │ ├── protocol.ts │ ├── shard.ts │ ├── sockaddr.d.ts │ ├── user_k8s.ts │ ├── worker.ts │ └── worker_k8s.ts ├── cacheable-middleware.d.ts ├── config.ts ├── frontend.ts ├── logging.ts ├── main.ts ├── model │ ├── alexa_model.ts │ ├── blog.ts │ ├── device.ts │ ├── entity.ts │ ├── example.ts │ ├── mturk.ts │ ├── nlp_models.ts │ ├── oauth2.ts │ ├── organization.ts │ ├── schema.ts │ ├── snapshot.ts │ ├── strings.ts │ ├── training_job.ts │ └── user.ts ├── nlp │ ├── admin.ts │ ├── learn.ts │ ├── main.ts │ ├── nlp_model.ts │ ├── nlu.ts │ ├── proxy.ts │ ├── query.ts │ └── voice │ │ ├── backend-microsoft.ts │ │ └── index.ts ├── routes │ ├── about.ts │ ├── admin.ts │ ├── admin_mturk.ts │ ├── admin_upload.ts │ ├── blog.ts │ ├── bridges │ │ └── gassistant │ │ │ └── index.ts │ ├── cloud-sync.ts │ ├── commandpedia.ts │ ├── developer_console.ts │ ├── developer_mturk.ts │ ├── developer_oauth2.ts │ ├── devices.ts │ ├── devices_compat.ts │ ├── markdown-it-container-pandoc.d.ts │ ├── markdown-it-footnote.d.ts │ ├── markdown-it-table-of-contents.d.ts │ ├── mturk.ts │ ├── my_api.ts │ ├── my_conversation.ts │ ├── my_internal_api.ts │ ├── my_oauth2.ts │ ├── my_recording.ts │ ├── my_stuff.ts │ ├── proxy.ts │ ├── qrcode.ts │ ├── status.ts │ ├── thingengine_ws.ts │ ├── thingpedia_api.ts │ ├── thingpedia_cheatsheet.ts │ ├── thingpedia_devices.ts │ ├── thingpedia_entities.ts │ ├── thingpedia_examples.ts │ ├── thingpedia_portal.ts │ ├── thingpedia_profiles.ts │ ├── thingpedia_schemas.ts │ ├── thingpedia_snapshots.ts │ ├── thingpedia_strings.ts │ ├── thingpedia_translate.ts │ ├── thingpedia_upload.ts │ ├── thirty-two.d.ts │ ├── user.ts │ └── webhook.ts ├── scripts │ ├── bootstrap.ts │ ├── compile-exact-btrie.js │ ├── download-dataset.ts │ ├── download-log.ts │ ├── download-recordings.ts │ ├── execute-sql-file.js │ ├── generate-cheatsheet.js │ ├── get-config.js │ ├── get-user-shards.js │ ├── migrate-dataset.js │ ├── sync-discourse-sso.js │ └── upload-dataset.js ├── training │ ├── backends │ │ ├── kubernetes.js │ │ └── local.js │ ├── daemon.js │ ├── job_specs.js │ ├── lib │ │ ├── action_set_flag.js │ │ ├── constant-file.js │ │ ├── dataset_generator.js │ │ └── param_provider.js │ ├── run-training-task.js │ ├── tasks │ │ ├── index.ts │ │ └── update-dataset.js │ ├── training_job.js │ └── workers │ │ └── generate-contextual-worker.js ├── types.ts └── util │ ├── abstract_fs.ts │ ├── address-formatter.d.ts │ ├── admin-thingpedia-client.ts │ ├── binary_search.ts │ ├── code_storage.ts │ ├── color-scheme.d.ts │ ├── color_scheme.ts │ ├── command.ts │ ├── commandpedia.ts │ ├── compat.ts │ ├── config_init.js │ ├── dataset.ts │ ├── db.ts │ ├── device_factories.ts │ ├── discovery │ ├── bluetooth.ts │ ├── index.ts │ └── upnp.ts │ ├── error_handling.ts │ ├── errors.ts │ ├── escaping.ts │ ├── example_names.ts │ ├── exec_sql.ts │ ├── fsutils.ts │ ├── genie_flag_utils.ts │ ├── growable_buffer.ts │ ├── highlightjs-thingtalk.ts │ ├── i18n.ts │ ├── img-color-extractor.d.ts │ ├── import_device.ts │ ├── input_validation.ts │ ├── json_datagram_socket.ts │ ├── json_websocket.ts │ ├── kf_inference_url.ts │ ├── local_fs.ts │ ├── location-linking.ts │ ├── lock.ts │ ├── manifest_to_schema.ts │ ├── metrics.ts │ ├── mturk.ts │ ├── oauth2.ts │ ├── origin.ts │ ├── pagination.ts │ ├── passport-totp.d.ts │ ├── passport.ts │ ├── random.ts │ ├── redis.ts │ ├── secret_key.ts │ ├── sendmail.ts │ ├── shard.ts │ ├── sleep.ts │ ├── stream-utils.ts │ ├── thingpedia-client.ts │ ├── timed_cache.ts │ ├── tokenize.ts │ ├── training_server.ts │ ├── upload_dataset.ts │ ├── user.ts │ └── validation.ts ├── stanford └── config.js ├── tests ├── check-migrations.sh ├── data │ ├── com.bing.png │ ├── com.bing.yaml │ ├── org.thingpedia.builtin.test.adminonly.yaml │ ├── org.thingpedia.builtin.test.invisible.yaml │ ├── stt-test1.wav │ ├── stt-test2.wav │ ├── test-examples-v1.json │ ├── test-examples-v3.json │ ├── test-oauth-logo.png │ ├── tt:location.txt │ ├── tt:long_free_text.txt │ ├── tt:path_name.txt │ ├── tt:person_first_name.txt │ ├── tt:search_query.txt │ └── tt:short_free_text.txt ├── everything.sh ├── install-nlp-deps.sh ├── linkcheck.js ├── load_test_thingpedia.ts ├── load_test_webalmond.js ├── login.js ├── nlp-integration.sh ├── nlp │ ├── index.js │ ├── parser_test_cases.json │ ├── test_nlu.js │ └── test_voice.js ├── test_thingpedia_api_tt1.js ├── test_thingpedia_api_v3.js ├── test_website_selenium.js ├── thingpedia-integration.sh ├── thingpedia-integration │ ├── Dockerfile │ ├── k8s │ │ ├── cluster.yaml │ │ ├── config.d │ │ │ └── config.yaml │ │ ├── controller │ │ │ ├── crd │ │ │ │ ├── backend.almond.stanford.edu_users.yaml │ │ │ │ └── kustomization.yaml │ │ │ ├── kustomization.yaml │ │ │ ├── manager │ │ │ │ ├── kustomization.yaml │ │ │ │ └── manager.yaml │ │ │ └── rbac │ │ │ │ ├── auth_proxy_client_clusterrole.yaml │ │ │ │ ├── auth_proxy_role.yaml │ │ │ │ ├── auth_proxy_role_binding.yaml │ │ │ │ ├── auth_proxy_service.yaml │ │ │ │ ├── controller_manager_role.yaml │ │ │ │ ├── controller_manager_role_binding.yaml │ │ │ │ ├── kustomization.yaml │ │ │ │ ├── leader_election_role.yaml │ │ │ │ ├── leader_election_role_binding.yaml │ │ │ │ ├── role.yaml │ │ │ │ ├── role_binding.yaml │ │ │ │ ├── service_account.yaml │ │ │ │ ├── user_editor_role.yaml │ │ │ │ ├── user_editor_role_binding.yaml │ │ │ │ └── user_viewer_role.yaml │ │ ├── database │ │ │ ├── create-db.yaml │ │ │ ├── kustomization.yaml │ │ │ └── mariadb.yaml │ │ ├── dbproxy.yaml │ │ ├── frontend.yaml │ │ ├── kustomization.yaml │ │ ├── manager-config │ │ │ ├── developer-deployment.json │ │ │ └── developer-service.json │ │ ├── sa.yaml │ │ ├── shared-backend.yaml │ │ └── start.sh │ ├── run-integration.sh │ ├── setup-integration.sh │ └── thingpedia-integration.sh ├── unit │ ├── index.js │ ├── test_abstract_fs.js │ ├── test_binary_search.js │ ├── test_class_validation.js │ ├── test_device_factories.js │ ├── test_example_names.js │ ├── test_input_validation.js │ ├── test_json_websocket.ts │ ├── test_k8s_api.js │ ├── test_kf_inference_url.js │ ├── test_lock.js │ ├── test_tokenize.js │ └── thingpedia.tt ├── util │ ├── csrf.js │ └── minidom.js ├── webalmond-integration.sh └── website │ ├── index.js │ ├── scaffold.js │ ├── test_admin.js │ ├── test_me.js │ ├── test_mturk.js │ ├── test_my_api.js │ ├── test_oauth.js │ ├── test_oauth_proxy.js │ ├── test_public_endpoints.js │ ├── test_register.js │ ├── test_sso.js │ └── test_string_entities.js ├── tmp └── .gitkeep ├── travis ├── docker-build.sh ├── id_rsa.autodeploy.enc ├── install-webalmond-deps.sh └── unlock-key.sh ├── tsconfig.json └── views ├── 2fa_login.pug ├── 2fa_setup.pug ├── about_index.pug ├── about_privacy.pug ├── about_tos.pug ├── admin_blog_archive.pug ├── admin_mturk_batch_list.pug ├── admin_org_details.pug ├── admin_org_list.pug ├── admin_portal.pug ├── admin_review_queue.pug ├── admin_training.pug ├── admin_user_list.pug ├── blog_archive.pug ├── blog_create_or_edit.pug ├── blog_home_page.pug ├── blog_post.pug ├── commandpedia.pug ├── conversation_mixin.pug ├── dev_console.pug ├── dev_devices.pug ├── dev_mturk_batch_list.pug ├── dev_oauth.pug ├── dev_overview.pug ├── dev_sidebar.pug ├── developer_access_ok.pug ├── developer_access_required.pug ├── device_selector.pug ├── devices_create.pug ├── email_verified.pug ├── error.pug ├── footer.pug ├── layout.pug ├── login.pug ├── login_required.pug ├── luinet_dataset.pug ├── luinet_dataset_list.pug ├── message.pug ├── mturk-submit.pug ├── mturk.pug ├── mturk_validate.pug ├── my_conversation.pug ├── my_stuff.pug ├── navbar.pug ├── oauth2_authorize.pug ├── password_recovery_continue.pug ├── password_recovery_start.pug ├── proxy_confirmation.pug ├── public_org_profile.pug ├── public_user_profile.pug ├── qrcode.pug ├── register.pug ├── register_mixins.pug ├── register_success.pug ├── stanford ├── about_get_almond.pug ├── about_get_involved.pug ├── about_index.pug ├── about_privacy.pug └── about_tos.pug ├── status.pug ├── thingpedia_cheatsheet.pug ├── thingpedia_device_create_or_edit.pug ├── thingpedia_device_details.pug ├── thingpedia_entity_list.pug ├── thingpedia_entity_values.pug ├── thingpedia_portal.pug ├── thingpedia_schema.pug ├── thingpedia_snapshot_list.pug ├── thingpedia_string_type_list.pug ├── thingpedia_translate_schema.pug └── user_profile.pug /.dockerignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.tsv 3 | *.zip 4 | *.bak 5 | *-bundle.js 6 | *.txt.pt 7 | *.pth 8 | *.bin 9 | .git 10 | .buildconfig 11 | 12 | home 13 | workdir 14 | shared 15 | tmp 16 | 17 | platform_config.js 18 | secret_config.js 19 | 20 | doc/doc-list.json 21 | doc/fts.json 22 | doc/thingpedia-api 23 | views/doc_*.pug 24 | !views/doc_base.pug 25 | !views/doc_sidebar.pug 26 | views/thingpedia_doc_index.pug 27 | 28 | tests/embeddings 29 | 30 | node_modules 31 | 32 | yarn-error.log 33 | 34 | .nyc_output 35 | .coverage 36 | 37 | .idea 38 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | public/javascripts/*-min.js 2 | public/javascripts/*.min.js 3 | public/javascripts/*-bundle.js 4 | public/javascripts/jsonlint.js 5 | public/javascripts/qrcode.js 6 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: npm 4 | directory: "/" 5 | schedule: 6 | interval: monthly 7 | time: "13:00" 8 | open-pull-requests-limit: 10 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.tsv 3 | *.zip 4 | *.bak 5 | *-bundle.js 6 | *.txt.pt 7 | *.pth 8 | *.bin 9 | .buildconfig 10 | 11 | /home 12 | /workdir 13 | /shared 14 | 15 | /platform_config.js 16 | /secret_config.js 17 | /public/cache 18 | /public/brassau 19 | /public/friendhub 20 | /public/download/devices 21 | /public/download/backgrounds 22 | /public/download/icons 23 | /public/download/blog-assets 24 | 25 | /views/doc_*.pug 26 | !/views/doc_base.pug 27 | !/views/doc_sidebar.pug 28 | /views/thingpedia_doc_index.pug 29 | 30 | /tests/embeddings 31 | 32 | node_modules/ 33 | /dist 34 | /go/backend/backend 35 | 36 | yarn-error.log 37 | 38 | /.nyc_output 39 | /coverage 40 | 41 | .idea 42 | 43 | custom_config.js 44 | 45 | /tmp 46 | -------------------------------------------------------------------------------- /.lgtm.yml: -------------------------------------------------------------------------------- 1 | queries: 2 | - exclude: js/stack-trace-exposure 3 | path_classifiers: 4 | library: 5 | - public/javascripts/qrcode.js 6 | - public/javascripts/jsonlint.js 7 | -------------------------------------------------------------------------------- /.node-version: -------------------------------------------------------------------------------- 1 | 12.22.5 -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Attach", 9 | "port": 9229, 10 | "request": "attach", 11 | "skipFiles": [ 12 | "/**" 13 | ], 14 | "type": "pwa-node" 15 | } 16 | 17 | ] 18 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cSpell.words": [ 3 | "bootstrapper", 4 | "kube", 5 | "kubectl", 6 | "kubernetes", 7 | "kust", 8 | "kustard", 9 | "kustomization", 10 | "kustomizations", 11 | "kustomize", 12 | "kustomized", 13 | "writabledir" 14 | ], 15 | "typescript.tsdk": "${workspaceFolder}/node_modules/typescript/lib/", 16 | "eslint.validate": [ 17 | "javascript", 18 | "javascriptreact", 19 | "typescript", 20 | "typescriptreact", 21 | ], 22 | "editor.codeActionsOnSave": { 23 | "source.fixAll.eslint": true, 24 | }, 25 | "[python]": { 26 | "editor.formatOnSave": true, 27 | "editor.tabSize": 4, 28 | "editor.insertSpaces": true 29 | }, 30 | "[typescript]": { 31 | "editor.tabSize": 4, 32 | "editor.insertSpaces": true 33 | }, 34 | } -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | sources = \ 2 | src/*.js \ 3 | src/*.ts \ 4 | src/*/*.js \ 5 | src/*/*.ts \ 6 | src/*/*/*.js \ 7 | src/*/*/*.ts \ 8 | src/*/*/*/*.js \ 9 | src/*/*/*/*.ts 10 | 11 | all: install prepare 12 | 13 | prepare: dist prepare-bundles prepare-mo 14 | 15 | dist: $(wildcard $(sources)) tsconfig.json 16 | tsc --build tsconfig.json 17 | chmod +x dist/main.js 18 | touch dist 19 | 20 | public/javascripts/%-bundle.js : browser/%.js browser/deps/* package-lock.json 21 | browserify -o $@ $< 22 | 23 | bundles := \ 24 | commandpedia \ 25 | thingpedia-device-create \ 26 | thingpedia-device-translate \ 27 | thingpedia-portal \ 28 | blog-editor \ 29 | conversation 30 | 31 | prepare-bundles: $(foreach b,$(bundles),public/javascripts/$(b)-bundle.js) 32 | 33 | %.mo: %.po 34 | msgfmt $< -o $@ 35 | 36 | languages := it zh_CN 37 | prepare-mo: $(foreach l,$(languages),po/$(l).mo) 38 | 39 | install: go/backend/backend 40 | make -C sandbox all || echo WARNING: failed to compile the sandbox 41 | 42 | go/backend/backend: go/*/*.go 43 | test -f /usr/local/bin/backend || ( cd go/backend && go build ) 44 | 45 | .PHONY: install prepare prepare-bundles prepare-mo 46 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | The following versions are supported: 6 | - the latest tagged stable version 7 | - the latest snapshot of the `production` branch 8 | - the latest snapshot of the `master` branch 9 | 10 | We welcome security reports for any supported version, and we will address them promptly. 11 | 12 | ## Reporting a Vulnerability 13 | 14 | If the vulnerability has low priority and is not directly exploitable (such as missing defensive code), please open an issue, and use the label `security`. 15 | For all other vulnerabilities, please send an email to thingpedia-admins@lists.stanford.edu and include the word "security" in the subject. 16 | Please include the affected version, any details to reproduce the problem, and whether an exploit is possible. 17 | 18 | We strive to triage all vulnerabilities promptly, and you should receive an update with a timeline shortly after your report. 19 | If the vulnerability is confirmed, it will receive a CVE identifier as soon as it is issued. 20 | Vulnerabilities in the `production` branch will be given additional priority. 21 | -------------------------------------------------------------------------------- /apidoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Thingpedia", 3 | "version": "0.3.0", 4 | "description": "Public API to access the Thingpedia database", 5 | "url": "https://thingpedia.stanford.edu/thingpedia/api", 6 | "sampleUrl": "https://thingpedia.stanford.edu/thingpedia/api", 7 | "template": { 8 | "forceLanguage": "en" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /browser/.eslintrc.yml: -------------------------------------------------------------------------------- 1 | env: 2 | browser: true 3 | es6: true 4 | node: true 5 | root: true 6 | parserOptions: 7 | ecmaVersion: 2017 8 | globals: 9 | $: false 10 | ThingEngine: false 11 | extends: 'eslint:recommended' 12 | rules: 13 | indent: off 14 | linebreak-style: 15 | - error 16 | - unix 17 | quotes: off 18 | no-console: off 19 | semi: 20 | - error 21 | - always 22 | consistent-return: warn 23 | curly: 24 | - error 25 | - multi-or-nest 26 | - consistent 27 | eqeqeq: 28 | - error 29 | - always 30 | no-unused-vars: 31 | - error 32 | - 33 | args: none 34 | no-case-declarations: warn 35 | no-eval: error 36 | no-proto: error 37 | no-sequences: error 38 | no-throw-literal: error 39 | no-unmodified-loop-condition: warn 40 | no-useless-call: warn 41 | no-useless-return: warn 42 | no-void: error 43 | prefer-promise-reject-errors: error 44 | strict: 45 | - error 46 | - global 47 | no-label-var: error 48 | no-lonely-if: off 49 | no-new-object: error 50 | arrow-body-style: off 51 | arrow-parens: 52 | - error 53 | - always 54 | prefer-arrow-callback: error 55 | prefer-numeric-literals: error 56 | require-atomic-updates: off 57 | -------------------------------------------------------------------------------- /build/apply-db-migrations.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | die() { 4 | echo "$@" 5 | exit 1 6 | } 7 | 8 | dry_run=0 9 | if test "$1" = "--dry-run" ; then 10 | dry_run=1 11 | shift 12 | fi 13 | 14 | old_head=$1 15 | test -n "$old_head" || die "Must pass the old commit head on the command line" 16 | old_head=`git rev-parse $old_head` 17 | 18 | set -e 19 | set -o pipefail 20 | 21 | srcdir=`dirname $0`/.. 22 | srcdir=`realpath $srcdir` 23 | 24 | for migration in $srcdir/model/migrations/* ; do 25 | test -x $migration || continue 26 | commit=`basename ${migration} | cut -f1 -d'-'` 27 | commit=`git rev-parse $commit` 28 | date=`git show --no-patch --pretty=tformat:%at ${commit}` 29 | if test -z "`git rev-list ${commit} ^${old_head}`" ; then 30 | continue 31 | fi 32 | 33 | printf "%s\t%s\t%s\n" "${date}" "${commit}" "${migration}" 34 | done | sort -n | while read date commit migration ; do 35 | echo "Applying `basename $migration` (from `date --date=@${date}`)" 36 | if test $dry_run -eq 1 ; then 37 | continue 38 | fi 39 | 40 | case $migration in 41 | *.sql) 42 | $srcdir/dist/main.js execute-sql-file $migration 43 | ;; 44 | *) 45 | npx ts-node $migration 46 | ;; 47 | esac 48 | done 49 | -------------------------------------------------------------------------------- /build/update-po.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | exec msgmerge -U $1 ./po/almond-cloud.pot 3 | -------------------------------------------------------------------------------- /cli/README.md: -------------------------------------------------------------------------------- 1 | `almond-cloud` CLI 2 | ============================================================================== 3 | 4 | Things you can do: 5 | 6 | 7 | -------------------------------------------------------------------------------- /cli/almond_cloud/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from clavier import Sesh 4 | 5 | from almond_cloud.config import CONFIG # NEED this FIRST! 6 | from almond_cloud import cmd 7 | 8 | 9 | def run(): 10 | sesh = Sesh(__name__, CONFIG.root / "cli" / "README.md", cmd) 11 | sesh.setup(CONFIG.log.level) 12 | sesh.parse() 13 | sesh.exec() 14 | -------------------------------------------------------------------------------- /cli/almond_cloud/cmd/__init__.py: -------------------------------------------------------------------------------- 1 | from clavier import dyn 2 | 3 | 4 | def add_parser(subparsers): 5 | subparsers.add_children(__name__, __path__) 6 | -------------------------------------------------------------------------------- /cli/almond_cloud/cmd/deploy.py: -------------------------------------------------------------------------------- 1 | from clavier import arg_par 2 | import splatlog as logging 3 | 4 | from almond_cloud.config import CONFIG 5 | from .image.build import build_image 6 | from .k8s.flip import flip 7 | 8 | 9 | LOG = logging.getLogger(__name__) 10 | 11 | DESC = f"""\ 12 | Rebuild the container and flip the pods that use it. 13 | """ 14 | 15 | 16 | def add_parser(subparsers: arg_par.Subparsers): 17 | parser = subparsers.add_parser( 18 | "deploy", 19 | target=deploy, 20 | help=DESC.splitlines()[0], 21 | description=DESC, 22 | ) 23 | 24 | 25 | def deploy(): 26 | build_image() 27 | flip(["image"]) 28 | -------------------------------------------------------------------------------- /cli/almond_cloud/cmd/image/__init__.py: -------------------------------------------------------------------------------- 1 | def add_parser(subparsers): 2 | parser = subparsers.add_parser( 3 | "image", 4 | help="Docker image", 5 | ) 6 | 7 | parser.add_children(__name__, __path__) 8 | -------------------------------------------------------------------------------- /cli/almond_cloud/cmd/image/build.py: -------------------------------------------------------------------------------- 1 | from argparse import BooleanOptionalAction 2 | import splatlog as logging 3 | 4 | from clavier import sh 5 | 6 | from almond_cloud.config import CONFIG 7 | 8 | 9 | LOG = logging.getLogger(__name__) 10 | 11 | 12 | def add_to(subparsers): 13 | parser = subparsers.add_parser( 14 | "build", target=build_image, help=f"Build {CONFIG.image.name}" 15 | ) 16 | 17 | parser.add_argument( 18 | "-p", 19 | "--plain", 20 | action=BooleanOptionalAction, 21 | default=False, 22 | help="Pass `--progress plain` to `docker build` (real Docker only!)", 23 | ) 24 | 25 | 26 | def build_image(plain: bool = False): 27 | opts = { 28 | "tag": CONFIG.image.name, 29 | "file": CONFIG.root / "docker" / "Dockerfile", 30 | } 31 | 32 | if plain: 33 | opts["progress"] = "plain" 34 | 35 | sh.run( 36 | "docker", 37 | "build", 38 | opts, 39 | ".", 40 | cwd=CONFIG.root, 41 | log=LOG, 42 | rel_paths=True, 43 | opts_style=" ", 44 | ) 45 | -------------------------------------------------------------------------------- /cli/almond_cloud/cmd/k8s/__init__.py: -------------------------------------------------------------------------------- 1 | def add_parser(subparsers): 2 | parser = subparsers.add_parser( 3 | "k8s", 4 | help="Do Kubernetes stuff", 5 | ) 6 | 7 | parser.add_children(__name__, __path__) 8 | -------------------------------------------------------------------------------- /cli/almond_cloud/cmd/k8s/create.py: -------------------------------------------------------------------------------- 1 | from clavier import arg_par, sh 2 | 3 | from almond_cloud.config import CONFIG 4 | from almond_cloud.lib import kustard 5 | 6 | 7 | def add_parser(subparsers: arg_par.Subparsers): 8 | parser = subparsers.add_parser( 9 | "create", 10 | target=create, 11 | help="Create (bootstrap) the deployment", 12 | ) 13 | 14 | 15 | def create(): 16 | src = CONFIG.kust.kustomizations_dir / "dev" / "bootstrap" 17 | resources = kustard.build( 18 | src, 19 | options={ 20 | "enable-alpha-plugins": True, 21 | "enable-exec": True, 22 | "load-restrictor": "LoadRestrictionsNone", 23 | }, 24 | ) 25 | sh.run( 26 | "kubectl", 27 | "apply", 28 | "--filename", 29 | "-", 30 | input=resources, 31 | ) 32 | -------------------------------------------------------------------------------- /cli/almond_cloud/cmd/k8s/destroy.py: -------------------------------------------------------------------------------- 1 | from clavier import arg_par 2 | from kubernetes import client, config 3 | import splatlog as logging 4 | 5 | from almond_cloud.config import CONFIG 6 | 7 | LOG = logging.getLogger(__name__) 8 | 9 | 10 | def add_parser(subparsers: arg_par.Subparsers): 11 | parser = subparsers.add_parser( 12 | "destroy", 13 | target=destroy, 14 | help="Knock out the deployment completely (delete namespace)", 15 | ) 16 | 17 | 18 | def destroy(): 19 | config.load_kube_config() 20 | api_v1 = client.CoreV1Api() 21 | status = api_v1.delete_namespace( 22 | CONFIG.k8s.namespace, grace_period_seconds=0 23 | ) 24 | LOG.info( 25 | "Namespace deleted", 26 | namespace=CONFIG.k8s.namespace, 27 | status=status, 28 | ) 29 | -------------------------------------------------------------------------------- /cli/almond_cloud/cmd/k8s/nlp/__init__.py: -------------------------------------------------------------------------------- 1 | def add_parser(subparsers): 2 | parser = subparsers.add_parser( 3 | "nlp", 4 | help="Muck with local nlp server", 5 | ) 6 | 7 | parser.add_children(__name__, __path__) 8 | -------------------------------------------------------------------------------- /cli/almond_cloud/cmd/k8s/nlp/create.py: -------------------------------------------------------------------------------- 1 | from argparse import BooleanOptionalAction 2 | from almond_cloud.config import CONFIG 3 | 4 | import splatlog as logging 5 | 6 | from almond_cloud.lib import targets, kustard 7 | 8 | LOG = logging.getLogger(__name__) 9 | 10 | DESC = f"""\ 11 | Create local nlp service. 12 | 13 | Can be used to locally hack on STT and TTS endpoints, which normally run on 14 | staging. 15 | """ 16 | 17 | DEFAULT_DEBUG = False 18 | 19 | 20 | def add_parser(subparsers): 21 | parser = subparsers.add_parser( 22 | "create", 23 | target=create, 24 | help=DESC.splitlines()[0], 25 | description=DESC, 26 | ) 27 | 28 | parser.add_argument( 29 | "-d", 30 | "--debug", 31 | action=BooleanOptionalAction, 32 | default=DEFAULT_DEBUG, 33 | help="Use the debug version (live-coding, debugger port)", 34 | ) 35 | 36 | 37 | def create(debug: bool = DEFAULT_DEBUG): 38 | target = targets.get("local") 39 | 40 | if debug: 41 | src = CONFIG.kust.kustomizations_dir / "debug" / "nlp" 42 | else: 43 | src = CONFIG.kust.kustomizations_dir / "dev" / "nlp" 44 | 45 | kustard.apply(src, kubectl_context=target.get("k8s.context")) 46 | -------------------------------------------------------------------------------- /cli/almond_cloud/cmd/k8s/nlp/delete.py: -------------------------------------------------------------------------------- 1 | from argparse import BooleanOptionalAction 2 | from almond_cloud.config import CONFIG 3 | 4 | import splatlog as logging 5 | 6 | from almond_cloud.lib import targets, kustard 7 | 8 | LOG = logging.getLogger(__name__) 9 | 10 | DESC = f"""\ 11 | Delete local nlp service. 12 | """ 13 | 14 | DEFAULT_DEBUG = False 15 | 16 | 17 | def add_parser(subparsers): 18 | parser = subparsers.add_parser( 19 | "delete", 20 | target=delete, 21 | help=DESC.splitlines()[0], 22 | description=DESC, 23 | ) 24 | 25 | parser.add_argument( 26 | "-d", 27 | "--debug", 28 | action=BooleanOptionalAction, 29 | default=DEFAULT_DEBUG, 30 | help="Use the debug version (live-coding, debugger port)", 31 | ) 32 | 33 | 34 | def delete(debug: bool = DEFAULT_DEBUG): 35 | target = targets.get("local") 36 | 37 | if debug: 38 | src = CONFIG.kust.kustomizations_dir / "debug" / "nlp" 39 | else: 40 | src = CONFIG.kust.kustomizations_dir / "dev" / "nlp" 41 | 42 | kustard.apply(src, kubectl_context=target.get("k8s.context")) 43 | -------------------------------------------------------------------------------- /cli/almond_cloud/cmd/k8s/repl.py: -------------------------------------------------------------------------------- 1 | import splatlog as logging 2 | from kubernetes import client, config 3 | 4 | from almond_cloud.config import CONFIG 5 | 6 | LOG = logging.getLogger(__name__) 7 | 8 | DESC = f"""\ 9 | Start a REPL with a `kubernetes.client.CoreV1Api` loaded up as `api_v1`. 10 | 11 | `CONFIG` is also available. Readline and tab-completion are hooked up too. 12 | 13 | You can use this to bang-around the Kubernetes Python API. Useful when writing 14 | new commands. 15 | """ 16 | 17 | 18 | def add_parser(subparsers): 19 | parser = subparsers.add_parser( 20 | "repl", 21 | target=repl, 22 | help=DESC.splitlines()[0], 23 | description=DESC, 24 | ) 25 | 26 | 27 | def repl(): 28 | import code 29 | 30 | config.load_kube_config() 31 | api_v1 = client.CoreV1Api() 32 | console = code.InteractiveConsole(locals={**globals(), **locals()}) 33 | 34 | # https://stackoverflow.com/a/35116399 35 | console.push("import readline") 36 | console.push("from rlcompleter import Completer") 37 | console.push("""readline.parse_and_bind("tab: complete")""") 38 | console.push("readline.set_completer(Completer(locals()).complete)") 39 | 40 | console.interact() 41 | -------------------------------------------------------------------------------- /cli/almond_cloud/cmd/k8s/update.py: -------------------------------------------------------------------------------- 1 | from clavier import arg_par, sh 2 | import splatlog as logging 3 | 4 | from almond_cloud.config import CONFIG 5 | from almond_cloud.lib import kustard 6 | 7 | 8 | LOG = logging.getLogger(__name__) 9 | 10 | 11 | def add_parser(subparsers: arg_par.Subparsers): 12 | parser = subparsers.add_parser( 13 | "update", 14 | target=update, 15 | help="Update the deployment", 16 | ) 17 | 18 | 19 | def update(): 20 | src = CONFIG.kust.kustomizations_dir / "dev" / "core" 21 | resources = kustard.build(src) 22 | sh.run( 23 | "kubectl", 24 | "apply", 25 | "--filename", 26 | "-", 27 | input=resources, 28 | ) 29 | -------------------------------------------------------------------------------- /cli/almond_cloud/cmd/kust/__init__.py: -------------------------------------------------------------------------------- 1 | def add_parser(subparsers): 2 | parser = subparsers.add_parser( 3 | "kust", 4 | help="Do Kustomize stuff", 5 | ) 6 | 7 | parser.add_children(__name__, __path__) 8 | -------------------------------------------------------------------------------- /cli/almond_cloud/cmd/target/__init__.py: -------------------------------------------------------------------------------- 1 | def add_parser(subparsers): 2 | parser = subparsers.add_parser( 3 | "target", 4 | help="Work with deployment targets", 5 | ) 6 | 7 | parser.add_children(__name__, __path__) 8 | -------------------------------------------------------------------------------- /cli/almond_cloud/cmd/target/get.py: -------------------------------------------------------------------------------- 1 | from os import environ 2 | from pathlib import Path 3 | from typing import List 4 | 5 | import splatlog as logging 6 | from clavier import arg_par, sh 7 | 8 | from almond_cloud.config import CONFIG 9 | from almond_cloud.etc.path import TFilename 10 | from almond_cloud.lib import targets 11 | 12 | LOG = logging.getLogger(__name__) 13 | 14 | DESC = f"""\ 15 | Get a target. 16 | """ 17 | 18 | 19 | def add_parser(subparsers: arg_par.Subparsers): 20 | parser = subparsers.add_parser( 21 | "get", 22 | target=get, 23 | help=DESC.splitlines()[0], 24 | description=DESC, 25 | ) 26 | 27 | parser.add_argument( 28 | "target_name", 29 | default="local", 30 | help="Target name with the Thingpedia url and access-token to use", 31 | ) 32 | 33 | 34 | def get(target_name: str): 35 | return targets.get(target_name) 36 | -------------------------------------------------------------------------------- /cli/almond_cloud/cmd/target/set.py: -------------------------------------------------------------------------------- 1 | from os import environ 2 | from pathlib import Path 3 | from typing import List 4 | 5 | import splatlog as logging 6 | from clavier import arg_par, sh 7 | 8 | from almond_cloud.config import CONFIG 9 | from almond_cloud.etc.path import TFilename 10 | from almond_cloud.lib import targets 11 | 12 | LOG = logging.getLogger(__name__) 13 | 14 | DESC = f"""\ 15 | Set a target key to a value. 16 | """ 17 | 18 | 19 | def add_parser(subparsers: arg_par.Subparsers): 20 | parser = subparsers.add_parser( 21 | "set", 22 | target=target_set, 23 | help=DESC.splitlines()[0], 24 | description=DESC, 25 | ) 26 | 27 | parser.add_argument( 28 | "target_name", 29 | default="local", 30 | help="Target name with the Thingpedia url and access-token to use", 31 | ) 32 | 33 | parser.add_argument( 34 | "key", 35 | help="Key to set", 36 | ) 37 | 38 | parser.add_argument( 39 | "value", 40 | help="Value to set", 41 | ) 42 | 43 | 44 | def target_set(target_name: str, key: str, value: str): 45 | return targets.set(target_name, key, value) 46 | -------------------------------------------------------------------------------- /cli/almond_cloud/cmd/thingpedia/__init__.py: -------------------------------------------------------------------------------- 1 | def add_parser(subparsers): 2 | parser = subparsers.add_parser( 3 | "thingpedia", 4 | help="Work with thingpedia-common-devices", 5 | ) 6 | 7 | parser.add_children(__name__, __path__) 8 | -------------------------------------------------------------------------------- /cli/almond_cloud/etc/coll.py: -------------------------------------------------------------------------------- 1 | ############################################################################## 2 | # Collection Manipulators 3 | # ============================================================================ 4 | ############################################################################## 5 | 6 | from typing import Mapping, Sequence 7 | 8 | 9 | def dig(target, *path, not_found=None): 10 | while len(path) > 0: 11 | key, *path = path 12 | if isinstance(target, Mapping): 13 | if key in target: 14 | target = target[key] 15 | else: 16 | return not_found 17 | elif isinstance(target, Sequence): 18 | if isinstance(key, int): 19 | if key > len(target): 20 | return not_found 21 | target = target[key] 22 | else: 23 | return not_found 24 | else: 25 | return not_found 26 | return target 27 | -------------------------------------------------------------------------------- /cli/almond_cloud/etc/path.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | from typing import Union 3 | 4 | TFilename = Union[str, Path] 5 | 6 | 7 | def path_for(filename: TFilename) -> Path: 8 | if isinstance(filename, Path): 9 | return filename 10 | return Path(filename) 11 | 12 | 13 | def dot_ext(ext: str) -> str: 14 | if ext.startswith("."): 15 | return ext 16 | return f".{ext}" 17 | 18 | 19 | def undot_ext(ext: str) -> str: 20 | if ext.startswith("."): 21 | return ext[1:] 22 | return ext 23 | 24 | 25 | def add_ext(filename: TFilename, ext: str) -> Path: 26 | path = path_for(filename) 27 | return path.parent / (path.name + dot_ext(ext)) 28 | -------------------------------------------------------------------------------- /cli/almond_cloud/lib/k8s.py: -------------------------------------------------------------------------------- 1 | from typing import Iterable, List 2 | 3 | from kubernetes.client.models.v1_pod import V1Pod 4 | 5 | from almond_cloud.config import CONFIG 6 | 7 | 8 | def match_pod_name(pod_names: Iterable[str], pod: V1Pod) -> bool: 9 | for name in pod_names: 10 | if pod.metadata.name == name or pod.metadata.name.startswith( 11 | f"{name}-" 12 | ): 13 | return True 14 | return False 15 | 16 | 17 | def expand_names(names: List[str]) -> List[str]: 18 | expanded = set() 19 | for name in names: 20 | if name in CONFIG.k8s.name_groups: 21 | for n in CONFIG.k8s.name_groups[name]: 22 | expanded.add(n) 23 | else: 24 | expanded.add(name) 25 | return sorted(list(expanded)) 26 | -------------------------------------------------------------------------------- /cli/bin/almond-cloud: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # PYTHON_ARGCOMPLETE_OK 3 | 4 | from almond_cloud import run # pylint: disable=import-self 5 | 6 | run() 7 | -------------------------------------------------------------------------------- /cli/requirements.txt: -------------------------------------------------------------------------------- 1 | # These are the **dev** requirements, and do _not_ include the cli package 2 | # itself. 3 | # 4 | # So, for a full-setup (from the repo root): 5 | # 6 | # pip install -r ./cli/requirements.txt 7 | # pip install -e ./cli 8 | # 9 | 10 | # Building and publishing 11 | # setuptools 12 | # wheel 13 | # twine 14 | 15 | # VSCode / formatting stuff, updated 2021-10-26 16 | black==21.9b0 # No idea how this versioning crap works 17 | pylint>=2.11.1,<3.0 18 | rope>=0.21.0,<0.22 19 | mypy>=0.910 20 | 21 | # # Doc generation 22 | # sphinx>=3.5.2,<4 23 | # # Guess this is supposed to get us Markdown 24 | # # myst-parser>=0.13.5,<2 25 | # # recommonmark>=0.7.1 26 | # commonmark>=0.9.1 27 | # # Read The Docs theme, which hopefully doesn't look so terrible 28 | # sphinx-rtd-theme>=0.5.1 29 | -------------------------------------------------------------------------------- /cli/setup.py: -------------------------------------------------------------------------------- 1 | import setuptools 2 | 3 | setuptools.setup( 4 | name="almond-cloud-cli", 5 | version="0.0.0", 6 | author="Stanford OVAL", 7 | author_email="thingpedia-admins@lists.stanford.edu", 8 | description="Command Line Interface (CLI) for Almond Cloud development and deployment", 9 | url="https://github.com/stanford-oval/almond-cloud", 10 | packages=setuptools.find_packages(), 11 | python_requires=">=3,<4", 12 | install_requires=[ 13 | "clavier==0.1.3a3", 14 | "kubernetes>=19.15.0,<20", 15 | "pyyaml>=6.0,<7", 16 | ], 17 | scripts=[ 18 | "bin/almond-cloud", 19 | ], 20 | ) 21 | -------------------------------------------------------------------------------- /cli/share/bash-completion.sh: -------------------------------------------------------------------------------- 1 | # `source` this file, like 2 | # 3 | # source "$(git rev-parse --show-toplevel)/cli/share/bash-completion.sh" 4 | # 5 | eval "$(register-python-argcomplete almond-cloud)" 6 | -------------------------------------------------------------------------------- /data/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/data/icon.png -------------------------------------------------------------------------------- /data/messaging/dataset.tt: -------------------------------------------------------------------------------- 1 | dataset @messaging language "en" { 2 | } 3 | -------------------------------------------------------------------------------- /data/messaging/manifest.tt: -------------------------------------------------------------------------------- 1 | abstract class @messaging 2 | #_[thingpedia_name="Messaging Interface"] 3 | #_[thingpedia_description="This interface is provided by all devices that can be used as messaging backends for communicating Almond."] 4 | #[repository="https://github.com/stanford-oval/genie-toolkit"] 5 | #[subcategory="communication"] 6 | { 7 | } 8 | -------------------------------------------------------------------------------- /data/messaging/metadata.yaml: -------------------------------------------------------------------------------- 1 | thingpedia_name: Messaging Interface 2 | thingpedia_description: This interface is provided by all devices that can be used as messaging backends for communicating Almond. 3 | repository: https://github.com/stanford-oval/genie-toolkit 4 | subcategory: communication 5 | -------------------------------------------------------------------------------- /data/org.thingpedia.builtin.bluetooth.generic/dataset.tt: -------------------------------------------------------------------------------- 1 | dataset @org.thingpedia.builtin.bluetooth.generic language "en" { 2 | } 3 | -------------------------------------------------------------------------------- /data/org.thingpedia.builtin.bluetooth.generic/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/data/org.thingpedia.builtin.bluetooth.generic/icon.png -------------------------------------------------------------------------------- /data/org.thingpedia.builtin.bluetooth.generic/manifest.tt: -------------------------------------------------------------------------------- 1 | class @org.thingpedia.builtin.bluetooth.generic 2 | #_[thingpedia_name="Generic Bluetooth Device"] 3 | #_[thingpedia_description="The most generic of Bluetooth classes, it supports no operation at all. It is used if nothing more specific is found."] 4 | #[repository="https://github.com/stanford-oval/genie-toolkit"] 5 | #[subcategory="home"] 6 | { 7 | import loader from @org.thingpedia.builtin(); 8 | import config from @org.thingpedia.config.discovery.bluetooth(uuids=[]); 9 | } 10 | -------------------------------------------------------------------------------- /data/org.thingpedia.builtin.bluetooth.generic/metadata.yaml: -------------------------------------------------------------------------------- 1 | thingpedia_name: Generic Bluetooth Device 2 | thingpedia_description: The most generic of Bluetooth classes, it supports no operation at all. It is used if nothing more specific is found. 3 | repository: https://github.com/stanford-oval/genie-toolkit 4 | subcategory: home 5 | -------------------------------------------------------------------------------- /data/org.thingpedia.builtin.test: -------------------------------------------------------------------------------- 1 | ../node_modules/genie-toolkit/data/builtins/org.thingpedia.builtin.test -------------------------------------------------------------------------------- /data/org.thingpedia.builtin.thingengine: -------------------------------------------------------------------------------- 1 | ../node_modules/genie-toolkit/data/builtins/org.thingpedia.builtin.thingengine -------------------------------------------------------------------------------- /data/org.thingpedia.builtin.thingengine.builtin: -------------------------------------------------------------------------------- 1 | ../node_modules/genie-toolkit/data/builtins/org.thingpedia.builtin.thingengine.builtin -------------------------------------------------------------------------------- /data/org.thingpedia.volume-control: -------------------------------------------------------------------------------- 1 | ../node_modules/genie-toolkit/data/builtins/org.thingpedia.volume-control -------------------------------------------------------------------------------- /dev/.gitignore: -------------------------------------------------------------------------------- 1 | # Local (possible sensitive) environment variables used for configuration 2 | /.env 3 | -------------------------------------------------------------------------------- /dev/bin/almond-dev.configure.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Common / useful `set` commands 4 | set -Ee # Exit on error 5 | set -o pipefail # Check status of piped commands 6 | set -u # Error on undefined vars 7 | # set -v # Print everything 8 | # set -x # Print commands (with expanded vars) 9 | 10 | REPO_ROOT="$(git rev-parse --show-toplevel)" 11 | DEST_PATH="${REPO_ROOT}/k8s/config/dev/secret.yaml" 12 | 13 | test -f "${REPO_ROOT}/dev/.env" && source "${REPO_ROOT}/dev/.env" 14 | 15 | SECRET_PATH="${REPO_ROOT}/k8s/config/dev/secret.yaml" 16 | 17 | SHARED_PATH="${REPO_ROOT}/tmp/shared" 18 | 19 | for x in devices icons backgrounds blog-assets template-files/en; do 20 | mkdir -p "${SHARED_PATH}/download/$x" 21 | done 22 | 23 | SECRET_KEY="$(openssl rand -hex 32)" 24 | AES_SECRET_KEY="$(openssl rand -hex 16)" 25 | JWT_SIGNING_KEY="$(openssl rand -hex 32)" 26 | 27 | cat <"${SECRET_PATH}" 28 | SECRET_KEY: ${SECRET_KEY} 29 | AES_SECRET_KEY: ${AES_SECRET_KEY} 30 | JWT_SIGNING_KEY: ${JWT_SIGNING_KEY} 31 | END 32 | -------------------------------------------------------------------------------- /dev/bin/almond-dev.connect-mysql.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | exec kubectl -n almond-dev run --restart=Never --rm -ti --image mariadb:10.2.22 --command mariadb -- mysql -hdb -ppassword -Dthingengine_dev --default-character-set=utf8mb4 4 | -------------------------------------------------------------------------------- /dev/kind/cluster.yaml: -------------------------------------------------------------------------------- 1 | kind: Cluster 2 | apiVersion: kind.x-k8s.io/v1alpha4 3 | nodes: 4 | # one node hosting a control plane 5 | - role: control-plane 6 | kubeadmConfigPatches: 7 | - | 8 | kind: InitConfiguration 9 | nodeRegistration: 10 | kubeletExtraArgs: 11 | node-labels: "ingress-ready=true" 12 | extraMounts: 13 | - hostPath: path-to-almond-cloud 14 | containerPath: /host 15 | readOnly: false 16 | selinuxRelabel: false 17 | propagation: None 18 | extraPortMappings: 19 | - containerPort: 80 20 | hostPort: 8080 21 | protocol: TCP 22 | 23 | -------------------------------------------------------------------------------- /dev/macos/Brewfile: -------------------------------------------------------------------------------- 1 | brew "kustomize" 2 | -------------------------------------------------------------------------------- /docker/hooks/build: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | set -x 5 | echo "Running in $(pwd)" 6 | 7 | docker build -f $(basename $DOCKERFILE_PATH) -t $IMAGE_NAME .. 8 | -------------------------------------------------------------------------------- /docker/hooks/post_push: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | version=$(git describe) 4 | docker tag $IMAGE_NAME $DOCKER_REPO:$version 5 | docker push $DOCKER_REPO:$version 6 | -------------------------------------------------------------------------------- /docker/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | NODE_MAX_OLD_SPACE_SIZE=${NODE_MAX_OLD_SPACE_SIZE:-500} 3 | exec node --max_old_space_size=${NODE_MAX_OLD_SPACE_SIZE} /opt/almond-cloud/dist/main.js "$@" 4 | -------------------------------------------------------------------------------- /go/backend/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 The Board of Trustees of the Leland Stanford Junior University 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | package main 15 | 16 | import ( 17 | "almond-cloud/config" 18 | "almond-cloud/dbproxy" 19 | "almond-cloud/k8s/manager" 20 | 21 | "log" 22 | "os" 23 | ) 24 | 25 | func main() { 26 | 27 | err := config.InitAlmondConfig() 28 | if err != nil { 29 | log.Printf("Warning: failed to initialize almond config: %v", err) 30 | } 31 | 32 | if len(os.Args) < 2 { 33 | usage() 34 | os.Exit(1) 35 | } 36 | 37 | switch os.Args[1] { 38 | case "dbproxy": 39 | dbproxy.Run(os.Args[2:]) 40 | case "manager": 41 | manager.Run(os.Args[2:]) 42 | default: 43 | usage() 44 | os.Exit(1) 45 | } 46 | } 47 | 48 | func usage() { 49 | dbproxy.Usage() 50 | } 51 | -------------------------------------------------------------------------------- /go/go.mod: -------------------------------------------------------------------------------- 1 | module almond-cloud 2 | 3 | go 1.16 4 | 5 | require ( 6 | github.com/DATA-DOG/go-sqlmock v1.5.0 7 | github.com/gin-gonic/gin v1.7.2 8 | github.com/go-logr/logr v0.4.0 9 | github.com/go-playground/validator/v10 v10.6.1 // indirect 10 | github.com/go-sql-driver/mysql v1.6.0 11 | github.com/go-test/deep v1.0.7 12 | github.com/golang-jwt/jwt v3.2.1+incompatible 13 | github.com/google/go-cmp v0.5.6 // indirect 14 | github.com/leodido/go-urn v1.2.1 // indirect 15 | github.com/mattn/go-isatty v0.0.13 // indirect 16 | github.com/prometheus/client_golang v1.11.0 17 | github.com/stretchr/testify v1.7.0 18 | github.com/ugorji/go v1.2.6 // indirect 19 | golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a // indirect 20 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect 21 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b 22 | gorm.io/driver/mysql v1.1.0 23 | gorm.io/gorm v1.21.10 24 | k8s.io/api v0.21.2 25 | k8s.io/apimachinery v0.21.2 26 | k8s.io/client-go v0.21.2 27 | sigs.k8s.io/controller-runtime v0.9.2 28 | ) 29 | -------------------------------------------------------------------------------- /go/k8s/api/v1/groupversion_info.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 The Board of Trustees of the Leland Stanford Junior University 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | package v1 15 | 16 | import ( 17 | "k8s.io/apimachinery/pkg/runtime/schema" 18 | "sigs.k8s.io/controller-runtime/pkg/scheme" 19 | ) 20 | 21 | var ( 22 | // GroupVersion is group version used to register these objects 23 | GroupVersion = schema.GroupVersion{Group: "backend.almond.stanford.edu", Version: "v1"} 24 | 25 | // SchemeBuilder is used to add go types to the GroupVersionKind scheme 26 | SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} 27 | 28 | // AddToScheme adds the types in this group-version to the given scheme. 29 | AddToScheme = SchemeBuilder.AddToScheme 30 | ) 31 | -------------------------------------------------------------------------------- /go/sql/mysql_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 The Board of Trustees of the Leland Stanford Junior University 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | package sql 15 | 16 | import ( 17 | "testing" 18 | 19 | "github.com/stretchr/testify/require" 20 | ) 21 | 22 | func TestMySQLDSN(t *testing.T) { 23 | input := "mysql://user:pwd@host.name/database?charset=utf8mb4_bin&ssl=Amazon%20RDS&acquireTimeout=120000&connectTimeout=120000&timezone=Z" 24 | want := "user:pwd@tcp(host.name)/database?charset=utf8mb4&loc=UTC&parseTime=true&tls=aws&timeout=120000ms" 25 | got, err := MySQLDSN(input) 26 | require.Nil(t, err) 27 | require.Equal(t, want, got) 28 | } 29 | -------------------------------------------------------------------------------- /go/tools/sign-jwt/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "almond-cloud/config" 5 | "almond-cloud/dbproxy" 6 | "fmt" 7 | "os" 8 | "strconv" 9 | ) 10 | 11 | func main() { 12 | signingKey := config.GetAlmondConfig().JWTSigningKey 13 | fmt.Println("using signing key", signingKey) 14 | id, _ := strconv.ParseInt(os.Args[1], 10, 64) 15 | token, err := dbproxy.SignToken(id) 16 | fmt.Printf("%d: %s err:%v\n", id, token, err) 17 | } 18 | -------------------------------------------------------------------------------- /k8s/.gitignore: -------------------------------------------------------------------------------- 1 | *.local.yaml 2 | -------------------------------------------------------------------------------- /k8s/README.md: -------------------------------------------------------------------------------- 1 | # Almond Cloud Development Configuration 2 | 3 | The configuration is divided in components, and each component has a "base" 4 | directory shared by all environment, and an environment-specific directory. 5 | 6 | ## Components 7 | 8 | - config: shared almond-cloud configuration files, and base k8s resources like namespace and service account 9 | - controller: TODO 10 | - mysql: MariaDB 11 | - dbproxy: service that engine (?) nodes use to access the db 12 | - frontend: almond-cloud frontend servers 13 | - shared-backend: almond-cloud backend service 14 | 15 | ## Deployment Commands 16 | 17 | (paths are relative to this directory) 18 | 19 | ```bash 20 | kustomize build | kubectl apply -f - 21 | ``` 22 | -------------------------------------------------------------------------------- /k8s/components/bootstrap/base/bootstrap.job.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: batch/v1 2 | kind: Job 3 | metadata: 4 | name: bootstrap 5 | labels: 6 | app: bootstrap 7 | 8 | spec: 9 | completions: 1 10 | parallelism: 1 11 | backoffLimit: 0 12 | 13 | template: 14 | metadata: 15 | labels: 16 | app: bootstrap 17 | spec: 18 | restartPolicy: Never 19 | containers: 20 | - name: main 21 | image: stanfordoval/almond-cloud:latest 22 | args: ["bootstrap"] 23 | volumeMounts: 24 | - mountPath: /etc/almond-cloud/config.d/config.yaml 25 | subPath: config.yaml 26 | name: config 27 | readOnly: true 28 | - mountPath: /etc/almond-cloud/config.d/secret.yaml 29 | subPath: secret.yaml 30 | name: secret 31 | readOnly: true 32 | volumes: 33 | - name: config 34 | configMap: 35 | name: almond-config 36 | - name: secret 37 | secret: 38 | secretName: almond-secret 39 | -------------------------------------------------------------------------------- /k8s/components/bootstrap/base/create-db.job.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: batch/v1 2 | kind: Job 3 | metadata: 4 | name: create-db 5 | labels: 6 | app: bootstrap 7 | 8 | spec: 9 | backoffLimit: 0 10 | 11 | template: 12 | metadata: 13 | labels: 14 | app: bootstrap 15 | spec: 16 | restartPolicy: Never 17 | containers: 18 | - name: create-db 19 | image: mariadb:10.2.22 20 | imagePullPolicy: IfNotPresent 21 | env: 22 | - name: MYSQL_ROOT_PASSWORD 23 | command: 24 | - /bin/bash 25 | - -c 26 | - | 27 | set -ex 28 | while ! mysqladmin ping -h db --silent; do 29 | sleep 1 30 | done 31 | mysql -h db -p${MYSQL_ROOT_PASSWORD} -e "create database if not exists thingengine_dev;" 32 | -------------------------------------------------------------------------------- /k8s/components/bootstrap/base/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - create-db.job.yaml 3 | - bootstrap.job.yaml 4 | -------------------------------------------------------------------------------- /k8s/components/bootstrap/debug/bootstrap.job.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: batch/v1 2 | kind: Job 3 | metadata: 4 | name: bootstrap 5 | spec: 6 | template: 7 | spec: 8 | containers: 9 | - name: main 10 | command: 11 | - /bin/bash 12 | args: 13 | - -c 14 | - | 15 | set -ex 16 | cd /opt/almond-cloud 17 | /usr/bin/npm run start:dev -- bootstrap 18 | env: 19 | - name: THINGENGINE_ROOTDIR 20 | value: /home/almond-cloud 21 | volumeMounts: 22 | - mountPath: /opt/almond-cloud/src 23 | name: src 24 | volumes: 25 | - name: src 26 | hostPath: 27 | type: Directory 28 | path: //src 29 | -------------------------------------------------------------------------------- /k8s/components/bootstrap/debug/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1alpha1 2 | kind: Component 3 | 4 | components: 5 | - ../dev 6 | 7 | patches: 8 | - bootstrap.job.yaml 9 | -------------------------------------------------------------------------------- /k8s/components/bootstrap/dev/bootstrap.job.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: batch/v1 2 | kind: Job 3 | metadata: 4 | name: bootstrap 5 | spec: 6 | template: 7 | spec: 8 | containers: 9 | - name: main 10 | imagePullPolicy: IfNotPresent 11 | env: 12 | - name: NODE_ENV 13 | value: development 14 | volumeMounts: 15 | - mountPath: /home/almond-cloud/shared 16 | name: shared 17 | volumes: 18 | - name: shared 19 | hostPath: 20 | type: Directory 21 | path: //tmp/shared 22 | -------------------------------------------------------------------------------- /k8s/components/bootstrap/dev/create-db.job.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: batch/v1 2 | kind: Job 3 | metadata: 4 | name: create-db 5 | spec: 6 | template: 7 | spec: 8 | containers: 9 | - name: create-db 10 | env: 11 | - name: MYSQL_ROOT_PASSWORD 12 | value: password 13 | -------------------------------------------------------------------------------- /k8s/components/bootstrap/dev/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1alpha1 2 | kind: Component 3 | 4 | bases: 5 | - ../base 6 | 7 | patches: 8 | - create-db.job.yaml 9 | - bootstrap.job.yaml 10 | -------------------------------------------------------------------------------- /k8s/components/config/base/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - sa.yaml 3 | -------------------------------------------------------------------------------- /k8s/components/config/base/sa.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: default-editor 5 | -------------------------------------------------------------------------------- /k8s/components/config/dev/.gitignore: -------------------------------------------------------------------------------- 1 | # Everyone needs to create their own dev instance secrets (example file TBD) 2 | /secret.yaml 3 | -------------------------------------------------------------------------------- /k8s/components/config/dev/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1alpha1 2 | kind: Component 3 | 4 | bases: 5 | - ../base 6 | 7 | resources: 8 | - namespace.yaml 9 | 10 | patches: 11 | - namespace.yaml 12 | 13 | configMapGenerator: 14 | - name: almond-config 15 | files: 16 | - config.yaml 17 | # FIXME These are here -- rather than in base -- because they embed several 18 | # instance-specific configuration variables. Maybe the user controller 19 | # thing should fill them in..? 20 | - name: manager-config 21 | files: 22 | - manager-config/developer-deployment.json 23 | - manager-config/developer-service.json 24 | 25 | secretGenerator: 26 | - name: almond-secret 27 | files: 28 | # NOTE This file must be created locally, see adjacent 29 | # `secret.yaml.EXAMPLE` file 30 | - secret.yaml 31 | -------------------------------------------------------------------------------- /k8s/components/config/dev/manager-config/developer-service.json: -------------------------------------------------------------------------------- 1 | { 2 | "apiVersion": "v1", 3 | "kind": "Service", 4 | "metadata": { 5 | "labels": { 6 | "app": "" 7 | }, 8 | "name": "", 9 | "namespace": "default" 10 | }, 11 | "spec": { 12 | "ports": [ 13 | { 14 | "port": 8100, 15 | "protocol": "TCP", 16 | "targetPort": 8100 17 | } 18 | ], 19 | "selector": { 20 | "app": "" 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /k8s/components/config/dev/namespace.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | labels: 5 | serving.kubeflow.org/inferenceservice: enabled 6 | control-plane: controller-manager 7 | name: almond-dev 8 | -------------------------------------------------------------------------------- /k8s/components/controller/crd/base/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - backend.almond.stanford.edu_users.yaml -------------------------------------------------------------------------------- /k8s/components/controller/crd/dev/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1alpha1 2 | kind: Component 3 | 4 | bases: 5 | - ../base 6 | -------------------------------------------------------------------------------- /k8s/components/controller/manager/base/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - deployment.yaml 3 | -------------------------------------------------------------------------------- /k8s/components/controller/manager/dev/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: controller-manager 5 | spec: 6 | template: 7 | spec: 8 | containers: 9 | - name: manager 10 | imagePullPolicy: IfNotPresent 11 | args: 12 | - --namespace=almond-dev 13 | -------------------------------------------------------------------------------- /k8s/components/controller/manager/dev/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1alpha1 2 | kind: Component 3 | 4 | bases: 5 | - ../base 6 | 7 | # patches: 8 | # - controller-manager/deployment.yaml 9 | 10 | patchesJson6902: 11 | - target: 12 | group: apps 13 | version: v1 14 | kind: Deployment 15 | name: controller-manager 16 | patch: |- 17 | - op: replace 18 | path: /spec/template/spec/containers/1/args/1 19 | value: --namespace=almond-dev 20 | -------------------------------------------------------------------------------- /k8s/components/controller/rbac/base/auth_proxy_client_clusterrole.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | name: metrics-reader 5 | rules: 6 | - nonResourceURLs: 7 | - "/metrics" 8 | verbs: 9 | - get 10 | -------------------------------------------------------------------------------- /k8s/components/controller/rbac/base/auth_proxy_role.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: Role 3 | metadata: 4 | name: proxy-role 5 | rules: 6 | - apiGroups: 7 | - authentication.k8s.io 8 | resources: 9 | - tokenreviews 10 | verbs: 11 | - create 12 | - apiGroups: 13 | - authorization.k8s.io 14 | resources: 15 | - subjectaccessreviews 16 | verbs: 17 | - create 18 | -------------------------------------------------------------------------------- /k8s/components/controller/rbac/base/auth_proxy_role_binding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: RoleBinding 3 | metadata: 4 | name: proxy-rolebinding 5 | roleRef: 6 | apiGroup: rbac.authorization.k8s.io 7 | kind: Role 8 | name: proxy-role 9 | subjects: 10 | - kind: ServiceAccount 11 | name: controller-manager 12 | -------------------------------------------------------------------------------- /k8s/components/controller/rbac/base/auth_proxy_service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | labels: 5 | control-plane: controller-manager 6 | name: controller-manager-metrics-service 7 | spec: 8 | ports: 9 | - name: https 10 | port: 8443 11 | targetPort: https 12 | selector: 13 | control-plane: controller-manager 14 | -------------------------------------------------------------------------------- /k8s/components/controller/rbac/base/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | # All RBAC will be applied under this service account in 3 | # the deployment namespace. You may comment out this resource 4 | # if your manager will use a service account that exists at 5 | # runtime. Be sure to update RoleBinding and ClusterRoleBinding 6 | # subjects if changing service account names. 7 | - service_account.yaml 8 | - role.yaml 9 | - role_binding.yaml 10 | - leader_election_role.yaml 11 | - leader_election_role_binding.yaml 12 | # Comment the following 4 lines if you want to disable 13 | # the auth proxy (https://github.com/brancz/kube-rbac-proxy) 14 | # which protects your /metrics endpoint. 15 | - auth_proxy_service.yaml 16 | - auth_proxy_role.yaml 17 | - auth_proxy_role_binding.yaml 18 | - auth_proxy_client_clusterrole.yaml 19 | - user_editor_role.yaml 20 | - user_editor_role_binding.yaml 21 | -------------------------------------------------------------------------------- /k8s/components/controller/rbac/base/leader_election_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions to do leader election. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: Role 4 | metadata: 5 | name: leader-election-role 6 | rules: 7 | - apiGroups: 8 | - "" 9 | resources: 10 | - configmaps 11 | verbs: 12 | - get 13 | - list 14 | - watch 15 | - create 16 | - update 17 | - patch 18 | - delete 19 | - apiGroups: 20 | - coordination.k8s.io 21 | resources: 22 | - leases 23 | verbs: 24 | - get 25 | - list 26 | - watch 27 | - create 28 | - update 29 | - patch 30 | - delete 31 | - apiGroups: 32 | - "" 33 | resources: 34 | - events 35 | verbs: 36 | - create 37 | - patch 38 | -------------------------------------------------------------------------------- /k8s/components/controller/rbac/base/leader_election_role_binding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: RoleBinding 3 | metadata: 4 | name: leader-election-rolebinding 5 | roleRef: 6 | apiGroup: rbac.authorization.k8s.io 7 | kind: Role 8 | name: leader-election-role 9 | subjects: 10 | - kind: ServiceAccount 11 | name: controller-manager 12 | -------------------------------------------------------------------------------- /k8s/components/controller/rbac/base/role.yaml: -------------------------------------------------------------------------------- 1 | 2 | --- 3 | apiVersion: rbac.authorization.k8s.io/v1 4 | kind: Role 5 | metadata: 6 | creationTimestamp: null 7 | name: manager-role 8 | rules: 9 | - apiGroups: 10 | - "" 11 | resources: 12 | - endpoints 13 | verbs: 14 | - get 15 | - list 16 | - watch 17 | - apiGroups: 18 | - backend.almond.stanford.edu 19 | resources: 20 | - users 21 | verbs: 22 | - create 23 | - delete 24 | - get 25 | - list 26 | - patch 27 | - update 28 | - watch 29 | - apiGroups: 30 | - backend.almond.stanford.edu 31 | resources: 32 | - users/finalizers 33 | verbs: 34 | - update 35 | - apiGroups: 36 | - backend.almond.stanford.edu 37 | resources: 38 | - users/status 39 | verbs: 40 | - get 41 | - patch 42 | - update 43 | -------------------------------------------------------------------------------- /k8s/components/controller/rbac/base/role_binding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: RoleBinding 3 | metadata: 4 | name: manager-rolebinding 5 | roleRef: 6 | apiGroup: rbac.authorization.k8s.io 7 | kind: Role 8 | name: manager-role 9 | subjects: 10 | - kind: ServiceAccount 11 | name: controller-manager 12 | -------------------------------------------------------------------------------- /k8s/components/controller/rbac/base/service_account.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: controller-manager 5 | -------------------------------------------------------------------------------- /k8s/components/controller/rbac/base/user_editor_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions for end users to edit users. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: Role 4 | metadata: 5 | name: user-editor-role 6 | rules: 7 | - apiGroups: 8 | - backend.almond.stanford.edu 9 | resources: 10 | - users 11 | verbs: 12 | - create 13 | - delete 14 | - get 15 | - list 16 | - patch 17 | - update 18 | - watch 19 | - apiGroups: 20 | - backend.almond.stanford.edu 21 | resources: 22 | - users/status 23 | verbs: 24 | - get 25 | -------------------------------------------------------------------------------- /k8s/components/controller/rbac/base/user_editor_role_binding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: RoleBinding 3 | metadata: 4 | name: user-editor-rolebinding 5 | roleRef: 6 | apiGroup: rbac.authorization.k8s.io 7 | kind: Role 8 | name: user-editor-role 9 | subjects: 10 | - kind: ServiceAccount 11 | name: default-editor 12 | -------------------------------------------------------------------------------- /k8s/components/controller/rbac/base/user_viewer_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions for end users to view users. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: Role 4 | metadata: 5 | name: user-viewer-role 6 | rules: 7 | - apiGroups: 8 | - backend.almond.stanford.edu 9 | resources: 10 | - users 11 | verbs: 12 | - get 13 | - list 14 | - watch 15 | - apiGroups: 16 | - backend.almond.stanford.edu 17 | resources: 18 | - users/status 19 | verbs: 20 | - get 21 | -------------------------------------------------------------------------------- /k8s/components/controller/rbac/dev/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1alpha1 2 | kind: Component 3 | 4 | bases: 5 | - ../base 6 | -------------------------------------------------------------------------------- /k8s/components/dashboard/dev/deployment.yaml: -------------------------------------------------------------------------------- 1 | kind: Deployment 2 | apiVersion: apps/v1 3 | metadata: 4 | name: kubernetes-dashboard 5 | namespace: kubernetes-dashboard 6 | spec: 7 | template: 8 | spec: 9 | containers: 10 | - name: kubernetes-dashboard 11 | args: 12 | - --auto-generate-certificates 13 | - --namespace=kubernetes-dashboard 14 | - --enable-skip-login 15 | -------------------------------------------------------------------------------- /k8s/components/dashboard/dev/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1alpha1 2 | kind: Component 3 | 4 | resources: 5 | - https://raw.githubusercontent.com/kubernetes/dashboard/v2.3.1/aio/deploy/recommended.yaml 6 | 7 | patches: 8 | - deployment.yaml 9 | -------------------------------------------------------------------------------- /k8s/components/db/base/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: db 5 | spec: 6 | replicas: 1 7 | selector: 8 | matchLabels: 9 | app: db 10 | template: 11 | metadata: 12 | labels: 13 | app: db 14 | spec: 15 | containers: 16 | - name: mariadb 17 | image: mariadb:10.2.22 18 | imagePullPolicy: IfNotPresent 19 | env: 20 | - name: MYSQL_ROOT_PASSWORD 21 | ports: 22 | - containerPort: 3306 23 | protocol: TCP 24 | volumeMounts: 25 | - name: storage 26 | mountPath: /var/lib/mysql 27 | volumes: 28 | - name: storage 29 | persistentVolumeClaim: 30 | claimName: db-storage 31 | --- 32 | apiVersion: v1 33 | kind: PersistentVolumeClaim 34 | metadata: 35 | name: db-storage 36 | spec: 37 | accessModes: 38 | - ReadWriteOnce 39 | resources: 40 | requests: 41 | storage: 1Gi 42 | -------------------------------------------------------------------------------- /k8s/components/db/base/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - deployment.yaml 3 | - service.yaml 4 | -------------------------------------------------------------------------------- /k8s/components/db/base/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: db 5 | spec: 6 | ports: 7 | - port: 3306 8 | targetPort: 3306 9 | selector: 10 | app: db 11 | -------------------------------------------------------------------------------- /k8s/components/db/dev/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: db 5 | spec: 6 | template: 7 | spec: 8 | containers: 9 | - name: mariadb 10 | env: 11 | - name: MYSQL_ROOT_PASSWORD 12 | value: password 13 | -------------------------------------------------------------------------------- /k8s/components/db/dev/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1alpha1 2 | kind: Component 3 | 4 | bases: 5 | - ../base 6 | 7 | patches: 8 | - deployment.yaml 9 | -------------------------------------------------------------------------------- /k8s/components/dbproxy/base/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: "dbproxy" 5 | spec: 6 | replicas: 1 7 | selector: 8 | matchLabels: 9 | app: "dbproxy" 10 | template: 11 | metadata: 12 | labels: 13 | app: "dbproxy" 14 | spec: 15 | serviceAccountName: default-editor 16 | containers: 17 | - name: "main" 18 | image: stanfordoval/almond-cloud:latest 19 | command: ["/usr/local/bin/backend"] 20 | args: ["dbproxy", "-port", "8200"] #, "-aws-tls-cert", "/etc/aws/aws-global-bundle.pem"] 21 | env: 22 | - name: GIN_MODE 23 | value: "release" 24 | volumeMounts: 25 | - mountPath: /etc/almond-cloud/config.d/config.yaml 26 | subPath: config.yaml 27 | name: config 28 | readOnly: true 29 | - mountPath: /etc/almond-cloud/config.d/secret.yaml 30 | subPath: secret.yaml 31 | name: secret 32 | readOnly: true 33 | ports: 34 | - containerPort: 8200 35 | name: web 36 | resources: 37 | requests: 38 | memory: 100M 39 | limits: 40 | memory: 2500M 41 | volumes: 42 | - name: config 43 | configMap: 44 | name: almond-config 45 | - name: secret 46 | secret: 47 | secretName: almond-secret 48 | -------------------------------------------------------------------------------- /k8s/components/dbproxy/base/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - deployment.yaml 3 | - service.yaml 4 | -------------------------------------------------------------------------------- /k8s/components/dbproxy/base/service.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: dbproxy 6 | annotations: 7 | almond.metrics.scrape: "true" 8 | spec: 9 | ports: 10 | - port: 8200 11 | protocol: TCP 12 | selector: 13 | app: dbproxy 14 | -------------------------------------------------------------------------------- /k8s/components/dbproxy/dev/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: "dbproxy" 5 | spec: 6 | template: 7 | spec: 8 | containers: 9 | - name: "main" 10 | imagePullPolicy: IfNotPresent -------------------------------------------------------------------------------- /k8s/components/dbproxy/dev/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1alpha1 2 | kind: Component 3 | 4 | bases: 5 | - ../base 6 | 7 | patches: 8 | - deployment.yaml 9 | -------------------------------------------------------------------------------- /k8s/components/frontend/base/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - deployment.yaml 3 | - service.yaml 4 | -------------------------------------------------------------------------------- /k8s/components/frontend/base/service.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: frontend 6 | annotations: 7 | almond.metrics.scrape: "true" 8 | spec: 9 | ports: 10 | - port: 8080 11 | protocol: TCP 12 | selector: 13 | app: frontend 14 | -------------------------------------------------------------------------------- /k8s/components/frontend/debug/deployment.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | name: frontend 6 | spec: 7 | template: 8 | spec: 9 | containers: 10 | - name: main 11 | imagePullPolicy: IfNotPresent 12 | command: 13 | - /bin/bash 14 | args: 15 | - -c 16 | - | 17 | set -ex 18 | cd /opt/almond-cloud 19 | /usr/bin/npm run debug -- run-frontend --k8s 20 | env: 21 | - name: THINGENGINE_ROOTDIR 22 | value: /home/almond-cloud 23 | volumeMounts: 24 | - mountPath: /opt/almond-cloud/src 25 | name: src 26 | - mountPath: /opt/almond-cloud/views 27 | name: views 28 | volumes: 29 | - name: src 30 | hostPath: 31 | type: Directory 32 | path: //src 33 | - name: views 34 | hostPath: 35 | type: Directory 36 | path: //views 37 | -------------------------------------------------------------------------------- /k8s/components/frontend/debug/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1alpha1 2 | kind: Component 3 | 4 | components: 5 | - ../dev 6 | 7 | patches: 8 | - deployment.yaml 9 | -------------------------------------------------------------------------------- /k8s/components/frontend/dev/deployment.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | name: frontend 6 | spec: 7 | template: 8 | spec: 9 | containers: 10 | - name: main 11 | imagePullPolicy: IfNotPresent 12 | env: 13 | - name: NODE_ENV 14 | value: development 15 | volumeMounts: 16 | - mountPath: /home/almond-cloud/shared 17 | name: shared 18 | volumes: 19 | - name: shared 20 | hostPath: 21 | type: Directory 22 | path: //tmp/shared 23 | -------------------------------------------------------------------------------- /k8s/components/frontend/dev/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1alpha1 2 | kind: Component 3 | 4 | bases: 5 | - ../base 6 | 7 | resources: 8 | - ingress.yaml 9 | 10 | patches: 11 | - deployment.yaml 12 | -------------------------------------------------------------------------------- /k8s/components/ingress-nginx/dev/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1alpha1 2 | kind: Component 3 | 4 | resources: 5 | - https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.0.0/deploy/static/provider/cloud/deploy.yaml 6 | 7 | patches: 8 | - service.yaml 9 | -------------------------------------------------------------------------------- /k8s/components/ingress-nginx/dev/service.yaml: -------------------------------------------------------------------------------- 1 | # Source: ingress-nginx/templates/controller-service.yaml 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: ingress-nginx-controller 6 | namespace: ingress-nginx 7 | spec: 8 | ports: 9 | - $patch: replace 10 | - name: http 11 | port: 8080 12 | protocol: TCP 13 | targetPort: http 14 | appProtocol: http 15 | - name: https 16 | port: 8443 17 | protocol: TCP 18 | targetPort: https 19 | appProtocol: https 20 | -------------------------------------------------------------------------------- /k8s/components/nlp/base/cluster-role-binding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | name: nlp-role-bind 5 | roleRef: 6 | kind: ClusterRole 7 | name: nlp-role 8 | apiGroup: rbac.authorization.k8s.io 9 | subjects: 10 | - kind: ServiceAccount 11 | name: training-nlp 12 | -------------------------------------------------------------------------------- /k8s/components/nlp/base/cluster-role.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | name: nlp-role 5 | rules: 6 | - apiGroups: 7 | - '' 8 | resources: 9 | - endpoints 10 | verbs: 11 | - get 12 | - list 13 | - watch 14 | -------------------------------------------------------------------------------- /k8s/components/nlp/base/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: nlp 5 | spec: 6 | replicas: 1 7 | selector: 8 | matchLabels: 9 | app: nlp 10 | template: 11 | metadata: 12 | labels: 13 | app: nlp 14 | spec: 15 | serviceAccountName: training-nlp 16 | containers: 17 | - name: nlp 18 | image: stanfordoval/almond-cloud:latest 19 | imagePullPolicy: IfNotPresent 20 | env: 21 | - name: NODE_ENV 22 | value: "production" 23 | args: ["run-nlp"] 24 | volumeMounts: 25 | - mountPath: /etc/almond-cloud/config.d/config.yaml 26 | subPath: config.yaml 27 | name: config 28 | readOnly: true 29 | - mountPath: /etc/almond-cloud/config.d/secret.yaml 30 | subPath: secret.yaml 31 | name: secret 32 | readOnly: true 33 | resources: 34 | requests: 35 | memory: 1G 36 | limits: 37 | memory: 2G 38 | readinessProbe: 39 | tcpSocket: 40 | port: 8400 41 | periodSeconds: 20 42 | securityContext: 43 | fsGroup: 65534 44 | volumes: 45 | - name: config 46 | configMap: 47 | name: almond-config 48 | - name: secret 49 | secret: 50 | secretName: almond-secret -------------------------------------------------------------------------------- /k8s/components/nlp/base/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - service-account.yaml 3 | - cluster-role.yaml 4 | - cluster-role-binding.yaml 5 | - deployment.yaml 6 | - service.yaml 7 | 8 | -------------------------------------------------------------------------------- /k8s/components/nlp/base/service-account.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: training-nlp 5 | -------------------------------------------------------------------------------- /k8s/components/nlp/base/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: nlp 5 | annotations: 6 | almond.metrics.scrape: "true" 7 | spec: 8 | selector: 9 | app: nlp 10 | ports: 11 | - protocol: TCP 12 | port: 8400 13 | -------------------------------------------------------------------------------- /k8s/components/nlp/debug/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: nlp 5 | spec: 6 | template: 7 | spec: 8 | containers: 9 | - name: nlp 10 | command: 11 | - /bin/bash 12 | args: 13 | - -c 14 | - | 15 | set -ex 16 | cd /opt/almond-cloud 17 | /usr/bin/npm run debug -- run-nlp 18 | env: 19 | - name: THINGENGINE_ROOTDIR 20 | value: /home/almond-cloud 21 | volumeMounts: 22 | - mountPath: /opt/almond-cloud/src 23 | name: src 24 | - mountPath: /opt/almond-cloud/views 25 | name: views 26 | - mountPath: /home/almond-cloud/shared 27 | name: shared 28 | volumes: 29 | - name: src 30 | hostPath: 31 | type: Directory 32 | path: //src 33 | - name: views 34 | hostPath: 35 | type: Directory 36 | path: //views 37 | - name: shared 38 | hostPath: 39 | type: Directory 40 | path: //tmp/shared 41 | -------------------------------------------------------------------------------- /k8s/components/nlp/debug/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1alpha1 2 | kind: Component 3 | 4 | components: 5 | - ../dev 6 | 7 | patches: 8 | - deployment.yaml 9 | -------------------------------------------------------------------------------- /k8s/components/nlp/dev/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: nlp 5 | spec: 6 | template: 7 | spec: 8 | containers: 9 | - name: nlp 10 | imagePullPolicy: IfNotPresent 11 | env: 12 | - name: NODE_ENV 13 | value: development 14 | -------------------------------------------------------------------------------- /k8s/components/nlp/dev/ingress.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.k8s.io/v1 2 | kind: Ingress 3 | metadata: 4 | name: nlp 5 | annotations: 6 | kubernetes.io/ingress.class: nginx 7 | nginx.ingress.kubernetes.io/proxy-send-timeout: "3600" 8 | nginx.ingress.kubernetes.io/proxy-read-timeout: "3600" 9 | # set a very large value so we can upload string datasets 10 | nginx.ingress.kubernetes.io/proxy-body-size: "64m" 11 | labels: 12 | app: nlp 13 | spec: 14 | rules: 15 | - host: nlp.almond-cloud.test 16 | http: 17 | paths: 18 | - backend: 19 | service: 20 | name: nlp 21 | port: 22 | number: 8400 23 | path: / 24 | pathType: ImplementationSpecific 25 | -------------------------------------------------------------------------------- /k8s/components/nlp/dev/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1alpha1 2 | kind: Component 3 | 4 | bases: 5 | - ../base 6 | 7 | resources: 8 | - ingress.yaml 9 | 10 | patches: 11 | - deployment.yaml 12 | - deployment.local.yaml 13 | -------------------------------------------------------------------------------- /k8s/components/redis/base/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: redis 5 | spec: 6 | replicas: 1 7 | selector: 8 | matchLabels: 9 | app: redis 10 | template: 11 | metadata: 12 | labels: 13 | app: redis 14 | spec: 15 | containers: 16 | - name: redis 17 | image: redis:6.2.5-buster 18 | imagePullPolicy: IfNotPresent 19 | ports: 20 | - containerPort: 6379 21 | name: redis 22 | env: 23 | - name: MASTER 24 | value: "true" 25 | -------------------------------------------------------------------------------- /k8s/components/redis/base/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - deployment.yaml 3 | - service.yaml 4 | -------------------------------------------------------------------------------- /k8s/components/redis/base/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: redis 5 | spec: 6 | ports: 7 | - port: 6379 8 | targetPort: 6379 9 | selector: 10 | app: redis 11 | -------------------------------------------------------------------------------- /k8s/components/redis/dev/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1alpha1 2 | kind: Component 3 | 4 | bases: 5 | - ../base 6 | -------------------------------------------------------------------------------- /k8s/components/shared-backend/base/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - service.yaml 3 | - stateful-set.yaml 4 | -------------------------------------------------------------------------------- /k8s/components/shared-backend/base/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: shared-backend 5 | labels: 6 | app: shared-backend 7 | spec: 8 | ports: 9 | - port: 8100 10 | protocol: TCP 11 | selector: 12 | app: shared-backend 13 | -------------------------------------------------------------------------------- /k8s/components/shared-backend/base/stateful-set.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: StatefulSet 3 | metadata: 4 | name: shared-backend 5 | spec: 6 | selector: 7 | matchLabels: 8 | app: shared-backend 9 | replicas: 1 10 | serviceName: shared-backend 11 | template: 12 | metadata: 13 | labels: 14 | app: shared-backend 15 | spec: 16 | serviceAccountName: default-editor 17 | containers: 18 | - name: main 19 | image: stanfordoval/almond-cloud:latest 20 | env: 21 | - name: THINGPEDIA_URL 22 | - name: NL_SERVER_URL 23 | - name: OAUTH_REDIRECT_URL 24 | - name: THINGENGINE_ROOTDIR 25 | value: /home/almond-cloud 26 | args: 27 | - run-worker 28 | - --thingpedia-url=$(THINGPEDIA_URL) 29 | - --nl-server-url=$(NL_SERVER_URL) 30 | - --oauth-redirect-origin=$(OAUTH_REDIRECT_URL) 31 | - --faq-models={} 32 | - --notification-config={} 33 | - --locale=en-US 34 | workingDir: /srv/thingengine 35 | volumeMounts: 36 | - mountPath: /srv/thingengine 37 | name: local-storage 38 | resources: 39 | requests: 40 | memory: 200M 41 | ports: 42 | - containerPort: 8100 43 | name: almond 44 | securityContext: 45 | fsGroup: 65534 46 | volumes: 47 | - name: local-storage 48 | emptyDir: {} -------------------------------------------------------------------------------- /k8s/components/shared-backend/debug/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1alpha1 2 | kind: Component 3 | 4 | components: 5 | - ../dev 6 | 7 | patches: 8 | - stateful-set.yaml 9 | -------------------------------------------------------------------------------- /k8s/components/shared-backend/debug/stateful-set.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: StatefulSet 3 | metadata: 4 | name: shared-backend 5 | spec: 6 | template: 7 | spec: 8 | containers: 9 | - name: main 10 | command: 11 | - /bin/bash 12 | args: 13 | - -c 14 | - | 15 | set -ex 16 | cd /opt/almond-cloud 17 | /usr/bin/npm run debug -- \ 18 | run-worker \ 19 | --thingpedia-url=${THINGPEDIA_URL} \ 20 | --nl-server-url=${NL_SERVER_URL} \ 21 | --oauth-redirect-origin=${OAUTH_REDIRECT_URL} \ 22 | --faq-models={} \ 23 | --notification-config={} \ 24 | --locale=en-US 25 | volumeMounts: 26 | - mountPath: /opt/almond-cloud/src 27 | name: src 28 | volumes: 29 | - name: src 30 | hostPath: 31 | type: Directory 32 | path: //src 33 | -------------------------------------------------------------------------------- /k8s/components/shared-backend/dev/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1alpha1 2 | kind: Component 3 | 4 | bases: 5 | - ../base 6 | 7 | patches: 8 | - stateful-set.yaml 9 | -------------------------------------------------------------------------------- /k8s/components/shared-backend/dev/stateful-set.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: StatefulSet 3 | metadata: 4 | name: shared-backend 5 | spec: 6 | template: 7 | spec: 8 | containers: 9 | - name: main 10 | imagePullPolicy: IfNotPresent 11 | env: 12 | - name: NODE_ENV 13 | value: development 14 | - name: THINGPEDIA_URL 15 | value: http://frontend:8080/thingpedia 16 | - name: NL_SERVER_URL 17 | value: https://nlp-staging.almond.stanford.edu 18 | - name: OAUTH_REDIRECT_URL 19 | value: http://localhost:8080 20 | 21 | -------------------------------------------------------------------------------- /k8s/kustomizations/debug/bootstrap/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | 4 | namespace: almond-dev 5 | components: 6 | - ../../../components/config/dev 7 | - ../../../components/db/dev 8 | - ../../../components/redis/dev 9 | - ../../../components/bootstrap/debug 10 | - ../../../components/frontend/debug 11 | - ../../../components/dbproxy/dev 12 | - ../../../components/shared-backend/debug 13 | - ../../../components/controller/crd/dev 14 | - ../../../components/controller/rbac/dev 15 | - ../../../components/controller/manager/dev 16 | 17 | images: 18 | - name: stanfordoval/almond-cloud 19 | newName: localhost/almond-cloud 20 | 21 | transformers: 22 | - ../../../plugins/resolve-host-paths/transformer.yaml 23 | -------------------------------------------------------------------------------- /k8s/kustomizations/debug/core/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | 4 | namespace: almond-dev 5 | components: 6 | - ../../../components/config/dev 7 | - ../../../components/db/dev 8 | - ../../../components/redis/dev 9 | - ../../../components/frontend/debug 10 | - ../../../components/dbproxy/dev 11 | - ../../../components/shared-backend/debug 12 | - ../../../components/controller/crd/dev 13 | - ../../../components/controller/rbac/dev 14 | - ../../../components/controller/manager/dev 15 | 16 | images: 17 | - name: stanfordoval/almond-cloud 18 | newName: localhost/almond-cloud 19 | 20 | transformers: 21 | - ../../../plugins/resolve-host-paths/transformer.yaml 22 | -------------------------------------------------------------------------------- /k8s/kustomizations/debug/nlp/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | 4 | namespace: almond-dev 5 | components: 6 | - ../../../components/config/dev 7 | - ../../../components/nlp/debug 8 | 9 | images: 10 | - name: stanfordoval/almond-cloud 11 | newName: localhost/almond-cloud 12 | 13 | transformers: 14 | - ../../../plugins/resolve-host-paths/transformer.yaml 15 | -------------------------------------------------------------------------------- /k8s/kustomizations/dev/bootstrap/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | 4 | namespace: almond-dev 5 | components: 6 | - ../../../components/config/dev 7 | - ../../../components/db/dev 8 | - ../../../components/redis/dev 9 | - ../../../components/bootstrap/dev 10 | - ../../../components/frontend/dev 11 | - ../../../components/dbproxy/dev 12 | - ../../../components/shared-backend/dev 13 | - ../../../components/controller/crd/dev 14 | - ../../../components/controller/rbac/dev 15 | - ../../../components/controller/manager/dev 16 | 17 | images: 18 | - name: stanfordoval/almond-cloud 19 | newName: localhost/almond-cloud 20 | 21 | transformers: 22 | - ../../../plugins/resolve-host-paths/transformer.yaml 23 | -------------------------------------------------------------------------------- /k8s/kustomizations/dev/core/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | 4 | namespace: almond-dev 5 | components: 6 | - ../../../components/config/dev 7 | - ../../../components/db/dev 8 | - ../../../components/redis/dev 9 | - ../../../components/frontend/dev 10 | - ../../../components/dbproxy/dev 11 | - ../../../components/shared-backend/dev 12 | - ../../../components/controller/crd/dev 13 | - ../../../components/controller/rbac/dev 14 | - ../../../components/controller/manager/dev 15 | 16 | images: 17 | - name: stanfordoval/almond-cloud 18 | newName: localhost/almond-cloud 19 | 20 | transformers: 21 | - ../../../plugins/resolve-host-paths/transformer.yaml 22 | -------------------------------------------------------------------------------- /k8s/kustomizations/dev/nlp/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | 4 | namespace: almond-dev 5 | components: 6 | - ../../../components/config/dev 7 | - ../../../components/nlp/dev 8 | 9 | images: 10 | - name: stanfordoval/almond-cloud 11 | newName: localhost/almond-cloud 12 | 13 | transformers: 14 | - ../../../plugins/resolve-host-paths/transformer.yaml 15 | -------------------------------------------------------------------------------- /k8s/plugins/resolve-host-paths/transformer.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: almond-cloud 2 | kind: ResolveHostPaths 3 | metadata: 4 | name: resolve-host-paths 5 | annotations: 6 | config.kubernetes.io/function: | 7 | exec: 8 | path: resolve-host-paths.py 9 | spec: {} 10 | -------------------------------------------------------------------------------- /k8s/plugins/testy.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import yaml 4 | import sys 5 | import os.path 6 | 7 | from clavier import sh 8 | 9 | 10 | def main(): 11 | input = yaml.safe_load(sys.stdin) 12 | 13 | print(f"INPUT\n", file=sys.stderr) 14 | yaml.safe_dump(input, sys.stderr) 15 | 16 | repo_root = sh.get("git", "rev-parse", "--show-toplevel", format="strip") 17 | 18 | volumes = [ 19 | {"name": name, "hostPath": {"path": os.path.join(repo_root, path)}} 20 | for name, path in [ 21 | ["src", "src"], 22 | ["views", "views"], 23 | ["shared", "tmp/shared"], 24 | ] 25 | ] 26 | 27 | item = { 28 | "apiVersion": "apps/v1", 29 | "kind": "Deployment", 30 | "metadata": { 31 | "name": "nlp", 32 | "annotations": {"kustomize.config.k8s.io/behavior": "merge"}, 33 | }, 34 | "spec": {"template": {"spec": {"volumes": volumes}}}, 35 | } 36 | 37 | result = { 38 | "apiVersion": "config.kubernetes.io/v1", 39 | "kind": "ResourceList", 40 | "items": [item], 41 | } 42 | 43 | yaml.safe_dump(result, sys.stdout) 44 | 45 | 46 | if __name__ == "__main__": 47 | main() 48 | -------------------------------------------------------------------------------- /model/migrations/022a5a5-models_version.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE `models` 2 | ADD `version` int(11) NOT NULL DEFAULT 0; 3 | -------------------------------------------------------------------------------- /model/migrations/02f414e-device_class_tag.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE IF EXISTS `device_class_tag`; 2 | /*!40101 SET @saved_cs_client = @@character_set_client */; 3 | /*!40101 SET character_set_client = utf8 */; 4 | CREATE TABLE `device_class_tag` ( 5 | `device_id` int(11) NOT NULL, 6 | `tag` varchar(255) COLLATE utf8_bin NOT NULL, 7 | PRIMARY KEY (`device_id`,`tag`), 8 | KEY `tag` (`tag`), 9 | CONSTRAINT `device_class_tag_ibfk_1` FOREIGN KEY (`device_id`) REFERENCES `device_class` (`id`) 10 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; 11 | /*!40101 SET character_set_client = @saved_cs_client */; 12 | -------------------------------------------------------------------------------- /model/migrations/084e6e3-models_new_fields.sql: -------------------------------------------------------------------------------- 1 | SET FOREIGN_KEY_CHECKS=0; 2 | ALTER TABLE `models` 3 | ADD `language` char(15) COLLATE utf8_bin NOT NULL DEFAULT 'en' FIRST, 4 | DROP PRIMARY KEY, 5 | ADD PRIMARY KEY(`language`, `tag`), 6 | ADD `owner` int(11) NOT NULL AFTER `tag`, 7 | ADD `access_token` char(64) COLLATE utf8_bin NULL AFTER `owner`, 8 | ADD KEY `owner` (`owner`), 9 | ADD CONSTRAINT `models_ibfk_1` FOREIGN KEY (`owner`) REFERENCES `organizations` (`id`) ON UPDATE CASCADE 10 | ; 11 | UPDATE `models` SET `owner` = 1; 12 | -------------------------------------------------------------------------------- /model/migrations/25a672b-email_verified.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE `users` ADD `email_verified` tinyint(1) NOT NULL DEFAULT 0 AFTER `email`; 2 | UPDATE `users` SET `email_verified` = 1 WHERE `developer_org` IS NOT NULL OR (`username` = `email` AND `google_id` IS NOT NULL); 3 | -------------------------------------------------------------------------------- /model/migrations/2704af0-oauth.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE IF EXISTS `oauth2_permissions`; 2 | /*!40101 SET @saved_cs_client = @@character_set_client */; 3 | /*!40101 SET character_set_client = utf8 */; 4 | CREATE TABLE `oauth2_permissions` ( 5 | `user_id` char(64) COLLATE utf8_bin NOT NULL, 6 | `client_id` char(64) COLLATE utf8_bin NOT NULL, 7 | `scope` text COLLATE utf8_bin NOT NULL, 8 | PRIMARY KEY (`user_id`,`client_id`), 9 | KEY `client_id` (`client_id`), 10 | CONSTRAINT `oauth2_permissions_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`cloud_id`) ON DELETE CASCADE ON UPDATE CASCADE, 11 | CONSTRAINT `oauth2_permissions_ibfk_2` FOREIGN KEY (`client_id`) REFERENCES `oauth2_clients` (`id`) ON DELETE CASCADE ON UPDATE CASCADE 12 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; 13 | /*!40101 SET character_set_client = @saved_cs_client */; 14 | 15 | DROP TABLE IF EXISTS `oauth2_auth_codes`; 16 | DROP TABLE IF EXISTS `oauth2_access_tokens`; 17 | 18 | ALTER TABLE oauth2_clients ADD `allowed_scopes` text COLLATE utf8_bin, 19 | ADD `allowed_redirect_uris` text COLLATE utf8_bin; 20 | UPDATE oauth2_clients SET `allowed_scopes` = '["profile"]', `allowed_redirect_uris` = '[]'; 21 | 22 | ALTER TABLE oauth2_clients MODIFY `allowed_scopes` text COLLATE utf8_bin NOT NULL, 23 | MODIFY `allowed_redirect_uris` text COLLATE utf8_bin NOT NULL; -------------------------------------------------------------------------------- /model/migrations/29ea218-example_name.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE `example_utterances` 2 | ADD `name` varchar(128) COLLATE utf8_bin DEFAULT NULL, 3 | ADD UNIQUE KEY `intent_name` (`language`, `schema_id`, `name`); 4 | -------------------------------------------------------------------------------- /model/migrations/342392c-example_context.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE `example_utterances` 2 | ADD `context` text COLLATE utf8mb4_bin NULL AFTER `target_code`; 3 | -------------------------------------------------------------------------------- /model/migrations/342dbfb-no_template_files.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE `models` 2 | DROP CONSTRAINT `models_ibfk_2`; 3 | ALTER TABLE `models` 4 | DROP COLUMN `template_file`; 5 | 6 | DROP VIEW IF EXISTS `org_statistics`; 7 | /*!40101 SET @saved_cs_client = @@character_set_client */; 8 | /*!40101 SET character_set_client = utf8 */; 9 | CREATE SQL SECURITY INVOKER VIEW `org_statistics` 10 | AS SELECT 11 | org.id, 12 | (select count(*) from device_class where owner = org.id) as device_count, 13 | (select count(*) from device_class where license_gplcompatible and owner = org.id) as oss_device_count, 14 | (select count(*) from device_class where approved_version is not null and owner = org.id) as approved_device_count, 15 | (select count(*) from device_class where license_gplcompatible and approved_version is not null and owner = org.id) as oss_approved_device_count 16 | from organizations org; 17 | /*!40101 SET character_set_client = @saved_cs_client */; 18 | 19 | DROP TABLE `template_files`; 20 | -------------------------------------------------------------------------------- /model/migrations/3b78ae3-org_credits.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE `organizations` 2 | ADD `credits` int(11) NOT NULL DEFAULT 100; 3 | -------------------------------------------------------------------------------- /model/migrations/409ee66-models_trained_flag.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE `models` 2 | ADD `trained` boolean NOT NULL DEFAULT false; 3 | -------------------------------------------------------------------------------- /model/migrations/4b93ac8-models_use_exact.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE `models` 2 | ADD `use_exact` boolean NOT NULL DEFAULT false; 3 | 4 | UPDATE `models` SET `use_exact` = 1 WHERE tag in ( 5 | 'org.thingpedia.models.default', 'org.thingpedia.models.developer', 6 | 'org.thingpedia.models.contextual', 'org.thingpedia.models.developer.contextual'); 7 | -------------------------------------------------------------------------------- /model/migrations/4b96642-blog.sql: -------------------------------------------------------------------------------- 1 | -- 2 | -- Table structure for table `blog_posts` 3 | -- 4 | 5 | DROP TABLE IF EXISTS `blog_posts`; 6 | /*!40101 SET @saved_cs_client = @@character_set_client */; 7 | /*!40101 SET character_set_client = utf8 */; 8 | CREATE TABLE `blog_posts` ( 9 | `id` int(11) NOT NULL AUTO_INCREMENT, 10 | `author` int(11) NOT NULL, 11 | `slug` varchar(255) COLLATE utf8_bin NOT NULL, 12 | `title` varchar(255) CHARACTER SET utf8 NOT NULL, 13 | `blurb` text CHARACTER SET utf8mb4 NOT NULL, 14 | `source` mediumtext CHARACTER SET utf8mb4 NOT NULL, 15 | `body` mediumtext CHARACTER SET utf8mb4 NOT NULL, 16 | `pub_date` datetime NULL, 17 | `upd_date` datetime NOT NULL DEFAULT current_timestamp(), 18 | PRIMARY KEY (`id`), 19 | KEY `author` (`author`), 20 | KEY `upd_date` (`upd_date`), 21 | CONSTRAINT `blog_posts_ibfk_1` FOREIGN KEY (`author`) REFERENCES `users` (`id`) ON UPDATE CASCADE ON DELETE RESTRICT 22 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; 23 | /*!40101 SET character_set_client = @saved_cs_client */; 24 | /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; -------------------------------------------------------------------------------- /model/migrations/4e67dec-user_conversation_state.sql: -------------------------------------------------------------------------------- 1 | -- 2 | -- Table structure for table `user_conversation_state` 3 | -- 4 | DROP TABLE IF EXISTS `user_conversation_state`; 5 | /*!40101 SET @saved_cs_client = @@character_set_client */; 6 | /*!40101 SET character_set_client = utf8 */; 7 | CREATE TABLE `user_conversation_state` ( 8 | `userId` int(11) not NULL, 9 | `uniqueId` varchar(255) COLLATE utf8mb4_bin not NULL, 10 | `history` text COLLATE utf8mb4_bin NULL, 11 | `dialogueState` text COLLATE utf8mb4_bin NULL, 12 | `lastMessageId` int(11) NULL, 13 | PRIMARY KEY (`userId`, `uniqueId`) 14 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; 15 | /*!40101 SET character_set_client = @saved_cs_client */; -------------------------------------------------------------------------------- /model/migrations/64a125f-dummy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo "dummy migration, does nothing" 3 | -------------------------------------------------------------------------------- /model/migrations/64a125f-dummy.sql: -------------------------------------------------------------------------------- 1 | -- dummy migration, does nothing 2 | select 1 from dual; 3 | -------------------------------------------------------------------------------- /model/migrations/6797316-homepage_links.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE blog_posts ADD 2 | `in_homepage` boolean NOT NULL DEFAULT true; 3 | 4 | DROP TABLE IF EXISTS `homepage_links`; 5 | /*!40101 SET @saved_cs_client = @@character_set_client */; 6 | /*!40101 SET character_set_client = utf8 */; 7 | CREATE TABLE `homepage_links` ( 8 | `id` int(11) NOT NULL AUTO_INCREMENT, 9 | `title` varchar(255) CHARACTER SET utf8 NOT NULL, 10 | `image` varchar(255) CHARACTER SET utf8 NOT NULL, 11 | `blurb` text CHARACTER SET utf8mb4 NOT NULL, 12 | `link` text CHARACTER SET utf8 NOT NULL, 13 | `upd_date` datetime NOT NULL DEFAULT current_timestamp(), 14 | PRIMARY KEY (`id`), 15 | KEY `upd_date` (`upd_date`) 16 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; 17 | /*!40101 SET character_set_client = @saved_cs_client */; 18 | -------------------------------------------------------------------------------- /model/migrations/7254ac6-user_conversation.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE IF EXISTS `user_conversation`; 2 | /*!40101 SET @saved_cs_client = @@character_set_client */; 3 | /*!40101 SET character_set_client = utf8 */; 4 | CREATE TABLE `user_conversation` ( 5 | `userId` int(11) not NULL, 6 | `uniqueId` varchar(255) COLLATE utf8mb4_bin NOT NULL, 7 | `conversationId` varchar(255) COLLATE utf8mb4_bin NOT NULL, 8 | `previousId` varchar(255) COLLATE utf8mb4_bin NULL, 9 | `dialogueId` varchar(255) COLLATE utf8mb4_bin NOT NULL, 10 | `context` text COLLATE utf8mb4_bin NULL, 11 | `agent` varchar(255) COLLATE utf8mb4_bin NULL, 12 | -- iso 8601 string (for sqlite compatibility) 13 | `agentTimestamp` char(24) COLLATE utf8mb4_bin NULL, 14 | `agentTarget` text COLLATE utf8mb4_bin NULL, 15 | `intermediateContext` text COLLATE utf8mb4_bin NULL, 16 | `user` varchar(255) COLLATE utf8mb4_bin NOT NULL, 17 | -- iso 8601 string (for sqlite compatibility) 18 | `userTimestamp` char(24) COLLATE utf8mb4_bin NULL, 19 | `userTarget` text COLLATE utf8mb4_bin NOT NULL, 20 | `vote` ENUM('up', 'down') COLLATE utf8mb4_bin NULL, 21 | `comment` text COLLATE utf8mb4_bin NULL, 22 | PRIMARY KEY (`userId`, `uniqueId`) 23 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; 24 | /*!40101 SET character_set_client = @saved_cs_client */; 25 | -------------------------------------------------------------------------------- /model/migrations/72ccf68-utterance_log_time.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE utterance_log 2 | ADD COLUMN IF NOT EXISTS time datetime DEFAULT current_timestamp(); 3 | -------------------------------------------------------------------------------- /model/migrations/78f159b-new_roles_nlp_discourse_admin.sql: -------------------------------------------------------------------------------- 1 | UPDATE `users` SET `roles` = `roles` | (16+32) WHERE `roles` & 0x1; 2 | -------------------------------------------------------------------------------- /model/migrations/7a10973-blog-images.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE `blog_posts` ADD `image` varchar(255) CHARACTER SET utf8 NULL AFTER `title`; -------------------------------------------------------------------------------- /model/migrations/7c832a4-entity_subtyping.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE `entity_names` 2 | ADD `subtype_of` varchar(64) COLLATE utf8_bin DEFAULT NULL; 3 | 4 | ALTER TABLE `entity_names_snapshot` 5 | ADD `subtype_of` varchar(64) COLLATE utf8_bin DEFAULT NULL; 6 | -------------------------------------------------------------------------------- /model/migrations/871a27f-model_config.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE `models` 2 | ADD `config` MEDIUMTEXT COLLATE utf8_bin NOT NULL DEFAULT '{}' AFTER `use_exact`, 3 | ADD `trained_config` MEDIUMTEXT COLLATE utf8_bin DEFAULT NULL AFTER `metrics`; 4 | 5 | ALTER TABLE `training_jobs` 6 | ADD `owner` int(11) NULL DEFAULT NULL, 7 | ADD FOREIGN KEY (`owner`) REFERENCES `organizations` (`id`) ON UPDATE CASCADE ON DELETE RESTRICT; 8 | -------------------------------------------------------------------------------- /model/migrations/8b4218a-users_undo_developer_model.sql: -------------------------------------------------------------------------------- 1 | UPDATE `users` SET `model_tag` = NULL WHERE `model_tag` IN 2 | ('default', 'org.thingpedia.models.default', 'org.thingpedia.models.contextual', 3 | 'org.thingpedia.models.developer', 'org.thingpedia.models.developer.contextual'); 4 | -------------------------------------------------------------------------------- /model/migrations/8ef5fbb-schema_extends.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE device_schema_channels 2 | ADD `extends` text COLLATE utf8_bin NULL AFTER `channel_type`; 3 | -------------------------------------------------------------------------------- /model/migrations/9256a08-blog_editor.sql: -------------------------------------------------------------------------------- 1 | UPDATE `users` SET `roles` = 3 where `roles` = 1; 2 | -------------------------------------------------------------------------------- /model/migrations/96df512-github_login.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE `users` ADD `github_id` varchar(255) COLLATE utf8_bin DEFAULT NULL AFTER `google_id`; 2 | 3 | -------------------------------------------------------------------------------- /model/migrations/9afc8bd-model_metrics.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE `models` 2 | ADD `metrics` MEDIUMTEXT COLLATE utf8_bin DEFAULT NULL; 3 | -------------------------------------------------------------------------------- /model/migrations/a3f600e-users_developer_model.sql: -------------------------------------------------------------------------------- 1 | UPDATE `users` set `model_tag` = 'org.thingpedia.models.developer' where model_tag is null and developer_org is not null; 2 | -------------------------------------------------------------------------------- /model/migrations/a8dd900-model_contextual_flag.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE `models` 2 | ADD `contextual` boolean NOT NULL DEFAULT false AFTER `flags`; 3 | -------------------------------------------------------------------------------- /model/migrations/aa91e09-conversation_state_history.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE `user_conversation_state` 2 | DROP COLUMN `history`, 3 | ADD COLUMN `recording` boolean NOT NULL default false; 4 | 5 | DROP TABLE IF EXISTS `user_conversation_history`; 6 | /*!40101 SET @saved_cs_client = @@character_set_client */; 7 | /*!40101 SET character_set_client = utf8 */; 8 | CREATE TABLE `user_conversation_history` ( 9 | `userId` int(11) not NULL, 10 | `uniqueId` varchar(255) COLLATE utf8mb4_bin NOT NULL, 11 | `conversationId` varchar(255) COLLATE utf8mb4_bin NOT NULL, 12 | `messageId` int(11) NOT NULL, 13 | `message` text COLLATE utf8mb4_bin NOT NULL, 14 | PRIMARY KEY (`userId`, `uniqueId`), 15 | UNIQUE KEY (`userId`, `conversationId`, `messageId`) 16 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; 17 | /*!40101 SET character_set_client = @saved_cs_client */; 18 | -------------------------------------------------------------------------------- /model/migrations/b6fafa8-org_invitations.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE IF EXISTS `org_invitations`; 2 | /*!40101 SET @saved_cs_client = @@character_set_client */; 3 | /*!40101 SET character_set_client = utf8 */; 4 | CREATE TABLE `org_invitations` ( 5 | `user_id` int(11) NOT NULL, 6 | `org_id` int(11) NOT NULL, 7 | `developer_status` tinyint(4) NOT NULL DEFAULT 0, 8 | PRIMARY KEY (`user_id`, `org_id`), 9 | KEY `org_id` (`org_id`) 10 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; 11 | /*!40101 SET character_set_client = @saved_cs_client */; 12 | -------------------------------------------------------------------------------- /model/migrations/b77ba97-function_annotation_confirm.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE `device_schema_channels` 2 | ADD `confirm` tinyint(1) NOT NULL DEFAULT 1; 3 | UPDATE `device_schema_channels` SET confirm = 0 WHERE `channel_type` = 'action'; 4 | -------------------------------------------------------------------------------- /model/migrations/bb1d2a9-admin_dev_status.sql: -------------------------------------------------------------------------------- 1 | UPDATE `users` SET `developer_status` = 2, `roles` = `roles` | 4 WHERE `developer_status` = 3; 2 | -------------------------------------------------------------------------------- /model/migrations/c6f6de7-totp.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE `users` ADD `totp_key` varchar(128) COLLATE utf8_bin DEFAULT NULL AFTER `salt`; 2 | -------------------------------------------------------------------------------- /model/migrations/c84c8c2-user_preference.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE IF EXISTS `user_preference`; 2 | /*!40101 SET @saved_cs_client = @@character_set_client */; 3 | /*!40101 SET character_set_client = utf8 */; 4 | CREATE TABLE `user_preference` ( 5 | `userId` int(11) not NULL, 6 | `uniqueId` varchar(255) COLLATE utf8mb4_bin NOT NULL, 7 | `value` text COLLATE utf8mb4_bin NOT NULL, 8 | PRIMARY KEY (`userId`, `uniqueId`) 9 | )ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; 10 | /*!40101 SET character_set_client = @saved_cs_client */; 11 | -------------------------------------------------------------------------------- /model/migrations/c953506-log_context.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE `utterance_log` 2 | ADD `context` text NULL AFTER `language`; 3 | -------------------------------------------------------------------------------- /model/migrations/cd30315-pkg_metadata.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE `device_class` ADD `license` text COLLATE utf8_bin AFTER `description`, 2 | ADD `license_gplcompatible` boolean AFTER `license`, 3 | ADD `website` text COLLATE utf8_bin AFTER `license_gplcompatible`, 4 | ADD `repository` text COLLATE utf8_bin AFTER `website`, 5 | ADD `issue_tracker` text COLLATE utf8_bin AFTER `repository`; 6 | 7 | UPDATE `device_class` SET `license` = '', `license_gplcompatible` = false, `website` ='', 8 | `repository` = '', `issue_tracker` = ''; 9 | 10 | ALTER TABLE `device_class` MODIFY `license` text COLLATE utf8_bin NOT NULL, 11 | MODIFY `license_gplcompatible` boolean NOT NULL, 12 | MODIFY `website` text COLLATE utf8_bin NOT NULL, 13 | MODIFY `repository` text COLLATE utf8_bin NOT NULL, 14 | MODIFY `issue_tracker` text COLLATE utf8_bin NOT NULL; -------------------------------------------------------------------------------- /model/migrations/e1a71a4-user_phone.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE `users` 2 | ADD `phone` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL AFTER email_verified; 3 | -------------------------------------------------------------------------------- /model/migrations/e6ce32d-example_likes.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE IF EXISTS `example_likes`; 2 | /*!40101 SET @saved_cs_client = @@character_set_client */; 3 | /*!40101 SET character_set_client = utf8 */; 4 | CREATE TABLE `example_likes` ( 5 | `example_id` int(11) NOT NULL AUTO_INCREMENT, 6 | `user_id` int(11) NOT NULL, 7 | PRIMARY KEY (`example_id`, `user_id`), 8 | CONSTRAINT `example_likes_ibfk_1` FOREIGN KEY (`example_id`) REFERENCES `example_utterances` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, 9 | CONSTRAINT `example_likes_ibfk_2` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE 10 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; 11 | /*!40101 SET character_set_client = @saved_cs_client */; 12 | 13 | ALTER TABLE `example_utterances` ADD `like_count` int(11) NOT NULL DEFAULT 0 AFTER `click_count`; -------------------------------------------------------------------------------- /model/migrations/f931b89-mturk_batch_owner.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE `mturk_batch` 2 | ADD `owner` int(11) NOT NULL AFTER `id`, 3 | ADD `id_hash` char(32) COLLATE utf8_bin NOT NULL AFTER `id`; 4 | -- not very crypto secure but good enough for the few batches we already have 5 | UPDATE `mturk_batch` SET `owner` = 1, `id_hash` = MD5(RAND()); 6 | ALTER TABLE `mturk_batch` 7 | ADD CONSTRAINT `mturk_batch_ibfk_1` FOREIGN KEY (`owner`) REFERENCES `organizations` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE; 8 | -------------------------------------------------------------------------------- /model/migrations/fb205b8-trusted_dev_status.sql: -------------------------------------------------------------------------------- 1 | UPDATE `users` SET `developer_status` = 1, `roles` = `roles` | 8 WHERE `developer_status` = 2; 2 | -------------------------------------------------------------------------------- /po/.gitignore: -------------------------------------------------------------------------------- 1 | *.mo 2 | *.pot 3 | -------------------------------------------------------------------------------- /public/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/public/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /public/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/public/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /public/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/public/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /public/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/public/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /public/google1b619b92c63c82e6.html: -------------------------------------------------------------------------------- 1 | google-site-verification: google1b619b92c63c82e6.html -------------------------------------------------------------------------------- /public/images/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/public/images/.keep -------------------------------------------------------------------------------- /public/images/almond-background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/public/images/almond-background.png -------------------------------------------------------------------------------- /public/images/almond.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/public/images/almond.png -------------------------------------------------------------------------------- /public/images/almond_error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/public/images/almond_error.png -------------------------------------------------------------------------------- /public/images/almond_music.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/public/images/almond_music.jpg -------------------------------------------------------------------------------- /public/images/bubble_almond.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/public/images/bubble_almond.png -------------------------------------------------------------------------------- /public/images/bubble_user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/public/images/bubble_user.png -------------------------------------------------------------------------------- /public/images/carousel-alexa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/public/images/carousel-alexa.png -------------------------------------------------------------------------------- /public/images/carousel-nasa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/public/images/carousel-nasa.png -------------------------------------------------------------------------------- /public/images/carousel-nest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/public/images/carousel-nest.png -------------------------------------------------------------------------------- /public/images/carousel-nyt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/public/images/carousel-nyt.png -------------------------------------------------------------------------------- /public/images/carousel-teardrop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/public/images/carousel-teardrop.png -------------------------------------------------------------------------------- /public/images/cheatsheet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/public/images/cheatsheet.png -------------------------------------------------------------------------------- /public/images/docs/metadata_page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/public/images/docs/metadata_page.png -------------------------------------------------------------------------------- /public/images/docs/thingpedia_catalog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/public/images/docs/thingpedia_catalog.png -------------------------------------------------------------------------------- /public/images/docs/train_almond_page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/public/images/docs/train_almond_page.png -------------------------------------------------------------------------------- /public/images/example-bitcoin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/public/images/example-bitcoin.png -------------------------------------------------------------------------------- /public/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/public/images/favicon.ico -------------------------------------------------------------------------------- /public/images/home_assistant.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/public/images/home_assistant.png -------------------------------------------------------------------------------- /public/images/icon-cloud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/public/images/icon-cloud.png -------------------------------------------------------------------------------- /public/images/icon-compound.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/public/images/icon-compound.png -------------------------------------------------------------------------------- /public/images/icon-email.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/public/images/icon-email.png -------------------------------------------------------------------------------- /public/images/icon-memory.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/public/images/icon-memory.png -------------------------------------------------------------------------------- /public/images/icon-multi-user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/public/images/icon-multi-user.png -------------------------------------------------------------------------------- /public/images/icon-nn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/public/images/icon-nn.png -------------------------------------------------------------------------------- /public/images/icon-phone.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/images/icon-spotify.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/public/images/icon-spotify.png -------------------------------------------------------------------------------- /public/images/icon-thingpedia.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/public/images/icon-thingpedia.png -------------------------------------------------------------------------------- /public/images/icon-tt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/public/images/icon-tt.png -------------------------------------------------------------------------------- /public/images/logo-discord.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/public/images/logo-discord.png -------------------------------------------------------------------------------- /public/images/logo-email.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/public/images/logo-email.png -------------------------------------------------------------------------------- /public/images/logo-forum.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/public/images/logo-forum.png -------------------------------------------------------------------------------- /public/images/logo-github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/public/images/logo-github.png -------------------------------------------------------------------------------- /public/images/logo-rss.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/public/images/logo-rss.png -------------------------------------------------------------------------------- /public/images/logo-slack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/public/images/logo-slack.png -------------------------------------------------------------------------------- /public/images/logo-twitter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/public/images/logo-twitter.png -------------------------------------------------------------------------------- /public/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/public/images/logo.png -------------------------------------------------------------------------------- /public/images/mmi.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/public/images/mmi.jpg -------------------------------------------------------------------------------- /public/images/multi_user_almond.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/public/images/multi_user_almond.jpg -------------------------------------------------------------------------------- /public/images/news-logo-hackaday.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/public/images/news-logo-hackaday.png -------------------------------------------------------------------------------- /public/images/news-logo-hostingadvice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/public/images/news-logo-hostingadvice.png -------------------------------------------------------------------------------- /public/images/news-logo-nyt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/public/images/news-logo-nyt.png -------------------------------------------------------------------------------- /public/images/news-logo-techhq.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 9 | 10 | 11 | 12 | 13 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /public/images/sports_wikidata.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/public/images/sports_wikidata.jpg -------------------------------------------------------------------------------- /public/images/stanford-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/public/images/stanford-logo.png -------------------------------------------------------------------------------- /public/images/stanford-signature.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/public/images/stanford-signature.png -------------------------------------------------------------------------------- /public/images/symbolic-logo-community.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | 13 | 14 | -------------------------------------------------------------------------------- /public/images/symbolic-logo-discord.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | 16 | 17 | -------------------------------------------------------------------------------- /public/images/symbolic-logo-email.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /public/images/thingpedia-icon-cloud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/public/images/thingpedia-icon-cloud.png -------------------------------------------------------------------------------- /public/images/user-no-avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/public/images/user-no-avatar.png -------------------------------------------------------------------------------- /public/javascripts/.eslintrc.yml: -------------------------------------------------------------------------------- 1 | env: 2 | browser: true 3 | es6: true 4 | root: true 5 | globals: 6 | $: false 7 | QRCode: false 8 | jstz: false 9 | Glide: false 10 | ThingEngine: true 11 | extends: 'eslint:recommended' 12 | rules: 13 | indent: off 14 | linebreak-style: 15 | - error 16 | - unix 17 | quotes: off 18 | no-console: off 19 | semi: 20 | - error 21 | - always 22 | consistent-return: warn 23 | curly: 24 | - error 25 | - multi-or-nest 26 | - consistent 27 | eqeqeq: 28 | - error 29 | - always 30 | no-unused-vars: 31 | - error 32 | - 33 | args: none 34 | no-case-declarations: warn 35 | no-eval: error 36 | no-proto: error 37 | no-sequences: error 38 | no-throw-literal: error 39 | no-unmodified-loop-condition: warn 40 | no-useless-call: warn 41 | no-useless-return: warn 42 | no-void: error 43 | prefer-promise-reject-errors: error 44 | strict: 45 | - error 46 | - global 47 | no-label-var: error 48 | no-lonely-if: off 49 | no-new-object: error 50 | 51 | -------------------------------------------------------------------------------- /public/javascripts/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/public/javascripts/.keep -------------------------------------------------------------------------------- /public/javascripts/2fa_setup.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | $(() => { 3 | var text = $('#qrcode-target').text(); 4 | new QRCode('qrcode-placeholder', text); 5 | }); 6 | -------------------------------------------------------------------------------- /public/javascripts/admin.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | $(() => { 3 | $('.form-delete-user').on('submit', () => { 4 | return confirm("Are you 100% sure you want to delete this user?"); 5 | }); 6 | }); 7 | -------------------------------------------------------------------------------- /public/javascripts/apps.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | $(() => { 3 | $('.form-delete').on('submit', () => { 4 | return confirm("Are you sure?"); 5 | }); 6 | 7 | let coll = $('.collapsible'); 8 | for (let i = 0; i < coll.length; i++) { 9 | coll[i].addEventListener("click", function() { 10 | this.classList.toggle("active"); 11 | let content = this.nextElementSibling; 12 | if (content.style.display === "block") 13 | content.style.display = "none"; 14 | else 15 | content.style.display = "block"; 16 | 17 | }); 18 | } 19 | }); 20 | -------------------------------------------------------------------------------- /public/javascripts/device.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | $(() => { 3 | $('.form-delete-device').on('submit', () => { 4 | return confirm("Are you sure?"); 5 | }); 6 | 7 | $('.upvote-btn').click(function(event) { 8 | event.preventDefault(); 9 | $.post('/thingpedia/examples/upvote/' + $(this).attr('data-example-id'), '_csrf=' + $(this).attr('data-csrfToken')); 10 | }); 11 | 12 | $('.downvote-btn').click(function(event) { 13 | event.preventDefault(); 14 | $.post('/thingpedia/examples/downvote/' + $(this).attr('data-example-id'), '_csrf=' + $(this).attr('data-csrfToken')); 15 | }); 16 | 17 | $('.hide-example-btn').click(function(event) { 18 | event.preventDefault(); 19 | $.post('/thingpedia/examples/hide/' + $(this).attr('data-example-id'), '_csrf=' + $(this).attr('data-csrfToken')); 20 | }); 21 | 22 | $('.delete-example-btn').click(function(event) { 23 | event.preventDefault(); 24 | $.post('/thingpedia/examples/delete/' + $(this).attr('data-example-id'), '_csrf=' + $(this).attr('data-csrfToken')); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /public/javascripts/get-involved.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | $(() => { 3 | var glide = new Glide('#jumbotron-carousel', { 4 | type: 'carousel', 5 | perView: 5, 6 | focusAt: 'center', 7 | autoplay: 2500, 8 | animationDuration: 1500, 9 | breakpoints: { 10 | 1800: { 11 | perView: 4 12 | }, 13 | 1450: { 14 | perView: 3 15 | }, 16 | 1100: { 17 | perView: 2 18 | }, 19 | 780: { 20 | perView: 1 21 | } 22 | } 23 | }); 24 | 25 | glide.mount(); 26 | }); 27 | -------------------------------------------------------------------------------- /public/javascripts/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | (function() { 3 | ThingEngine.setCloudIdWhenReady(); 4 | })(); 5 | $(() => { 6 | function openConversation() { 7 | $('#try-almond-now-consent-form').addClass('hidden'); 8 | 9 | const section = $('#try-almond-now-conversation').removeClass('hidden')[0]; 10 | const top = section.offsetTop + 45; 11 | $(document.documentElement).animate({ scrollTop: top }, 800); 12 | event.preventDefault(); 13 | } 14 | 15 | $('#try-almond-now').click((event) => { 16 | event.preventDefault(); 17 | $('#try-almond-now-row').addClass('expanded'); 18 | 19 | openConversation(); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /public/javascripts/profile.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | $(() => { 3 | var text = $('#qrcode-target').text(); 4 | try { 5 | new QRCode('qrcode-placeholder', text); 6 | } catch(e) { 7 | // ignore errors 8 | } 9 | 10 | if (navigator.userAgent.match(/android/i)) { 11 | $('#config-phone-desktop-browser').hide(); 12 | $('#config-phone-mobile-browser').show(); 13 | } 14 | 15 | $('#issue-token-form').submit((event) => { 16 | event.preventDefault(); 17 | 18 | var csrfToken = document.body.dataset.csrfToken; 19 | $.ajax('/user/token', { data: { _csrf: csrfToken }, method: 'POST' }).then((response) => { 20 | $('#issue-token-result').removeClass('hidden'); 21 | $('#issue-token-result-placeholder').text(response.token); 22 | }, (err) => { 23 | console.error(err); 24 | }); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /public/javascripts/register.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | $(() => { 3 | var tz = jstz.determine(); 4 | $('#timezone').val(tz.name()); 5 | }); 6 | -------------------------------------------------------------------------------- /public/javascripts/shared.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | (function() { 3 | window.ThingEngine = {}; 4 | 5 | window.ThingEngine.setCloudId = function(cloudId, authToken) { 6 | if (window.Android !== undefined) 7 | window.Android.setCloudId(cloudId, authToken); 8 | else 9 | console.log('Setting cloud ID and auth token: ' + cloudId + ',' + authToken); 10 | }; 11 | 12 | window.ThingEngine.setCloudIdWhenReady = function() { 13 | $(() => { 14 | var holder = $('#cloud-id-holder'); 15 | window.ThingEngine.setCloudId(holder.attr('data-cloud-id'), 16 | holder.attr('data-auth-token')); 17 | }); 18 | }; 19 | 20 | window.ThingEngine.getThingpedia = function() { 21 | return $('body[data-thingpedia-url]').attr('data-thingpedia-url') || ''; 22 | }; 23 | })(); 24 | 25 | $(() => { 26 | if (window.Android) 27 | $('#navbar-login-button').hide(); 28 | }); 29 | -------------------------------------------------------------------------------- /public/stylesheets/admin.css: -------------------------------------------------------------------------------- 1 | #users-table td { 2 | vertical-align: middle; 3 | } 4 | 5 | #users-table th .glyphicon { 6 | font-size: 80%; 7 | } 8 | 9 | .actions-dropdown button { 10 | margin-top: 6px; 11 | margin-bottom: 6px; 12 | } 13 | 14 | #user-search-navbar { 15 | margin-top: 1em; 16 | } 17 | 18 | .nowrap { 19 | white-space: nowrap; 20 | } 21 | 22 | .nowrap .form-inline { 23 | display: inline-block; 24 | } 25 | 26 | .list-group-item.blog-post img { 27 | width: 64px; 28 | object-fit: contain; 29 | } -------------------------------------------------------------------------------- /public/stylesheets/blog-editor.css: -------------------------------------------------------------------------------- 1 | .CodeMirror { 2 | border: 1px solid #cccccc; 3 | } 4 | 5 | #blog-upload-file-after-upload { 6 | display: none; 7 | } 8 | -------------------------------------------------------------------------------- /public/stylesheets/docs.css: -------------------------------------------------------------------------------- 1 | .documentation { 2 | text-align: justify; 3 | max-width: 1000px; 4 | } 5 | 6 | .documentation > h1 { 7 | padding-bottom: 0.1em; 8 | border-bottom: 1px solid gray; 9 | margin-bottom: 0.7em; 10 | } 11 | .table-of-contents { 12 | float: left; 13 | background-color: #f9f9f9; 14 | padding: 15px 20px 10px 0; 15 | } 16 | .table-of-contents + * { 17 | clear: both; 18 | } 19 | 20 | /* emulate bootstrap styling of .table with no class name */ 21 | 22 | .documentation table { 23 | width: 100%; 24 | max-width: 100%; 25 | margin-bottom: 21px; 26 | } 27 | 28 | .documentation table td, .documentation table th { 29 | padding: 8px; 30 | line-height: 1.42857; 31 | } 32 | 33 | .documentation table td { 34 | vertical-align: top; 35 | } 36 | 37 | .documentation table th { 38 | vertical-align: bottom; 39 | } 40 | 41 | img[alt=screenshot] { 42 | display: block; 43 | margin: auto; 44 | max-width: 800px; 45 | } 46 | 47 | img[alt=architecture] { 48 | display: block; 49 | margin: auto; 50 | max-width: 600px; 51 | } -------------------------------------------------------------------------------- /public/stylesheets/glide.core.min.css: -------------------------------------------------------------------------------- 1 | .glide{position:relative;width:100%;box-sizing:border-box}.glide *{box-sizing:inherit}.glide__track{overflow:hidden}.glide__slides{position:relative;width:100%;list-style:none;backface-visibility:hidden;transform-style:preserve-3d;touch-action:pan-Y;overflow:hidden;padding:0;white-space:nowrap;display:flex;flex-wrap:nowrap;will-change:transform}.glide__slides--dragging{user-select:none}.glide__slide{width:100%;height:100%;flex-shrink:0;white-space:normal;user-select:none;-webkit-touch-callout:none;-webkit-tap-highlight-color:transparent}.glide__slide a{user-select:none;-webkit-user-drag:none;-moz-user-select:none;-ms-user-select:none}.glide__arrows{-webkit-touch-callout:none;user-select:none}.glide__bullets{-webkit-touch-callout:none;user-select:none}.glide--rtl{direction:rtl} -------------------------------------------------------------------------------- /public/stylesheets/glide.theme.min.css: -------------------------------------------------------------------------------- 1 | .glide__arrow{position:absolute;display:block;top:50%;z-index:2;color:white;text-transform:uppercase;padding:9px 12px;background-color:transparent;border:2px solid rgba(255,255,255,0.5);border-radius:4px;box-shadow:0 0.25em 0.5em 0 rgba(0,0,0,0.1);text-shadow:0 0.25em 0.5em rgba(0,0,0,0.1);opacity:1;cursor:pointer;transition:opacity 150ms ease, border 300ms ease-in-out;transform:translateY(-50%);line-height:1}.glide__arrow:focus{outline:none}.glide__arrow:hover{border-color:white}.glide__arrow--left{left:2em}.glide__arrow--right{right:2em}.glide__arrow--disabled{opacity:0.33}.glide__bullets{position:absolute;z-index:2;bottom:2em;left:50%;display:inline-flex;list-style:none;transform:translateX(-50%)}.glide__bullet{background-color:rgba(255,255,255,0.5);width:9px;height:9px;padding:0;border-radius:50%;border:2px solid transparent;transition:all 300ms ease-in-out;cursor:pointer;line-height:0;box-shadow:0 0.25em 0.5em 0 rgba(0,0,0,0.1);margin:0 0.25em}.glide__bullet:focus{outline:none}.glide__bullet:hover,.glide__bullet:focus{border:2px solid white;background-color:rgba(255,255,255,0.5)}.glide__bullet--active{background-color:white}.glide--swipeable{cursor:grab;cursor:-moz-grab;cursor:-webkit-grab}.glide--dragging{cursor:grabbing;cursor:-moz-grabbing;cursor:-webkit-grabbing} -------------------------------------------------------------------------------- /public/stylesheets/luinet-dataset.css: -------------------------------------------------------------------------------- 1 | .utterance { 2 | } 3 | 4 | .preprocessed { 5 | font-family: monospace; 6 | } -------------------------------------------------------------------------------- /public/stylesheets/mturk.css: -------------------------------------------------------------------------------- 1 | .warning { 2 | color: red; 3 | } 4 | 5 | .hint{ 6 | color: dimgray; 7 | } 8 | 9 | .synthetic { 10 | background-color: #f3f4f2; 11 | } 12 | 13 | #paraphrase-row { 14 | padding: 1em; 15 | } 16 | 17 | #submit-section { 18 | margin-top: 3em; 19 | } 20 | 21 | 22 | #token { 23 | text-align: center; 24 | margin: auto; 25 | width: 20%; 26 | } 27 | 28 | #message { 29 | text-align: center; 30 | margin-top: 5em; 31 | margin-bottom: 100em; 32 | } -------------------------------------------------------------------------------- /public/stylesheets/my_stuff.css: -------------------------------------------------------------------------------- 1 | .app-template { 2 | border: 1px gray; 3 | border-radius: 5px; 4 | } 5 | 6 | .installed-dev .panel-heading { 7 | display: block; 8 | } 9 | 10 | .installed-dev .panel-footer { 11 | min-height: 56px; 12 | } 13 | 14 | .form-delete-app { 15 | float: right; 16 | } 17 | 18 | 19 | /* Style the button that is used to open and close the collapsible content */ 20 | 21 | .collapsible { 22 | background-color: #f3f4f2; 23 | cursor: pointer; 24 | padding: 10px; 25 | width: 100%; 26 | border: none; 27 | text-align: left; 28 | outline: none; 29 | font-size: 20px; 30 | } 31 | 32 | .active, 33 | .collapsible:hover { 34 | background-color: #7f030a; 35 | color: white; 36 | } 37 | 38 | .device-list .aligned-grid { 39 | margin-bottom: 1em; 40 | } 41 | 42 | .my-stuff-collapsible { 43 | max-width: 800px; 44 | margin: auto; 45 | margin-bottom: 1em; 46 | } 47 | -------------------------------------------------------------------------------- /public/stylesheets/oauth2.css: -------------------------------------------------------------------------------- 1 | #app-icon-large { 2 | display: block; 3 | float: left; 4 | } 5 | 6 | #app-icon-large > img { 7 | display: block; 8 | width: 160px; 9 | /* accept non-perfectly square images */ 10 | height: 160px; 11 | object-fit: contain; 12 | border-radius: 10px; 13 | margin-right: 1em; 14 | margin-bottom: 1em; 15 | } 16 | -------------------------------------------------------------------------------- /public/stylesheets/profiles.css: -------------------------------------------------------------------------------- 1 | #user-profile-pic { 2 | width: 250px; 3 | margin: 0 auto; 4 | } 5 | -------------------------------------------------------------------------------- /public/stylesheets/status.css: -------------------------------------------------------------------------------- 1 | #log-view { 2 | height: 30em; 3 | overflow: auto; 4 | } 5 | 6 | #log-view p { 7 | margin-bottom: 0; 8 | margin-top: 0; 9 | } 10 | -------------------------------------------------------------------------------- /public/stylesheets/thingpedia-cheatsheet.css: -------------------------------------------------------------------------------- 1 | #cheatsheet h3 { 2 | font-size: medium; 3 | font-weight: bold; 4 | } 5 | 6 | #cheatsheet h3 > img { 7 | width: 24px; 8 | height: 24px; 9 | object-fit: contain; 10 | margin-right: 0.5em; 11 | } 12 | 13 | #cheatsheet li { 14 | font-size: small; 15 | } 16 | 17 | #cheatsheet ul { 18 | padding-left: 10.5px; 19 | } 20 | 21 | .trigger { 22 | color: red; 23 | } 24 | 25 | .query { 26 | color: rgb(220,136,8); 27 | } 28 | 29 | .action { 30 | color: rgb(34,139,34); 31 | } 32 | 33 | h3 > .trigger, h3 > .query, h3 > .action { 34 | font-weight: normal; 35 | } 36 | 37 | #cheatsheet .grid-item { 38 | width: 100%; 39 | } 40 | 41 | @media (min-width: 992px) { 42 | #cheatsheet .grid-item { 43 | width: 32%; 44 | } 45 | } 46 | 47 | @media (min-width: 1200px) { 48 | #cheatsheet .grid-item { 49 | width: 24%; 50 | } 51 | } 52 | 53 | -------------------------------------------------------------------------------- /sandbox/.gitignore: -------------------------------------------------------------------------------- 1 | sandbox 2 | -------------------------------------------------------------------------------- /sandbox/Makefile: -------------------------------------------------------------------------------- 1 | 2 | all: sandbox 3 | 4 | CFLAGS := -Wall -Werror -g -O2 -fno-strict-overflow -fstack-protector-strong 5 | DEPS := $(shell pkg-config --cflags --libs libsystemd && echo "-DHAVE_SYSTEMD") 6 | CPPFLAGS := -D_FORTIFY_SOURCE=2 7 | 8 | sandbox: sandbox.c 9 | $(CC) -o $@ $(CFLAGS) $(CPPFLAGS) $< $(DEPS) 10 | 11 | clean: 12 | rm -f sandbox 13 | -------------------------------------------------------------------------------- /src/almond/sockaddr.d.ts: -------------------------------------------------------------------------------- 1 | // TODO move to upstream repository 2 | 3 | declare module 'sockaddr' { 4 | function sockaddr(address : string, options ?: { 5 | defaultPort : number 6 | }) : sockaddr.SocketAddress; 7 | 8 | namespace sockaddr { 9 | export type SocketAddress = { 10 | host : string; 11 | port : number; 12 | } | { 13 | path : string; 14 | } 15 | } 16 | 17 | export = sockaddr; 18 | } 19 | -------------------------------------------------------------------------------- /src/cacheable-middleware.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'cacheable-middleware' { 2 | import { RequestHandler, Request, Response, NextFunction } from 'express'; 3 | import * as moment from 'moment'; 4 | 5 | function Cacheable(duration ?: number, durationKey ?: moment.unitOfTime.DurationConstructor) : RequestHandler; 6 | namespace Cacheable { 7 | function cachedResponse(ms : number, req : Request, res : Response, next : NextFunction) : void; 8 | 9 | function cacheFor(this : Response, ms : number) : Response; 10 | } 11 | 12 | export = Cacheable; 13 | } 14 | declare namespace Express { 15 | interface Response { 16 | cacheFor(duration : moment.Duration) : this; 17 | cacheFor(value : number, durationKey ?: moment.unitOfTime.DurationConstructor) : this; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/logging.ts: -------------------------------------------------------------------------------- 1 | import * as Path from "path"; 2 | 3 | import * as Winston from "winston"; 4 | import { Factory, Format } from "@stanford-oval/logging"; 5 | 6 | const RUN_ROOT = Path.resolve(__dirname, ".."); 7 | 8 | export default new Factory({ 9 | runRoot: RUN_ROOT, 10 | level: "http", 11 | envVarPrefix: "GENIE_LOG", 12 | transports: [ 13 | new Winston.transports.Console({ 14 | format: Format.prettySimple({ colorize: true }), 15 | }), 16 | ], 17 | }); 18 | -------------------------------------------------------------------------------- /src/routes/markdown-it-container-pandoc.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'markdown-it-container-pandoc' { 2 | import { PluginSimple } from 'markdown-it'; 3 | 4 | const plugin : PluginSimple; 5 | export = plugin; 6 | } 7 | -------------------------------------------------------------------------------- /src/routes/markdown-it-footnote.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'markdown-it-footnote' { 2 | import { PluginSimple } from 'markdown-it'; 3 | 4 | const plugin : PluginSimple; 5 | export = plugin; 6 | } 7 | -------------------------------------------------------------------------------- /src/routes/markdown-it-table-of-contents.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'markdown-it-table-of-contents' { 2 | import { PluginWithOptions } from 'markdown-it'; 3 | 4 | const plugin : PluginWithOptions<{ 5 | includeLevel ?: number[] 6 | }>; 7 | export = plugin; 8 | } 9 | -------------------------------------------------------------------------------- /src/routes/qrcode.ts: -------------------------------------------------------------------------------- 1 | // -*- mode: js; indent-tabs-mode: nil; js-basic-offset: 4 -*- 2 | // 3 | // This file is part of Almond 4 | // 5 | // Copyright 2016-2018 The Board of Trustees of the Leland Stanford Junior University 6 | // 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | // 11 | // http://www.apache.org/licenses/LICENSE-2.0 12 | // 13 | // Unless required by applicable law or agreed to in writing, software 14 | // distributed under the License is distributed on an "AS IS" BASIS, 15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | // See the License for the specific language governing permissions and 17 | // limitations under the License. 18 | // 19 | // Author: Giovanni Campagna 20 | 21 | import express from 'express'; 22 | 23 | const router = express.Router(); 24 | 25 | router.get('/qrcode-cloud/:cloud_id/:auth_token', (req, res, next) => { 26 | res.render('qrcode', { for_: 'cloud', 27 | link: req.originalUrl, 28 | authToken: req.params.auth_token, 29 | cloudId: req.params.cloud_id }); 30 | }); 31 | 32 | export default router; 33 | -------------------------------------------------------------------------------- /src/routes/thirty-two.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'thirty-two' { 2 | export function encode(buffer : string|Buffer) : string; 3 | 4 | export function decode(string : string|Buffer) : Buffer; 5 | } 6 | -------------------------------------------------------------------------------- /src/scripts/execute-sql-file.js: -------------------------------------------------------------------------------- 1 | // -*- mode: js; indent-tabs-mode: nil; js-basic-offset: 4 -*- 2 | // 3 | // This file is part of Almond 4 | // 5 | // Copyright 2018-2019 The Board of Trustees of the Leland Stanford Junior University 6 | // 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | // 11 | // http://www.apache.org/licenses/LICENSE-2.0 12 | // 13 | // Unless required by applicable law or agreed to in writing, software 14 | // distributed under the License is distributed on an "AS IS" BASIS, 15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | // See the License for the specific language governing permissions and 17 | // limitations under the License. 18 | // 19 | // Author: Giovanni Campagna 20 | 21 | import * as execSql from '../util/exec_sql'; 22 | 23 | export function initArgparse(subparsers) { 24 | const parser = subparsers.add_parser('execute-sql-file', { 25 | description: 'Execute a SQL script against the configured Almond Cloud database' 26 | }); 27 | parser.add_argument('filename', { 28 | help: "The file to execute" 29 | }); 30 | } 31 | 32 | export async function main(argv) { 33 | try { 34 | execSql.exec(argv.filename); 35 | } catch(e) { 36 | console.error(e); 37 | process.exit(1); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/scripts/get-config.js: -------------------------------------------------------------------------------- 1 | // -*- mode: js; indent-tabs-mode: nil; js-basic-offset: 4 -*- 2 | // 3 | // This file is part of Almond 4 | // 5 | // Copyright 2019 The Board of Trustees of the Leland Stanford Junior University 6 | // 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | // 11 | // http://www.apache.org/licenses/LICENSE-2.0 12 | // 13 | // Unless required by applicable law or agreed to in writing, software 14 | // distributed under the License is distributed on an "AS IS" BASIS, 15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | // See the License for the specific language governing permissions and 17 | // limitations under the License. 18 | // 19 | // Author: Jim Deng 20 | 21 | import * as Config from '../config'; 22 | 23 | export function initArgparse(subparsers) { 24 | const parser = subparsers.add_parser('get-config', { 25 | description: 'Print a configuration value' 26 | }); 27 | parser.add_argument('key', { 28 | help: 'The configuration key to print', 29 | }); 30 | } 31 | 32 | export async function main(argv) { 33 | if (Config[argv.key] === undefined) // null/false/0 are valid configuration values, so don't use ! 34 | throw Error(`Invalid configuration key ${argv.key}`); 35 | console.log(Config[argv.key]); 36 | } 37 | -------------------------------------------------------------------------------- /src/training/lib/action_set_flag.js: -------------------------------------------------------------------------------- 1 | // -*- mode: js; indent-tabs-mode: nil; js-basic-offset: 4 -*- 2 | // 3 | // This file is part of Almond 4 | // 5 | // Copyright 2019 The Board of Trustees of the Leland Stanford Junior University 6 | // 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | // 11 | // http://www.apache.org/licenses/LICENSE-2.0 12 | // 13 | // Unless required by applicable law or agreed to in writing, software 14 | // distributed under the License is distributed on an "AS IS" BASIS, 15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | // See the License for the specific language governing permissions and 17 | // limitations under the License. 18 | // 19 | // Author: Giovanni Campagna 20 | 21 | import * as argparse from 'argparse'; 22 | 23 | export default class ActionSetFlag extends argparse.Action { 24 | call(parser, namespace, value) { 25 | if (!namespace.flags) 26 | namespace.flags = {}; 27 | namespace.flags[value] = this.const; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/training/tasks/index.ts: -------------------------------------------------------------------------------- 1 | // -*- mode: typescript; indent-tabs-mode: nil; js-basic-offset: 4 -*- 2 | // 3 | // This file is part of Almond 4 | // 5 | // Copyright 2019-2020 The Board of Trustees of the Leland Stanford Junior University 6 | // 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | // 11 | // http://www.apache.org/licenses/LICENSE-2.0 12 | // 13 | // Unless required by applicable law or agreed to in writing, software 14 | // distributed under the License is distributed on an "AS IS" BASIS, 15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | // See the License for the specific language governing permissions and 17 | // limitations under the License. 18 | // 19 | // Author: Giovanni Campagna 20 | 21 | import updateDataset from './update-dataset'; 22 | 23 | export default { 24 | 'update-dataset': updateDataset, 25 | }; 26 | -------------------------------------------------------------------------------- /src/util/address-formatter.d.ts: -------------------------------------------------------------------------------- 1 | declare module '@fragaria/address-formatter' { 2 | export function format(address : Record, options : { 3 | abbreviate ?: boolean; 4 | appendCountry ?: boolean; 5 | countryCode ?: string; 6 | fallbackCountryCode ?: string; 7 | output : 'array' 8 | }) : string[]; 9 | export function format(address : Record, options ?: { 10 | abbreviate ?: boolean; 11 | appendCountry ?: boolean; 12 | countryCode ?: string; 13 | fallbackCountryCode ?: string; 14 | }) : string; 15 | } 16 | -------------------------------------------------------------------------------- /src/util/binary_search.ts: -------------------------------------------------------------------------------- 1 | // -*- mode: typescript; indent-tabs-mode: nil; js-basic-offset: 4 -*- 2 | // 3 | // This file is part of Almond 4 | // 5 | // Copyright 2018-2019 The Board of Trustees of the Leland Stanford Junior University 6 | // 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | // 11 | // http://www.apache.org/licenses/LICENSE-2.0 12 | // 13 | // Unless required by applicable law or agreed to in writing, software 14 | // distributed under the License is distributed on an "AS IS" BASIS, 15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | // See the License for the specific language governing permissions and 17 | // limitations under the License. 18 | // 19 | // Author: Giovanni Campagna 20 | 21 | export default function binarySearch(cumsum : number[], value : number) { 22 | if (cumsum.length === 0) 23 | return undefined; 24 | let a = 0, b = cumsum.length; 25 | for (;;) { 26 | if (b - a === 1) 27 | return a; 28 | if (b - a === 2) { 29 | if (value <= cumsum[a]) 30 | return a; 31 | else 32 | return a+1; 33 | } 34 | const m = Math.floor((a+b)/2); 35 | if (value <= cumsum[m]) 36 | b = m+1; 37 | else 38 | a = m; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/util/color-scheme.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'color-scheme' { 2 | class ColorScheme { 3 | constructor(); 4 | 5 | from_hue(hue : number) : this; 6 | from_hex(hex : string) : this; 7 | 8 | scheme(s ?: 'mono' | 'contrast' | 'triade' | 'tetrade' | 'analogic') : this; 9 | variation(v : 'default' | 'pastel' | 'soft' | 'light' | 'hard' | 'pale') : this; 10 | distance(d : number) : this; 11 | add_complement(b : boolean) : this; 12 | web_safe(b : boolean) : this; 13 | 14 | colors() : string[]; 15 | colorset() : string[][]; 16 | } 17 | 18 | export = ColorScheme; 19 | } 20 | -------------------------------------------------------------------------------- /src/util/escaping.ts: -------------------------------------------------------------------------------- 1 | // -*- mode: typescript; indent-tabs-mode: nil; js-basic-offset: 4 -*- 2 | // 3 | // This file is part of Almond 4 | // 5 | // Copyright 2018 The Board of Trustees of the Leland Stanford Junior University 6 | // 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | // 11 | // http://www.apache.org/licenses/LICENSE-2.0 12 | // 13 | // Unless required by applicable law or agreed to in writing, software 14 | // distributed under the License is distributed on an "AS IS" BASIS, 15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | // See the License for the specific language governing permissions and 17 | // limitations under the License. 18 | // 19 | // Author: Giovanni Campagna 20 | 21 | export function stringEscape(str : string|null|undefined) { 22 | if (str === null || str === undefined) 23 | return 'null'; 24 | return '"' + str.replace(/(["\\])/g, '\\$1').replace(/\n/g, '\\n') + '"'; 25 | // the following comment fixes broken syntax highlighting in GtkSourceView 26 | //]/ 27 | } 28 | -------------------------------------------------------------------------------- /src/util/genie_flag_utils.ts: -------------------------------------------------------------------------------- 1 | // -*- mode: typescript; indent-tabs-mode: nil; js-basic-offset: 4 -*- 2 | // 3 | // This file is part of Almond 4 | // 5 | // Copyright 2019 The Board of Trustees of the Leland Stanford Junior University 6 | // 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | // 11 | // http://www.apache.org/licenses/LICENSE-2.0 12 | // 13 | // Unless required by applicable law or agreed to in writing, software 14 | // distributed under the License is distributed on an "AS IS" BASIS, 15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | // See the License for the specific language governing permissions and 17 | // limitations under the License. 18 | // 19 | // Author: Giovanni Campagna 20 | 21 | function parseFlags(flags : string) { 22 | const parsed : Record = {}; 23 | for (const flag of flags.split(',')) 24 | parsed[flag] = true; 25 | return parsed; 26 | } 27 | 28 | function makeFlags(flags : Record) : string { 29 | return Object.keys(flags).filter((k) => !!flags[k]).join(','); 30 | } 31 | 32 | export { 33 | parseFlags, 34 | makeFlags, 35 | }; 36 | -------------------------------------------------------------------------------- /src/util/img-color-extractor.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'img-color-extractor' { 2 | import * as stream from 'stream'; 3 | 4 | export interface Options { 5 | background ?: string; 6 | alphaMin ?: number; 7 | dist ?: number; 8 | greyVa ?: number; 9 | } 10 | export interface Color { 11 | color : string; 12 | n : number; 13 | r : number; 14 | } 15 | 16 | export function extract(readable : stream.Readable, opts ?: Options) : Promise; 17 | } 18 | -------------------------------------------------------------------------------- /src/util/passport-totp.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'passport-totp' { 2 | import passport from 'passport'; 3 | 4 | type SetupFunction = (user : Express.User, cb : (err : Error|null, key ?: string|Buffer, window ?: number) => void) => void; 5 | 6 | export class Strategy extends passport.Strategy { 7 | constructor(options : { codeField ?: string, window ?: number }, setup : SetupFunction); 8 | constructor(setup : SetupFunction); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/util/shard.ts: -------------------------------------------------------------------------------- 1 | // -*- mode: typescript; indent-tabs-mode: nil; js-basic-offset: 4 -*- 2 | // 3 | // This file is part of Almond 4 | // 5 | // Copyright 2019 The Board of Trustees of the Leland Stanford Junior University 6 | // 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | // 11 | // http://www.apache.org/licenses/LICENSE-2.0 12 | // 13 | // Unless required by applicable law or agreed to in writing, software 14 | // distributed under the License is distributed on an "AS IS" BASIS, 15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | // See the License for the specific language governing permissions and 17 | // limitations under the License. 18 | // 19 | // Author: Giovanni Campagna 20 | 21 | 22 | // compute the shard of a user, based on a simple hashing scheme 23 | 24 | export default function shard(userId : number, nShards : number) { 25 | // in theory, we could just do userId % nShards 26 | // because userIds are assigned sequentially 27 | // so that would be balanced 28 | // 29 | // in practice 30 | 31 | // randomize the userId a bit 32 | 33 | userId += 33; 34 | userId *= 7; 35 | userId += 33; 36 | userId *= 7; 37 | 38 | return userId % nShards; 39 | } 40 | -------------------------------------------------------------------------------- /src/util/sleep.ts: -------------------------------------------------------------------------------- 1 | // -*- mode: typescript; indent-tabs-mode: nil; js-basic-offset: 4 -*- 2 | // 3 | // This file is part of Almond 4 | // 5 | // Copyright 2019 The Board of Trustees of the Leland Stanford Junior University 6 | // 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | // 11 | // http://www.apache.org/licenses/LICENSE-2.0 12 | // 13 | // Unless required by applicable law or agreed to in writing, software 14 | // distributed under the License is distributed on an "AS IS" BASIS, 15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | // See the License for the specific language governing permissions and 17 | // limitations under the License. 18 | // 19 | // Author: Giovanni Campagna 20 | 21 | export default async function sleep(ms : number) { 22 | return new Promise((resolve, reject) => { 23 | setTimeout(resolve, ms); 24 | }); 25 | } 26 | -------------------------------------------------------------------------------- /tests/check-migrations.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | set -o pipefail 5 | 6 | srcdir=`dirname $0`/.. 7 | srcdir=`realpath $srcdir` 8 | 9 | for migration in $srcdir/model/migrations/* ; do 10 | if ! test -x $migration ; then 11 | case `basename $migration` in 12 | *.sql|*.sh|*.js) 13 | echo "Found migration file $migration that is not executable" 14 | exit 1 15 | ;; 16 | *) 17 | continue 18 | ;; 19 | esac 20 | fi 21 | commit=`basename $migration | cut -f1 -d'-'` 22 | git rev-parse --verify "$commit^{commit}" 23 | done -------------------------------------------------------------------------------- /tests/data/com.bing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/tests/data/com.bing.png -------------------------------------------------------------------------------- /tests/data/org.thingpedia.builtin.test.adminonly.yaml: -------------------------------------------------------------------------------- 1 | thingpedia_name: Admin-only Device 2 | thingpedia_description: This device does not exist. This entry is visible only to the administrators of Thingpedia. It exists to test that the Thingpedia API properly masks and reveals devices based on the appropriate developer key. DO NOT APPROVE THIS DEVICE. 3 | subcategory: service 4 | 5 | class: | 6 | class @org.thingpedia.builtin.test.adminonly 7 | #[system=true] 8 | { 9 | import loader from @org.thingpedia.builtin(); 10 | import config from @org.thingpedia.config.none(); 11 | 12 | action eat_data(in req data : String #_[prompt="What do you want me to consume?"]) 13 | #[doc="consume some data, do nothing"] 14 | #_[confirmation="consume $data"] 15 | #_[canonical="eat data on test"]; 16 | } 17 | 18 | dataset: | 19 | dataset @org.thingpedia.builtin.test.adminonly language "en" { 20 | action := @org.thingpedia.builtin.test.adminonly.eat_data() 21 | #_[utterances=["test admin-only example"]]; 22 | } 23 | -------------------------------------------------------------------------------- /tests/data/org.thingpedia.builtin.test.invisible.yaml: -------------------------------------------------------------------------------- 1 | thingpedia_name: "Invisible Device" 2 | thingpedia_description: "This device is owned by Bob. It was not approved." 3 | subcategory: service 4 | 5 | class: | 6 | class @org.thingpedia.builtin.test.invisible 7 | #[system=true] 8 | { 9 | import loader from @org.thingpedia.builtin(); 10 | import config from @org.thingpedia.config.custom_oauth(); 11 | 12 | action eat_data(in req data : String #_[prompt="What do you want me to consume?"]) 13 | #[doc="consume some data, do nothing"] 14 | #_[confirmation="consume $data"] 15 | #_[canonical="eat data on test"]; 16 | } 17 | 18 | dataset: | 19 | dataset @org.thingpedia.builtin.test.invisible language "en" { 20 | action := @org.thingpedia.builtin.test.invisible.eat_data() 21 | #_[utterances=["test admin-only example"]]; 22 | } 23 | -------------------------------------------------------------------------------- /tests/data/stt-test1.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/tests/data/stt-test1.wav -------------------------------------------------------------------------------- /tests/data/stt-test2.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/tests/data/stt-test2.wav -------------------------------------------------------------------------------- /tests/data/test-oauth-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/tests/data/test-oauth-logo.png -------------------------------------------------------------------------------- /tests/data/tt:location.txt: -------------------------------------------------------------------------------- 1 | seattle 2 | palo alto 3 | santa clara 4 | stanford 5 | stanford california 6 | serra mall stanford 7 | campus drive stanford 8 | redwood city 9 | menlo park 10 | fremont 11 | san francisco 12 | berkeley califonia 13 | oaklan california 14 | new york city 15 | los angeles ca 16 | boston 17 | washington 18 | washington dc 19 | miami 20 | melbourne australia 21 | paris 22 | paris texas 23 | paris tx 24 | london 25 | cambridge ma 26 | new castle 27 | newcastle 28 | milan 29 | turin 30 | venice 31 | rome 32 | florence 33 | neaples 34 | bologna 35 | 36 | -------------------------------------------------------------------------------- /tests/data/tt:path_name.txt: -------------------------------------------------------------------------------- 1 | desktop desktop 1000.0 2 | my documents my documents 1000.0 3 | my network my network 1000.0 4 | pictures pictures 1000.0 5 | android android 1000.0 6 | ios ios 1000.0 7 | files files 1000.0 8 | downloads downloads 1000.0 9 | music music 1000.0 10 | videos videos 1000.0 11 | -------------------------------------------------------------------------------- /tests/data/tt:person_first_name.txt: -------------------------------------------------------------------------------- 1 | sinath sinath 1 2 | amariss amariss 1 3 | thyrome thyrome 1 4 | leiona leiona 1 5 | delantae delantae 1 6 | nohl nohl 1 7 | gaddiel gaddiel 1 8 | durl durl 1 9 | melo melo 1 10 | colon colon 1 11 | saratha saratha 1 12 | caprina caprina 1 13 | evolett evolett 1 14 | rekesha rekesha 1 15 | jerrianna jerrianna 1 16 | gurshaan gurshaan 1 17 | finnly finnly 1 18 | teenamarie teenamarie 1 19 | madhulika madhulika 1 20 | kiomy kiomy 1 21 | -------------------------------------------------------------------------------- /tests/data/tt:search_query.txt: -------------------------------------------------------------------------------- 1 | nfl national anthem protests 2 | poke bowl calories 3 | yodeling kid remix 4 | spyro reignited 5 | bad and boujee 6 | michelle wolf speech 7 | aaron judge 8 | kod j cole 9 | shiba inu 10 | what is bitcoin ? 11 | walmart yodel 12 | netflix 13 | jan blankers 14 | burpees exercise 15 | brenna spencer 16 | hiit workout routine 17 | traductor 18 | daca 19 | lift yourself 20 | you tube 21 | -------------------------------------------------------------------------------- /tests/data/tt:short_free_text.txt: -------------------------------------------------------------------------------- 1 | for instance a site 2 | because of excessive 3 | is an affectingly 4 | that he turned to 5 | undercurrent silent and making it 6 | illustrated by a 7 | long the waco 8 | of shell-psychology would 9 | he told boats 10 | lay people 11 | about 2.5 per cent 12 | afforded the opportunity 13 | buckets were filled the 14 | of his execution 15 | the fuses however 16 | church 17 | see their errors we 18 | the depth of my conviction 19 | however ; ; 20 | -------------------------------------------------------------------------------- /tests/everything.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | set -x 5 | 6 | srcdir=`dirname $0`/.. 7 | 8 | TZ="America/Los_Angeles" 9 | export TZ 10 | 11 | # build tests 12 | $srcdir/tests/check-migrations.sh 13 | 14 | # unit tests 15 | ts-node $srcdir/tests/unit 16 | 17 | # integration tests 18 | # (these spawn the whole system, with all the bells and whistles, 19 | # and fire requests at it, checking the result) 20 | 21 | $srcdir/tests/webalmond-integration.sh 22 | $srcdir/tests/thingpedia-integration.sh 23 | $srcdir/tests/nlp-integration.sh 24 | $srcdir/tests/training-integration.sh 25 | -------------------------------------------------------------------------------- /tests/install-nlp-deps.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | set -x 5 | set -o pipefail 6 | 7 | srcdir=`dirname $0`/.. 8 | srcdir=`realpath $srcdir` 9 | 10 | # HACK: fix broken dependencies through kfserving 11 | pip3 install 'ray[serve]==1.6.0' 12 | which genienlp >/dev/null 2>&1 || pip3 install genienlp==0.7.0a2 13 | which genienlp 14 | 15 | mkdir -p $srcdir/tests/embeddings 16 | -------------------------------------------------------------------------------- /tests/nlp/index.js: -------------------------------------------------------------------------------- 1 | // -*- mode: js; indent-tabs-mode: nil; js-basic-offset: 4 -*- 2 | // 3 | // This file is part of Almond 4 | // 5 | // Copyright 2019-2020 The Board of Trustees of the Leland Stanford Junior University 6 | // 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | // 11 | // http://www.apache.org/licenses/LICENSE-2.0 12 | // 13 | // Unless required by applicable law or agreed to in writing, software 14 | // distributed under the License is distributed on an "AS IS" BASIS, 15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | // See the License for the specific language governing permissions and 17 | // limitations under the License. 18 | // 19 | 20 | 21 | process.on('unhandledRejection', (up) => { throw up; }); 22 | import '../../src/util/config_init'; 23 | process.env.TEST_MODE = '1'; 24 | 25 | async function seq(array) { 26 | for (let fn of array) { 27 | if (fn === null) 28 | continue; 29 | console.log(`Running tests for ${fn}`); 30 | await (await import(fn)).default(); 31 | } 32 | } 33 | 34 | seq([ 35 | ('./test_voice'), 36 | ('./test_nlu'), 37 | ]); 38 | -------------------------------------------------------------------------------- /tests/nlp/parser_test_cases.json: -------------------------------------------------------------------------------- 1 | [ 2 | "yes", 3 | "no", 4 | "of course", 5 | "42", 6 | "never mind", 7 | "tweet i'm happy", 8 | "send a dm on twitter to @alice saying i'm happy", 9 | "follow user @alice on twitter", 10 | "show a popup with title news and body i'm happy", 11 | "set my phone to normal", 12 | "call 911", 13 | "get a random xkcd", 14 | "get the latest xkcd", 15 | "get current time", 16 | "give me a random number between 10 and 20", 17 | "turn on my lightbulb", 18 | "get a cat picture" 19 | ] 20 | -------------------------------------------------------------------------------- /tests/thingpedia-integration/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM localhost/almond-cloud 2 | 3 | USER root 4 | 5 | COPY --chown=almond-cloud:almond-cloud ./tests /opt/almond-cloud/tests 6 | 7 | RUN curl -sL https://rpmfind.net/linux/epel/7/x86_64/Packages/l/libpmem-1.1-1.el7.x86_64.rpm -o libpmem-1.1-1.el7.x86_64.rpm && \ 8 | curl -sS https://downloads.mariadb.com/MariaDB/mariadb_repo_setup | bash && \ 9 | dnf -y install libpmem-1.1-1.el7.x86_64.rpm MariaDB-client && \ 10 | rm -f libpmem-1.1-1.el7.x86_64.rpm && rm -rf /var/cache/dnf 11 | 12 | RUN dnf -y install gcc gcc-c++ && \ 13 | curl -sL https://dl.google.com/go/go1.16.4.linux-amd64.tar.gz -o go1.16.4.linux-amd64.tar.gz && \ 14 | tar -xzf go1.16.4.linux-amd64.tar.gz && \ 15 | mv go /usr/local 16 | 17 | RUN /usr/local/go/bin/go get golang.org/x/tools/cmd/cover 18 | 19 | WORKDIR /opt/almond-cloud/go 20 | RUN /usr/local/go/bin/go test -cover -v ./... 21 | 22 | WORKDIR /home/almond-cloud 23 | RUN mkdir -p shared/download && mkdir -p shared/cache 24 | RUN for x in devices icons backgrounds blog-assets template-files/en; \ 25 | do mkdir -p shared/download/$x; \ 26 | done 27 | RUN echo '{"tt:stock_id:goog": "fb80c6ac2685d4401806795765550abdce2aa906.png"}' > shared/cache/index.json 28 | RUN curl -sL https://thingpedia.stanford.edu/thingpedia/api/v3/devices/package/com.bing -o /opt/almond-cloud/tests/data/com.bing.zip 29 | 30 | 31 | 32 | ENTRYPOINT ["/opt/almond-cloud/docker/start.sh"] -------------------------------------------------------------------------------- /tests/thingpedia-integration/k8s/cluster.yaml: -------------------------------------------------------------------------------- 1 | kind: Cluster 2 | apiVersion: kind.x-k8s.io/v1alpha4 3 | nodes: 4 | - role: control-plane 5 | extraPortMappings: 6 | - containerPort: 30950 7 | hostPort: 8080 8 | -------------------------------------------------------------------------------- /tests/thingpedia-integration/k8s/config.d/config.yaml: -------------------------------------------------------------------------------- 1 | DATABASE_URL: "mysql://root:password@mariadb.default.svc.cluster.local/thingengine_test?charset=utf8mb4_bin" 2 | DATABASE_PROXY_URL: "http://dbproxy.default.svc.cluster.local:8200" 3 | SERVER_ORIGIN: "http://localhost:8080" 4 | CDN_HOST: /download 5 | WITH_THINGPEDIA: embedded 6 | WITH_LUINET: embedded 7 | THINGPEDIA_URL: /thingpedia 8 | ENABLE_DEVELOPER_PROGRAM: true 9 | ENABLE_DEVELOPER_BACKEND: true 10 | ENABLE_ANONYMOUS_USER: true 11 | ENABLE_PROMETHEUS: true 12 | PROMETHEUS_ACCESS_TOKEN: my-prometheus-access-token 13 | DISCOURSE_SSO_SECRET: d836444a9e4084d5b224a60c208dce14 14 | AES_SECRET_KEY: 80bb23f93126074ba01410c8a2278c0c 15 | JWT_SIGNING_KEY: "not so secret key" 16 | SECRET_KEY: "not so secret key" 17 | NL_SERVER_URL: https://nlp-staging.almond.stanford.edu 18 | SUPPORTED_LANGUAGES: 19 | - en-US 20 | - it-IT 21 | - zh-CN 22 | - zh-TW 23 | USE_BRAND: stanford 24 | 25 | ABOUT_OVERRIDE: 26 | index: stanford/about_index.pug 27 | tos: stanford/about_tos.pug 28 | privacy: stanford/about_privacy.pug 29 | 30 | EXTRA_ABOUT_PAGES: 31 | - url: get-almond 32 | view: stanford/about_get_almond.pug 33 | title: "Get Almond" 34 | - url: get-involved 35 | view: stanford/about_get_involved.pug 36 | title: "Get Involved With Almond" 37 | 38 | EXTRA_NAVBAR: 39 | - url: https://oval.cs.stanford.edu 40 | title: "OVAL Lab" 41 | 42 | DISCOURSE_SSO_REDIRECT: https://discourse.almond.stanford.edu -------------------------------------------------------------------------------- /tests/thingpedia-integration/k8s/controller/crd/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - backend.almond.stanford.edu_users.yaml -------------------------------------------------------------------------------- /tests/thingpedia-integration/k8s/controller/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1alpha1 2 | kind: Component 3 | 4 | bases: 5 | - crd 6 | - rbac 7 | - manager -------------------------------------------------------------------------------- /tests/thingpedia-integration/k8s/controller/manager/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - manager.yaml 3 | -------------------------------------------------------------------------------- /tests/thingpedia-integration/k8s/controller/rbac/auth_proxy_client_clusterrole.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | name: metrics-reader 5 | rules: 6 | - nonResourceURLs: 7 | - "/metrics" 8 | verbs: 9 | - get 10 | -------------------------------------------------------------------------------- /tests/thingpedia-integration/k8s/controller/rbac/auth_proxy_role.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: Role 3 | metadata: 4 | name: proxy-role 5 | rules: 6 | - apiGroups: 7 | - authentication.k8s.io 8 | resources: 9 | - tokenreviews 10 | verbs: 11 | - create 12 | - apiGroups: 13 | - authorization.k8s.io 14 | resources: 15 | - subjectaccessreviews 16 | verbs: 17 | - create 18 | -------------------------------------------------------------------------------- /tests/thingpedia-integration/k8s/controller/rbac/auth_proxy_role_binding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: RoleBinding 3 | metadata: 4 | name: proxy-rolebinding 5 | roleRef: 6 | apiGroup: rbac.authorization.k8s.io 7 | kind: Role 8 | name: proxy-role 9 | subjects: 10 | - kind: ServiceAccount 11 | name: controller-manager 12 | -------------------------------------------------------------------------------- /tests/thingpedia-integration/k8s/controller/rbac/auth_proxy_service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | labels: 5 | control-plane: controller-manager 6 | name: controller-manager-metrics-service 7 | spec: 8 | ports: 9 | - name: https 10 | port: 8443 11 | targetPort: https 12 | selector: 13 | control-plane: controller-manager 14 | -------------------------------------------------------------------------------- /tests/thingpedia-integration/k8s/controller/rbac/controller_manager_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions for end users to edit users. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: Role 4 | metadata: 5 | name: controller-manager-role 6 | rules: 7 | - apiGroups: 8 | - apps 9 | - "" 10 | resources: 11 | - deployments 12 | - services 13 | verbs: 14 | - create 15 | - delete 16 | - get 17 | - list 18 | - patch 19 | - update 20 | - watch 21 | -------------------------------------------------------------------------------- /tests/thingpedia-integration/k8s/controller/rbac/controller_manager_role_binding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: RoleBinding 3 | metadata: 4 | name: controller-manager-rolebinding 5 | roleRef: 6 | apiGroup: rbac.authorization.k8s.io 7 | kind: Role 8 | name: controller-manager-role 9 | subjects: 10 | - kind: ServiceAccount 11 | name: controller-manager 12 | -------------------------------------------------------------------------------- /tests/thingpedia-integration/k8s/controller/rbac/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | # All RBAC will be applied under this service account in 3 | # the deployment namespace. You may comment out this resource 4 | # if your manager will use a service account that exists at 5 | # runtime. Be sure to update RoleBinding and ClusterRoleBinding 6 | # subjects if changing service account names. 7 | - service_account.yaml 8 | - role.yaml 9 | - role_binding.yaml 10 | - leader_election_role.yaml 11 | - leader_election_role_binding.yaml 12 | # Comment the following 4 lines if you want to disable 13 | # the auth proxy (https://github.com/brancz/kube-rbac-proxy) 14 | # which protects your /metrics endpoint. 15 | - auth_proxy_service.yaml 16 | - auth_proxy_role.yaml 17 | - auth_proxy_role_binding.yaml 18 | - auth_proxy_client_clusterrole.yaml 19 | - user_editor_role.yaml 20 | - user_editor_role_binding.yaml 21 | - controller_manager_role.yaml 22 | - controller_manager_role_binding.yaml 23 | -------------------------------------------------------------------------------- /tests/thingpedia-integration/k8s/controller/rbac/leader_election_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions to do leader election. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: Role 4 | metadata: 5 | name: leader-election-role 6 | rules: 7 | - apiGroups: 8 | - "" 9 | resources: 10 | - configmaps 11 | verbs: 12 | - get 13 | - list 14 | - watch 15 | - create 16 | - update 17 | - patch 18 | - delete 19 | - apiGroups: 20 | - coordination.k8s.io 21 | resources: 22 | - leases 23 | verbs: 24 | - get 25 | - list 26 | - watch 27 | - create 28 | - update 29 | - patch 30 | - delete 31 | - apiGroups: 32 | - "" 33 | resources: 34 | - events 35 | verbs: 36 | - create 37 | - patch 38 | -------------------------------------------------------------------------------- /tests/thingpedia-integration/k8s/controller/rbac/leader_election_role_binding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: RoleBinding 3 | metadata: 4 | name: leader-election-rolebinding 5 | roleRef: 6 | apiGroup: rbac.authorization.k8s.io 7 | kind: Role 8 | name: leader-election-role 9 | subjects: 10 | - kind: ServiceAccount 11 | name: controller-manager 12 | -------------------------------------------------------------------------------- /tests/thingpedia-integration/k8s/controller/rbac/role.yaml: -------------------------------------------------------------------------------- 1 | 2 | --- 3 | apiVersion: rbac.authorization.k8s.io/v1 4 | kind: Role 5 | metadata: 6 | creationTimestamp: null 7 | name: manager-role 8 | rules: 9 | - apiGroups: 10 | - "" 11 | resources: 12 | - endpoints 13 | verbs: 14 | - get 15 | - list 16 | - watch 17 | - apiGroups: 18 | - backend.almond.stanford.edu 19 | resources: 20 | - users 21 | verbs: 22 | - create 23 | - delete 24 | - get 25 | - list 26 | - patch 27 | - update 28 | - watch 29 | - apiGroups: 30 | - backend.almond.stanford.edu 31 | resources: 32 | - users/finalizers 33 | verbs: 34 | - update 35 | - apiGroups: 36 | - backend.almond.stanford.edu 37 | resources: 38 | - users/status 39 | verbs: 40 | - get 41 | - patch 42 | - update 43 | -------------------------------------------------------------------------------- /tests/thingpedia-integration/k8s/controller/rbac/role_binding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: RoleBinding 3 | metadata: 4 | name: manager-rolebinding 5 | roleRef: 6 | apiGroup: rbac.authorization.k8s.io 7 | kind: Role 8 | name: manager-role 9 | subjects: 10 | - kind: ServiceAccount 11 | name: controller-manager 12 | -------------------------------------------------------------------------------- /tests/thingpedia-integration/k8s/controller/rbac/service_account.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: controller-manager 5 | -------------------------------------------------------------------------------- /tests/thingpedia-integration/k8s/controller/rbac/user_editor_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions for end users to edit users. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: Role 4 | metadata: 5 | name: user-editor-role 6 | rules: 7 | - apiGroups: 8 | - backend.almond.stanford.edu 9 | resources: 10 | - users 11 | verbs: 12 | - create 13 | - delete 14 | - get 15 | - list 16 | - patch 17 | - update 18 | - watch 19 | - apiGroups: 20 | - backend.almond.stanford.edu 21 | resources: 22 | - users/status 23 | verbs: 24 | - get 25 | -------------------------------------------------------------------------------- /tests/thingpedia-integration/k8s/controller/rbac/user_editor_role_binding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: RoleBinding 3 | metadata: 4 | name: user-editor-rolebinding 5 | roleRef: 6 | apiGroup: rbac.authorization.k8s.io 7 | kind: Role 8 | name: user-editor-role 9 | subjects: 10 | - kind: ServiceAccount 11 | name: default-editor 12 | -------------------------------------------------------------------------------- /tests/thingpedia-integration/k8s/controller/rbac/user_viewer_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions for end users to view users. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: Role 4 | metadata: 5 | name: user-viewer-role 6 | rules: 7 | - apiGroups: 8 | - backend.almond.stanford.edu 9 | resources: 10 | - users 11 | verbs: 12 | - get 13 | - list 14 | - watch 15 | - apiGroups: 16 | - backend.almond.stanford.edu 17 | resources: 18 | - users/status 19 | verbs: 20 | - get 21 | -------------------------------------------------------------------------------- /tests/thingpedia-integration/k8s/database/create-db.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: batch/v1 2 | kind: Job 3 | metadata: 4 | name: create-db 5 | spec: 6 | backoffLimit: 0 7 | template: 8 | spec: 9 | restartPolicy: Never 10 | containers: 11 | - name: create-db 12 | image: mariadb:10.2.22 13 | command: 14 | - /bin/bash 15 | - -c 16 | - | 17 | set -ex 18 | while ! mysqladmin ping -h mariadb --silent; do 19 | sleep 1 20 | done 21 | mysql -h mariadb -ppassword -e "create database if not exists thingengine_test;" 22 | -------------------------------------------------------------------------------- /tests/thingpedia-integration/k8s/database/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1alpha1 2 | kind: Component 3 | 4 | resources: 5 | - mariadb.yaml 6 | - create-db.yaml 7 | -------------------------------------------------------------------------------- /tests/thingpedia-integration/k8s/database/mariadb.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: mariadb 5 | spec: 6 | replicas: 1 7 | selector: 8 | matchLabels: 9 | app: mariadb 10 | template: 11 | metadata: 12 | labels: 13 | app: mariadb 14 | spec: 15 | containers: 16 | - env: 17 | - name: MYSQL_ROOT_PASSWORD 18 | value: password 19 | image: mariadb:10.2.22 20 | imagePullPolicy: IfNotPresent 21 | name: mariadb 22 | ports: 23 | - containerPort: 3306 24 | protocol: TCP 25 | --- 26 | apiVersion: v1 27 | kind: Service 28 | metadata: 29 | name: mariadb 30 | spec: 31 | ports: 32 | - port: 3306 33 | targetPort: 3306 34 | selector: 35 | app: mariadb 36 | -------------------------------------------------------------------------------- /tests/thingpedia-integration/k8s/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1alpha1 2 | kind: Component 3 | 4 | resources: 5 | - sa.yaml 6 | - dbproxy.yaml 7 | - shared-backend.yaml 8 | - frontend.yaml 9 | 10 | components: 11 | - controller 12 | 13 | configMapGenerator: 14 | - name: almond-config 15 | files: 16 | - config.d/config.yaml 17 | - name: manager-config 18 | files: 19 | - manager-config/developer-deployment.json 20 | - manager-config/developer-service.json 21 | -------------------------------------------------------------------------------- /tests/thingpedia-integration/k8s/manager-config/developer-service.json: -------------------------------------------------------------------------------- 1 | { 2 | "apiVersion": "v1", 3 | "kind": "Service", 4 | "metadata": { 5 | "labels": { 6 | "app": "" 7 | }, 8 | "name": "", 9 | "namespace": "default" 10 | }, 11 | "spec": { 12 | "ports": [ 13 | { 14 | "port": 8100, 15 | "protocol": "TCP", 16 | "targetPort": 8100 17 | } 18 | ], 19 | "selector": { 20 | "app": "" 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tests/thingpedia-integration/k8s/sa.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: default-editor 5 | -------------------------------------------------------------------------------- /tests/thingpedia-integration/k8s/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -ex 3 | 4 | cd /home/almond-cloud 5 | /opt/almond-cloud/dist/main.js "$@" & 6 | pid=$! 7 | echo $pid > /home/almond-cloud/pid 8 | wait $pid -------------------------------------------------------------------------------- /tests/thingpedia-integration/setup-integration.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -ex 4 | srcdir=`dirname $0`/../.. 5 | srcdir=`realpath $srcdir` 6 | cd $srcdir 7 | 8 | docker build -f docker/Dockerfile -t localhost/almond-cloud . 9 | docker build -f tests/thingpedia-integration/Dockerfile -t localhost/almond-test . 10 | kind create cluster --config=$srcdir/tests/thingpedia-integration/k8s/cluster.yaml 11 | kind load docker-image localhost/almond-test 12 | kustomize build $srcdir/tests/thingpedia-integration/k8s/database | kubectl apply -f - 13 | kubectl wait --timeout=120s --for=condition=complete job/create-db 14 | kustomize build $srcdir/tests/thingpedia-integration/k8s | kubectl apply -f - 15 | kubectl wait --timeout=120s --for=condition=Available deployment/frontend -------------------------------------------------------------------------------- /tests/util/csrf.js: -------------------------------------------------------------------------------- 1 | // -*- mode: js; indent-tabs-mode: nil; js-basic-offset: 4 -*- 2 | // 3 | // This file is part of Almond 4 | // 5 | // Copyright 2019 The Board of Trustees of the Leland Stanford Junior University 6 | // 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | // 11 | // http://www.apache.org/licenses/LICENSE-2.0 12 | // 13 | // Unless required by applicable law or agreed to in writing, software 14 | // distributed under the License is distributed on an "AS IS" BASIS, 15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | // See the License for the specific language governing permissions and 17 | // limitations under the License. 18 | // 19 | // Author: Giovanni Campagna 20 | 21 | import * as minidom from './minidom'; 22 | 23 | function getCsrfToken(htmlString) { 24 | const [body] = minidom.getElementsByTagName(minidom.parse(htmlString), 'body'); 25 | return minidom.getAttribute(body, 'data-csrf-token'); 26 | } 27 | 28 | export { getCsrfToken }; 29 | -------------------------------------------------------------------------------- /tmp/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/tmp/.gitkeep -------------------------------------------------------------------------------- /travis/docker-build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | set -x 5 | 6 | cd docker 7 | 8 | export DOCKERFILE_PATH=docker/Dockerfile 9 | export DOCKER_REPO=stanfordoval/almond-cloud 10 | 11 | export IMAGE_NAME=stanfordoval/almond-cloud:latest 12 | ./hooks/build 13 | docker push $IMAGE_NAME 14 | ./hooks/post_push 15 | -------------------------------------------------------------------------------- /travis/id_rsa.autodeploy.enc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-oval/genie-cloud/95744da7aec789359093689704f4e2a989de1600/travis/id_rsa.autodeploy.enc -------------------------------------------------------------------------------- /travis/install-webalmond-deps.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | set -x 5 | 6 | mkdir geckodriver/ 7 | wget https://github.com/mozilla/geckodriver/releases/download/v0.22.0/geckodriver-v0.22.0-linux64.tar.gz 8 | tar xvf geckodriver-v0.22.0-linux64.tar.gz -C geckodriver/ 9 | 10 | sudo add-apt-repository -y ppa:openstack-ci-core/bubblewrap 11 | sudo apt-get update -q -y 12 | sudo apt-get install -y graphicsmagick libsystemd-dev bubblewrap python3 13 | 14 | mysql -u root -e " 15 | create database if not exists thingengine_test; 16 | grant all privileges on thingengine_test.* to 'thingengine'@'%' identified by 'thingengine'; 17 | " 18 | -------------------------------------------------------------------------------- /travis/unlock-key.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | srcdir=`dirname $0` 5 | 6 | if test "$TRAVIS_REPO_SLUG" != "stanford-oval/almond-cloud" ; then 7 | exit 0 8 | fi 9 | if test "$TRAVIS_PULL_REQUEST" != "false" ; then 10 | exit 0 11 | fi 12 | 13 | echo "Unlocking Travis autodeploy key..." 14 | openssl aes-256-cbc \ 15 | -K $encrypted_6dd165f04fd2_key -iv $encrypted_6dd165f04fd2_iv \ 16 | -in $srcdir/id_rsa.autodeploy.enc \ 17 | -out $srcdir/id_rsa.autodeploy \ 18 | -d 19 | chmod 0600 $srcdir/id_rsa.autodeploy 20 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "src/**/*" 4 | ], 5 | "compilerOptions": { 6 | "target": "es2019", 7 | "lib": ["es2020"], 8 | "module": "commonjs", 9 | "allowJs": true, 10 | "esModuleInterop": true, 11 | "moduleResolution": "node", 12 | "resolveJsonModule": true, 13 | "strict": true, 14 | "noUnusedLocals": true, 15 | "outDir": "dist", 16 | "sourceMap": true, 17 | "incremental": true, 18 | "declaration": false 19 | }, 20 | "typedocOptions": { 21 | "out": "jsdoc", 22 | "readme": "README.md", 23 | "includeVersion": true, 24 | "excludeExternals": true, 25 | "listInvalidSymbolLinks": true 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /views/2fa_login.pug: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block page_name 4 | = _("Login") 5 | 6 | block content 7 | each error in errors 8 | div.alert.alert-danger.alert-dismissible.fade.in(role='alert') 9 | button(type='button', data-dismiss='alert', aria-label="Close").close 10 | span(aria-hidden='true') × 11 | 12 | p= error 13 | p= _("You have configured two-factor authentication for this user. Please enter the One Time Password generated from your Authenticator app.") 14 | form(action='/user/2fa/login', method='post') 15 | input(type='hidden',name='_csrf',value=csrfToken) 16 | div.form-group 17 | label(for='twofa-code').control-label= _("OTP") 18 | input(type='text',name='code').form-control#twofa-code 19 | div.form-group 20 | div.checkbox 21 | label 22 | input(type='checkbox',name='remember_me',value='1',checked=false) 23 | = _("Remember me on this computer.") 24 | div.form-group 25 | button(type='submit').btn.btn-primary= _("Log in") 26 | 27 | p= _("Having trouble? If you have lost access to your authenticator app, please contact us to regain access to your account.") 28 | -------------------------------------------------------------------------------- /views/about_privacy.pug: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block page_name 4 | = _("Privacy Policy") 5 | 6 | block content 7 | div.alert.alert-danger(role='alert') 8 | | This page is empty! The website administrator has not added content here. 9 | -------------------------------------------------------------------------------- /views/about_tos.pug: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block page_name 4 | = _("Terms & Conditions") 5 | 6 | block content 7 | div.alert.alert-danger(role='alert') 8 | | This page is empty! The website administrator has not added content here. 9 | -------------------------------------------------------------------------------- /views/blog_archive.pug: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block page_name 4 | = _("Genie News") 5 | 6 | block content 7 | for post in posts.slice(0, 10) 8 | div.blog-post-ref 9 | div.media 10 | div.media-left 11 | img(src=post.image, role='presentation').media-object 12 | div.media-body 13 | h2.media-heading 14 | if post.link.startsWith('/') 15 | a(href=post.link)= post.title 16 | else 17 | a(href=post.link,rel='noopener')= post.title 18 | p= post.blurb 19 | 20 | p 21 | small 22 | if post.author_name 23 | = _("By %s. ").format(post.author_name) 24 | = _("Published %s.").format(post.pub_date.toLocaleString(locale, { timeZone: timezone, year: 'numeric', month: 'long', day: 'numeric' })) 25 | 26 | nav 27 | ul.pager 28 | if page_num > 0 29 | li 30 | a(href='/blog?page=' + (page_num-1))= _("Previous") 31 | if posts.length > 10 32 | li 33 | a(href='/blog?page=' + (page_num+1))= _("Next") 34 | -------------------------------------------------------------------------------- /views/blog_home_page.pug: -------------------------------------------------------------------------------- 1 | // section.divider#latest-news 2 | // h3= _("What's new in Genie") 3 | // div.container 4 | // div.row 5 | // for post in news 6 | // div.col-md-4 7 | // img(src=post.image, role='presentation').img-responsive 8 | // h4= post.title 9 | // p= post.blurb 10 | // p 11 | // a(href=post.link)= _("Read more") 12 | // p.text-center 13 | // a(href='/blog')= _("More news...") 14 | -------------------------------------------------------------------------------- /views/blog_post.pug: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block page_name 4 | - var index = true; 5 | = _("Genie Blog") 6 | 7 | block content 8 | div.row 9 | div.col-lg-8.col-lg-offset-2.blog-post 10 | h1 11 | = post.title 12 | | 13 | | 14 | small 15 | a(aria-label=_("Permalink"),title=_("Permalink"),href='/blog/' + post.id + '-' + post.slug) # 16 | hr 17 | img(role='presentation', src=post.image).img-responsive.cover-photo 18 | 19 | p.byline 20 | if post.pub_date === null 21 | = _("By %s. Not published yet.").format(post.author_name) 22 | else if +post.upd_date == +post.pub_date 23 | = _("By %s. Published %s.").format(post.author_name, post.pub_date.toLocaleString(locale, { timeZone: timezone, year: 'numeric', month: 'short', day: 'numeric', hour: 'numeric', minute: 'numeric' })) 24 | else 25 | = _("By %s. Published %s, updated %s.").format(post.author_name, post.pub_date.toLocaleString(locale, { timeZone: timezone, year: 'numeric', month: 'short', day: 'numeric', hour: 'numeric', minute: 'numeric' }), post.upd_date.toLocaleString(locale, { timeZone: timezone, year: 'numeric', month: 'short', day: 'numeric', hour: 'numeric', minute: 'numeric' })) 26 | 27 | != post.body 28 | 29 | if authenticated && (user.roles & Constants.Role.BLOG_EDITOR) 30 | p 31 | a(href='/admin/blog/update/' + post.id).btn.btn-default= _("Edit") 32 | -------------------------------------------------------------------------------- /views/dev_overview.pug: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block styles 4 | link(rel='stylesheet', href=Config.ASSET_CDN + '/stylesheets/thingpedia.css') 5 | link(rel='stylesheet', href=Config.ASSET_CDN + '/stylesheets/dev_sidebar.css') 6 | 7 | block scripts 8 | script(src=Config.ASSET_CDN + '/javascripts/device.js') 9 | 10 | block page_name 11 | - stdlayout = false; 12 | - var section = 'overview'; 13 | = _("Developer Console") 14 | 15 | block content 16 | div.container-fluid#page-body 17 | div.row 18 | div.col-lg-3.col-md-4 19 | include dev_sidebar 20 | 21 | div.col-xs-12.col-md-8.col-lg-9 22 | include dev_console 23 | -------------------------------------------------------------------------------- /views/dev_sidebar.pug: -------------------------------------------------------------------------------- 1 | nav#doc-sidebar 2 | ul 3 | li(class=(section === 'overview' ? 'current' : '')) 4 | a.doc-sidebar-subtitle(href='/developers')= _("Overview") 5 | li(class = (section === 'status' ? 'current' : '')) 6 | a.doc-sidebar-subtitle(href='/me/status')= _("Genie Status and Logs") 7 | if user.developer_org !== null 8 | if Config.WITH_THINGPEDIA === 'embedded' 9 | li(class=(section === 'devices' ? 'current' : '')) 10 | a.doc-sidebar-subtitle(href='/developers/devices')= _("Thingpedia Devices") 11 | li(class=(section === 'oauth' ? 'current' : '')) 12 | a.doc-sidebar-subtitle(href='/developers/oauth')= _("OAuth Applications") 13 | if Config.WITH_LUINET === 'embedded' 14 | //-li(class=(section === 'mturk' ? 'current' : '')) 15 | a.doc-sidebar-subtitle(href='/developers/mturk')= _("MTurk Paraphrasing (Beta)") 16 | 17 | 18 | -------------------------------------------------------------------------------- /views/developer_access_ok.pug: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block content 4 | h1= _("Success") 5 | 6 | p= _("Your developer organization has been created. You can now start contributing!") 7 | p 8 | a(href='/developers').btn.btn-primary= _("Go to my developer console") 9 | -------------------------------------------------------------------------------- /views/device_selector.pug: -------------------------------------------------------------------------------- 1 | mixin device_selector(id, name, title, helptext) 2 | section.device-selector(id=id) 3 | div.form-group.fallback 4 | label(for=id + '-fallback').control-label= title 5 | input(type='text',name=name, id=id + '-fallback').form-control 6 | span.help-block= helptext 7 | div.panel.panel-default 8 | div.panel-heading 9 | h4.panel-title= title 10 | div.panel-body 11 | span.help-block= helptext 12 | 13 | h5= _("Selected") 14 | ul.list-group.selected-devices 15 | 16 | h5= _("Add new") 17 | input(type='text', placeholder=_("Type to search…"), aria-label=_("Name of the new device")).form-control.search-bar 18 | div.list-group.add-new-devices 19 | -------------------------------------------------------------------------------- /views/devices_create.pug: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block scripts 4 | script(src=Config.ASSET_CDN + '/javascripts/devices-create.js') 5 | 6 | block page_name 7 | = _("New Skill") 8 | 9 | block content 10 | p= _("What skill do you want to set up?") 11 | div#online-account-selector.container 12 | -------------------------------------------------------------------------------- /views/email_verified.pug: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block page_name 4 | - index = true; 5 | | Genie 6 | 7 | block content 8 | div.jumbotron.text-center 9 | h1= _("Welcome to Genie, %s!").format(user.username) 10 | 11 | p 12 | = _("Thank you for verifying your email. You can now use the full functionality of your account.") 13 | 14 | p 15 | a(href='/me').btn.btn-primary= _("Go to My Genie") 16 | //-| 17 | //-a(href='https://play.google.com/store/apps/details?id=edu.stanford.thingengine.engine').btn.btn-primary= _("Download The Android App") 18 | //-a(href='https://crowdie.stanford.edu/flatpak/edu.stanford.Genie.flatpakref').btn.btn-primary= _("Download Genie On Your PC") 19 | -------------------------------------------------------------------------------- /views/error.pug: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block page_name 4 | = _("Error") 5 | 6 | block content 7 | div.msg-container 8 | div.msg-left-block 9 | img.msg-image(src=Config.ASSET_CDN + '/images/almond_error.png') 10 | div.msg-right-block 11 | div.msg-title 12 | h2.p= _("Sorry that did not work") 13 | div.msg-body 14 | if typeof message === 'string' 15 | h3.p= message 16 | else if message.name === 'SyntaxError' 17 | h3.p= _("Syntax error at %s line %d: %s").format(message.fileName, message.lineNumber, message.message) 18 | else if message.message 19 | h3.p= message.message 20 | else 21 | h3.p= String(message) 22 | div.msg-button 23 | a(href='javascript:history.back()').btn.btn-primary.custom-btn= _("Go back") -------------------------------------------------------------------------------- /views/login.pug: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block page_name 4 | = _("Login") 5 | 6 | block content 7 | each error in errors 8 | div.alert.alert-danger.alert-dismissible.fade.in(role='alert') 9 | button(type='button', data-dismiss='alert', aria-label="Close").close 10 | span(aria-hidden='true') × 11 | 12 | p= error 13 | form(action='/user/login', method='post') 14 | input(type='hidden',name='_csrf',value=csrfToken) 15 | div.form-group 16 | label(for='username').control-label= _("Username") 17 | input(type='text',name='username',autocorrect='off',autocapitalize='none').form-control#username 18 | div.form-group 19 | label(for='password').control-label= _("Password") 20 | input(type='password',name='password').form-control#password 21 | div.form-group 22 | button(type='submit').btn.btn-primary.custom-btn= _("Log in") 23 | 24 | p= _("Don't have a username and password yet? ") 25 | a.dont(href='/user/register')= _("Sign up now!") 26 | p 27 | a(href='/user/recovery/start')= _("I forgot my password") 28 | if Config.GOOGLE_CLIENT_ID 29 | p 30 | a.btn.btn-primary.custom-btn(href='/user/oauth2/google')= _("Log In with Google") 31 | if Config.GITHUB_CLIENT_ID 32 | p 33 | a.btn.btn-primary.custom-btn(href='/user/oauth2/github')= _("Log In with Github") 34 | -------------------------------------------------------------------------------- /views/login_required.pug: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block page_name 4 | = _("Error") 5 | 6 | block content 7 | div.msg-container 8 | div.msg-left-block 9 | img.msg-image(src=Config.ASSET_CDN + '/images/almond_error.png') 10 | div.msg-right-block 11 | div.msg-title 12 | h2.p=_("Login required") 13 | div.msg-body 14 | h3.p=_("Sorry but you must log in before opening this page.") 15 | div.msg-button 16 | a(href='/user/login').btn.btn-primary=_("Log in") 17 | -------------------------------------------------------------------------------- /views/luinet_dataset_list.pug: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block page_name 4 | = _("Datasets") 5 | 6 | block styles 7 | link(rel='stylesheet', href=Config.ASSET_CDN + '/stylesheets/thingpedia.css') 8 | 9 | block content 10 | table.table 11 | thead 12 | tr 13 | th= _("Language") 14 | th= _("Type") 15 | th= _("Size") 16 | tbody 17 | for set in datasets 18 | tr 19 | td= set.language 20 | td 21 | a(href='/luinet/datasets/' + set.language + '/' + set.type)= set.type 22 | td= set.size 23 | -------------------------------------------------------------------------------- /views/message.pug: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block page_name 4 | = _("Success") 5 | 6 | block content 7 | p= message 8 | p 9 | a(href='/').btn.btn-primary= _("Go to the home page") 10 | -------------------------------------------------------------------------------- /views/mturk-submit.pug: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block styles 4 | link(rel='stylesheet', href=Config.ASSET_CDN + '/stylesheets/mturk.css') 5 | 6 | block page_name 7 | = _('Thank You!') 8 | 9 | block content 10 | div#message 11 | p= _("You paraphrases has been submitted. Thank you a lot for contributing to Genie. We will mark your submission once we finish this batch.") 12 | p= _("Here is your submission code. Make sure you copy and paste it into your Mechanical Turk submission.") 13 | div#token 14 | pre= token 15 | 16 | -------------------------------------------------------------------------------- /views/my_conversation.pug: -------------------------------------------------------------------------------- 1 | extends layout 2 | include ./conversation_mixin 3 | 4 | block scripts 5 | script(src=Config.ASSET_CDN + '/javascripts/conversation-bundle.js') 6 | 7 | block styles 8 | link(rel='stylesheet', href=Config.ASSET_CDN + '/stylesheets/spinner.css') 9 | link(rel='stylesheet', href=Config.ASSET_CDN + '/stylesheets/conversation.css') 10 | 11 | block page_name 12 | = _("Web Genie") 13 | 14 | block content 15 | +conversation_recording_mixin() 16 | +conversation_mixin('/me/ws/conversation')(class='single') 17 | -------------------------------------------------------------------------------- /views/navbar.pug: -------------------------------------------------------------------------------- 1 | ul.nav.navbar-nav 2 | li.hidden-md.hidden-lg.hidden-sm 3 | a(href="/")= _("Home") 4 | for page in Config.EXTRA_NAVBAR 5 | li 6 | a(href=page.url)= _(page.title) 7 | li 8 | a(href=Config.THINGPEDIA_URL)= _("Thingpedia") 9 | li 10 | a(href='https://wiki.almond.stanford.edu')= _("Docs") 11 | 12 | ul.nav.navbar-nav.navbar-right 13 | if authenticated 14 | li 15 | a(href="/me")= _("My Genie") 16 | if authenticated 17 | li 18 | a(href=Config.THINGPEDIA_URL + '/cheatsheet')= _("Cheatsheet") 19 | if authenticated && user.developer_org 20 | li 21 | a(href='/developers')= _("Console") 22 | if authenticated && (user.roles & Constants.Role.ALL_ADMIN) !== 0 23 | li 24 | a(href="/admin")= _("Admin") 25 | if authenticated 26 | li 27 | a(href="/user/profile")= _("Settings") 28 | li 29 | if authenticated 30 | a.navbar-login#navbar-login-button(href='/user/logout')= _("Log Out") 31 | else 32 | a.navbar-login#navbar-login-button(href='/user/login')= _("Log In") 33 | -------------------------------------------------------------------------------- /views/password_recovery_start.pug: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block page_name 4 | = _("Password Reset") 5 | 6 | block content 7 | p= _("To reset your Genie password, please enter your username. An email with instructions will be sent to the address associated with it.") 8 | form(action='/user/recovery/start', method='post', data-toggle='validator') 9 | input(type='hidden',name='_csrf',value=csrfToken) 10 | div.form-group 11 | label(for='username').control-label= _("Username") 12 | input(type='text',name='username',value='',required=true,maxlength=255,autocorrect='off',autocapitalize='none').form-control#username 13 | div.form-group 14 | button(type='submit').btn.btn-primary.custom-btn= _("Reset Password") 15 | -------------------------------------------------------------------------------- /views/proxy_confirmation.pug: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block content 4 | div.container.panel.panel-body.panel-default.oauth-pan 5 | section.divider#request-info 6 | h2= _("OAuth request for: ") 7 | span= _(" ") 8 | h3=kind 9 | span= _(" ") 10 | h2= _("from: ") 11 | h3=redirect_address 12 | 13 | br 14 | p.text-center 15 | = _('Are you sure you would like to grant %s access to the credentials of device: %s').format(redirect_address, kind) 16 | br 17 | div.text-center 18 | div.oa-col-left 19 | form(action='/proxy/oauth2', method='post').form-inline 20 | input(type='hidden',name='_csrf',value=csrfToken) 21 | input(type='hidden',name='device_type',value=kind) 22 | button(type='submit').btn.btn-primary.custom-btn= _("Continue") 23 | 24 | div.oa-col-right 25 | p.text-center 26 | a.btn.btn-primary.custom-btn(href=redirect_address)= _("Cancel") 27 | -------------------------------------------------------------------------------- /views/public_user_profile.pug: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block styles 4 | link(rel='stylesheet', href=Config.ASSET_CDN + '/stylesheets/profiles.css') 5 | 6 | block page_name 7 | if profile.human_name && (profile.profile_flags & Constants.ProfileFlags.SHOW_HUMAN_NAME) 8 | = _("User: %s (%s)").format(profile.human_name, profile.username) 9 | else 10 | = _("User: %s").format(profile.username) 11 | 12 | block content 13 | div.row 14 | div.col-md-4 15 | img(src=profile.profile_pic_url, alt=_("Profile picture of %s").format(profile.username)).img-responsive.img-rounded#user-profile-pic 16 | 17 | div.col-md-8 18 | if profile.developer_org !== null 19 | p 20 | = _("Member of ") 21 | a(href='/profiles/organization/' + profile.developer_org_id_hash)= profile.developer_org_name -------------------------------------------------------------------------------- /views/qrcode.pug: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block page_name 4 | - index = true; 5 | = _("Error") 6 | 7 | block content 8 | h2= _("This is not the page you're looking for") 9 | 10 | if for_ === 'cloud' && authenticated && user.auth_token !== authToken 11 | p 12 | strong= _("You should not have this link.") 13 | = _(" This is a pairing link for a different Genie account than yours.") 14 | p 15 | = _("If you obtained it by mistake, you should destroy it immediately by clearing the browser history and cache, and you should contact whoever gave this link that they risk having their account compromised.") 16 | 17 | else 18 | p= _("You must open the QR code link with the Genie app, not with your browser.") 19 | 20 | if for_ === 'cloud' 21 | if !authenticated 22 | p!= _("If you were trying to link your Genie account to your phone, you should log in first.") 23 | -------------------------------------------------------------------------------- /views/register.pug: -------------------------------------------------------------------------------- 1 | extends layout 2 | include ./register_mixins 3 | 4 | block scripts 5 | script(src=Config.ASSET_CDN + '/javascripts/register.js') 6 | 7 | block page_name 8 | = _("Register") 9 | 10 | block content 11 | div.row 12 | div.col-lg-6.col-lg-offset-3.col-md-6.col-md-offset-3.col-sm-8.col-sm-offset-2 13 | if error 14 | div.alert.alert-danger.alert-dismissible.fade.in(role='alert') 15 | button(type='button', data-dismiss='alert', aria-label="Close").close 16 | span(aria-hidden='true') × 17 | if typeof error === 'string' 18 | p= error 19 | else if error.message 20 | p= error.message 21 | else 22 | p= String(error) 23 | 24 | +registration_form(true) 25 | -------------------------------------------------------------------------------- /views/thingpedia_cheatsheet.pug: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block styles 4 | link(rel='stylesheet', href=Config.ASSET_CDN + '/stylesheets/thingpedia-cheatsheet.css') 5 | 6 | block scripts 7 | script(src="https://unpkg.com/packery@2/dist/packery.pkgd.min.js") 8 | 9 | block page_name 10 | = _("Genie Cheatsheet") 11 | 12 | block content 13 | div.grid(data-packery='{ "itemSelector": ".grid-item", "gutter": 10 }')#cheatsheet 14 | mixin do_command(e) 15 | span(title=e.target_code) 16 | if e.type === 'stream' 17 | span.trigger= _("WHEN: ") 18 | else if e.type === 'query' 19 | span.query= _("GET: ") 20 | else if e.type === 'action' 21 | span.action= _("DO: ") 22 | for chunk in e.utterance_chunks 23 | if typeof chunk === 'string' 24 | = chunk 25 | else 26 | - var [match, param1, param2, opt] = chunk; 27 | if match === '$$' 28 | | $ 29 | else 30 | | ____ #[small= '(' + clean(param1||param2) + ')'] 31 | 32 | each d in devices 33 | if d.examples.length === 0 34 | - continue; 35 | div.grid-item 36 | h3 37 | img(src=CDN_HOST + '/icons/' + d.primary_kind + '.png', alt="Icon for " + d.name) 38 | a(href='/thingpedia/devices/by-id/' + d.primary_kind)= d.name 39 | ul 40 | for ex in d.examples 41 | li 42 | +do_command(ex) 43 | --------------------------------------------------------------------------------