diff --git a/.devcontainer/multicontainer-node/devcontainer.json b/.devcontainer/multicontainer-node/devcontainer.json
new file mode 100644
index 0000000..c556c95
--- /dev/null
+++ b/.devcontainer/multicontainer-node/devcontainer.json
@@ -0,0 +1,39 @@
+{
+ "name": "Node Multi-Container",
+ "dockerComposeFile": ["../../docker-compose.yml"],
+ "service": "node-app",
+ "shutdownAction": "none",
+ "workspaceFolder": "/workspace/src/node",
+
+ // Features to add to the dev container. More info: https://containers.dev/features.
+ // "features": {},
+
+ // Configure tool-specific properties.
+ "customizations": {
+ // Configure properties specific to VS Code.
+ "vscode": {
+ "settings": {},
+ "extensions": [
+ "streetsidesoftware.code-spell-checker"
+ ]
+ }
+ },
+
+ // Use 'forwardPorts' to make a list of ports inside the container available locally.
+ // "forwardPorts": [3000],
+
+ // Use 'portsAttributes' to set default properties for specific forwarded ports.
+ // More info: https://containers.dev/implementors/json_reference/#port-attributes
+ "portsAttributes": {
+ "3000": {
+ "label": "Hello Remote World",
+ "onAutoForward": "notify"
+ }
+ },
+
+ // Use 'postCreateCommand' to run commands after the container is created.
+ "postCreateCommand": "yarn install"
+
+ // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
+ // "remoteUser": "root"
+}
diff --git a/.devcontainer/multicontainer-python/devcontainer.json b/.devcontainer/multicontainer-python/devcontainer.json
new file mode 100644
index 0000000..59cd7ca
--- /dev/null
+++ b/.devcontainer/multicontainer-python/devcontainer.json
@@ -0,0 +1,39 @@
+{
+ "name": "Python Multi-Container",
+ "dockerComposeFile": ["../../docker-compose.yml"],
+ "service": "python-api",
+ "shutdownAction": "none",
+ "workspaceFolder": "/workspace/src/python",
+
+ // Features to add to the dev container. More info: https://containers.dev/features.
+ // "features": {},
+
+ // Configure tool-specific properties.
+ "customizations": {
+ // Configure properties specific to VS Code.
+ "vscode": {
+ "settings": {},
+ "extensions": [
+ "streetsidesoftware.code-spell-checker"
+ ]
+ }
+ },
+
+ // Use 'forwardPorts' to make a list of ports inside the container available locally.
+ // "forwardPorts": [9000],
+
+ // Use 'portsAttributes' to set default properties for specific forwarded ports.
+ // More info: https://containers.dev/implementors/json_reference/#port-attributes
+ "portsAttributes": {
+ "9000": {
+ "label": "Hello Remote World",
+ "onAutoForward": "notify"
+ }
+ },
+
+ // Use 'postCreateCommand' to run commands after the container is created.
+ "postCreateCommand": "pip3 install -r requirements.txt"
+
+ // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
+ // "remoteUser": "root"
+}
diff --git a/.markdownlint.json b/.markdownlint.json
index 06ac46f..03c2167 100644
--- a/.markdownlint.json
+++ b/.markdownlint.json
@@ -1,5 +1,6 @@
{
"default": true,
+ "MD013": false,
"MD024": { "siblings_only": true },
"MD025": false,
"MD033": false
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..488967a
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,16 @@
+services:
+ python-api:
+ image: mcr.microsoft.com/devcontainers/python:1-3.12-bookworm
+ volumes:
+ # Mount the root folder that contains .git
+ - .:/workspace
+ command: sleep infinity
+ # ...
+
+ node-app:
+ image: mcr.microsoft.com/devcontainers/typescript-node:1-20-bookworm
+ volumes:
+ # Mount the root folder that contains .git
+ - .:/workspace
+ command: sleep infinity
+ # ...
diff --git a/slides/Slides.md b/slides/Slides.md
index cbe0dba..f723f3d 100644
--- a/slides/Slides.md
+++ b/slides/Slides.md
@@ -1,11 +1,12 @@
+---
marp: true
-theme: custom-default
footer: '@Chris_L_Ayers - https://chris-ayers.com'
+theme: custom-default
---
# The Power of Dev Containers and GitHub Codespaces
-### From Local Dev to Cloud Ready: Portable Environments with Dev Containers & Codespaces
+## From Local Dev to Cloud Ready
##  Chris Ayers
@@ -25,462 +26,323 @@ footer: '@Chris_L_Ayers - https://chris-ayers.com'
LinkedIn: - [chris\-l\-ayers](https://linkedin.com/in/chris-l-ayers/)
Blog: [https://chris-ayers\.com/](https://chris-ayers.com/)
GitHub: [Codebytes](https://github.com/codebytes)
- Mastodon: @Chrisayers@hachyderm.io
+ Mastodon: [@Chrisayers@hachyderm.io](https://hachyderm.io/@Chrisayers)
~~ Twitter: @Chris_L_Ayers~~
---
# Agenda
-- Prerequisites
-- What Are Dev Containers?
-- Why Use Dev Containers?
-- How Dev Containers Work
-- How to Build a Dev Container
-- Templates, Features, Customization
+- Why Dev Containers
+- What They Are & How They Work
+- Quick Start & Building
+- Templates vs Features vs Customizations
+- Core Concepts (Image vs Feature vs Template)
- GitHub Codespaces
- Demo
-
----
-
-# Prerequisites
-
-
-
-
-## DevContainers
-
-- VSCode
- - Dev Containers Extension
- - GitHub Codespaces Extension
-- IntelliJ IDEA
-
-
-
-
-
-## Docker
-
-- Docker installed locally
-- Remote Docker host (optional for remote container execution)
-- Other Docker compliant CLIs, installed locally or remotely
-
-
-
-
-## GitHub Codespaces Requirement
-
-- GitHub Account
-- GitHub Codespaces
-
-
+- Advanced: Security, Multi-Service, Prebuilds, Performance & Cost, Debug & Ports, Troubleshooting, Limits
+- Resources & Q&A
---
-# What are Dev Containers?
+# Why Dev Containers?
-- Environments that run in a container
-- Containers that let you open or mount any folder and still use VS Code UI and tooling
-- Places to run Apps, Tools, or Runtimes needed for a project or codebase
-- [Containers.dev](https://containers.dev/) - An open specification for enriching containers with development specific content and settings.
+- Onboard new contributors quickly
+- Consistent tooling and versions for all developers
+- Reduce system conflicts and "works on my machine" issues
+- Secure, isolated environments for development
+- Easy startup tasks and reproducible builds
---
-
-
+# What Are Dev Containers?
-# Why use Dev Containers?
+- Containerized environments for development
+- Let you open any folder in VS Code with all dependencies ready
+- Run apps, tools, or runtimes needed for a project
+- Based on the open [containers.dev](https://containers.dev/) specification
-
-
+---
-- Onboard new People
-- Use consistent tooling
-- Use consistent versions
-- Reduce System Conflicts
-- Perform Startup Tasks
- Improve security via isolation
+# Prerequisites
-
-
+- VS Code (Dev Containers extension, Codespaces extension)
+- Docker (local or remote)
+- GitHub account (for Codespaces)
+- Optionally: IntelliJ IDEA, other containers CLIs like podman
---
-
+# How Dev Containers Work
-# Inner and Outer Loops
+Your editor talks to a containerized environment with all dependencies, keeping your local system clean.
-
+
---
-
+# Building a Dev Container
-# How Dev Containers Work
+From the Command Palette:
-
-
-Your editor talks to a containerized environment with all the dependencies, so your local system stays clean.
+
---
-# Where do Dev Containers Live?
+# Templates, Features, Customizations
-
+- Templates: project bootstrap (scaffold config)
+- Features: add tools/runtimes (idempotent, versioned)
+- Customizations: editor settings, extensions, startup tasks, port forwarding
---
-# Multiple Dev Container Configurations
-
-Tooling supports multiple devcontainers.
-Each one should be in its own subdirectory at:
-
-.devcontainer/SUBDIRECTORY/devcontainer.json.
+# Image vs Feature vs Template
-
+| Concept | When to Use | Change Frequency | Pinning Strategy |
+|---------|-------------|------------------|------------------|
+| Base Image | Need different language/runtime base or OS | Low | Tag (e.g. :1-20-bookworm) or digest |
+| Feature | Add/upgrade a CLI (gh, kubectl), language, or utility | Medium | Major tag (node:1) or minor for guarantees |
+| Template | Starting a new repo / adding devcontainer from scratch | One-off | Template version (commit / release) |
---
-# How do you build a Dev Container?
+# Principles & Practices
-From the Command Pallet
+Principles:
+- Keep Dockerfile minimal; use Features for add-ons
+- Templates are for initial setup, not ongoing changes
+- Prebuild images for slow, shared setup (language servers, SDKs)
-
+Practices:
+- Everyone needs it & rarely changes? → Bake into image/Feature
+- Project-scoped & changes often? → postCreateCommand
+- Personal? → Dotfiles/Settings Sync
---
-# Which Dev Container do I Pick?
+# Managing Extensions Deep Dive
-
+- Add via customizations.vscode.extensions
+- Opt-out: prefix with '-' to remove inherited extension
+- Default extensions (user setting): dev.containers.defaultExtensions
+- Force location (rare): remote.extensionKind overrides
+- Keep lean: only language / tooling essentials; reduces startup & index time
---
-# Templates
+# Extensions Example
-Full List: [https://containers.dev/templates](https://containers.dev/templates)
-
-- Base (Alpine, Debian, Ubuntu)
-- Language Based (C#, C++, Java, Go, Node, Python, Rust, Ruby, PHP)
-- Tool Focused (Markdown, Kubernetes, Docker, Jekyll)
+```json
+"customizations": {
+ "vscode": {
+ "extensions": [
+ "ms-azuretools.vscode-docker",
+ "-dbaeumer.vscode-eslint" // opt-out inherited
+ ]
+ }
+}
+```
---
-# Customizations
+# Port Forwarding
-- Features - Install tools into the container image.
-- Extensions - Install extensions for the editor inside the container.
-- Settings - Configure the editor settings inside the container.
-- Startup Tasks - Run commands when the container starts.
-- Networking - Port Forwarding - Expose ports to the host.
+- Auto port detection: output parsing ("Listening on 3000") triggers forward suggestion
+- forwardPorts: auto-forward on start; portsAttributes: label, onAutoForward, visibility
+- Published vs Forwarded:
+ - Forwarded: appears as localhost to app (ideal for dev auth flows)
+ - Published: network-accessible (team demos, external callbacks)
+- Browser preview & automatic HTTPS upgrade (if dev server supports)
---
+# Example portsAttributes
-# Features
-
-Full list here: [https://containers.dev/features](https://containers.dev/features)
-
-- CLIs (azure, gh, gcp, aws)
-- Tools (Terraform, kubernetes...)
-- Runtimes (Node, Python, Go, Java, .NET, PHP, Ruby, Rust, C/C++, C#)
+```json
+"portsAttributes": {
+ "3000": { "label": "Web UI", "onAutoForward": "openBrowser" },
+ "9229": { "label": "Node Inspector", "elevateIfNeeded": true }
+}
+```
---
-# Docker-in-Docker vs Docker-on-Docker
-
-- **Docker-in-Docker (DinD):**
- - Runs its own Docker daemon inside the dev container
- - Good for isolation and CI
- - Slightly slower, more resource use
+# Minimal devcontainer.json Example
-- **Docker-on-Docker (DoD):**
- - Shares host Docker socket (`/var/run/docker.sock`)
- - Faster, but less isolated
- - Not always available (e.g., Codespaces)
+```json
+{
+ "image": "mcr.microsoft.com/devcontainers/typescript-node:1-20-bookworm",
+ "features": {
+ "ghcr.io/devcontainers/features/github-cli:1": {},
+ "ghcr.io/devcontainers/features/node:1": { "version": "20" }
+ },
+ "forwardPorts": [3000],
+ "customizations": {
+ "vscode": {
+ "extensions": ["dbaeumer.vscode-eslint", "ms-azuretools.vscode-docker"],
+ "settings": { "editor.formatOnSave": true }
+ }
+ },
+ "postCreateCommand": "npm ci",
+ "remoteUser": "node"
+}
+```
---
-# Image Selection for Dev Containers
+# Environment Variables in Dev Containers
-- Use the official .NET 9 image for Aspire workloads
-- Extend or use a custom Dockerfile for extra tools
-- Most local dev: DoD is faster and simpler
-- CI or Codespaces: DinD is safer and more portable
+Set environment variables in `devcontainer.json`:
-# Configuration Loop
+```json
+{
+ "containerEnv": { "MY_ENV_VAR": "value" },
+ "remoteEnv": { "API_TOKEN": "${localEnv:API_TOKEN}" }
+}
+```
-
+- `containerEnv`: for all processes in the container
+- `remoteEnv`: for the VS Code server and extensions
---
-# GitHub Codespaces
-
-- Don't need to worry about Docker Desktop locally
-- Access from VS Code Desktop, Browser, GitHub CLI, IntelliJ (JetBrains Gateway)
-- Machine types: 2 -> 32 cores, 8 -> 128 GB RAM, 32 -> 128 GB storage (quota + plan dependent)
-- Default universal base image when no config present
-- Only Linux (x86_64) today; same environment regardless of local OS
-- Prebuilds optionally warm caches & dependencies for faster start
-- Spin up secure, disposable environments for PR reviews, experiments, onboarding
-
-# devcontainer.json – Core Anatomy
+# Env Vars: Container vs Remote (Advanced)
-Key properties (spec: containers.dev)
-
-- image | build : Base image or build definition
-- features : Add runtime/tooling building blocks (OCI delivered)
-- name , workspaceFolder , workspaceMount
-- customizations.vscode : extensions, settings, commands
-- forwardPorts , portsAttributes , appPort (publish)
-- postCreateCommand | onCreateCommand (initial provisioning)
-- postStartCommand (runs each container start)
-- postAttachCommand (runs after editor attaches)
-- updateContentCommand (runs when repo content changes / rebuild)
-- remoteUser | containerUser , userEnvProbe
-- containerEnv | remoteEnv (environment vars)
-- runArgs , overrides (Compose), mounts (extra volumes / bind mounts)
-- shutdownAction , hostRequirements (cpu/ram/storage expectations)
-
-Keep it minimal: prefer pre-built images + Features over large inline scripts.
+- **containerEnv**: set at container start (Dockerfile, Compose, or devcontainer.json)
+- **remoteEnv**: injected at attach time (user, secrets, paths)
+- Use dynamic values: `${localEnv:VAR}` or `${containerWorkspaceFolder}`
+- `userEnvProbe`: merge shell profile exports into remoteEnv ("loginShell", "interactiveShell", or "none")
---
-# Lifecycle & Personalization
-
-- onCreateCommand / postCreateCommand : one-time setup (install deps)
-- postStartCommand : after container starts (lightweight tasks)
-- postAttachCommand : when editor connects (show tips, start watchers)
-- updateContentCommand : react to repo content updates (regen code, build docs)
-- Dotfiles repo (shell, aliases, tooling) auto-applied
-- Settings Sync (VS Code) for editor preferences
-- Extensions: add in customizations.vscode.extensions (use -ext.id to opt-out)
-- Always install defaults via dev.containers.defaultExtensions / defaultFeatures
+# Mounting Local Folders
-Tip: Keep long-running tasks out of postStart to reduce initial readiness time.
+You can mount local folders or files into your dev container using the `mounts` property:
----
-
-# Advanced Configuration Highlights
+```json
+{
+ "mounts": [
+ "source=${localWorkspaceFolder}/.npmrc,target=/root/.npmrc,type=bind,consistency=cached",
+ "source=${env:HOME}/.ssh,target=/root/.ssh,type=bind,consistency=cached"
+ ]
+}
+```
-- Multi-container: docker-compose.yml + service property
-- Mounts: bind, volume, tmpfs for caches (node_modules, package cache)
-- portsAttributes: label, auto-open, visibility (public / private)
-- hostRequirements: signal required resources for Codespaces selection
-- remoteEnv vs containerEnv (apply after attach vs base container)
-- Pre-built image metadata labels merge devcontainer settings
-- Multiple configurations: .devcontainer/
/devcontainer.json choices
-- Non-root user (features often add 'vscode' or 'devcontainer' user) for security
+This is useful for sharing config files, SSH keys, or other resources from your host.
---
-# Pre-building Images & Codespaces Prebuilds
+# Non-Root User Best Practice
+
+Always run as a non-root user for security. Most official images set `remoteUser` to `vscode` or `devcontainer` by default.
-- Pre-build (CI) container images to bake in deps, tools, language servers
-- Use Dev Container CLI or devcontainers/ci GitHub Action
-- Benefits: Faster startup, deterministic builds, pinned versions, supply chain traceability
-- Include metadata labels (devcontainer.metadata) to auto-apply config
-- Codespaces Prebuilds: run build + postCreate on default branches / PRs
-- Reduces time-to-first-keystroke for large mono-repos
-- Cache package managers (npm, pip, cargo, go mod) inside layer
+To enforce non-root:
+```json
+{
+ "remoteUser": "vscode"
+}
+```
+Or add the non-root-user Feature if needed.
-Measure: Track median create time before/after prebuild adoption.
+More: [Add a non-root user](https://code.visualstudio.com/remote/advancedcontainers/add-nonroot-user)
---
-# Codespaces Personalization & Secrets
-- Dotfiles repo: ~/.dotfiles (configurable target + install script)
-- Settings Sync: unify keybindings, snippets, UI
-- User-level secrets: injected as env vars; never commit secrets in devcontainer.json
-- Repository / Org secrets for workflows vs Codespaces user secrets separation
-- Port forwarding: automatic detection (server output) + manual forward
-- Shared terminals (pairing) & Live Share (optional) for collaboration
-- GitHub CLI inside container simplifies auth & repo ops
+# GitHub Codespaces: What & Why
-Principle: Keep personal customization (dotfiles) separate from project config.
+- Cloud-hosted, instant dev environments for any repo
+- No local Docker or setup required
+- Consistent, secure, and disposable workspaces
+- Fast onboarding: prebuilds, dotfiles, and settings sync
---
-# Performance Tips
-- Prefer pre-built images + Features over large postCreate scripts
-- Use volumes instead of bind mounts for heavy I/O on macOS/Windows
-- Cache language deps in image layers (lock files first for better cache hits)
-- Trim image size: multi-stage builds, remove build toolchains in final stage
-- Avoid unnecessary apt-get upgrade; pin versions
-- Use updateContentCommand only for light incremental tasks
-- Rebuild when changing Dockerfile; use Reopen in Recovery Container to fix build errors fast
+# GitHub Codespaces: Architecture
-Metric to watch: Codespaces create time (goal: < 30s perceived ready).
+
---
-# Security Best Practices
-- Non-root user (remoteUser) with least privileges
-- Pin image tags (avoid :latest) & verify supply chain (SBOM where possible)
-- Minimal Feature set: install only required tools
-- Regularly rebuild to pick up CVE patches (automated CI scan)
-- Secrets via Codespaces secrets; never bake into image layers
-- Consider readonly mounts for source during audits / review sessions
-- Use Dependabot / container scanning for base image & dependencies
+# Codespaces: Key Features
-Outcome: Reproducible, auditable, least-privilege environments.
+- Start a dev environment from any branch, PR, or template
+- Prebuilds: dependencies and tools ready before you connect
+- Port forwarding, shared terminals, and Live Share for collaboration
+- Personalization: dotfiles, settings sync, user secrets
---
-# Known Limitations & Constraints
-- Codespaces: Linux only (no Windows/macOS containers)
-- Architecture: x86_64 (arm64 building requires remote emulation or CI build)
-- Dev Containers: Windows container images not supported in VS Code extension
-- Alpine images: some extensions fail (glibc expectations)
-- Multi-root workspace: single container context (unless Compose multi-service)
-- Network: corporate proxies require explicit HTTP(S)_PROXY env vars
-- Performance: bind mounts slower on macOS/Windows; prefer volumes
+# Codespaces: How to Use
-Plan mitigations early (prebuild, volumes, pinned tool versions).
+- Open any repo in a codespace from GitHub.com, VS Code, or CLI
+- Choose machine size, region, and devcontainer config
+- Suspend, resume, or delete codespaces as needed
+- Works with VS Code (browser/desktop), JetBrains Gateway, and GitHub CLI
---
-# GitHub Codespaces Architecture
+# Codespaces: Limitations & Cost
-
-
-
+- Linux-only (x86_64); no Windows containers
+- Single container unless using Compose
+- Bind mounts slower on macOS/Windows (prefer volumes)
+- Pay for compute, storage, and prebuilds (beyond free quota)
+- See [docs.github.com/codespaces](https://docs.github.com/en/codespaces/) for details
---
-# GitHub Codespace templates
-
-[https://github.com/codespaces/templates](https://github.com/codespaces/templates)
+# GitHub Codespaces: Billing & Cost Control
-
+- Pay for compute hours, storage, and prebuild usage (beyond free quota)
+- Key levers: machine size, idle timeout, auto-delete unused codespaces
+- Strategies: right-size, prebuild only critical branches, monitor usage/cost
+- Always check current docs for pricing details
---
-# DEMO TIME
+# Demo Time

---
-
+# Advanced Topics
---
-# Codespaces Billing & Cost Control
-
-- Billing dimensions: compute hours (core/hour), storage (persistent disk), prebuild usage
-- Free included quota varies by plan; beyond that pay-as-you-go with budgets/spending limits
-- Cost levers: machine type, idle timeout, automatic deletion of unused codespaces
-- Strategies:
- - Right-size: start small, scale up only when tests / builds need it
- - Prebuild only critical branches (main, release/*, high-traffic PRs)
- - Pause / stop vs delete (stop retains storage; delete frees cost)
- - Archive artifacts externally (cache warm vs extra storage)
-- Monitor: Usage dashboard + budget alerts; treat create time & cost per PR as KPIs
-
-Note: Exact pricing subject to change—always verify current docs before presenting numbers.
-
----
+# Dev Container CLI
-# Workspace Trust & Safety
+The `devcontainer` CLI lets you build, run, and automate dev containers from the terminal—no VS Code required.
-- First open: VS Code prompts to Trust repository (controls auto-exec of tasks, extensions)
-- Trust decisions propagate to container actions (build, postCreate scripts)
-- Recovery container: safe mode to fix failing builds without executing untrusted scripts
-- Recommendations:
- - Review Dockerfile & scripts before trusting third-party repos
- - Pin base images & Features; avoid curl | bash patterns without checksum
- - Use readonly mounts for exploration when uncertain
+- `devcontainer build --workspace-folder .` Build a dev container image
+- `devcontainer up --workspace-folder .` Start a dev container
+- `devcontainer exec --workspace-folder . bash -lc "npm test"` Run a command inside
-Outcome: Minimize supply chain risk while preserving inner-loop speed.
+[github.com/devcontainers/cli](https://github.com/devcontainers/cli)
---
-# Managing Extensions Deep Dive
-
-- Add via customizations.vscode.extensions
-- Opt-out: prefix with '-' to remove inherited extension
-- Default extensions (user setting): dev.containers.defaultExtensions
-- Force location (rare): remote.extensionKind overrides
-- Keep lean: only language / tooling essentials; reduces startup & index time
-- Example:
-
-```
-"customizations": {
- "vscode": {
- "extensions": [
- "ms-azuretools.vscode-docker",
- "-dbaeumer.vscode-eslint" // opt-out inherited
- ]
- }
-}
-```
-
----
-
-# Debugging & Port Forwarding
-
-- Debug flows identical: launch.json attaches inside container
-- Auto port detection: output parsing ("Listening on 3000") triggers forward suggestion
-- forwardPorts: auto-forward on start; portsAttributes: label, onAutoForward, visibility
-- Published vs Forwarded:
- - Forwarded: appears as localhost to app (ideal for dev auth flows)
- - Published: network-accessible (team demos, external callbacks)
-- Browser preview & automatic HTTPS upgrade (if dev server supports)
-
-Example portsAttributes:
-```
-"portsAttributes": {
- "3000": { "label": "Web UI", "onAutoForward": "openBrowser" },
- "9229": { "label": "Node Inspector", "elevateIfNeeded": true }
-}
-```
-
----
+# Prebuild & CI Integration Example
-# Minimal devcontainer.json Example
+devcontainer.json (simplified):
-```
+```json
{
- "image": "mcr.microsoft.com/devcontainers/typescript-node:1-20-bookworm",
- "features": {
- "ghcr.io/devcontainers/features/github-cli:1": {},
- "ghcr.io/devcontainers/features/node:1": { "version": "20" }
- },
- "forwardPorts": [3000],
- "customizations": {
- "vscode": {
- "extensions": ["dbaeumer.vscode-eslint", "ms-azuretools.vscode-docker"],
- "settings": { "editor.formatOnSave": true }
- }
- },
- "postCreateCommand": "npm ci",
- "remoteUser": "node"
+ "image": "ghcr.io/your-org/your-prebuilt:latest",
+ "postAttachCommand": "npm run dev"
}
```
---
-# Prebuild & CI Integration Example
+# Prebuild CI Workflow (GitHub Actions)
-devcontainer.json (simplified):
-```
-{
- "image": "ghcr.io/your-org/your-prebuilt:latest",
- "postAttachCommand": "npm run dev"
-}
-```
-GitHub Action (devcontainers/ci):
-```
+```yaml
name: Prebuild Dev Container
on:
push:
@@ -503,43 +365,23 @@ jobs:
---
-# Multi-Service (Compose) Pattern
+# Tips & Tricks: Git Line Endings (Windows/WSL)
-- docker-compose.yml defines api, db, cache, worker services
-- devcontainer.json references primary service: "service": "api"
-- Shared network: service hostnames = service names (db:5432)
-- volumes: persist database state or ephemeral for clean tests
-- Add Features only to dev container service; others use minimal images
-- Tip: Use HEALTHCHECK for dependent service readiness (faster stabilize)
+On Windows/WSL, you may see many modified files due to line ending differences between host and container.
-Flow: Editor -> api container (extensions) -> other services via internal network.
+- Add a `.gitattributes` file to enforce consistent line endings:
----
-
-# Metrics & Continuous Improvement
-
-Track:
-- Time to first keystroke (creation start -> editor ready)
-- PostCreate duration (optimize by prebuilding layers)
-- Container image size & layer churn
-- Cache hit rate for package managers
-- Codespaces cost per PR (optional)
-
-Improve Loop:
-1 Measure -> 2 Identify slow stage -> 3 Shift left into image -> 4 Validate -> 5 Automate.
+```gitattributes
+* text=auto eol=lf
+*.{cmd,[cC][mM][dD]} text eol=crlf
+*.{bat,[bB][aA][tT]} text eol=crlf
+```
---
# Troubleshooting & Recovery
-- Build fails: Reopen in Recovery Container -> fix Dockerfile -> Rebuild
-- Slow startup: inspect logs (Dev Containers output), compare against prebuild baseline
-- Missing tools: confirm Features applied (metadata labels vs local file)
-- Port conflict: adjust forwardPorts or use random host mapping
-- Extension issues: run with --log-level trace, temporarily disable customizations
-- Disk performance (macOS/Windows): prefer volume (Clone in Container Volume)
-
-Mindset: Fail fast, keep recovery path frictionless.
+
---
@@ -556,9 +398,7 @@ Mindset: Fail fast, keep recovery path frictionless.
- [Beginner's Series to Dev Containers](https://learn.microsoft.com/en-us/shows/beginners-series-to-dev-containers/)
- [devcontainer.json Reference](https://containers.dev/implementors/json_reference)
- [Dev Container CLI](https://code.visualstudio.com/docs/devcontainers/devcontainer-cli)
-- [Prebuilds (GitHub Codespaces)](https://docs.github.com/codespaces)
- [Advanced Config (VS Code)](https://code.visualstudio.com/remote/advancedcontainers/overview)
-- [https://github.com/codebytes](https://github.com/codebytes)
diff --git a/src/go/.devcontainer/devcontainer.json b/src/go/.devcontainer/devcontainer.json
new file mode 100644
index 0000000..c9ac758
--- /dev/null
+++ b/src/go/.devcontainer/devcontainer.json
@@ -0,0 +1,39 @@
+// For format details, see https://aka.ms/devcontainer.json. For config options, see the
+// README at: https://github.com/devcontainers/templates/tree/main/src/go
+{
+ "name": "Go",
+ // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
+ "image": "mcr.microsoft.com/devcontainers/go:1-1.22-bookworm",
+
+ // Features to add to the dev container. More info: https://containers.dev/features.
+ // "features": {},
+
+ // Configure tool-specific properties.
+ "customizations": {
+ // Configure properties specific to VS Code.
+ "vscode": {
+ "settings": {},
+ "extensions": [
+ "streetsidesoftware.code-spell-checker"
+ ]
+ }
+ },
+
+ // Use 'forwardPorts' to make a list of ports inside the container available locally.
+ "forwardPorts": [9000],
+
+ // Use 'portsAttributes' to set default properties for specific forwarded ports.
+ // More info: https://containers.dev/implementors/json_reference/#port-attributes
+ "portsAttributes": {
+ "9000": {
+ "label": "Hello Remote World",
+ "onAutoForward": "notify"
+ }
+ }
+
+ // Use 'postCreateCommand' to run commands after the container is created.
+ // "postCreateCommand": "go version",
+
+ // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
+ // "remoteUser": "root"
+}
diff --git a/src/go/.gitattributes b/src/go/.gitattributes
new file mode 100644
index 0000000..314766e
--- /dev/null
+++ b/src/go/.gitattributes
@@ -0,0 +1,3 @@
+* text=auto eol=lf
+*.{cmd,[cC][mM][dD]} text eol=crlf
+*.{bat,[bB][aA][tT]} text eol=crlf
diff --git a/src/go/.gitignore b/src/go/.gitignore
new file mode 100644
index 0000000..d121356
--- /dev/null
+++ b/src/go/.gitignore
@@ -0,0 +1,336 @@
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+##
+## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
+
+# User-specific files
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
+
+# User-specific files (MonoDevelop/Xamarin Studio)
+*.userprefs
+
+# Build results
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+[Rr]eleases/
+x64/
+x86/
+bld/
+[Bb]in/
+[Oo]bj/
+[Ll]og/
+
+# Visual Studio 2015/2017 cache/options directory
+.vs/
+# Uncomment if you have tasks that create the project's static files in wwwroot
+#wwwroot/
+
+# Visual Studio 2017 auto generated files
+Generated\ Files/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+# NUNIT
+*.VisualState.xml
+TestResult.xml
+
+# Build Results of an ATL Project
+[Dd]ebugPS/
+[Rr]eleasePS/
+dlldata.c
+
+# Benchmark Results
+BenchmarkDotNet.Artifacts/
+
+# .NET Core
+project.lock.json
+project.fragment.lock.json
+artifacts/
+**/Properties/launchSettings.json
+
+# StyleCop
+StyleCopReport.xml
+
+# Files built by Visual Studio
+*_i.c
+*_p.c
+*_i.h
+*.ilk
+*.meta
+*.obj
+*.iobj
+*.pch
+*.pdb
+*.ipdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*.log
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.svclog
+*.scc
+
+# Chutzpah Test files
+_Chutzpah*
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opendb
+*.opensdf
+*.sdf
+*.cachefile
+*.VC.db
+*.VC.VC.opendb
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+*.sap
+
+# Visual Studio Trace Files
+*.e2e
+
+# TFS 2012 Local Workspace
+$tf/
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+*.DotSettings.user
+
+# JustCode is a .NET coding add-in
+.JustCode
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# AxoCover is a Code Coverage Tool
+.axoCover/*
+!.axoCover/settings.json
+
+# Visual Studio code coverage results
+*.coverage
+*.coveragexml
+
+# NCrunch
+_NCrunch_*
+.*crunch*.local.xml
+nCrunchTemp_*
+
+# MightyMoose
+*.mm.*
+AutoTest.Net/
+
+# Web workbench (sass)
+.sass-cache/
+
+# Installshield output folder
+[Ee]xpress/
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish/
+
+# Publish Web Output
+*.[Pp]ublish.xml
+*.azurePubxml
+# Note: Comment the next line if you want to checkin your web deploy settings,
+# but database connection strings (with potential passwords) will be unencrypted
+*.pubxml
+*.publishproj
+
+# Microsoft Azure Web App publish settings. Comment the next line if you want to
+# checkin your Azure Web App publish settings, but sensitive information contained
+# in these scripts will be unencrypted
+PublishScripts/
+
+# NuGet Packages
+*.nupkg
+# The packages folder can be ignored because of Package Restore
+**/[Pp]ackages/*
+# except build/, which is used as an MSBuild target.
+!**/[Pp]ackages/build/
+# Uncomment if necessary however generally it will be regenerated when needed
+#!**/[Pp]ackages/repositories.config
+# NuGet v3's project.json files produces more ignorable files
+*.nuget.props
+*.nuget.targets
+
+# Microsoft Azure Build Output
+csx/
+*.build.csdef
+
+# Microsoft Azure Emulator
+ecf/
+rcf/
+
+# Windows Store app package directories and files
+AppPackages/
+BundleArtifacts/
+Package.StoreAssociation.xml
+_pkginfo.txt
+*.appx
+
+# Visual Studio cache files
+# files ending in .cache can be ignored
+*.[Cc]ache
+# but keep track of directories ending in .cache
+!*.[Cc]ache/
+
+# Others
+ClientBin/
+~$*
+*~
+*.dbmdl
+*.dbproj.schemaview
+*.jfm
+*.pfx
+*.publishsettings
+orleans.codegen.cs
+
+# Including strong name files can present a security risk
+# (https://github.com/github/gitignore/pull/2483#issue-259490424)
+#*.snk
+
+# Since there are multiple workflows, uncomment next line to ignore bower_components
+# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
+#bower_components/
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file
+# to a newer Visual Studio version. Backup files are not needed,
+# because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+UpgradeLog*.htm
+ServiceFabricBackup/
+*.rptproj.bak
+
+# SQL Server files
+*.mdf
+*.ldf
+*.ndf
+
+# Business Intelligence projects
+*.rdl.data
+*.bim.layout
+*.bim_*.settings
+*.rptproj.rsuser
+
+# Microsoft Fakes
+FakesAssemblies/
+
+# GhostDoc plugin setting file
+*.GhostDoc.xml
+
+# Node.js Tools for Visual Studio
+.ntvs_analysis.dat
+node_modules/
+
+# Visual Studio 6 build log
+*.plg
+
+# Visual Studio 6 workspace options file
+*.opt
+
+# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
+*.vbw
+
+# Visual Studio LightSwitch build output
+**/*.HTMLClient/GeneratedArtifacts
+**/*.DesktopClient/GeneratedArtifacts
+**/*.DesktopClient/ModelManifest.xml
+**/*.Server/GeneratedArtifacts
+**/*.Server/ModelManifest.xml
+_Pvt_Extensions
+
+# Paket dependency manager
+.paket/paket.exe
+paket-files/
+
+# FAKE - F# Make
+.fake/
+
+# JetBrains Rider
+.idea/
+*.sln.iml
+
+# CodeRush
+.cr/
+
+# Python Tools for Visual Studio (PTVS)
+__pycache__/
+*.pyc
+
+# Cake - Uncomment if you are using it
+# tools/**
+# !tools/packages.config
+
+# Tabs Studio
+*.tss
+
+# Telerik's JustMock configuration file
+*.jmconfig
+
+# BizTalk build output
+*.btp.cs
+*.btm.cs
+*.odx.cs
+*.xsd.cs
+
+# OpenCover UI analysis results
+OpenCover/
+
+# Azure Stream Analytics local run output
+ASALocalRun/
+
+# MSBuild Binary and Structured Log
+*.binlog
+
+# NVidia Nsight GPU debugger configuration file
+*.nvuser
+
+# MFractors (Xamarin productivity tool) working folder
+.mfractor/
+
+*.DS_Store
+
+out
+pkg
+debug
diff --git a/src/go/.vscode/launch.json b/src/go/.vscode/launch.json
new file mode 100644
index 0000000..01f10d4
--- /dev/null
+++ b/src/go/.vscode/launch.json
@@ -0,0 +1,12 @@
+{
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "name": "Launch Server",
+ "type": "go",
+ "request": "launch",
+ "mode": "debug",
+ "program": "${workspaceFolder}/server.go"
+ }
+ ]
+}
diff --git a/src/go/go.mod b/src/go/go.mod
new file mode 100644
index 0000000..fe93d39
--- /dev/null
+++ b/src/go/go.mod
@@ -0,0 +1,3 @@
+module github.com/microsoft/vscode-remote-try-go
+
+go 1.19
diff --git a/src/go/hello/hello.go b/src/go/hello/hello.go
new file mode 100644
index 0000000..db44cd1
--- /dev/null
+++ b/src/go/hello/hello.go
@@ -0,0 +1,22 @@
+package hello
+
+// User user type
+type User struct {
+ ID int64
+ Name string
+ Addr *Address
+}
+
+// Address address type
+type Address struct {
+ City string
+ ZIP int
+ LatLng [2]float64
+}
+
+var alex = User{}
+
+// Hello writes a welcome string
+func Hello() string {
+ return "Hello, " + alex.Name
+}
diff --git a/src/go/server.go b/src/go/server.go
new file mode 100644
index 0000000..28dbdb4
--- /dev/null
+++ b/src/go/server.go
@@ -0,0 +1,25 @@
+/*----------------------------------------------------------------------------------------
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See LICENSE in the project root for license information.
+ *---------------------------------------------------------------------------------------*/
+
+package main
+
+import (
+ "fmt"
+ "io"
+ "net/http"
+
+ "github.com/microsoft/vscode-remote-try-go/hello"
+)
+
+func handle(w http.ResponseWriter, r *http.Request) {
+ io.WriteString(w, hello.Hello())
+}
+
+func main() {
+ portNumber := "9000"
+ http.HandleFunc("/", handle)
+ fmt.Println("Server listening on port ", portNumber)
+ http.ListenAndServe(":"+portNumber, nil)
+}
diff --git a/src/node/.eslintrc.json b/src/node/.eslintrc.json
new file mode 100644
index 0000000..6144597
--- /dev/null
+++ b/src/node/.eslintrc.json
@@ -0,0 +1,21 @@
+{
+ "root": true,
+ "env": {
+ "node": true,
+ "es6": true
+ },
+ "rules": {
+ "no-console": 0,
+ "eqeqeq":"warn",
+ "no-cond-assign": 0,
+ "no-unused-vars": 1,
+ "no-extra-semi": "warn",
+ "semi": "warn"
+ },
+ "extends": "eslint:recommended",
+ "parserOptions": {
+ "ecmaFeatures": {
+ "experimentalObjectRestSpread": true
+ }
+ }
+}
diff --git a/src/node/.gitattributes b/src/node/.gitattributes
new file mode 100644
index 0000000..314766e
--- /dev/null
+++ b/src/node/.gitattributes
@@ -0,0 +1,3 @@
+* text=auto eol=lf
+*.{cmd,[cC][mM][dD]} text eol=crlf
+*.{bat,[bB][aA][tT]} text eol=crlf
diff --git a/src/node/.gitignore b/src/node/.gitignore
new file mode 100644
index 0000000..1aae53a
--- /dev/null
+++ b/src/node/.gitignore
@@ -0,0 +1,334 @@
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+##
+## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
+
+# User-specific files
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
+
+# User-specific files (MonoDevelop/Xamarin Studio)
+*.userprefs
+
+# Build results
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+[Rr]eleases/
+x64/
+x86/
+bld/
+[Bb]in/
+[Oo]bj/
+[Ll]og/
+
+# Visual Studio 2015/2017 cache/options directory
+.vs/
+# Uncomment if you have tasks that create the project's static files in wwwroot
+#wwwroot/
+
+# Visual Studio 2017 auto generated files
+Generated\ Files/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+# NUNIT
+*.VisualState.xml
+TestResult.xml
+
+# Build Results of an ATL Project
+[Dd]ebugPS/
+[Rr]eleasePS/
+dlldata.c
+
+# Benchmark Results
+BenchmarkDotNet.Artifacts/
+
+# .NET Core
+project.lock.json
+project.fragment.lock.json
+artifacts/
+**/Properties/launchSettings.json
+
+# StyleCop
+StyleCopReport.xml
+
+# Files built by Visual Studio
+*_i.c
+*_p.c
+*_i.h
+*.ilk
+*.meta
+*.obj
+*.iobj
+*.pch
+*.pdb
+*.ipdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*.log
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.svclog
+*.scc
+
+# Chutzpah Test files
+_Chutzpah*
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opendb
+*.opensdf
+*.sdf
+*.cachefile
+*.VC.db
+*.VC.VC.opendb
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+*.sap
+
+# Visual Studio Trace Files
+*.e2e
+
+# TFS 2012 Local Workspace
+$tf/
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+*.DotSettings.user
+
+# JustCode is a .NET coding add-in
+.JustCode
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# AxoCover is a Code Coverage Tool
+.axoCover/*
+!.axoCover/settings.json
+
+# Visual Studio code coverage results
+*.coverage
+*.coveragexml
+
+# NCrunch
+_NCrunch_*
+.*crunch*.local.xml
+nCrunchTemp_*
+
+# MightyMoose
+*.mm.*
+AutoTest.Net/
+
+# Web workbench (sass)
+.sass-cache/
+
+# Installshield output folder
+[Ee]xpress/
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish/
+
+# Publish Web Output
+*.[Pp]ublish.xml
+*.azurePubxml
+# Note: Comment the next line if you want to checkin your web deploy settings,
+# but database connection strings (with potential passwords) will be unencrypted
+*.pubxml
+*.publishproj
+
+# Microsoft Azure Web App publish settings. Comment the next line if you want to
+# checkin your Azure Web App publish settings, but sensitive information contained
+# in these scripts will be unencrypted
+PublishScripts/
+
+# NuGet Packages
+*.nupkg
+# The packages folder can be ignored because of Package Restore
+**/[Pp]ackages/*
+# except build/, which is used as an MSBuild target.
+!**/[Pp]ackages/build/
+# Uncomment if necessary however generally it will be regenerated when needed
+#!**/[Pp]ackages/repositories.config
+# NuGet v3's project.json files produces more ignorable files
+*.nuget.props
+*.nuget.targets
+
+# Microsoft Azure Build Output
+csx/
+*.build.csdef
+
+# Microsoft Azure Emulator
+ecf/
+rcf/
+
+# Windows Store app package directories and files
+AppPackages/
+BundleArtifacts/
+Package.StoreAssociation.xml
+_pkginfo.txt
+*.appx
+
+# Visual Studio cache files
+# files ending in .cache can be ignored
+*.[Cc]ache
+# but keep track of directories ending in .cache
+!*.[Cc]ache/
+
+# Others
+ClientBin/
+~$*
+*~
+*.dbmdl
+*.dbproj.schemaview
+*.jfm
+*.pfx
+*.publishsettings
+orleans.codegen.cs
+
+# Including strong name files can present a security risk
+# (https://github.com/github/gitignore/pull/2483#issue-259490424)
+#*.snk
+
+# Since there are multiple workflows, uncomment next line to ignore bower_components
+# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
+#bower_components/
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file
+# to a newer Visual Studio version. Backup files are not needed,
+# because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+UpgradeLog*.htm
+ServiceFabricBackup/
+*.rptproj.bak
+
+# SQL Server files
+*.mdf
+*.ldf
+*.ndf
+
+# Business Intelligence projects
+*.rdl.data
+*.bim.layout
+*.bim_*.settings
+*.rptproj.rsuser
+
+# Microsoft Fakes
+FakesAssemblies/
+
+# GhostDoc plugin setting file
+*.GhostDoc.xml
+
+# Node.js Tools for Visual Studio
+.ntvs_analysis.dat
+node_modules/
+
+# Visual Studio 6 build log
+*.plg
+
+# Visual Studio 6 workspace options file
+*.opt
+
+# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
+*.vbw
+
+# Visual Studio LightSwitch build output
+**/*.HTMLClient/GeneratedArtifacts
+**/*.DesktopClient/GeneratedArtifacts
+**/*.DesktopClient/ModelManifest.xml
+**/*.Server/GeneratedArtifacts
+**/*.Server/ModelManifest.xml
+_Pvt_Extensions
+
+# Paket dependency manager
+.paket/paket.exe
+paket-files/
+
+# FAKE - F# Make
+.fake/
+
+# JetBrains Rider
+.idea/
+*.sln.iml
+
+# CodeRush
+.cr/
+
+# Python Tools for Visual Studio (PTVS)
+__pycache__/
+*.pyc
+
+# Cake - Uncomment if you are using it
+# tools/**
+# !tools/packages.config
+
+# Tabs Studio
+*.tss
+
+# Telerik's JustMock configuration file
+*.jmconfig
+
+# BizTalk build output
+*.btp.cs
+*.btm.cs
+*.odx.cs
+*.xsd.cs
+
+# OpenCover UI analysis results
+OpenCover/
+
+# Azure Stream Analytics local run output
+ASALocalRun/
+
+# MSBuild Binary and Structured Log
+*.binlog
+
+# NVidia Nsight GPU debugger configuration file
+*.nvuser
+
+# MFractors (Xamarin productivity tool) working folder
+.mfractor/
+
+*.DS_Store
+
+out
\ No newline at end of file
diff --git a/src/node/.vscode/launch.json b/src/node/.vscode/launch.json
new file mode 100644
index 0000000..179ed34
--- /dev/null
+++ b/src/node/.vscode/launch.json
@@ -0,0 +1,14 @@
+{
+ // Use IntelliSense to learn about possible attributes.
+ // Hover to view descriptions of existing attributes.
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "type": "node",
+ "request": "launch",
+ "name": "Launch Program",
+ "program": "${workspaceFolder}/server.js"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/src/node/package.json b/src/node/package.json
new file mode 100644
index 0000000..c52b0e2
--- /dev/null
+++ b/src/node/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "docker_web_app",
+ "version": "1.0.0",
+ "description": "Node.js on Docker",
+ "author": "First Last
",
+ "main": "server.js",
+ "private": true,
+ "scripts": {
+ "start": "node server.js"
+ },
+ "dependencies": {
+ "express": "^4.20.0"
+ }
+}
diff --git a/src/node/server.js b/src/node/server.js
new file mode 100644
index 0000000..6de36ad
--- /dev/null
+++ b/src/node/server.js
@@ -0,0 +1,28 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+'use strict';
+
+const express = require('express');
+
+// Constants
+const PORT = 3000;
+const HOST = '0.0.0.0';
+
+// App
+const app = express();
+app.get('/', (req, res) => {
+ res.send('Hello remote world!\n');
+});
+
+// New endpoint: GET /hello?name=YOUR_NAME -> "hello YOUR_NAME"
+app.get('/hello', (req, res) => {
+ const nameParam = req.query && typeof req.query.name === 'string' ? req.query.name.trim() : '';
+ const name = nameParam.length > 0 ? nameParam : 'world';
+ res.send(`hello ${name}\n`);
+});
+
+app.listen(PORT, HOST);
+console.log(`Running on http://${HOST}:${PORT}`);
\ No newline at end of file
diff --git a/src/node/yarn.lock b/src/node/yarn.lock
new file mode 100644
index 0000000..1a2f702
--- /dev/null
+++ b/src/node/yarn.lock
@@ -0,0 +1,468 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+accepts@~1.3.8:
+ version "1.3.8"
+ resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e"
+ integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==
+ dependencies:
+ mime-types "~2.1.34"
+ negotiator "0.6.3"
+
+array-flatten@1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
+ integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==
+
+body-parser@1.20.3:
+ version "1.20.3"
+ resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.3.tgz#1953431221c6fb5cd63c4b36d53fab0928e548c6"
+ integrity sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==
+ dependencies:
+ bytes "3.1.2"
+ content-type "~1.0.5"
+ debug "2.6.9"
+ depd "2.0.0"
+ destroy "1.2.0"
+ http-errors "2.0.0"
+ iconv-lite "0.4.24"
+ on-finished "2.4.1"
+ qs "6.13.0"
+ raw-body "2.5.2"
+ type-is "~1.6.18"
+ unpipe "1.0.0"
+
+bytes@3.1.2:
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5"
+ integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==
+
+call-bind@^1.0.7:
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9"
+ integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==
+ dependencies:
+ es-define-property "^1.0.0"
+ es-errors "^1.3.0"
+ function-bind "^1.1.2"
+ get-intrinsic "^1.2.4"
+ set-function-length "^1.2.1"
+
+content-disposition@0.5.4:
+ version "0.5.4"
+ resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe"
+ integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==
+ dependencies:
+ safe-buffer "5.2.1"
+
+content-type@~1.0.4, content-type@~1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918"
+ integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==
+
+cookie-signature@1.0.6:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
+ integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==
+
+cookie@0.7.1:
+ version "0.7.1"
+ resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.7.1.tgz#2f73c42142d5d5cf71310a74fc4ae61670e5dbc9"
+ integrity sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==
+
+debug@2.6.9:
+ version "2.6.9"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
+ integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
+ dependencies:
+ ms "2.0.0"
+
+define-data-property@^1.1.4:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e"
+ integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==
+ dependencies:
+ es-define-property "^1.0.0"
+ es-errors "^1.3.0"
+ gopd "^1.0.1"
+
+depd@2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df"
+ integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==
+
+destroy@1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015"
+ integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==
+
+ee-first@1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
+ integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==
+
+encodeurl@~1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
+ integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==
+
+encodeurl@~2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-2.0.0.tgz#7b8ea898077d7e409d3ac45474ea38eaf0857a58"
+ integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==
+
+es-define-property@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845"
+ integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==
+ dependencies:
+ get-intrinsic "^1.2.4"
+
+es-errors@^1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f"
+ integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==
+
+escape-html@~1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
+ integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==
+
+etag@~1.8.1:
+ version "1.8.1"
+ resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
+ integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==
+
+express@^4.20.0:
+ version "4.21.1"
+ resolved "https://registry.yarnpkg.com/express/-/express-4.21.1.tgz#9dae5dda832f16b4eec941a4e44aa89ec481b281"
+ integrity sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==
+ dependencies:
+ accepts "~1.3.8"
+ array-flatten "1.1.1"
+ body-parser "1.20.3"
+ content-disposition "0.5.4"
+ content-type "~1.0.4"
+ cookie "0.7.1"
+ cookie-signature "1.0.6"
+ debug "2.6.9"
+ depd "2.0.0"
+ encodeurl "~2.0.0"
+ escape-html "~1.0.3"
+ etag "~1.8.1"
+ finalhandler "1.3.1"
+ fresh "0.5.2"
+ http-errors "2.0.0"
+ merge-descriptors "1.0.3"
+ methods "~1.1.2"
+ on-finished "2.4.1"
+ parseurl "~1.3.3"
+ path-to-regexp "0.1.10"
+ proxy-addr "~2.0.7"
+ qs "6.13.0"
+ range-parser "~1.2.1"
+ safe-buffer "5.2.1"
+ send "0.19.0"
+ serve-static "1.16.2"
+ setprototypeof "1.2.0"
+ statuses "2.0.1"
+ type-is "~1.6.18"
+ utils-merge "1.0.1"
+ vary "~1.1.2"
+
+finalhandler@1.3.1:
+ version "1.3.1"
+ resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.3.1.tgz#0c575f1d1d324ddd1da35ad7ece3df7d19088019"
+ integrity sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==
+ dependencies:
+ debug "2.6.9"
+ encodeurl "~2.0.0"
+ escape-html "~1.0.3"
+ on-finished "2.4.1"
+ parseurl "~1.3.3"
+ statuses "2.0.1"
+ unpipe "~1.0.0"
+
+forwarded@0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811"
+ integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==
+
+fresh@0.5.2:
+ version "0.5.2"
+ resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
+ integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==
+
+function-bind@^1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c"
+ integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==
+
+get-intrinsic@^1.1.3, get-intrinsic@^1.2.4:
+ version "1.2.4"
+ resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd"
+ integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==
+ dependencies:
+ es-errors "^1.3.0"
+ function-bind "^1.1.2"
+ has-proto "^1.0.1"
+ has-symbols "^1.0.3"
+ hasown "^2.0.0"
+
+gopd@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c"
+ integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==
+ dependencies:
+ get-intrinsic "^1.1.3"
+
+has-property-descriptors@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854"
+ integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==
+ dependencies:
+ es-define-property "^1.0.0"
+
+has-proto@^1.0.1:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd"
+ integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==
+
+has-symbols@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8"
+ integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==
+
+hasown@^2.0.0:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003"
+ integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==
+ dependencies:
+ function-bind "^1.1.2"
+
+http-errors@2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3"
+ integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==
+ dependencies:
+ depd "2.0.0"
+ inherits "2.0.4"
+ setprototypeof "1.2.0"
+ statuses "2.0.1"
+ toidentifier "1.0.1"
+
+iconv-lite@0.4.24:
+ version "0.4.24"
+ resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
+ integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
+ dependencies:
+ safer-buffer ">= 2.1.2 < 3"
+
+inherits@2.0.4:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
+ integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
+
+ipaddr.js@1.9.1:
+ version "1.9.1"
+ resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3"
+ integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==
+
+media-typer@0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
+ integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==
+
+merge-descriptors@1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.3.tgz#d80319a65f3c7935351e5cfdac8f9318504dbed5"
+ integrity sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==
+
+methods@~1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
+ integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==
+
+mime-db@1.52.0:
+ version "1.52.0"
+ resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
+ integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
+
+mime-types@~2.1.24, mime-types@~2.1.34:
+ version "2.1.35"
+ resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
+ integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
+ dependencies:
+ mime-db "1.52.0"
+
+mime@1.6.0:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
+ integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
+
+ms@2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
+ integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==
+
+ms@2.1.3:
+ version "2.1.3"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
+ integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
+
+negotiator@0.6.3:
+ version "0.6.3"
+ resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd"
+ integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==
+
+object-inspect@^1.13.1:
+ version "1.13.2"
+ resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.2.tgz#dea0088467fb991e67af4058147a24824a3043ff"
+ integrity sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==
+
+on-finished@2.4.1:
+ version "2.4.1"
+ resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f"
+ integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==
+ dependencies:
+ ee-first "1.1.1"
+
+parseurl@~1.3.3:
+ version "1.3.3"
+ resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
+ integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==
+
+path-to-regexp@0.1.10:
+ version "0.1.10"
+ resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.10.tgz#67e9108c5c0551b9e5326064387de4763c4d5f8b"
+ integrity sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==
+
+proxy-addr@~2.0.7:
+ version "2.0.7"
+ resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025"
+ integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==
+ dependencies:
+ forwarded "0.2.0"
+ ipaddr.js "1.9.1"
+
+qs@6.13.0:
+ version "6.13.0"
+ resolved "https://registry.yarnpkg.com/qs/-/qs-6.13.0.tgz#6ca3bd58439f7e245655798997787b0d88a51906"
+ integrity sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==
+ dependencies:
+ side-channel "^1.0.6"
+
+range-parser@~1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
+ integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==
+
+raw-body@2.5.2:
+ version "2.5.2"
+ resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a"
+ integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==
+ dependencies:
+ bytes "3.1.2"
+ http-errors "2.0.0"
+ iconv-lite "0.4.24"
+ unpipe "1.0.0"
+
+safe-buffer@5.2.1:
+ version "5.2.1"
+ resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
+ integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
+
+"safer-buffer@>= 2.1.2 < 3":
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
+ integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
+
+send@0.19.0:
+ version "0.19.0"
+ resolved "https://registry.yarnpkg.com/send/-/send-0.19.0.tgz#bbc5a388c8ea6c048967049dbeac0e4a3f09d7f8"
+ integrity sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==
+ dependencies:
+ debug "2.6.9"
+ depd "2.0.0"
+ destroy "1.2.0"
+ encodeurl "~1.0.2"
+ escape-html "~1.0.3"
+ etag "~1.8.1"
+ fresh "0.5.2"
+ http-errors "2.0.0"
+ mime "1.6.0"
+ ms "2.1.3"
+ on-finished "2.4.1"
+ range-parser "~1.2.1"
+ statuses "2.0.1"
+
+serve-static@1.16.2:
+ version "1.16.2"
+ resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.16.2.tgz#b6a5343da47f6bdd2673848bf45754941e803296"
+ integrity sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==
+ dependencies:
+ encodeurl "~2.0.0"
+ escape-html "~1.0.3"
+ parseurl "~1.3.3"
+ send "0.19.0"
+
+set-function-length@^1.2.1:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449"
+ integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==
+ dependencies:
+ define-data-property "^1.1.4"
+ es-errors "^1.3.0"
+ function-bind "^1.1.2"
+ get-intrinsic "^1.2.4"
+ gopd "^1.0.1"
+ has-property-descriptors "^1.0.2"
+
+setprototypeof@1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424"
+ integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==
+
+side-channel@^1.0.6:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2"
+ integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==
+ dependencies:
+ call-bind "^1.0.7"
+ es-errors "^1.3.0"
+ get-intrinsic "^1.2.4"
+ object-inspect "^1.13.1"
+
+statuses@2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63"
+ integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==
+
+toidentifier@1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35"
+ integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==
+
+type-is@~1.6.18:
+ version "1.6.18"
+ resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"
+ integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==
+ dependencies:
+ media-typer "0.3.0"
+ mime-types "~2.1.24"
+
+unpipe@1.0.0, unpipe@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
+ integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==
+
+utils-merge@1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
+ integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==
+
+vary@~1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
+ integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==
diff --git a/src/python/.gitattributes b/src/python/.gitattributes
new file mode 100644
index 0000000..314766e
--- /dev/null
+++ b/src/python/.gitattributes
@@ -0,0 +1,3 @@
+* text=auto eol=lf
+*.{cmd,[cC][mM][dD]} text eol=crlf
+*.{bat,[bB][aA][tT]} text eol=crlf
diff --git a/src/python/.gitignore b/src/python/.gitignore
new file mode 100644
index 0000000..9787daf
--- /dev/null
+++ b/src/python/.gitignore
@@ -0,0 +1,332 @@
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+##
+## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
+
+# User-specific files
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
+
+# User-specific files (MonoDevelop/Xamarin Studio)
+*.userprefs
+
+# Build results
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+[Rr]eleases/
+x64/
+x86/
+bld/
+[Bb]in/
+[Oo]bj/
+[Ll]og/
+
+# Visual Studio 2015/2017 cache/options directory
+.vs/
+# Uncomment if you have tasks that create the project's static files in wwwroot
+#wwwroot/
+
+# Visual Studio 2017 auto generated files
+Generated\ Files/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+# NUNIT
+*.VisualState.xml
+TestResult.xml
+
+# Build Results of an ATL Project
+[Dd]ebugPS/
+[Rr]eleasePS/
+dlldata.c
+
+# Benchmark Results
+BenchmarkDotNet.Artifacts/
+
+# .NET Core
+project.lock.json
+project.fragment.lock.json
+artifacts/
+**/Properties/launchSettings.json
+
+# StyleCop
+StyleCopReport.xml
+
+# Files built by Visual Studio
+*_i.c
+*_p.c
+*_i.h
+*.ilk
+*.meta
+*.obj
+*.iobj
+*.pch
+*.pdb
+*.ipdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*.log
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.svclog
+*.scc
+
+# Chutzpah Test files
+_Chutzpah*
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opendb
+*.opensdf
+*.sdf
+*.cachefile
+*.VC.db
+*.VC.VC.opendb
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+*.sap
+
+# Visual Studio Trace Files
+*.e2e
+
+# TFS 2012 Local Workspace
+$tf/
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+*.DotSettings.user
+
+# JustCode is a .NET coding add-in
+.JustCode
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# AxoCover is a Code Coverage Tool
+.axoCover/*
+!.axoCover/settings.json
+
+# Visual Studio code coverage results
+*.coverage
+*.coveragexml
+
+# NCrunch
+_NCrunch_*
+.*crunch*.local.xml
+nCrunchTemp_*
+
+# MightyMoose
+*.mm.*
+AutoTest.Net/
+
+# Web workbench (sass)
+.sass-cache/
+
+# Installshield output folder
+[Ee]xpress/
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish/
+
+# Publish Web Output
+*.[Pp]ublish.xml
+*.azurePubxml
+# Note: Comment the next line if you want to checkin your web deploy settings,
+# but database connection strings (with potential passwords) will be unencrypted
+*.pubxml
+*.publishproj
+
+# Microsoft Azure Web App publish settings. Comment the next line if you want to
+# checkin your Azure Web App publish settings, but sensitive information contained
+# in these scripts will be unencrypted
+PublishScripts/
+
+# NuGet Packages
+*.nupkg
+# The packages folder can be ignored because of Package Restore
+**/[Pp]ackages/*
+# except build/, which is used as an MSBuild target.
+!**/[Pp]ackages/build/
+# Uncomment if necessary however generally it will be regenerated when needed
+#!**/[Pp]ackages/repositories.config
+# NuGet v3's project.json files produces more ignorable files
+*.nuget.props
+*.nuget.targets
+
+# Microsoft Azure Build Output
+csx/
+*.build.csdef
+
+# Microsoft Azure Emulator
+ecf/
+rcf/
+
+# Windows Store app package directories and files
+AppPackages/
+BundleArtifacts/
+Package.StoreAssociation.xml
+_pkginfo.txt
+*.appx
+
+# Visual Studio cache files
+# files ending in .cache can be ignored
+*.[Cc]ache
+# but keep track of directories ending in .cache
+!*.[Cc]ache/
+
+# Others
+ClientBin/
+~$*
+*~
+*.dbmdl
+*.dbproj.schemaview
+*.jfm
+*.pfx
+*.publishsettings
+orleans.codegen.cs
+
+# Including strong name files can present a security risk
+# (https://github.com/github/gitignore/pull/2483#issue-259490424)
+#*.snk
+
+# Since there are multiple workflows, uncomment next line to ignore bower_components
+# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
+#bower_components/
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file
+# to a newer Visual Studio version. Backup files are not needed,
+# because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+UpgradeLog*.htm
+ServiceFabricBackup/
+*.rptproj.bak
+
+# SQL Server files
+*.mdf
+*.ldf
+*.ndf
+
+# Business Intelligence projects
+*.rdl.data
+*.bim.layout
+*.bim_*.settings
+*.rptproj.rsuser
+
+# Microsoft Fakes
+FakesAssemblies/
+
+# GhostDoc plugin setting file
+*.GhostDoc.xml
+
+# Node.js Tools for Visual Studio
+.ntvs_analysis.dat
+node_modules/
+
+# Visual Studio 6 build log
+*.plg
+
+# Visual Studio 6 workspace options file
+*.opt
+
+# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
+*.vbw
+
+# Visual Studio LightSwitch build output
+**/*.HTMLClient/GeneratedArtifacts
+**/*.DesktopClient/GeneratedArtifacts
+**/*.DesktopClient/ModelManifest.xml
+**/*.Server/GeneratedArtifacts
+**/*.Server/ModelManifest.xml
+_Pvt_Extensions
+
+# Paket dependency manager
+.paket/paket.exe
+paket-files/
+
+# FAKE - F# Make
+.fake/
+
+# JetBrains Rider
+.idea/
+*.sln.iml
+
+# CodeRush
+.cr/
+
+# Python Tools for Visual Studio (PTVS)
+__pycache__/
+*.pyc
+
+# Cake - Uncomment if you are using it
+# tools/**
+# !tools/packages.config
+
+# Tabs Studio
+*.tss
+
+# Telerik's JustMock configuration file
+*.jmconfig
+
+# BizTalk build output
+*.btp.cs
+*.btm.cs
+*.odx.cs
+*.xsd.cs
+
+# OpenCover UI analysis results
+OpenCover/
+
+# Azure Stream Analytics local run output
+ASALocalRun/
+
+# MSBuild Binary and Structured Log
+*.binlog
+
+# NVidia Nsight GPU debugger configuration file
+*.nvuser
+
+# MFractors (Xamarin productivity tool) working folder
+.mfractor/
+
+*.DS_Store
diff --git a/src/python/.vscode/launch.json b/src/python/.vscode/launch.json
new file mode 100644
index 0000000..bed8fa4
--- /dev/null
+++ b/src/python/.vscode/launch.json
@@ -0,0 +1,27 @@
+{
+ // Use IntelliSense to learn about possible attributes.
+ // Hover to view descriptions of existing attributes.
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "name": "Python: Flask",
+ "type": "python",
+ "request": "launch",
+ "module": "flask",
+ "env": {
+ "FLASK_APP": "app.py",
+ "FLASK_ENV": "development",
+ "FLASK_DEBUG": "0"
+ },
+ "args": [
+ "run",
+ "--host","0.0.0.0",
+ "--port","9000",
+ "--no-debugger",
+ "--no-reload"
+ ],
+ "jinja": true
+ }
+ ]
+}
\ No newline at end of file
diff --git a/src/python/app.py b/src/python/app.py
new file mode 100644
index 0000000..8c27ec7
--- /dev/null
+++ b/src/python/app.py
@@ -0,0 +1,11 @@
+#-----------------------------------------------------------------------------------------
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License. See LICENSE in the project root for license information.
+#-----------------------------------------------------------------------------------------
+
+from flask import Flask
+app = Flask(__name__)
+
+@app.route("/")
+def hello():
+ return app.send_static_file("index.html")
diff --git a/src/python/requirements.txt b/src/python/requirements.txt
new file mode 100644
index 0000000..8ab6294
--- /dev/null
+++ b/src/python/requirements.txt
@@ -0,0 +1 @@
+flask
\ No newline at end of file
diff --git a/src/python/static/index.html b/src/python/static/index.html
new file mode 100644
index 0000000..ea0d532
--- /dev/null
+++ b/src/python/static/index.html
@@ -0,0 +1,9 @@
+
+
+ VS Code Rocks!
+
+
+ VS Code can do that?
+ Yes it can!
+
+
\ No newline at end of file