Showing preview only (5,334K chars total). Download the full file or copy to clipboard to get everything.
Repository: Azure/phippyandfriends
Branch: master
Commit: 340200eec1d0
Files: 591
Total size: 5.0 MB
Directory structure:
gitextract_tafhqydv/
├── .gitignore
├── LICENSE
├── README.md
├── captainkube/
│ ├── .dockerignore
│ ├── .draft-tasks.toml
│ ├── .draftignore
│ ├── Dockerfile
│ ├── cd-pipeline.yml
│ ├── charts/
│ │ └── captainkube/
│ │ ├── .helmignore
│ │ ├── Chart.yaml
│ │ ├── templates/
│ │ │ ├── NOTES.txt
│ │ │ ├── _helpers.tpl
│ │ │ ├── deployment.yaml
│ │ │ └── secret.yaml
│ │ └── values.yaml
│ ├── ci-pipeline.yml
│ ├── draft.toml
│ └── main.go
├── common/
│ ├── cd-steps-template.yml
│ ├── cd-vars-template.yml
│ ├── ci-steps-template.yml
│ └── ci-vars-template.yml
├── nodebrady/
│ ├── .dockerignore
│ ├── .draft-tasks.toml
│ ├── .draftignore
│ ├── .editorconfig
│ ├── .jshintrc
│ ├── Dockerfile
│ ├── app.js
│ ├── cd-pipeline.yml
│ ├── charts/
│ │ └── nodebrady/
│ │ ├── .helmignore
│ │ ├── Chart.yaml
│ │ ├── templates/
│ │ │ ├── NOTES.txt
│ │ │ ├── _helpers.tpl
│ │ │ ├── deployment.yaml
│ │ │ ├── ingress.yaml
│ │ │ ├── secret.yaml
│ │ │ └── service.yaml
│ │ └── values.yaml
│ ├── ci-pipeline.yml
│ ├── controllers/
│ │ └── messages.js
│ ├── draft.toml
│ ├── package.json
│ ├── public/
│ │ ├── scripts/
│ │ │ └── .gitkeep
│ │ └── styles/
│ │ └── main.css
│ ├── test/
│ │ └── routeSpec.js
│ └── views/
│ ├── layout.html
│ └── list.html
├── parrot/
│ ├── .dockerignore
│ ├── .draft-tasks.toml
│ ├── .draftignore
│ ├── .vscode/
│ │ ├── launch.json
│ │ └── tasks.json
│ ├── Controllers/
│ │ ├── ClusterStatusController.cs
│ │ ├── HomeController.cs
│ │ └── test.json
│ ├── Dockerfile
│ ├── Hubs/
│ │ └── Daemon.cs
│ ├── Models/
│ │ ├── ErrorViewModel.cs
│ │ └── Pod.cs
│ ├── NOTICE
│ ├── Program.cs
│ ├── Startup.cs
│ ├── Views/
│ │ ├── Home/
│ │ │ └── Index.cshtml
│ │ ├── Shared/
│ │ │ ├── Error.cshtml
│ │ │ ├── _Layout.cshtml
│ │ │ └── _ValidationScriptsPartial.cshtml
│ │ ├── _ViewImports.cshtml
│ │ └── _ViewStart.cshtml
│ ├── appsettings.Development.json
│ ├── appsettings.json
│ ├── bundleconfig.json
│ ├── cd-pipeline.yml
│ ├── charts/
│ │ └── parrot/
│ │ ├── .helmignore
│ │ ├── Chart.yaml
│ │ ├── templates/
│ │ │ ├── NOTES.txt
│ │ │ ├── _helpers.tpl
│ │ │ ├── deployment.yaml
│ │ │ ├── ingress.yaml
│ │ │ ├── secret.yaml
│ │ │ └── service.yaml
│ │ └── values.yaml
│ ├── ci-pipeline.yml
│ ├── draft.toml
│ ├── package.json
│ ├── parrot.csproj
│ ├── semantic/
│ │ ├── gulpfile.js
│ │ ├── src/
│ │ │ ├── definitions/
│ │ │ │ ├── behaviors/
│ │ │ │ │ ├── api.js
│ │ │ │ │ ├── form.js
│ │ │ │ │ └── visibility.js
│ │ │ │ ├── collections/
│ │ │ │ │ ├── breadcrumb.less
│ │ │ │ │ ├── form.less
│ │ │ │ │ ├── grid.less
│ │ │ │ │ ├── menu.less
│ │ │ │ │ ├── message.less
│ │ │ │ │ └── table.less
│ │ │ │ ├── elements/
│ │ │ │ │ ├── button.less
│ │ │ │ │ ├── container.less
│ │ │ │ │ ├── divider.less
│ │ │ │ │ ├── flag.less
│ │ │ │ │ ├── header.less
│ │ │ │ │ ├── icon.less
│ │ │ │ │ ├── image.less
│ │ │ │ │ ├── input.less
│ │ │ │ │ ├── label.less
│ │ │ │ │ ├── list.less
│ │ │ │ │ ├── loader.less
│ │ │ │ │ ├── rail.less
│ │ │ │ │ ├── reveal.less
│ │ │ │ │ ├── segment.less
│ │ │ │ │ └── step.less
│ │ │ │ ├── globals/
│ │ │ │ │ ├── reset.less
│ │ │ │ │ ├── site.js
│ │ │ │ │ └── site.less
│ │ │ │ ├── modules/
│ │ │ │ │ ├── accordion.js
│ │ │ │ │ ├── accordion.less
│ │ │ │ │ ├── checkbox.js
│ │ │ │ │ ├── checkbox.less
│ │ │ │ │ ├── dimmer.js
│ │ │ │ │ ├── dimmer.less
│ │ │ │ │ ├── dropdown.js
│ │ │ │ │ ├── dropdown.less
│ │ │ │ │ ├── embed.js
│ │ │ │ │ ├── embed.less
│ │ │ │ │ ├── modal.js
│ │ │ │ │ ├── modal.less
│ │ │ │ │ ├── nag.js
│ │ │ │ │ ├── nag.less
│ │ │ │ │ ├── popup.js
│ │ │ │ │ ├── popup.less
│ │ │ │ │ ├── progress.js
│ │ │ │ │ ├── progress.less
│ │ │ │ │ ├── rating.js
│ │ │ │ │ ├── rating.less
│ │ │ │ │ ├── search.js
│ │ │ │ │ ├── search.less
│ │ │ │ │ ├── shape.js
│ │ │ │ │ ├── shape.less
│ │ │ │ │ ├── sidebar.js
│ │ │ │ │ ├── sidebar.less
│ │ │ │ │ ├── sticky.js
│ │ │ │ │ ├── sticky.less
│ │ │ │ │ ├── tab.js
│ │ │ │ │ ├── tab.less
│ │ │ │ │ ├── transition.js
│ │ │ │ │ └── transition.less
│ │ │ │ └── views/
│ │ │ │ ├── ad.less
│ │ │ │ ├── card.less
│ │ │ │ ├── comment.less
│ │ │ │ ├── feed.less
│ │ │ │ ├── item.less
│ │ │ │ └── statistic.less
│ │ │ ├── semantic.less
│ │ │ ├── site/
│ │ │ │ ├── collections/
│ │ │ │ │ ├── breadcrumb.overrides
│ │ │ │ │ ├── breadcrumb.variables
│ │ │ │ │ ├── form.overrides
│ │ │ │ │ ├── form.variables
│ │ │ │ │ ├── grid.overrides
│ │ │ │ │ ├── grid.variables
│ │ │ │ │ ├── menu.overrides
│ │ │ │ │ ├── menu.variables
│ │ │ │ │ ├── message.overrides
│ │ │ │ │ ├── message.variables
│ │ │ │ │ ├── table.overrides
│ │ │ │ │ └── table.variables
│ │ │ │ ├── elements/
│ │ │ │ │ ├── button.overrides
│ │ │ │ │ ├── button.variables
│ │ │ │ │ ├── container.overrides
│ │ │ │ │ ├── container.variables
│ │ │ │ │ ├── divider.overrides
│ │ │ │ │ ├── divider.variables
│ │ │ │ │ ├── flag.overrides
│ │ │ │ │ ├── flag.variables
│ │ │ │ │ ├── header.overrides
│ │ │ │ │ ├── header.variables
│ │ │ │ │ ├── icon.overrides
│ │ │ │ │ ├── icon.variables
│ │ │ │ │ ├── image.overrides
│ │ │ │ │ ├── image.variables
│ │ │ │ │ ├── input.overrides
│ │ │ │ │ ├── input.variables
│ │ │ │ │ ├── label.overrides
│ │ │ │ │ ├── label.variables
│ │ │ │ │ ├── list.overrides
│ │ │ │ │ ├── list.variables
│ │ │ │ │ ├── loader.overrides
│ │ │ │ │ ├── loader.variables
│ │ │ │ │ ├── rail.overrides
│ │ │ │ │ ├── rail.variables
│ │ │ │ │ ├── reveal.overrides
│ │ │ │ │ ├── reveal.variables
│ │ │ │ │ ├── segment.overrides
│ │ │ │ │ ├── segment.variables
│ │ │ │ │ ├── step.overrides
│ │ │ │ │ └── step.variables
│ │ │ │ ├── globals/
│ │ │ │ │ ├── reset.overrides
│ │ │ │ │ ├── reset.variables
│ │ │ │ │ ├── site.overrides
│ │ │ │ │ └── site.variables
│ │ │ │ ├── modules/
│ │ │ │ │ ├── accordion.overrides
│ │ │ │ │ ├── accordion.variables
│ │ │ │ │ ├── chatroom.overrides
│ │ │ │ │ ├── chatroom.variables
│ │ │ │ │ ├── checkbox.overrides
│ │ │ │ │ ├── checkbox.variables
│ │ │ │ │ ├── dimmer.overrides
│ │ │ │ │ ├── dimmer.variables
│ │ │ │ │ ├── dropdown.overrides
│ │ │ │ │ ├── dropdown.variables
│ │ │ │ │ ├── embed.overrides
│ │ │ │ │ ├── embed.variables
│ │ │ │ │ ├── modal.overrides
│ │ │ │ │ ├── modal.variables
│ │ │ │ │ ├── nag.overrides
│ │ │ │ │ ├── nag.variables
│ │ │ │ │ ├── popup.overrides
│ │ │ │ │ ├── popup.variables
│ │ │ │ │ ├── progress.overrides
│ │ │ │ │ ├── progress.variables
│ │ │ │ │ ├── rating.overrides
│ │ │ │ │ ├── rating.variables
│ │ │ │ │ ├── search.overrides
│ │ │ │ │ ├── search.variables
│ │ │ │ │ ├── shape.overrides
│ │ │ │ │ ├── shape.variables
│ │ │ │ │ ├── sidebar.overrides
│ │ │ │ │ ├── sidebar.variables
│ │ │ │ │ ├── sticky.overrides
│ │ │ │ │ ├── sticky.variables
│ │ │ │ │ ├── tab.overrides
│ │ │ │ │ ├── tab.variables
│ │ │ │ │ ├── transition.overrides
│ │ │ │ │ └── transition.variables
│ │ │ │ └── views/
│ │ │ │ ├── ad.overrides
│ │ │ │ ├── ad.variables
│ │ │ │ ├── card.overrides
│ │ │ │ ├── card.variables
│ │ │ │ ├── comment.overrides
│ │ │ │ ├── comment.variables
│ │ │ │ ├── feed.overrides
│ │ │ │ ├── feed.variables
│ │ │ │ ├── item.overrides
│ │ │ │ ├── item.variables
│ │ │ │ ├── statistic.overrides
│ │ │ │ └── statistic.variables
│ │ │ ├── theme.config
│ │ │ ├── theme.less
│ │ │ └── themes/
│ │ │ ├── amazon/
│ │ │ │ ├── elements/
│ │ │ │ │ ├── button.overrides
│ │ │ │ │ └── button.variables
│ │ │ │ └── globals/
│ │ │ │ └── site.variables
│ │ │ ├── basic/
│ │ │ │ ├── collections/
│ │ │ │ │ ├── table.overrides
│ │ │ │ │ └── table.variables
│ │ │ │ ├── elements/
│ │ │ │ │ ├── button.overrides
│ │ │ │ │ ├── button.variables
│ │ │ │ │ ├── icon.overrides
│ │ │ │ │ ├── icon.variables
│ │ │ │ │ ├── step.overrides
│ │ │ │ │ └── step.variables
│ │ │ │ ├── globals/
│ │ │ │ │ ├── reset.overrides
│ │ │ │ │ └── reset.variables
│ │ │ │ ├── modules/
│ │ │ │ │ ├── progress.overrides
│ │ │ │ │ └── progress.variables
│ │ │ │ └── views/
│ │ │ │ ├── card.overrides
│ │ │ │ └── card.variables
│ │ │ ├── bookish/
│ │ │ │ └── elements/
│ │ │ │ ├── header.overrides
│ │ │ │ └── header.variables
│ │ │ ├── bootstrap3/
│ │ │ │ └── elements/
│ │ │ │ ├── button.overrides
│ │ │ │ └── button.variables
│ │ │ ├── chubby/
│ │ │ │ ├── collections/
│ │ │ │ │ ├── form.overrides
│ │ │ │ │ ├── form.variables
│ │ │ │ │ ├── menu.overrides
│ │ │ │ │ └── menu.variables
│ │ │ │ ├── elements/
│ │ │ │ │ ├── button.overrides
│ │ │ │ │ ├── button.variables
│ │ │ │ │ ├── header.overrides
│ │ │ │ │ └── header.variables
│ │ │ │ ├── modules/
│ │ │ │ │ ├── accordion.overrides
│ │ │ │ │ └── accordion.variables
│ │ │ │ └── views/
│ │ │ │ ├── comment.overrides
│ │ │ │ └── comment.variables
│ │ │ ├── classic/
│ │ │ │ ├── collections/
│ │ │ │ │ ├── table.overrides
│ │ │ │ │ └── table.variables
│ │ │ │ ├── elements/
│ │ │ │ │ ├── button.overrides
│ │ │ │ │ ├── button.variables
│ │ │ │ │ ├── header.overrides
│ │ │ │ │ └── header.variables
│ │ │ │ ├── modules/
│ │ │ │ │ ├── progress.overrides
│ │ │ │ │ └── progress.variables
│ │ │ │ └── views/
│ │ │ │ ├── card.overrides
│ │ │ │ └── card.variables
│ │ │ ├── colored/
│ │ │ │ └── modules/
│ │ │ │ ├── checkbox.overrides
│ │ │ │ └── checkbox.variables
│ │ │ ├── default/
│ │ │ │ ├── collections/
│ │ │ │ │ ├── breadcrumb.overrides
│ │ │ │ │ ├── breadcrumb.variables
│ │ │ │ │ ├── form.overrides
│ │ │ │ │ ├── form.variables
│ │ │ │ │ ├── grid.overrides
│ │ │ │ │ ├── grid.variables
│ │ │ │ │ ├── menu.overrides
│ │ │ │ │ ├── menu.variables
│ │ │ │ │ ├── message.overrides
│ │ │ │ │ ├── message.variables
│ │ │ │ │ ├── table.overrides
│ │ │ │ │ └── table.variables
│ │ │ │ ├── elements/
│ │ │ │ │ ├── button.overrides
│ │ │ │ │ ├── button.variables
│ │ │ │ │ ├── container.overrides
│ │ │ │ │ ├── container.variables
│ │ │ │ │ ├── divider.overrides
│ │ │ │ │ ├── divider.variables
│ │ │ │ │ ├── flag.overrides
│ │ │ │ │ ├── flag.variables
│ │ │ │ │ ├── header.overrides
│ │ │ │ │ ├── header.variables
│ │ │ │ │ ├── icon.overrides
│ │ │ │ │ ├── icon.variables
│ │ │ │ │ ├── image.overrides
│ │ │ │ │ ├── image.variables
│ │ │ │ │ ├── input.overrides
│ │ │ │ │ ├── input.variables
│ │ │ │ │ ├── label.overrides
│ │ │ │ │ ├── label.variables
│ │ │ │ │ ├── list.overrides
│ │ │ │ │ ├── list.variables
│ │ │ │ │ ├── loader.overrides
│ │ │ │ │ ├── loader.variables
│ │ │ │ │ ├── rail.overrides
│ │ │ │ │ ├── rail.variables
│ │ │ │ │ ├── reveal.overrides
│ │ │ │ │ ├── reveal.variables
│ │ │ │ │ ├── segment.overrides
│ │ │ │ │ ├── segment.variables
│ │ │ │ │ ├── step.overrides
│ │ │ │ │ └── step.variables
│ │ │ │ ├── globals/
│ │ │ │ │ ├── reset.overrides
│ │ │ │ │ ├── reset.variables
│ │ │ │ │ ├── site.overrides
│ │ │ │ │ └── site.variables
│ │ │ │ ├── modules/
│ │ │ │ │ ├── accordion.overrides
│ │ │ │ │ ├── accordion.variables
│ │ │ │ │ ├── chatroom.overrides
│ │ │ │ │ ├── chatroom.variables
│ │ │ │ │ ├── checkbox.overrides
│ │ │ │ │ ├── checkbox.variables
│ │ │ │ │ ├── dimmer.overrides
│ │ │ │ │ ├── dimmer.variables
│ │ │ │ │ ├── dropdown.overrides
│ │ │ │ │ ├── dropdown.variables
│ │ │ │ │ ├── embed.overrides
│ │ │ │ │ ├── embed.variables
│ │ │ │ │ ├── modal.overrides
│ │ │ │ │ ├── modal.variables
│ │ │ │ │ ├── nag.overrides
│ │ │ │ │ ├── nag.variables
│ │ │ │ │ ├── popup.overrides
│ │ │ │ │ ├── popup.variables
│ │ │ │ │ ├── progress.overrides
│ │ │ │ │ ├── progress.variables
│ │ │ │ │ ├── rating.overrides
│ │ │ │ │ ├── rating.variables
│ │ │ │ │ ├── search.overrides
│ │ │ │ │ ├── search.variables
│ │ │ │ │ ├── shape.overrides
│ │ │ │ │ ├── shape.variables
│ │ │ │ │ ├── sidebar.overrides
│ │ │ │ │ ├── sidebar.variables
│ │ │ │ │ ├── sticky.overrides
│ │ │ │ │ ├── sticky.variables
│ │ │ │ │ ├── tab.overrides
│ │ │ │ │ ├── tab.variables
│ │ │ │ │ ├── transition.overrides
│ │ │ │ │ └── transition.variables
│ │ │ │ └── views/
│ │ │ │ ├── ad.overrides
│ │ │ │ ├── ad.variables
│ │ │ │ ├── card.overrides
│ │ │ │ ├── card.variables
│ │ │ │ ├── comment.overrides
│ │ │ │ ├── comment.variables
│ │ │ │ ├── feed.overrides
│ │ │ │ ├── feed.variables
│ │ │ │ ├── item.overrides
│ │ │ │ ├── item.variables
│ │ │ │ ├── statistic.overrides
│ │ │ │ └── statistic.variables
│ │ │ ├── duo/
│ │ │ │ └── elements/
│ │ │ │ ├── loader.overrides
│ │ │ │ └── loader.variables
│ │ │ ├── fixed-width/
│ │ │ │ ├── collections/
│ │ │ │ │ ├── grid.overrides
│ │ │ │ │ └── grid.variables
│ │ │ │ └── modules/
│ │ │ │ ├── modal.overrides
│ │ │ │ └── modal.variables
│ │ │ ├── flat/
│ │ │ │ ├── collections/
│ │ │ │ │ ├── form.overrides
│ │ │ │ │ └── form.variables
│ │ │ │ └── globals/
│ │ │ │ ├── site.overrides
│ │ │ │ └── site.variables
│ │ │ ├── github/
│ │ │ │ ├── collections/
│ │ │ │ │ ├── breadcrumb.variables
│ │ │ │ │ ├── form.overrides
│ │ │ │ │ ├── form.variables
│ │ │ │ │ ├── grid.variables
│ │ │ │ │ ├── menu.overrides
│ │ │ │ │ ├── menu.variables
│ │ │ │ │ ├── message.overrides
│ │ │ │ │ ├── message.variables
│ │ │ │ │ └── table.variables
│ │ │ │ ├── elements/
│ │ │ │ │ ├── button.overrides
│ │ │ │ │ ├── button.variables
│ │ │ │ │ ├── header.variables
│ │ │ │ │ ├── icon.overrides
│ │ │ │ │ ├── icon.variables
│ │ │ │ │ ├── image.variables
│ │ │ │ │ ├── input.overrides
│ │ │ │ │ ├── input.variables
│ │ │ │ │ ├── label.overrides
│ │ │ │ │ ├── label.variables
│ │ │ │ │ ├── segment.overrides
│ │ │ │ │ ├── segment.variables
│ │ │ │ │ ├── step.overrides
│ │ │ │ │ └── step.variables
│ │ │ │ ├── globals/
│ │ │ │ │ └── site.variables
│ │ │ │ └── modules/
│ │ │ │ ├── dropdown.overrides
│ │ │ │ ├── dropdown.variables
│ │ │ │ └── popup.variables
│ │ │ ├── gmail/
│ │ │ │ └── collections/
│ │ │ │ ├── message.overrides
│ │ │ │ └── message.variables
│ │ │ ├── instagram/
│ │ │ │ └── views/
│ │ │ │ ├── card.overrides
│ │ │ │ └── card.variables
│ │ │ ├── material/
│ │ │ │ ├── collections/
│ │ │ │ │ ├── menu.overrides
│ │ │ │ │ └── menu.variables
│ │ │ │ ├── elements/
│ │ │ │ │ ├── button.overrides
│ │ │ │ │ ├── button.variables
│ │ │ │ │ ├── header.overrides
│ │ │ │ │ ├── header.variables
│ │ │ │ │ ├── icon.overrides
│ │ │ │ │ └── icon.variables
│ │ │ │ ├── globals/
│ │ │ │ │ ├── site.overrides
│ │ │ │ │ └── site.variables
│ │ │ │ └── modules/
│ │ │ │ ├── dropdown.overrides
│ │ │ │ ├── dropdown.variables
│ │ │ │ ├── modal.overrides
│ │ │ │ └── modal.variables
│ │ │ ├── pulsar/
│ │ │ │ └── elements/
│ │ │ │ ├── loader.overrides
│ │ │ │ └── loader.variables
│ │ │ ├── raised/
│ │ │ │ └── elements/
│ │ │ │ ├── button.overrides
│ │ │ │ └── button.variables
│ │ │ ├── resetcss/
│ │ │ │ └── globals/
│ │ │ │ ├── reset.overrides
│ │ │ │ └── reset.variables
│ │ │ ├── round/
│ │ │ │ └── elements/
│ │ │ │ ├── button.overrides
│ │ │ │ └── button.variables
│ │ │ ├── rtl/
│ │ │ │ └── globals/
│ │ │ │ ├── site.overrides
│ │ │ │ └── site.variables
│ │ │ ├── striped/
│ │ │ │ └── modules/
│ │ │ │ ├── progress.overrides
│ │ │ │ └── progress.variables
│ │ │ ├── timeline/
│ │ │ │ └── views/
│ │ │ │ ├── feed.overrides
│ │ │ │ └── feed.variables
│ │ │ └── twitter/
│ │ │ └── elements/
│ │ │ ├── button.overrides
│ │ │ └── button.variables
│ │ └── tasks/
│ │ ├── README.md
│ │ ├── admin/
│ │ │ ├── components/
│ │ │ │ ├── create.js
│ │ │ │ ├── init.js
│ │ │ │ └── update.js
│ │ │ ├── distributions/
│ │ │ │ ├── create.js
│ │ │ │ ├── init.js
│ │ │ │ └── update.js
│ │ │ ├── publish.js
│ │ │ ├── register.js
│ │ │ └── release.js
│ │ ├── build/
│ │ │ ├── assets.js
│ │ │ ├── css.js
│ │ │ └── javascript.js
│ │ ├── build.js
│ │ ├── check-install.js
│ │ ├── clean.js
│ │ ├── collections/
│ │ │ ├── README.md
│ │ │ ├── admin.js
│ │ │ ├── build.js
│ │ │ ├── internal.js
│ │ │ └── rtl.js
│ │ ├── config/
│ │ │ ├── admin/
│ │ │ │ ├── github.js
│ │ │ │ ├── oauth.example.js
│ │ │ │ ├── release.js
│ │ │ │ └── templates/
│ │ │ │ ├── README.md
│ │ │ │ ├── bower.json
│ │ │ │ ├── component-package.js
│ │ │ │ ├── composer.json
│ │ │ │ ├── css-package.js
│ │ │ │ ├── less-package.js
│ │ │ │ └── package.json
│ │ │ ├── defaults.js
│ │ │ ├── docs.js
│ │ │ ├── npm/
│ │ │ │ └── gulpfile.js
│ │ │ ├── project/
│ │ │ │ ├── config.js
│ │ │ │ ├── install.js
│ │ │ │ └── release.js
│ │ │ ├── tasks.js
│ │ │ └── user.js
│ │ ├── docs/
│ │ │ ├── build.js
│ │ │ ├── metadata.js
│ │ │ └── serve.js
│ │ ├── install.js
│ │ ├── rtl/
│ │ │ ├── build.js
│ │ │ └── watch.js
│ │ ├── version.js
│ │ └── watch.js
│ ├── semantic.json
│ └── wwwroot/
│ ├── scripts/
│ │ ├── daemon.js
│ │ └── knockout-3.4.2.js
│ └── semantic/
│ ├── components/
│ │ ├── accordion.css
│ │ ├── accordion.js
│ │ ├── ad.css
│ │ ├── api.js
│ │ ├── breadcrumb.css
│ │ ├── button.css
│ │ ├── card.css
│ │ ├── checkbox.css
│ │ ├── checkbox.js
│ │ ├── comment.css
│ │ ├── container.css
│ │ ├── dimmer.css
│ │ ├── dimmer.js
│ │ ├── divider.css
│ │ ├── dropdown.css
│ │ ├── dropdown.js
│ │ ├── embed.css
│ │ ├── embed.js
│ │ ├── feed.css
│ │ ├── flag.css
│ │ ├── form.css
│ │ ├── form.js
│ │ ├── grid.css
│ │ ├── header.css
│ │ ├── icon.css
│ │ ├── image.css
│ │ ├── input.css
│ │ ├── item.css
│ │ ├── label.css
│ │ ├── list.css
│ │ ├── loader.css
│ │ ├── menu.css
│ │ ├── message.css
│ │ ├── modal.css
│ │ ├── modal.js
│ │ ├── nag.css
│ │ ├── nag.js
│ │ ├── popup.css
│ │ ├── popup.js
│ │ ├── progress.css
│ │ ├── progress.js
│ │ ├── rail.css
│ │ ├── rating.css
│ │ ├── rating.js
│ │ ├── reset.css
│ │ ├── reveal.css
│ │ ├── search.css
│ │ ├── search.js
│ │ ├── segment.css
│ │ ├── shape.css
│ │ ├── shape.js
│ │ ├── sidebar.css
│ │ ├── sidebar.js
│ │ ├── site.css
│ │ ├── site.js
│ │ ├── statistic.css
│ │ ├── step.css
│ │ ├── sticky.css
│ │ ├── sticky.js
│ │ ├── tab.css
│ │ ├── tab.js
│ │ ├── table.css
│ │ ├── transition.css
│ │ ├── transition.js
│ │ └── visibility.js
│ ├── semantic.css
│ └── semantic.js
└── phippy/
├── .dockerignore
├── .draft-tasks.toml
├── .draftignore
├── Dockerfile
├── cd-pipeline.yml
├── charts/
│ └── phippy/
│ ├── .helmignore
│ ├── Chart.yaml
│ ├── templates/
│ │ ├── NOTES.txt
│ │ ├── _helpers.tpl
│ │ ├── deployment.yaml
│ │ ├── ingress.yaml
│ │ ├── secret.yaml
│ │ └── service.yaml
│ └── values.yaml
├── ci-pipeline.yml
├── composer.json
├── composer.phar
├── draft.toml
└── index.php
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
## 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/
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) Microsoft Corporation. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE
================================================
FILE: README.md
================================================
# Phippy and Friends
The [Children's Guide to Kubernetes](https://azure.microsoft.com/en-us/resources/videos/the-illustrated-children-s-guide-to-kubernetes/) is a simple, gentle answer a father gives his daughter, when she inquisitively asked about Kubernetes. It was written by [Matt](https://twitter.com/technosophos) [Butcher](http://technosophos.com/) on the [DEIS blog](https://deis.com/blog/2016/kubernetes-illustrated-guide/).
We loved the story and the imagery in it and thought the characters from the Illustrated Guide would make for an interesting demo. The demo has a few services, each of which represent an individual character in the story, as well as some we added. Each service is written in a different language, showing how the [Azure Kubernetes Service (AKS)](https://azure.microsoft.com/en-us/services/kubernetes-service/) cluster can run anything you can bring it.
## Table of Contents
1. [Prerequisites](#prerequisites)
1. [Getting Started](#get-started)
1. [Clone and open the code](#clone-and-open-the-code)
1. [Get your public URL](#get-your-aks-ingress-url)
1. [Connect to your Azure Container Registry](#connect-to-your-registry)
1. [Deploy with Helm and Draft](#deploy-parrot-and-captain-kube-with-draft-and-helm)
1. [Validate Deployment](#validate-the-deployment)
1. [Where is Phippy?](#but-where-is-phippy)
1. [Watch in real time](#watch-in-real-time)
1. [Try scaling your apps](#try-scaling-your-apps)
1. [Leverage Azure DevOps](#leverage-azure-devops)
1. [Issues and Contributions](#issues)
---
## Prerequisites
Here's a short list of all the things you'll need to do. Don't worry - you'll be up and running in about thirty minutes.
1. An [Azure](https://azure.microsoft.com/en-us/free/) subscription. You can [Sign up for Free](https://azure.microsoft.com/en-us/free/) and see for yourself how Azure Kubernetes Service (AKS) is the best place for developers using Kubernetes.
1. An Azure Kubernetes Service (AKS) Cluster, [enabled with Http Application Routing](https://docs.microsoft.com/en-us/azure/aks/http-application-routing) (this is **on** by default when you create a cluster via the Azure portal).
- *Important note: if your AKS cluster has RBAC enabled, you will need to run the following command to have `captainkube` able to read the information in the cluster: `kubectl create clusterrolebinding default-view --clusterrole=view --serviceaccount=phippyandfriends:default`.*
1. An Azure Container Registry instance (or a Docker Hub account if you prefer to use Docker Hub). If you opt to use Azure Container Registry, make sure you [configure RBAC access so that AKS has the proper role assignment to access your ACR](https://docs.microsoft.com/en-us/azure/container-registry/container-registry-auth-aks#grant-aks-access-to-acr).
1. You'll need to install a few tools handy for developing with containers and Kubernetes, and the Azure CLI:
1. [The Azure CLI](https://docs.microsoft.com/en-us/cli/azure/?view=azure-cli-latest)
1. [Helm](http://helm.sh) and [Draft](https://draft.sh/) are also required, as they enable deploying and debugging code in Kubernetes.
1. [Visual Studio Code](http://code.visualstudio.com) and the [Kubernetes extension](https://marketplace.visualstudio.com/items?itemName=ms-kubernetes-tools.vscode-kubernetes-tools) for it would also be great to have.
## Get Started!
To get started, follow these simple steps.
### Clone and Open the Code
The Phippy and Friends repository is public. Just clone it to your local machine and open the folder up in Visual Studio Code to get started.
```bash
git clone https://github.com/Azure/phippyandfriends.git
cd phippy-demo
code .
```
### Get your AKS Ingress URL
A few of the services will provide HTML UIs. To enable external access, Ingress needs to be set up on each of these services using the external DNS of the cluster. Don't worry, though, this is easy. You can use VS Code's integrated terminal or the Cloud Shell tools in VS Code to run this `az` command line call, which will get your AKS cluster's external DNS.
```bash
az aks show -n <your cluster name> -g <your resource group name> --query addonProfiles.httpApplicationRouting.config.HTTPApplicationRoutingZoneName
```

You can also get the DNS from the Azure portal if you prefer.

We'll be deploying the **parrot** service first (more on that in a moment), so let's take a look at the `values.yaml` file for parrot. The `values.yaml` file is where you can customize your service, release, deployment, and in our case, ingress settings. Find the `basedomain` property.

Change the value of the `basedomain` property to match the DNS for your AKS cluster.

### Connect to your Registry
If you want to select which registry to push to, use the command below:
```bash
draft config set registry <your Docker hub or Azure Container Registry>
```
If you're using ACR, you can also log into your registry using the Azure CLI.
```bash
az acr login -n <your ACR instance name> -g <your ACR instance resource group>
```
### Deploy Parrot and Captain Kube with Draft and Helm
Now you'll create the first two services, **parrot** and **captainkube**.
1. The captainkube service, a simple Go app, is represented by Captain Kube from the Children's Illustrated Guide to Kubernetes. This service constantly watches the pods running in the Kubernetes cluster. Whenever a pod is activated, updated, or deleted from the cluster, captainkube tells the parrot service what just happened.
1. The parrot service is essentially an ASP.NET Core app with a Web API back-end. The Web API bubbles events up to the HTML client via a SignalR Hub. Parrot essentially "parrots" what captainkube is telling him in the form of [Semantic UI](http://semantic-ui.com) cards on the UI side. When services pop into the cluster, they're represented by characters shown in the cards.
These two baseline services need to be running first, so you can Draft them up into the cluster using the commands below.
```bash
cd parrot
draft up
cd ..
cd captainkube
draft up
cd ..
```
You'll be provided feedback as the deployment takes place.

## Validate the Deployment
Once the deployment has completed, enter this Kubernetes CLI command to see everything you've deployed into the cluster.
```bash
kubectl get svc,pod,ing --namespace phippyandfriends
```
You should see something like this in your terminal window.
```bash
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
parrot-parrot ClusterIP 10.0.224.230 <none> 80/TCP 3m
NAME READY STATUS RESTARTS AGE
captainkube-captainkube-f5b4487c5-shw4p 1/1 Running 0 3m
parrot-parrot-677cc74b47-zdw6z 1/1 Running 0 3m
NAME HOSTS ADDRESS PORTS
parrot-parrot parrot.0d7b3d707c094da087a7.westus.aksapp.io 80
```
It may take a few minutes for the ingress DNS to be matched up to the public IP address for the cluster. If you don't see an IP address listed for the `parrot` service, just type this command and watch the terminal window update automatically until you have a public IP address for the ingress.
```bash
kubectl get ing --namespace phippyandfriends -w
```
Eventually, your ingress will reflect the public IP address, which is your sign that parrot's DNS will work. So copy it from the terminal window.

Drop parrot's ingress URI into a web browser and you'll see the dashboard, which confirms you've got two services - parrot and captainkube - running in your cluster.

### But where is Phippy?
The Phippy service is a super-simple PHP app.
Next, CD into the phippy directory, as we definitely want to make sure we deploy our star of the show, Phippy, into our AKS cluster. Use the same `draft up` command as you did for parrot and captainkube, and you'll see the phippy service's deployment status as it occurs.
The moment the deployment finishes, the dashboard will light up with Phippy!

### Watch in Real-time
The final service is a basic Node.js application represented by the Node.js-decorated [Azure Brady, the Open Cloud Ninja Sloth](https://github.com/Microsoft/OpenCloudNinjaSloth).
You can cd into this service's folder and deploy it using `draft up` as you did with the others. But for fun, do this in a window that's side-by-side with the parrot dashboard. This way you can see services appear as you `draft up` and vanish as you `draft delete`.
### Try Scaling your Apps
Scale your nodebrady by running this:
```bash
kubectl scale deployment/nodebrady-nodebrady --replicas 3 --namespace phippyandfriends
```
Watch as more brady ninjas come to life!
## Leverage Azure DevOps
You could also leverage [Azure DevOps](https://docs.microsoft.com/azure/devops) to implement a [CI/CD pipeline](https://docs.microsoft.com/azure/devops/pipelines) for each app. For that you could [create Azure build pipelines](https://docs.microsoft.com/azure/devops/pipelines/get-started-yaml#get-your-first-build) per app for both Build/CI and Release/CD by using the associated YAML definitions:
- [captainkube/ci-pipeline.yml](captainkube/ci-pipeline.yml) and [captainkube/cd-pipeline.yml](captainkube/cd-pipeline.yml)
- [nodebrady/ci-pipeline.yml](nodebrady/ci-pipeline.yml) and [nodebrady/cd-pipeline.yml](nodebrady/cd-pipeline.yml)
- [parrot/ci-pipeline.yml](parrot/ci-pipeline.yml) and [parrot/cd-pipeline.yml](parrot/cd-pipeline.yml)
- [phippy/ci-pipeline.yml](phippy/ci-pipeline.yml) and [phippy/cd-pipeline.yml](phippy/cd-pipeline.yml)

For more information, you could follow this tutorial: [Using Azure DevOps to setup a CI/CD pipeline and deploy to Kubernetes](https://open.microsoft.com/2018/11/27/tutorial-azure-devops-setup-cicd-pipeline-kubernetes-docker-helm).
## Issues?
Phippy and Friends is open-source, and we'd love your contributions. Submit issues, then work those issues and send us a pull request. Customize the parrot dashboard with a theme, put the characters on a boat, launch them into space. We'd love to see what other characters you'll add to the dashboard!
### Troubleshooting
Sometimes a previous deployment would fail and you would receive a message like so:
```sh
error while releasing: could not upgrade release: rpc error: code = Unknown desc = "parrot" has no deployed releases
```
if that happens, you need to delete that failed deployment by running the following command, replacing `parrot` with the failed deployment name:
```sh
helm uninstall parrot -n phippyandfriends
```
## Credits
Some awesome people worked on the Phippy and Friends demo. [Stella Lin]() brought the idea to [Brady Gaster](), who then got a **ton** of help from [Ralph Squillace]() and [Ahmed Sabbour](http://twitter.com/sabbour) to bring it to life and [Mathieu Benoit](http://github.com/mathieu-benoit) for his Azure DevOps pipelines. As mentioned earlier, Phippy and Friends was originally inspired by a blog post written by [Matt](https://twitter.com/technosophos) [Butcher](http://technosophos.com/). Phippy and friends were conceived by Matt Butcher, Karen Chu, and Bailey Beougher and are licensed by the CNCF under the CC-BY license. More info at [phippy.io](http://phippy.io). Goldie the Gopher is based on the Go Gopher by Renee French.
You can help too, by submitting a pull request and adding your own contributions. When you do, make sure to add your contributions' summary to this section, too!
================================================
FILE: captainkube/.dockerignore
================================================
Dockerfile
draft.toml
chart/
NOTICE
Godeps/
vendor/
================================================
FILE: captainkube/.draft-tasks.toml
================================================
================================================
FILE: captainkube/.draftignore
================================================
*.swp
*.tmp
*.temp
.git*
================================================
FILE: captainkube/Dockerfile
================================================
# Build
FROM golang:1.14.4 as builder
WORKDIR /build
COPY main.go .
# temporary workaroud for https://github.com/Azure/phippyandfriends/issues/44
RUN GO111MODULE=on; go mod init captainkube && go get k8s.io/client-go@v0.17.2 && go get -d -v
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .
# Run
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /build/app .
CMD ["./app"]
================================================
FILE: captainkube/cd-pipeline.yml
================================================
trigger: none
pr: none
variables:
- template: ../common/cd-vars-template.yml
parameters:
projectName: captainkube
# define 3 more variables: registryName, registryLogin and registryPassword in the Azure pipeline UI definition
resources:
pipelines:
- pipeline: ci-pipeline
source: captainkube-ci
trigger:
enabled: true
branches:
include:
- master
stages:
- stage: development
displayName: development
jobs:
- deployment: development
variables:
k8sNamespace: 'phippyandfriends'
# define 5 more variables: aks, rg, aksSpId, aksSpSecret and aksSpTenantId in the Azure pipeline UI definition
displayName: deploy helm chart into AKS
pool:
vmImage: ubuntu-latest
environment: development-$(projectName)
strategy:
runOnce:
deploy:
steps:
- template: ../common/cd-steps-template.yml
================================================
FILE: captainkube/charts/captainkube/.helmignore
================================================
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*~
# Various IDEs
.project
.idea/
*.tmproj
================================================
FILE: captainkube/charts/captainkube/Chart.yaml
================================================
apiVersion: v1
description: This app represents Captain Kube, who is taking care of all the containers in the cluster.
name: captainkube
version: v0.3.0
================================================
FILE: captainkube/charts/captainkube/templates/NOTES.txt
================================================
Tail the logs of the lighthouse pod
- kubectl logs -f --namespace {{ .Release.Namespace }} \
$(kubectl get pods --namespace {{ .Release.Namespace }} \
-l app={{ template "fullname" . }} \
-o jsonpath='{ .items[0].metadata.name }')
================================================
FILE: captainkube/charts/captainkube/templates/_helpers.tpl
================================================
{{/* vim: set filetype=mustache: */}}
{{/*
Expand the name of the chart.
*/}}
{{- define "name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
*/}}
{{- define "fullname" -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
Generate the imagePullSecret for a private Container Registry.
*/}}
{{- define "imagePullSecret" }}
{{- printf "{\"auths\": {\"%s\": {\"auth\": \"%s\"}}}" .Values.image.repository (printf "%s:%s" .Values.image.username .Values.image.password | b64enc) | b64enc }}
{{- end }}
================================================
FILE: captainkube/charts/captainkube/templates/deployment.yaml
================================================
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ template "fullname" . }}
labels:
app: {{ template "fullname" . }}
chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}"
release: "{{ .Release.Name }}"
heritage: "{{ .Release.Service }}"
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app: {{ template "fullname" . }}
template:
metadata:
labels:
app: {{ template "fullname" . }}
spec:
{{ if .Values.image.useImagePullSecrets }}
imagePullSecrets:
- name: {{ .Chart.Name }}-acr-secret
{{ end }}
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- containerPort: 3000
livenessProbe:
httpGet:
path: /healthz
port: 3000
initialDelaySeconds: 3
periodSeconds: 3
resources:
{{ toYaml .Values.resources | indent 12 }}
================================================
FILE: captainkube/charts/captainkube/templates/secret.yaml
================================================
{{ if .Values.image.private }}
apiVersion: v1
kind: Secret
metadata:
name: {{ .Chart.Name }}-acr-secret
type: kubernetes.io/dockerconfigjson
data:
.dockerconfigjson: {{ template "imagePullSecret" . }}
{{ end }}
================================================
FILE: captainkube/charts/captainkube/values.yaml
================================================
replicaCount: 1
image:
useImagePullSecrets: false
pullPolicy: Always
================================================
FILE: captainkube/ci-pipeline.yml
================================================
trigger:
batch: true
branches:
include:
- '*'
paths:
include:
- captainkube/
- common/ci-steps-template.yml
pr: none
pool:
vmImage: ubuntu-latest
variables:
- template: ../common/ci-vars-template.yml
parameters:
projectName: captainkube
# define 3 more variables: registryName, registryLogin and registryPassword in the Azure pipeline UI definition
steps:
- template: ../common/ci-steps-template.yml
================================================
FILE: captainkube/draft.toml
================================================
[environments]
[environments.development]
name = "captainkube"
namespace = "phippyandfriends"
wait = true
watch = false
watch-delay = 2
auto-connect = false
dockerfile = ""
chart = ""
================================================
FILE: captainkube/main.go
================================================
package main
import (
"time"
"bytes"
"encoding/json"
"net/http"
"log"
"reflect"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/cache"
)
type Pod struct {
Container string
ContainerImage string
Name string
Namespace string
Status string
Action string
}
func main() {
log.Println("Starting up Captain Kube")
informerChannel := make(chan struct{})
go runinformer(informerChannel)
runhealthz()
<-informerChannel
log.Println("Captain Kube shutting down")
}
func runhealthz() {
// Start listening for health checks
mux := http.NewServeMux()
mux.HandleFunc("/healthz", func(w http.ResponseWriter, req *http.Request) {
checkReq, err := http.NewRequest(http.MethodGet, "http://parrot-parrot/", bytes.NewBuffer([]byte(``)))
httpclient := &http.Client{}
_, err = httpclient.Do(checkReq)
if err != nil {
log.Println("Parrot is unreachable")
w.WriteHeader(http.StatusServiceUnavailable)
} else {
w.WriteHeader(http.StatusOK)
}
})
log.Println("Listening for health checks...")
http.ListenAndServe(":3000", mux)
}
func runinformer(done chan struct{}) {
// creates the in-cluster config
config, err := rest.InClusterConfig()
if err != nil {
panic(err.Error())
}
// creates the client
client, err := kubernetes.NewForConfig(config)
if err != nil {
panic(err.Error())
}
// Clear the cluster status, start with a blank slate
req, err := http.NewRequest(http.MethodDelete, "http://parrot-parrot/api/ClusterStatus", bytes.NewBuffer([]byte(``)))
httpclient := &http.Client{}
_, err = httpclient.Do(req)
if err != nil {
log.Printf("The HTTP request failed with error %s", err)
} else {
log.Printf("\n\n**** Cleared parrot****\n\n")
}
watchList := cache.NewListWatchFromClient(client.CoreV1().RESTClient(), "pods", v1.NamespaceAll, fields.Everything())
// Setup the informer that will start watching for pod triggers
informer := cache.NewSharedIndexInformer(
watchList,
&v1.Pod{},
10*time.Second,
cache.Indexers{},
) // We only want `Pod`, force resync every 10 seconds
// Setup the trigger handlers that will receive triggers
informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
// This method is executed when a new pod is created
AddFunc: func(obj interface{}) {
pod, ok := obj.(*v1.Pod) // cast the object as a pod
if !ok {
//log.Printf("Couldn't cast object as pod: %s", obj)
return
}
pingparrot(pod,"Added") // Ping the parrot
},
// This method is executed when an existing pod is updated
UpdateFunc: func(oldObj, newObj interface{}) {
newPod, ok := newObj.(*v1.Pod) // cast the object as a pod
if !ok {
//log.Printf("Couldn't cast object as pod: %s", newObj)
return
}
// Deep compare objects and only notify if they are truly different
if !reflect.DeepEqual(oldObj, newObj) {
pingparrot(newPod,"Updated") // Ping the parrot
}
},
// This method is executed when an existing pod is deleted
DeleteFunc: func(obj interface{}) {
pod, ok := obj.(*v1.Pod) // cast the object as a pod
if !ok {
//log.Printf("Couldn't cast object as pod: %s", obj)
return
}
pingparrot(pod,"Deleted") // Ping the parrot
},
})
// Start the informer, until `done` is closed
informer.Run(done)
}
func pingparrot(pod *v1.Pod, state string) {
if pod.ObjectMeta.Namespace != "kube-system" {
log.Printf("Pod %s: %s", state, pod.ObjectMeta.Name)
log.Printf("namespace: %s", pod.ObjectMeta.Namespace)
log.Printf("status: %s", pod.Status.Phase)
log.Printf("startTime: %s", pod.Status.StartTime)
log.Printf("conditions:")
for _, condition := range pod.Status.Conditions {
log.Printf("\ttype: %s", condition.Type)
log.Printf("\tlastTransitionTime: %s", condition.LastTransitionTime)
}
// shrink the object we send over
p := Pod{Action: state, Container: pod.Spec.Containers[0].Name, ContainerImage: pod.Spec.Containers[0].Image, Name: pod.ObjectMeta.Name, Namespace: pod.ObjectMeta.Namespace, Status: string(pod.Status.Phase)}
jsonValue, _ := json.Marshal(p)
//log.Printf("\n%s\n",jsonValue)
_, err := http.Post("http://parrot-parrot/api/ClusterStatus", "application/json", bytes.NewBuffer(jsonValue))
if err != nil {
log.Printf("The HTTP request failed with error %s", err)
} else {
log.Printf("Notified parrot: %s", state)
}
log.Printf("\n\n")
}
}
================================================
FILE: common/cd-steps-template.yml
================================================
steps:
- checkout: none
- task: HelmInstaller@1
displayName: 'install helm'
inputs:
helmVersionToInstall: $(helmVersion)
- download: ci-pipeline
artifact: build-artifact
- bash: |
az login \
--service-principal \
-u $(aksSpId) \
-p '$(aksSpSecret)' \
--tenant $(aksSpTenantId)
az aks get-credentials \
-n $(aks) \
-g $(rg)
helm repo add \
$(registryName) \
https://$(registryServerName)/helm/v1/repo \
--username $(registryLogin) \
--password '$(registryPassword)'
helmChartVersion=$(jq .helmChartVersion $(pipeline.workspace)/ci-pipeline/build-artifact/variables.json -r)
helm upgrade \
--namespace $(k8sNamespace) \
--create-namespace \
--install \
--wait \
--version $helmChartVersion \
--set image.repository=$(registryServerName)/$(projectName) \
--set ingress.enabled=false \
$(projectName) \
$(registryName)/$(projectName)
failOnStderr: true
displayName: 'deploy helm chart'
================================================
FILE: common/cd-vars-template.yml
================================================
parameters:
projectName: ''
variables:
helmVersion: 3.2.3
registryServerName: '$(registryName).azurecr.io'
projectName: ${{ parameters.projectName }}
================================================
FILE: common/ci-steps-template.yml
================================================
steps:
- bash: |
cd $(projectName)
docker build \
-t $(registryServerName)/$(imageName):$(imageTag) \
.
failOnStderr: true
displayName: 'docker build'
- bash: |
echo '$(registryPassword)' | docker login \
$(registryServerName) \
-u $(registryLogin) \
--password-stdin
condition: and(succeeded(), eq(variables['build.sourceBranch'], 'refs/heads/master'))
displayName: 'docker login'
- bash: |
docker push $(registryServerName)/$(imageName):$(imageTag)
failOnStderr: true
condition: and(succeeded(), eq(variables['build.sourceBranch'], 'refs/heads/master'))
displayName: 'docker push'
- task: HelmInstaller@1
displayName: 'install helm'
inputs:
helmVersionToInstall: $(helmVersion)
- bash: |
cd $(projectName)
helm package \
--version $(helmChartVersion) \
--app-version $(imageTag) \
charts/$(projectName)
failOnStderr: true
displayName: 'helm package'
- bash: |
cd $(projectName)
chartPackage=$(ls $(projectName)-$(helmChartVersion).tgz)
az acr helm push \
-n $(registryName) \
-u $(registryLogin) \
-p '$(registryPassword)' \
$chartPackage
echo $(jq -n --arg version "$(helmChartVersion)" '{helmChartVersion: $version}') > $(build.artifactStagingDirectory)/variables.json
failOnStderr: true
name: helmPush
condition: and(succeeded(), eq(variables['build.sourceBranch'], 'refs/heads/master'))
displayName: 'az acr helm push'
- publish: $(build.artifactStagingDirectory)
artifact: build-artifact
condition: and(succeeded(), eq(variables['build.sourceBranch'], 'refs/heads/master'))
================================================
FILE: common/ci-vars-template.yml
================================================
parameters:
projectName: ''
variables:
helmVersion: 3.2.3
registryServerName: '$(registryName).azurecr.io'
projectName: ${{ parameters.projectName }}
imageName: ${{ parameters.projectName }}
imageTag: $(build.buildId)
helmChartVersion: $(build.buildId)
================================================
FILE: nodebrady/.dockerignore
================================================
Dockerfile
draft.toml
chart/
NOTICE
node_modules
npm-debug.log
================================================
FILE: nodebrady/.draft-tasks.toml
================================================
================================================
FILE: nodebrady/.draftignore
================================================
*.swp
*.tmp
*.temp
.git*
================================================
FILE: nodebrady/.editorconfig
================================================
# http://editorconfig.org
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
================================================
FILE: nodebrady/.jshintrc
================================================
{
"node": true,
"esnext": true,
"bitwise": true,
"camelcase": true,
"curly": true,
"eqeqeq": true,
"immed": true,
"indent": 2,
"latedef": true,
"newcap": true,
"noarg": true,
"quotmark": "single",
"regexp": true,
"undef": true,
"unused": true,
"strict": true,
"trailing": true,
"smarttabs": true,
"white": true
}
================================================
FILE: nodebrady/Dockerfile
================================================
# Build
FROM node:carbon AS base
WORKDIR /app
# Dependencies
FROM base AS dependencies
# A wildcard is used to ensure both package.json AND package-lock.json are copied
COPY package*.json ./
# Install app dependencies including 'devDependencies'
RUN npm install
# Copy Files/Build ----
FROM dependencies AS build
WORKDIR /app
COPY . /app
# Release with Alpine
FROM node:14.4.0-alpine AS release
# Create app directory
WORKDIR /app
COPY --from=dependencies /app/package.json ./
# Install app dependencies
RUN npm install --only=production
COPY --from=build /app ./
CMD ["npm", "start"]
================================================
FILE: nodebrady/app.js
================================================
'use strict';
const messages = require('./controllers/messages');
const compress = require('koa-compress');
const logger = require('koa-logger');
const serve = require('koa-static');
const route = require('koa-route');
const koa = require('koa');
const path = require('path');
const app = module.exports = koa();
// Logger
app.use(logger());
app.use(route.get('/', messages.home));
app.use(route.get('/messages', messages.list));
app.use(route.get('/messages/:id', messages.fetch));
app.use(route.post('/messages', messages.create));
app.use(route.get('/async', messages.delay));
app.use(route.get('/promise', messages.promise));
// Serve static files
app.use(serve(path.join(__dirname, 'public')));
// Compress
app.use(compress());
if (!module.parent) {
app.listen(3000);
console.log('listening on port 3000');
}
================================================
FILE: nodebrady/cd-pipeline.yml
================================================
trigger: none
pr: none
variables:
- template: ../common/cd-vars-template.yml
parameters:
projectName: nodebrady
# define 3 more variables: registryName, registryLogin and registryPassword in the Azure pipeline UI definition
resources:
pipelines:
- pipeline: ci-pipeline
source: nodebrady-ci
trigger:
enabled: true
branches:
include:
- master
stages:
- stage: development
displayName: development
jobs:
- deployment: development
variables:
k8sNamespace: 'phippyandfriends'
# define 5 more variables: aks, rg, aksSpId, aksSpSecret and aksSpTenantId in the Azure pipeline UI definition
displayName: deploy helm chart into AKS
pool:
vmImage: ubuntu-latest
environment: development-$(projectName)
strategy:
runOnce:
deploy:
steps:
- template: ../common/cd-steps-template.yml
================================================
FILE: nodebrady/charts/nodebrady/.helmignore
================================================
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*~
# Various IDEs
.project
.idea/
*.tmproj
================================================
FILE: nodebrady/charts/nodebrady/Chart.yaml
================================================
apiVersion: v1
description: Azure Brady in his Node.js attire.
name: nodebrady
version: v0.3.0
================================================
FILE: nodebrady/charts/nodebrady/templates/NOTES.txt
================================================
Tail the logs of the lighthouse pod
- kubectl logs -f --namespace {{ .Release.Namespace }} \
$(kubectl get pods --namespace {{ .Release.Namespace }} \
-l app={{ template "fullname" . }} \
-o jsonpath='{ .items[0].metadata.name }')
================================================
FILE: nodebrady/charts/nodebrady/templates/_helpers.tpl
================================================
{{/* vim: set filetype=mustache: */}}
{{/*
Expand the name of the chart.
*/}}
{{- define "name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
*/}}
{{- define "fullname" -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
Generate the imagePullSecret for a private Container Registry.
*/}}
{{- define "imagePullSecret" }}
{{- printf "{\"auths\": {\"%s\": {\"auth\": \"%s\"}}}" .Values.image.repository (printf "%s:%s" .Values.image.username .Values.image.password | b64enc) | b64enc }}
{{- end }}
================================================
FILE: nodebrady/charts/nodebrady/templates/deployment.yaml
================================================
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ template "fullname" . }}
labels:
app: {{ template "fullname" . }}
chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}"
release: "{{ .Release.Name }}"
heritage: "{{ .Release.Service }}"
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app: {{ template "fullname" . }}
template:
metadata:
labels:
app: {{ template "fullname" . }}
spec:
{{ if .Values.image.useImagePullSecrets }}
imagePullSecrets:
- name: {{ .Chart.Name }}-acr-secret
{{ end }}
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- containerPort: {{ .Values.service.internalPort }}
resources:
{{ toYaml .Values.resources | indent 12 }}
================================================
FILE: nodebrady/charts/nodebrady/templates/ingress.yaml
================================================
{{ if .Values.ingress.enabled }}
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: {{ template "fullname" . }}
labels:
app: {{ template "fullname" . }}
chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}"
release: "{{ .Release.Name }}"
heritage: "{{ .Release.Service }}"
annotations:
kubernetes.io/ingress.class: addon-http-application-routing
spec:
rules:
- host: {{ .Release.Name }}.{{ .Values.ingress.basedomain }}
http:
paths:
- path: /
backend:
serviceName: {{ template "fullname" . }}
servicePort: {{ .Values.service.externalPort }}
{{ end }}
================================================
FILE: nodebrady/charts/nodebrady/templates/secret.yaml
================================================
{{ if .Values.image.private }}
apiVersion: v1
kind: Secret
metadata:
name: {{ .Chart.Name }}-acr-secret
type: kubernetes.io/dockerconfigjson
data:
.dockerconfigjson: {{ template "imagePullSecret" . }}
{{ end }}
================================================
FILE: nodebrady/charts/nodebrady/templates/service.yaml
================================================
apiVersion: v1
kind: Service
metadata:
name: {{ template "fullname" . }}
labels:
app: {{ template "fullname" . }}
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
release: "{{ .Release.Name }}"
heritage: "{{ .Release.Service }}"
spec:
ports:
- port: {{ .Values.service.externalPort }}
protocol: TCP
targetPort: {{ .Values.service.internalPort }}
selector:
app: {{ template "fullname" . }}
type: ClusterIP
================================================
FILE: nodebrady/charts/nodebrady/values.yaml
================================================
replicaCount: 1
image:
useImagePullSecrets: false
pullPolicy: Always
service:
internalPort: 3000
externalPort: 80
ingress:
enabled: false
#basedomain: CHANGE_TO_YOUR_DNS.REGION.aksapp.io # replace with your own from the portal
================================================
FILE: nodebrady/ci-pipeline.yml
================================================
trigger:
batch: true
branches:
include:
- '*'
paths:
include:
- nodebrady/
- common/ci-steps-template.yml
pr: none
pool:
vmImage: ubuntu-latest
variables:
- template: ../common/ci-vars-template.yml
parameters:
projectName: nodebrady
# define 3 more variables: registryName, registryLogin and registryPassword in the Azure pipeline UI definition
steps:
- template: ../common/ci-steps-template.yml
================================================
FILE: nodebrady/controllers/messages.js
================================================
'use strict';
const views = require('co-views');
const parse = require('co-body');
const messages = [
{ id: 0,
message: 'Koa next generation web framework for node.js'
},
{ id: 1,
message: 'Koa is a new web framework designed by the team behind Express'
}
];
const render = views(__dirname + '/../views', {
map: { html: 'swig' }
});
module.exports.home = function *home(ctx) {
this.body = yield render('list', { 'messages': messages });
};
module.exports.list = function *list() {
this.body = yield messages;
};
module.exports.fetch = function *fetch(id) {
const message = messages[id];
if (!message) {
this.throw(404, 'message with id = ' + id + ' was not found');
}
this.body = yield message;
};
module.exports.create = function *create() {
const message = yield parse(this);
const id = messages.push(message) - 1;
message.id = id;
this.redirect('/');
};
const asyncOperation = () => callback =>
setTimeout(
() => callback(null, 'this was loaded asynchronously and it took 2 seconds to complete'),
2000);
const returnsPromise = () =>
new Promise((resolve, reject) =>
setTimeout(() => resolve('promise resolved after 2 seconds'), 2000));
module.exports.delay = function *delay() {
this.body = yield asyncOperation();
};
module.exports.promise = function *promise() {
this.body = yield returnsPromise();
};
================================================
FILE: nodebrady/draft.toml
================================================
[environments]
[environments.development]
name = "nodebrady"
namespace = "phippyandfriends"
wait = true
watch = false
watch-delay = 2
auto-connect = false
dockerfile = ""
chart = ""
================================================
FILE: nodebrady/package.json
================================================
{
"name": "nodebrady",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node app.js",
"test": "mocha"
},
"dependencies": {
"koa": "^1.2.0",
"koa-logger": "^1.2.0",
"koa-static": "^2.0.0",
"koa-route": "^2.4.2",
"koa-compress": "^1.0.6",
"co-views": "^2.1.0",
"swig": "^1.3.2",
"co-body": "^4.0.0"
},
"devDependencies": {
"supertest": "^0.12.1",
"mocha": "^2.4.5"
}
}
================================================
FILE: nodebrady/public/scripts/.gitkeep
================================================
================================================
FILE: nodebrady/public/styles/main.css
================================================
ul {
margin: 100px auto 0;
list-style: none;
width: 700px;
font: 30px helvetica;
font-weight: 100;
}
li {
margin-bottom: 50px;
}
form {
width: 700px;
margin: 0 auto;
}
textarea {
border-style: none;
width: 700px;
margin-left: 20px;
height: 100px;
font: 30px helvetica;
font-weight: 100;
}
================================================
FILE: nodebrady/test/routeSpec.js
================================================
/*global describe, it*/
'use strict';
const superagent = require('supertest');
const app = require('../app');
const request = superagent(app.listen());
describe('Routes', () => {
describe('GET /', () => {
it('should return 200', done => {
request
.get('/')
.expect(200, done);
});
});
describe('GET /messages', () => {
it('should return 200', done => {
request
.get('/messages')
.expect('Content-Type', /json/)
.expect(200, done);
});
});
describe('GET /messages/notfound', () => {
it('should return 404', done => {
request
.get('/messages/notfound')
.expect(404, done);
});
});
});
================================================
FILE: nodebrady/views/layout.html
================================================
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}Messages{% endblock %}</title>
<link rel="stylesheet" type="text/css" href="styles/main.css">
</head>
<body>
<section id="content">
{% block content %}
<p>Forgot to add content?</p>
{% endblock %}
</section>
</body>
</html>
================================================
FILE: nodebrady/views/list.html
================================================
{% extends 'layout.html' %}
{% block title %}Messages{% endblock %}
{% block content %}
<ul class="messages">
{% for message in messages %}
<li class="message">{{ message.message }}</li>
{% endfor %}
</ul>
<form action="/messages" method="post" id="message-form">
<textarea placeholder="Insert a message" name="message"
onkeydown="if (event.keyCode == 13) document.getElementById('message-form').submit();"></textarea>
</form>
{% endblock %}
================================================
FILE: parrot/.dockerignore
================================================
Dockerfile
draft.toml
chart/
NOTICE
bin/
obj/
!published/
================================================
FILE: parrot/.draft-tasks.toml
================================================
================================================
FILE: parrot/.draftignore
================================================
*.swp
*.tmp
*.temp
.git*
================================================
FILE: parrot/.vscode/launch.json
================================================
{
// Use IntelliSense to find out which attributes exist for C# debugging
// Use hover for the description of the existing attributes
// For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
"version": "0.2.0",
"configurations": [
{
"name": ".NET Core Launch (web)",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
// If you have changed target frameworks, make sure to update the program path.
"program": "${workspaceFolder}/bin/Debug/netcoreapp2.0/parrot.dll",
"args": [],
"cwd": "${workspaceFolder}",
"stopAtEntry": false,
"internalConsoleOptions": "openOnSessionStart",
"launchBrowser": {
"enabled": true,
"args": "${auto-detect-url}",
"windows": {
"command": "cmd.exe",
"args": "/C start ${auto-detect-url}"
},
"osx": {
"command": "open"
},
"linux": {
"command": "xdg-open"
}
},
"env": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"sourceFileMap": {
"/Views": "${workspaceFolder}/Views"
}
},
{
"name": ".NET Core Attach",
"type": "coreclr",
"request": "attach",
"processId": "${command:pickProcess}"
}
,]
}
================================================
FILE: parrot/.vscode/tasks.json
================================================
{
"version": "2.0.0",
"tasks": [
{
"label": "build",
"command": "dotnet",
"type": "process",
"args": [
"build",
"${workspaceFolder}/parrot.csproj"
],
"problemMatcher": "$msCompile"
}
]
}
================================================
FILE: parrot/Controllers/ClusterStatusController.cs
================================================
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using parrot;
using parrot.Models;
namespace api.Controllers
{
[Route("api/[controller]")]
public class ClusterStatusController : Controller
{
public ClusterStatusController(ILogger<ClusterStatusController> logger, DaemonHub hub)
{
_hub = hub;
_logger = logger;
}
private DaemonHub _hub;
private readonly ILogger _logger;
[HttpGet]
public ActionResult Get()
{
return new OkResult();
}
[HttpDelete]
public ActionResult Delete()
{
_logger.LogDebug("Incoming Cluster Clear");
try {
_hub.clearClusterView();
}
catch(Exception ex) {
HttpContext.Response.StatusCode = (int)System.Net.HttpStatusCode.InternalServerError;
_logger.LogWarning(ex, "Error clearing cluster view");
return Json(new { status="error",message=$"error updating cluster view {ex.Message}"});
}
return new OkResult();
}
[HttpPost]
public ActionResult Post([FromBody]Pod pod)
{
_logger.LogDebug("Incoming Cluster Update");
_logger.LogDebug(pod.ToString());
try {
_hub.updateClusterView(pod);
}
catch(Exception ex) {
HttpContext.Response.StatusCode = (int)System.Net.HttpStatusCode.InternalServerError;
_logger.LogWarning(ex, "Error updating cluster view");
return Json(new { status="error",message=$"error updating cluster view {ex.Message}"});
}
return new OkResult();
}
}
}
================================================
FILE: parrot/Controllers/HomeController.cs
================================================
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using parrot.Models;
namespace parrot.Controllers
{
public class HomeController : Controller
{
public IActionResult Index()
{
return View();
}
public IActionResult Error()
{
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
}
}
================================================
FILE: parrot/Controllers/test.json
================================================
"metadata": {
"name": "nodeapp-nodeapp-66845c9868-phvqv",
"generateName": "nodeapp-nodeapp-66845c9868-",
"namespace": "default",
"selfLink": "/api/v1/namespaces/default/pods/nodeapp-nodeapp-66845c9868-phvqv",
"uid": "2c843057-75b3-11e8-bdbc-b20c0e5c020c",
"resourceVersion": "403506",
"creationTimestamp": "2018-06-22T00:28:24Z",
"labels": {
"app": "nodeapp-nodeapp",
"pod-template-hash": "2240175424"
},
"ownerReferences": [
{
"apiVersion": "extensions/v1beta1",
"kind": "ReplicaSet",
"name": "nodeapp-nodeapp-66845c9868",
"uid": "2c82728a-75b3-11e8-bdbc-b20c0e5c020c",
"controller": true,
"blockOwnerDeletion": true
}
]
},
"spec": {
"volumes": [
{
"name": "default-token-w8ncl",
"secret": {
"secretName": "default-token-w8ncl",
"defaultMode": 420
}
}
],
"containers": [
{
"name": "nodeapp",
"image": "phippy.azurecr.io/nodeapp:a11a2889166b4e3031ac506e35c238d9f8756fa3",
"ports": [
{
"containerPort": 3000,
"protocol": "TCP"
}
],
"resources": {},
"volumeMounts": [
{
"name": "default-token-w8ncl",
"readOnly": true,
"mountPath": "/var/run/secrets/kubernetes.io/serviceaccount"
}
],
"terminationMessagePath": "/dev/termination-log",
"terminationMessagePolicy": "File",
"imagePullPolicy": "Always"
}
],
"restartPolicy": "Always",
"terminationGracePeriodSeconds": 30,
"dnsPolicy": "ClusterFirst",
"serviceAccountName": "default",
"serviceAccount": "default",
"nodeName": "aks-agentpool-19990256-0",
"securityContext": {},
"imagePullSecrets": [
{
"name": "draft-pullsecret"
}
],
"schedulerName": "default-scheduler",
"tolerations": [
{
"key": "node.kubernetes.io/not-ready",
"operator": "Exists",
"effect": "NoExecute",
"tolerationSeconds": 300
},
{
"key": "node.kubernetes.io/unreachable",
"operator": "Exists",
"effect": "NoExecute",
"tolerationSeconds": 300
}
]
},
"status": {
"phase": "Running",
"conditions": [
{
"type": "Initialized",
"status": "True",
"lastProbeTime": null,
"lastTransitionTime": "2018-06-22T00:28:24Z"
},
{
"type": "Ready",
"status": "True",
"lastProbeTime": null,
"lastTransitionTime": "2018-06-22T00:28:26Z"
},
{
"type": "PodScheduled",
"status": "True",
"lastProbeTime": null,
"lastTransitionTime": "2018-06-22T00:28:24Z"
}
],
"hostIP": "10.240.0.4",
"podIP": "10.244.0.53",
"startTime": "2018-06-22T00:28:24Z",
"containerStatuses": [
{
"name": "nodeapp",
"state": {
"running": {
"startedAt": "2018-06-22T00:28:26Z"
}
},
"lastState": {},
"ready": true,
"restartCount": 0,
"image": "phippy.azurecr.io/nodeapp:a11a2889166b4e3031ac506e35c238d9f8756fa3",
"imageID": "docker-pullable://phippy.azurecr.io/nodeapp@sha256:b6cddce8c015b215bf1268420825b9ec3fca9e4075aee42bacf264cd055c010f",
"containerID": "docker://874c69c9b6a8cf4c9bc820ef762d55133fffd43074f52f15f1cb6388f371e51a"
}
],
"qosClass": "BestEffort"
}
================================================
FILE: parrot/Dockerfile
================================================
FROM mcr.microsoft.com/dotnet/core/sdk:3.1.301-alpine AS build-env
WORKDIR /app
# Copy csproj and restore as distinct layers
COPY *.csproj ./
RUN dotnet restore
# Copy everything else and build
COPY . ./
RUN dotnet publish -c Release -o out
# Build runtime image
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1.5-alpine
WORKDIR /app
COPY --from=build-env /app/out .
ENTRYPOINT ["dotnet", "parrot.dll"]
================================================
FILE: parrot/Hubs/Daemon.cs
================================================
using System.Threading.Tasks;
using System.Collections;
using System.Linq;
using System.Collections.Generic;
using Microsoft.AspNetCore.SignalR;
using parrot.Models;
namespace parrot
{
public class DaemonHub : Hub
{
static List<Pod> Pods { get; set; }
static List<string> DeletedPods { get; set; }
static DaemonHub()
{
Pods = new List<Pod>();
DeletedPods = new List<string>();
}
const string POD_DELETED_STATUS = "Deleted";
public override Task OnConnectedAsync()
{
Clients.All.SendAsync("clusterViewUpdated", Pods);
return base.OnConnectedAsync();
}
public void AddPod(Pod pod)
{
if(!DeletedPods.Contains(pod.Name))
{
Pods.Add(pod);
}
}
public void RemovePod(Pod pod)
{
Pods.Remove(Pods.First(x => x.Name == pod.Name));
DeletedPods.Add(pod.Name);
}
public void UpdatePod(Pod pod)
{
Pods.First(x => x.Name == pod.Name).Name = pod.Name;
Pods.First(x => x.Name == pod.Name).Container = pod.Container;
Pods.First(x => x.Name == pod.Name).NameSpace = pod.NameSpace;
Pods.First(x => x.Name == pod.Name).Status = pod.Status;
}
public void clearClusterView()
{
Pods.Clear();
Clients.All.SendAsync("clusterViewUpdated", Pods);
}
public void updateClusterView(Pod pod)
{
// If the container image is "image:tag", strip the ":tag", otherwise leave it alone
// not all images are tagged, so..
if(pod.ContainerImage.Contains(':'))
pod.ContainerImage = pod.ContainerImage.Substring(0, pod.ContainerImage.IndexOf(':'));
if (Pods.Any(x => x.Name == pod.Name))
if (pod.Action == POD_DELETED_STATUS)
RemovePod(pod);
else
UpdatePod(pod);
else
AddPod(pod);
Clients.All.SendAsync("clusterViewUpdated", Pods);
}
}
}
================================================
FILE: parrot/Models/ErrorViewModel.cs
================================================
using System;
namespace parrot.Models
{
public class ErrorViewModel
{
public string RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
}
}
================================================
FILE: parrot/Models/Pod.cs
================================================
using System;
namespace parrot.Models
{
public class Pod
{
public string Name { get; set; }
public string Container { get; set; }
public string NameSpace { get; set; }
public string ContainerImage { get; set; }
public string Status { get; set; }
public string Action { get; set; }
public string CardImageUrl
{
get { return string.Format("/media/{0}.png", Container); }
}
public override string ToString() {
return $"Name: {Name}\nContainer: {Container}\nNameSpace: {NameSpace}\nContainerImage: {ContainerImage}\nStatus: {Status}\nAction: {Action}\nCardImageUrl: {CardImageUrl}";
}
}
}
================================================
FILE: parrot/NOTICE
================================================
MIT License:
Copyright (C) 2017 Cloudbase Solutions, Srl
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
================================================
FILE: parrot/Program.cs
================================================
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
namespace parrot
{
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}
================================================
FILE: parrot/Startup.cs
================================================
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace parrot
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddSingleton(new DaemonHub());
services.AddSignalR();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapHub<DaemonHub>("/daemonhub");
endpoints.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}");
});
}
}
}
================================================
FILE: parrot/Views/Home/Index.cshtml
================================================
@{
ViewData["Title"] = "parrot";
}
<ul id="pods">
</ul>
<div class="ui link cards" id="podcards" data-bind="foreach: pods">
<div class="ui card">
<div class="image">
<img data-bind="attr:{src: cardImageUrl}"/>
</div>
<div class="content">
<a class="header"><span data-bind="text: container"></span></a>
</div>
<div class="extra content">
<span data-bind="text: name"></span>
</div>
</div>
</div>
@section footer
{
<div class="ui centered seven wide column">
<h4 class="ui centered inverted header">Connection Status: <span id="connectionStatus">Idle</span></h4>
</div>
}
@section scripts
{
<script src="~/scripts/knockout-3.4.2.js"></script>
<script src="~/scripts/signalr.min.js"></script>
<script src="~/scripts/daemon.js"></script>
}
================================================
FILE: parrot/Views/Shared/Error.cshtml
================================================
@model ErrorViewModel
@{
ViewData["Title"] = "Error";
}
<h1 class="text-danger">Error.</h1>
<h2 class="text-danger">An error occurred while processing your request.</h2>
@if (Model.ShowRequestId)
{
<p>
<strong>Request ID:</strong> <code>@Model.RequestId</code>
</p>
}
<h3>Development Mode</h3>
<p>
Swapping to <strong>Development</strong> environment will display more detailed information about the error that occurred.
</p>
<p>
<strong>Development environment should not be enabled in deployed applications</strong>, as it can result in sensitive information from exceptions being displayed to end users. For local debugging, development environment can be enabled by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>, and restarting the application.
</p>
================================================
FILE: parrot/Views/Shared/_Layout.cshtml
================================================
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - parrot</title>
<link rel="stylesheet" type="text/css" href="~/semantic/semantic.min.css">
<style type="text/css">
body {
background-color: #FFFFFF;
}
.ui.menu .item img.logo {
margin-right: 1.5em;
}
.main.container {
margin-top: 7em;
}
.wireframe {
margin-top: 2em;
}
.ui.footer.segment {
margin: 5em 0em 0em;
padding: 5em 0em;
}
</style>
</head>
<body>
<div class="ui fixed inverted menu">
<div class="ui container">
<a href="/" class="header item">
<img class="logo" src="~/media/parrot.png">
parrot tells us whatever captain kube is saying is happening in the cluster
</a>
</div>
</div>
<div class="ui main container">
@RenderBody()
</div>
<div class="ui inverted vertical footer segment">
@RenderSection("Footer", required: false)
</div>
<script
src="https://code.jquery.com/jquery-3.1.1.min.js"
integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8="
crossorigin="anonymous"></script>
<script src="semantic/semantic.min.js"></script>
@RenderSection("Scripts", required: false)
</body>
</html>
================================================
FILE: parrot/Views/Shared/_ValidationScriptsPartial.cshtml
================================================
<environment include="Development">
<script src="~/lib/jquery-validation/dist/jquery.validate.js"></script>
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script>
</environment>
<environment exclude="Development">
<script src="https://ajax.aspnetcdn.com/ajax/jquery.validate/1.14.0/jquery.validate.min.js"
asp-fallback-src="~/lib/jquery-validation/dist/jquery.validate.min.js"
asp-fallback-test="window.jQuery && window.jQuery.validator"
crossorigin="anonymous"
integrity="sha384-Fnqn3nxp3506LP/7Y3j/25BlWeA3PXTyT1l78LjECcPaKCV12TsZP7yyMxOe/G/k">
</script>
<script src="https://ajax.aspnetcdn.com/ajax/jquery.validation.unobtrusive/3.2.6/jquery.validate.unobtrusive.min.js"
asp-fallback-src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"
asp-fallback-test="window.jQuery && window.jQuery.validator && window.jQuery.validator.unobtrusive"
crossorigin="anonymous"
integrity="sha384-JrXK+k53HACyavUKOsL+NkmSesD2P+73eDMrbTtTk0h4RmOF8hF8apPlkp26JlyH">
</script>
</environment>
================================================
FILE: parrot/Views/_ViewImports.cshtml
================================================
@using parrot
@using parrot.Models
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
================================================
FILE: parrot/Views/_ViewStart.cshtml
================================================
@{
Layout = "_Layout";
}
================================================
FILE: parrot/appsettings.Development.json
================================================
{
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
}
}
================================================
FILE: parrot/appsettings.json
================================================
{
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Warning"
}
}
}
================================================
FILE: parrot/bundleconfig.json
================================================
// Configure bundling and minification for the project.
// More info at https://go.microsoft.com/fwlink/?LinkId=808241
[
{
"outputFileName": "wwwroot/css/site.min.css",
// An array of relative input file paths. Globbing patterns supported
"inputFiles": [
"wwwroot/css/site.css"
]
},
{
"outputFileName": "wwwroot/js/site.min.js",
"inputFiles": [
"wwwroot/js/site.js"
],
// Optionally specify minification options
"minify": {
"enabled": true,
"renameLocals": true
},
// Optionally generate .map file
"sourceMap": false
}
]
================================================
FILE: parrot/cd-pipeline.yml
================================================
trigger: none
pr: none
variables:
- template: ../common/cd-vars-template.yml
parameters:
projectName: parrot
# define 3 more variables: registryName, registryLogin and registryPassword in the Azure pipeline UI definition
resources:
pipelines:
- pipeline: ci-pipeline
source: parrot-ci
trigger:
enabled: true
branches:
include:
- master
stages:
- stage: development
displayName: development
jobs:
- deployment: development
variables:
k8sNamespace: 'phippyandfriends'
# define 5 more variables: aks, rg, aksSpId, aksSpSecret and aksSpTenantId in the Azure pipeline UI definition
displayName: deploy helm chart into AKS
pool:
vmImage: ubuntu-latest
environment: development-$(projectName)
strategy:
runOnce:
deploy:
steps:
- template: ../common/cd-steps-template.yml
================================================
FILE: parrot/charts/parrot/.helmignore
================================================
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*~
# Various IDEs
.project
.idea/
*.tmproj
================================================
FILE: parrot/charts/parrot/Chart.yaml
================================================
apiVersion: v1
description: Parrot is Captain Kube's sidekick, who shows everything the captain's doing on-screen.
name: parrot
version: v0.3.0
================================================
FILE: parrot/charts/parrot/templates/NOTES.txt
================================================
Tail the logs of the lighthouse pod
- kubectl logs -f --namespace {{ .Release.Namespace }} \
$(kubectl get pods --namespace {{ .Release.Namespace }} \
-l app={{ template "fullname" . }} \
-o jsonpath='{ .items[0].metadata.name }')
================================================
FILE: parrot/charts/parrot/templates/_helpers.tpl
================================================
{{/* vim: set filetype=mustache: */}}
{{/*
Expand the name of the chart.
*/}}
{{- define "name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
*/}}
{{- define "fullname" -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
Generate the imagePullSecret for a private Container Registry.
*/}}
{{- define "imagePullSecret" }}
{{- printf "{\"auths\": {\"%s\": {\"auth\": \"%s\"}}}" .Values.image.repository (printf "%s:%s" .Values.image.username .Values.image.password | b64enc) | b64enc }}
{{- end }}
================================================
FILE: parrot/charts/parrot/templates/deployment.yaml
================================================
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ template "fullname" . }}
labels:
app: {{ template "fullname" . }}
chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}"
release: "{{ .Release.Name }}"
heritage: "{{ .Release.Service }}"
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app: {{ template "fullname" . }}
template:
metadata:
labels:
app: {{ template "fullname" . }}
spec:
{{ if .Values.image.useImagePullSecrets }}
imagePullSecrets:
- name: {{ .Chart.Name }}-acr-secret
{{ end }}
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
resources:
{{ toYaml .Values.resources | indent 12 }}
env:
- name: ASPNETCORE_ENVIRONMENT
value: Development
================================================
FILE: parrot/charts/parrot/templates/ingress.yaml
================================================
{{ if .Values.ingress.enabled }}
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: {{ template "fullname" . }}
labels:
app: {{ template "fullname" . }}
chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}"
release: "{{ .Release.Name }}"
heritage: "{{ .Release.Service }}"
annotations:
kubernetes.io/ingress.class: addon-http-application-routing
spec:
rules:
- host: {{ .Release.Name }}.{{ .Values.ingress.basedomain }}
http:
paths:
- path: /
backend:
serviceName: {{ template "fullname" . }}
servicePort: {{ .Values.service.externalPort }}
{{ end }}
================================================
FILE: parrot/charts/parrot/templates/secret.yaml
================================================
{{ if .Values.image.private }}
apiVersion: v1
kind: Secret
metadata:
name: {{ .Chart.Name }}-acr-secret
type: kubernetes.io/dockerconfigjson
data:
.dockerconfigjson: {{ template "imagePullSecret" . }}
{{ end }}
================================================
FILE: parrot/charts/parrot/templates/service.yaml
================================================
apiVersion: v1
kind: Service
metadata:
name: {{ template "fullname" . }}
labels:
app: {{ template "fullname" . }}
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
release: "{{ .Release.Name }}"
heritage: "{{ .Release.Service }}"
spec:
ports:
- port: {{ .Values.service.externalPort }}
protocol: TCP
targetPort: {{ .Values.service.internalPort }}
selector:
app: {{ template "fullname" . }}
{{ if .Values.ingress.enabled }}
type: ClusterIP
{{ else }}
type: LoadBalancer
{{ end }}
================================================
FILE: parrot/charts/parrot/values.yaml
================================================
replicaCount: 1
image:
useImagePullSecrets: false
pullPolicy: Always
service:
internalPort: 80
externalPort: 80
ingress:
enabled: true
basedomain: <REPLACE WITH YOUR OWN AKS CLUSTER>.<YOUR REGION>.aksapp.io # replace with your own from the portal
================================================
FILE: parrot/ci-pipeline.yml
================================================
trigger:
batch: true
branches:
include:
- '*'
paths:
include:
- parrot/
- common/ci-steps-template.yml
pr: none
pool:
vmImage: ubuntu-latest
variables:
- template: ../common/ci-vars-template.yml
parameters:
projectName: parrot
# define 3 more variables: registryName, registryLogin and registryPassword in the build pipeline in UI
steps:
- template: ../common/ci-steps-template.yml
================================================
FILE: parrot/draft.toml
================================================
[environments]
[environments.development]
name = "parrot"
namespace = "phippyandfriends"
wait = true
watch = false
watch-delay = 2
auto-connect = false
dockerfile = ""
chart = ""
================================================
FILE: parrot/package.json
================================================
{
"name": "parrot",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"@aspnet/signalr": "^1.0.0",
"semantic-ui": "^2.3.2"
}
}
================================================
FILE: parrot/parrot.csproj
================================================
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Azure.SignalR" Version="1.4.3" />
</ItemGroup>
<ItemGroup>
<DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.4" />
<DotNetCliToolReference Include="Microsoft.DotNet.Watcher.Tools" Version="2.0.2" />
</ItemGroup>
</Project>
================================================
FILE: parrot/semantic/gulpfile.js
================================================
/*******************************
Set-up
*******************************/
var
gulp = require('gulp-help')(require('gulp')),
// read user config to know what task to load
config = require('./tasks/config/user'),
// watch changes
watch = require('./tasks/watch'),
// build all files
build = require('./tasks/build'),
buildJS = require('./tasks/build/javascript'),
buildCSS = require('./tasks/build/css'),
buildAssets = require('./tasks/build/assets'),
// utility
clean = require('./tasks/clean'),
version = require('./tasks/version'),
// docs tasks
serveDocs = require('./tasks/docs/serve'),
buildDocs = require('./tasks/docs/build'),
// rtl
buildRTL = require('./tasks/rtl/build'),
watchRTL = require('./tasks/rtl/watch')
;
/*******************************
Tasks
*******************************/
gulp.task('default', false, [
'watch'
]);
gulp.task('watch', 'Watch for site/theme changes', watch);
gulp.task('build', 'Builds all files from source', build);
gulp.task('build-javascript', 'Builds all javascript from source', buildJS);
gulp.task('build-css', 'Builds all css from source', buildCSS);
gulp.task('build-assets', 'Copies all assets from source', buildAssets);
gulp.task('clean', 'Clean dist folder', clean);
gulp.task('version', 'Displays current version of Semantic', version);
/*--------------
Docs
---------------*/
/*
Lets you serve files to a local documentation instance
https://github.com/Semantic-Org/Semantic-UI-Docs/
*/
gulp.task('serve-docs', 'Serve file changes to SUI Docs', serveDocs);
gulp.task('build-docs', 'Build all files and add to SUI Docs', buildDocs);
/*--------------
RTL
---------------*/
if(config.rtl) {
gulp.task('watch-rtl', 'Watch files as RTL', watchRTL);
gulp.task('build-rtl', 'Build all files as RTL', buildRTL);
}
================================================
FILE: parrot/semantic/src/definitions/behaviors/api.js
================================================
/*!
* # Semantic UI - API
* http://github.com/semantic-org/semantic-ui/
*
*
* Released under the MIT license
* http://opensource.org/licenses/MIT
*
*/
;(function ($, window, document, undefined) {
'use strict';
var
window = (typeof window != 'undefined' && window.Math == Math)
? window
: (typeof self != 'undefined' && self.Math == Math)
? self
: Function('return this')()
;
$.api = $.fn.api = function(parameters) {
var
// use window context if none specified
$allModules = $.isFunction(this)
? $(window)
: $(this),
moduleSelector = $allModules.selector || '',
time = new Date().getTime(),
performance = [],
query = arguments[0],
methodInvoked = (typeof query == 'string'),
queryArguments = [].slice.call(arguments, 1),
returnedValue
;
$allModules
.each(function() {
var
settings = ( $.isPlainObject(parameters) )
? $.extend(true, {}, $.fn.api.settings, parameters)
: $.extend({}, $.fn.api.settings),
// internal aliases
namespace = settings.namespace,
metadata = settings.metadata,
selector = settings.selector,
error = settings.error,
className = settings.className,
// define namespaces for modules
eventNamespace = '.' + namespace,
moduleNamespace = 'module-' + namespace,
// element that creates request
$module = $(this),
$form = $module.closest(selector.form),
// context used for state
$context = (settings.stateContext)
? $(settings.stateContext)
: $module,
// request details
ajaxSettings,
requestSettings,
url,
data,
requestStartTime,
// standard module
element = this,
context = $context[0],
instance = $module.data(moduleNamespace),
module
;
module = {
initialize: function() {
if(!methodInvoked) {
module.bind.events();
}
module.instantiate();
},
instantiate: function() {
module.verbose('Storing instance of module', module);
instance = module;
$module
.data(moduleNamespace, instance)
;
},
destroy: function() {
module.verbose('Destroying previous module for', element);
$module
.removeData(moduleNamespace)
.off(eventNamespace)
;
},
bind: {
events: function() {
var
triggerEvent = module.get.event()
;
if( triggerEvent ) {
module.verbose('Attaching API events to element', triggerEvent);
$module
.on(triggerEvent + eventNamespace, module.event.trigger)
;
}
else if(settings.on == 'now') {
module.debug('Querying API endpoint immediately');
module.query();
}
}
},
decode: {
json: function(response) {
if(response !== undefined && typeof response == 'string') {
try {
response = JSON.parse(response);
}
catch(e) {
// isnt json string
}
}
return response;
}
},
read: {
cachedResponse: function(url) {
var
response
;
if(window.Storage === undefined) {
module.error(error.noStorage);
return;
}
response = sessionStorage.getItem(url);
module.debug('Using cached response', url, response);
response = module.decode.json(response);
return response;
}
},
write: {
cachedResponse: function(url, response) {
if(response && response === '') {
module.debug('Response empty, not caching', response);
return;
}
if(window.Storage === undefined) {
module.error(error.noStorage);
return;
}
if( $.isPlainObject(response) ) {
response = JSON.stringify(response);
}
sessionStorage.setItem(url, response);
module.verbose('Storing cached response for url', url, response);
}
},
query: function() {
if(module.is.disabled()) {
module.debug('Element is disabled API request aborted');
return;
}
if(module.is.loading()) {
if(settings.interruptRequests) {
module.debug('Interrupting previous request');
module.abort();
}
else {
module.debug('Cancelling request, previous request is still pending');
return;
}
}
// pass element metadata to url (value, text)
if(settings.defaultData) {
$.extend(true, settings.urlData, module.get.defaultData());
}
// Add form content
if(settings.serializeForm) {
settings.data = module.add.formData(settings.data);
}
// call beforesend and get any settings changes
requestSettings = module.get.settings();
// check if before send cancelled request
if(requestSettings === false) {
module.cancelled = true;
module.error(error.beforeSend);
return;
}
else {
module.cancelled = false;
}
// get url
url = module.get.templatedURL();
if(!url && !module.is.mocked()) {
module.error(error.missingURL);
return;
}
// replace variables
url = module.add.urlData( url );
// missing url parameters
if( !url && !module.is.mocked()) {
return;
}
requestSettings.url = settings.base + url;
// look for jQuery ajax parameters in settings
ajaxSettings = $.extend(true, {}, settings, {
type : settings.method || settings.type,
data : data,
url : settings.base + url,
beforeSend : settings.beforeXHR,
success : function() {},
failure : function() {},
complete : function() {}
});
module.debug('Querying URL', ajaxSettings.url);
module.verbose('Using AJAX settings', ajaxSettings);
if(settings.cache === 'local' && module.read.cachedResponse(url)) {
module.debug('Response returned from local cache');
module.request = module.create.request();
module.request.resolveWith(context, [ module.read.cachedResponse(url) ]);
return;
}
if( !settings.throttle ) {
module.debug('Sending request', data, ajaxSettings.method);
module.send.request();
}
else {
if(!settings.throttleFirstRequest && !module.timer) {
module.debug('Sending request', data, ajaxSettings.method);
module.send.request();
module.timer = setTimeout(function(){}, settings.throttle);
}
else {
module.debug('Throttling request', settings.throttle);
clearTimeout(module.timer);
module.timer = setTimeout(function() {
if(module.timer) {
delete module.timer;
}
module.debug('Sending throttled request', data, ajaxSettings.method);
module.send.request();
}, settings.throttle);
}
}
},
should: {
removeError: function() {
return ( settings.hideError === true || (settings.hideError === 'auto' && !module.is.form()) );
}
},
is: {
disabled: function() {
return ($module.filter(selector.disabled).length > 0);
},
expectingJSON: function() {
return settings.dataType === 'json' || settings.dataType === 'jsonp';
},
form: function() {
return $module.is('form') || $context.is('form');
},
mocked: function() {
return (settings.mockResponse || settings.mockResponseAsync || settings.response || settings.responseAsync);
},
input: function() {
return $module.is('input');
},
loading: function() {
return (module.request)
? (module.request.state() == 'pending')
: false
;
},
abortedRequest: function(xhr) {
if(xhr && xhr.readyState !== undefined && xhr.readyState === 0) {
module.verbose('XHR request determined to be aborted');
return true;
}
else {
module.verbose('XHR request was not aborted');
return false;
}
},
validResponse: function(response) {
if( (!module.is.expectingJSON()) || !$.isFunction(settings.successTest) ) {
module.verbose('Response is not JSON, skipping validation', settings.successTest, response);
return true;
}
module.debug('Checking JSON returned success', settings.successTest, response);
if( settings.successTest(response) ) {
module.debug('Response passed success test', response);
return true;
}
else {
module.debug('Response failed success test', response);
return false;
}
}
},
was: {
cancelled: function() {
return (module.cancelled || false);
},
succesful: function() {
return (module.request && module.request.state() == 'resolved');
},
failure: function() {
return (module.request && module.request.state() == 'rejected');
},
complete: function() {
return (module.request && (module.request.state() == 'resolved' || module.request.state() == 'rejected') );
}
},
add: {
urlData: function(url, urlData) {
var
requiredVariables,
optionalVariables
;
if(url) {
requiredVariables = url.match(settings.regExp.required);
optionalVariables = url.match(settings.regExp.optional);
urlData = urlData || settings.urlData;
if(requiredVariables) {
module.debug('Looking for required URL variables', requiredVariables);
$.each(requiredVariables, function(index, templatedString) {
var
// allow legacy {$var} style
variable = (templatedString.indexOf('$') !== -1)
? templatedString.substr(2, templatedString.length - 3)
: templatedString.substr(1, templatedString.length - 2),
value = ($.isPlainObject(urlData) && urlData[variable] !== undefined)
? urlData[variable]
: ($module.data(variable) !== undefined)
? $module.data(variable)
: ($context.data(variable) !== undefined)
? $context.data(variable)
: urlData[variable]
;
// remove value
if(value === undefined) {
module.error(error.requiredParameter, variable, url);
url = false;
return false;
}
else {
module.verbose('Found required variable', variable, value);
value = (settings.encodeParameters)
? module.get.urlEncodedValue(value)
: value
;
url = url.replace(templatedString, value);
}
});
}
if(optionalVariables) {
module.debug('Looking for optional URL variables', requiredVariables);
$.each(optionalVariables, function(index, templatedString) {
var
// allow legacy {/$var} style
variable = (templatedString.indexOf('$') !== -1)
? templatedString.substr(3, templatedString.length - 4)
: templatedString.substr(2, templatedString.length - 3),
value = ($.isPlainObject(urlData) && urlData[variable] !== undefined)
? urlData[variable]
: ($module.data(variable) !== undefined)
? $module.data(variable)
: ($context.data(variable) !== undefined)
? $context.data(variable)
: urlData[variable]
;
// optional replacement
if(value !== undefined) {
module.verbose('Optional variable Found', variable, value);
url = url.replace(templatedString, value);
}
else {
module.verbose('Optional variable not found', variable);
// remove preceding slash if set
if(url.indexOf('/' + templatedString) !== -1) {
url = url.replace('/' + templatedString, '');
}
else {
url = url.replace(templatedString, '');
}
}
});
}
}
return url;
},
formData: function(data) {
var
canSerialize = ($.fn.serializeObject !== undefined),
formData = (canSerialize)
? $form.serializeObject()
: $form.serialize(),
hasOtherData
;
data = data || settings.data;
hasOtherData = $.isPlainObject(data);
if(hasOtherData) {
if(canSerialize) {
module.debug('Extending existing data with form data', data, formData);
data = $.extend(true, {}, data, formData);
}
else {
module.error(error.missingSerialize);
module.debug('Cant extend data. Replacing data with form data', data, formData);
data = formData;
}
}
else {
module.debug('Adding form data', formData);
data = formData;
}
return data;
}
},
send: {
request: function() {
module.set.loading();
module.request = module.create.request();
if( module.is.mocked() ) {
module.mockedXHR = module.create.mockedXHR();
}
else {
module.xhr = module.create.xhr();
}
settings.onRequest.call(context, module.request, module.xhr);
}
},
event: {
trigger: function(event) {
module.query();
if(event.type == 'submit' || event.type == 'click') {
event.preventDefault();
}
},
xhr: {
always: function() {
// nothing special
},
done: function(response, textStatus, xhr) {
var
context = this,
elapsedTime = (new Date().getTime() - requestStartTime),
timeLeft = (settings.loadingDuration - elapsedTime),
translatedResponse = ( $.isFunction(settings.onResponse) )
? module.is.expectingJSON()
? settings.onResponse.call(context, $.extend(true, {}, response))
: settings.onResponse.call(context, response)
: false
;
timeLeft = (timeLeft > 0)
? timeLeft
: 0
;
if(translatedResponse) {
module.debug('Modified API response in onResponse callback', settings.onResponse, translatedResponse, response);
response = translatedResponse;
}
if(timeLeft > 0) {
module.debug('Response completed early delaying state change by', timeLeft);
}
setTimeout(function() {
if( module.is.validResponse(response) ) {
module.request.resolveWith(context, [response, xhr]);
}
else {
module.request.rejectWith(context, [xhr, 'invalid']);
}
}, timeLeft);
},
fail: function(xhr, status, httpMessage) {
var
context = this,
elapsedTime = (new Date().getTime() - requestStartTime),
timeLeft = (settings.loadingDuration - elapsedTime)
;
timeLeft = (timeLeft > 0)
? timeLeft
: 0
;
if(timeLeft > 0) {
module.debug('Response completed early delaying state change by', timeLeft);
}
setTimeout(function() {
if( module.is.abortedRequest(xhr) ) {
module.request.rejectWith(context, [xhr, 'aborted', httpMessage]);
}
else {
module.request.rejectWith(context, [xhr, 'error', status, httpMessage]);
}
}, timeLeft);
}
},
request: {
done: function(response, xhr) {
module.debug('Successful API Response', response);
if(settings.cache === 'local' && url) {
module.write.cachedResponse(url, response);
module.debug('Saving server response locally', module.cache);
}
settings.onSuccess.call(context, response, $module, xhr);
},
complete: function(firstParameter, secondParameter) {
var
xhr,
response
;
// have to guess callback parameters based on request success
if( module.was.succesful() ) {
response = firstParameter;
xhr = secondParameter;
}
else {
xhr = firstParameter;
response = module.get.responseFromXHR(xhr);
}
module.remove.loading();
settings.onComplete.call(context, response, $module, xhr);
},
fail: function(xhr, status, httpMessage) {
var
// pull response from xhr if available
response = module.get.responseFromXHR(xhr),
errorMessage = module.get.errorFromRequest(response, status, httpMessage)
;
if(status == 'aborted') {
module.debug('XHR Aborted (Most likely caused by page navigation or CORS Policy)', status, httpMessage);
settings.onAbort.call(context, status, $module, xhr);
return true;
}
else if(status == 'invalid') {
module.debug('JSON did not pass success test. A server-side error has most likely occurred', response);
}
else if(status == 'error') {
if(xhr !== undefined) {
module.debug('XHR produced a server error', status, httpMessage);
// make sure we have an error to display to console
if( xhr.status != 200 && httpMessage !== undefined && httpMessage !== '') {
module.error(error.statusMessage + httpMessage, ajaxSettings.url);
}
settings.onError.call(context, errorMessage, $module, xhr);
}
}
if(settings.errorDuration && status !== 'aborted') {
module.debug('Adding error state');
module.set.error();
if( module.should.removeError() ) {
setTimeout(module.remove.error, settings.errorDuration);
}
}
module.debug('API Request failed', errorMessage, xhr);
settings.onFailure.call(context, response, $module, xhr);
}
}
},
create: {
request: function() {
// api request promise
return $.Deferred()
.always(module.event.request.complete)
.done(module.event.request.done)
.fail(module.event.request.fail)
;
},
mockedXHR: function () {
var
// xhr does not simulate these properties of xhr but must return them
textStatus = false,
status = false,
httpMessage = false,
responder = settings.mockResponse || settings.response,
asyncResponder = settings.mockResponseAsync || settings.responseAsync,
asyncCallback,
response,
mockedXHR
;
mockedXHR = $.Deferred()
.always(module.event.xhr.complete)
.done(module.event.xhr.done)
.fail(module.event.xhr.fail)
;
if(responder) {
if( $.isFunction(responder) ) {
module.debug('Using specified synchronous callback', responder);
response = responder.call(context, requestSettings);
}
else {
module.debug('Using settings specified response', responder);
response = responder;
}
// simulating response
mockedXHR.resolveWith(context, [ response, textStatus, { responseText: response }]);
}
else if( $.isFunction(asyncResponder) ) {
asyncCallback = function(response) {
module.debug('Async callback returned response', response);
if(response) {
mockedXHR.resolveWith(context, [ response, textStatus, { responseText: response }]);
}
else {
mockedXHR.rejectWith(context, [{ responseText: response }, status, httpMessage]);
}
};
module.debug('Using specified async response callback', asyncResponder);
asyncResponder.call(context, requestSettings, asyncCallback);
}
return mockedXHR;
},
xhr: function() {
var
xhr
;
// ajax request promise
xhr = $.ajax(ajaxSettings)
.always(module.event.xhr.always)
.done(module.event.xhr.done)
.fail(module.event.xhr.fail)
;
module.verbose('Created server request', xhr, ajaxSettings);
return xhr;
}
},
set: {
error: function() {
module.verbose('Adding error state to element', $context);
$context.addClass(className.error);
},
loading: function() {
module.verbose('Adding loading state to element', $context);
$context.addClass(className.loading);
requestStartTime = new Date().getTime();
}
},
remove: {
error: function() {
module.verbose('Removing error state from element', $context);
$context.removeClass(className.error);
},
loading: function() {
module.verbose('Removing loading state from element', $context);
$context.removeClass(className.loading);
}
},
get: {
responseFromXHR: function(xhr) {
return $.isPlainObject(xhr)
? (module.is.expectingJSON())
? module.decode.json(xhr.responseText)
: xhr.responseText
: false
;
},
errorFromRequest: function(response, status, httpMessage) {
return ($.isPlainObject(response) && response.error !== undefined)
? response.error // use json error message
: (settings.error[status] !== undefined) // use server error message
? settings.error[status]
: httpMessage
;
},
request: function() {
return module.request || false;
},
xhr: function() {
return module.xhr || false;
},
settings: function() {
var
runSettings
;
runSettings = settings.beforeSend.call(context, settings);
if(runSettings) {
if(runSettings.success !== undefined) {
module.debug('Legacy success callback detected', runSettings);
module.error(error.legacyParameters, runSettings.success);
runSettings.onSuccess = runSettings.success;
}
if(runSettings.failure !== undefined) {
module.debug('Legacy failure callback detected', runSettings);
module.error(error.legacyParameters, runSettings.failure);
runSettings.onFailure = runSettings.failure;
}
if(runSettings.complete !== undefined) {
module.debug('Legacy complete callback detected', runSettings);
module.error(error.legacyParameters, runSettings.complete);
runSettings.onComplete = runSettings.complete;
}
}
if(runSettings === undefined) {
module.error(error.noReturnedValue);
}
if(runSettings === false) {
return runSettings;
}
return (runSettings !== undefined)
? $.extend(true, {}, runSettings)
: $.extend(true, {}, settings)
;
},
urlEncodedValue: function(value) {
var
decodedValue = window.decodeURIComponent(value),
encodedValue = window.encodeURIComponent(value),
alreadyEncoded = (decodedValue !== value)
;
if(alreadyEncoded) {
module.debug('URL value is already encoded, avoiding double encoding', value);
return value;
}
module.verbose('Encoding value using encodeURIComponent', value, encodedValue);
return encodedValue;
},
defaultData: function() {
var
data = {}
;
if( !$.isWindow(element) ) {
if( module.is.input() ) {
data.value = $module.val();
}
else if( module.is.form() ) {
}
else {
data.text = $module.text();
}
}
return data;
},
event: function() {
if( $.isWindow(element) || settings.on == 'now' ) {
module.debug('API called without element, no events attached');
return false;
}
else if(settings.on == 'auto') {
if( $module.is('input') ) {
return (element.oninput !== undefined)
? 'input'
: (element.onpropertychange !== undefined)
? 'propertychange'
: 'keyup'
;
}
else if( $module.is('form') ) {
return 'submit';
}
else {
return 'click';
}
}
else {
return settings.on;
}
},
templatedURL: function(action) {
action = action || $module.data(metadata.action) || settings.action || false;
url = $module.data(metadata.url) || settings.url || false;
if(url) {
module.debug('Using specified url', url);
return url;
}
if(action) {
module.debug('Looking up url for action', action, settings.api);
if(settings.api[action] === undefined && !module.is.mocked()) {
module.error(error.missingAction, settings.action, settings.api);
return;
}
url = settings.api[action];
}
else if( module.is.form() ) {
url = $module.attr('action') || $context.attr('action') || false;
module.debug('No url or action specified, defaulting to form action', url);
}
return url;
}
},
abort: function() {
var
xhr = module.get.xhr()
;
if( xhr && xhr.state() !== 'resolved') {
module.debug('Cancelling API request');
xhr.abort();
}
},
// reset state
reset: function() {
module.remove.error();
module.remove.loading();
},
setting: function(name, value) {
module.debug('Changing setting', name, value);
if( $.isPlainObject(name) ) {
$.extend(true, settings, name);
}
else if(value !== undefined) {
if($.isPlainObject(settings[name])) {
$.extend(true, settings[name], value);
}
else {
settings[name] = value;
}
}
else {
return settings[name];
}
},
internal: function(name, value) {
if( $.isPlainObject(name) ) {
$.extend(true, module, name);
}
else if(value !== undefined) {
module[name] = value;
}
else {
return module[name];
}
},
debug: function() {
if(!settings.silent && settings.debug) {
if(settings.performance) {
module.performance.log(arguments);
}
else {
module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
module.debug.apply(console, arguments);
}
}
},
verbose: function() {
if(!settings.silent && settings.verbose && settings.debug) {
if(settings.performance) {
module.performance.log(arguments);
}
else {
module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
module.verbose.apply(console, arguments);
}
}
},
error: function() {
if(!settings.silent) {
module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
module.error.apply(console, arguments);
}
},
performance: {
log: function(message) {
var
currentTime,
executionTime,
previousTime
;
if(settings.performance) {
currentTime = new Date().getTime();
previousTime = time || currentTime;
executionTime = currentTime - previousTime;
time = currentTime;
performance.push({
'Name' : message[0],
'Arguments' : [].slice.call(message, 1) || '',
//'Element' : element,
'Execution Time' : executionTime
});
}
clearTimeout(module.performance.timer);
module.performance.timer = setTimeout(module.performance.display, 500);
},
display: function() {
var
title = settings.name + ':',
totalTime = 0
;
time = false;
clearTimeout(module.performance.timer);
$.each(performance, function(index, data) {
totalTime += data['Execution Time'];
});
title += ' ' + totalTime + 'ms';
if(moduleSelector) {
title += ' \'' + moduleSelector + '\'';
}
if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
console.groupCollapsed(title);
if(console.table) {
console.table(performance);
}
else {
$.each(performance, function(index, data) {
console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
});
}
console.groupEnd();
}
performance = [];
}
},
invoke: function(query, passedArguments, context) {
var
object = instance,
maxDepth,
found,
response
;
passedArguments = passedArguments || queryArguments;
context = element || context;
if(typeof query == 'string' && object !== undefined) {
query = query.split(/[\. ]/);
maxDepth = query.length - 1;
$.each(query, function(depth, value) {
var camelCaseValue = (depth != maxDepth)
? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
: query
;
if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
object = object[camelCaseValue];
}
else if( object[camelCaseValue] !== undefined ) {
found = object[camelCaseValue];
return false;
}
else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
object = object[value];
}
else if( object[value] !== undefined ) {
found = object[value];
return false;
}
else {
module.error(error.method, query);
return false;
}
});
}
if ( $.isFunction( found ) ) {
response = found.apply(context, passedArguments);
}
else if(found !== undefined) {
response = found;
}
if($.isArray(returnedValue)) {
returnedValue.push(response);
}
else if(returnedValue !== undefined) {
returnedValue = [returnedValue, response];
}
else if(response !== undefined) {
returnedValue = response;
}
return found;
}
};
if(methodInvoked) {
if(instance === undefined) {
module.initialize();
}
module.invoke(query);
}
else {
if(instance !== undefined) {
instance.invoke('destroy');
}
module.initialize();
}
})
;
return (returnedValue !== undefined)
? returnedValue
: this
;
};
$.api.settings = {
name : 'API',
namespace : 'api',
debug : false,
verbose : false,
performance : true,
// object containing all templates endpoints
api : {},
// whether to cache responses
cache : true,
// whether new requests should abort previous requests
interruptRequests : true,
// event binding
on : 'auto',
// context for applying state classes
stateContext : false,
// duration for loading state
loadingDuration : 0,
// whether to hide errors after a period of time
hideError : 'auto',
// duration for error state
errorDuration : 2000,
// whether parameters should be encoded with encodeURIComponent
encodeParameters : true,
// API action to use
action : false,
// templated URL to use
url : false,
// base URL to apply to all endpoints
base : '',
// data that will
urlData : {},
// whether to add default data to url data
defaultData : true,
// whether to serialize closest form
serializeForm : false,
// how long to wait before request should occur
throttle : 0,
// whether to throttle first request or only repeated
throttleFirstRequest : true,
// standard ajax settings
method : 'get',
data : {},
dataType : 'json',
// mock response
mockResponse : false,
mockResponseAsync : false,
// aliases for mock
response : false,
responseAsync : false,
// callbacks before request
beforeSend : function(settings) { return settings; },
beforeXHR : function(xhr) {},
onRequest : function(promise, xhr) {},
// after request
onResponse : false, // function(response) { },
// response was successful, if JSON passed validation
onSuccess : function(response, $module) {},
// request finished without aborting
onComplete : function(response, $module) {},
// failed JSON success test
onFailure : function(response, $module) {},
// server error
onError : function(errorMessage, $module) {},
// request aborted
onAbort : function(errorMessage, $module) {},
successTest : false,
// errors
error : {
beforeSend : 'The before send function has aborted the request',
error : 'There was an error with your request',
exitConditions : 'API Request Aborted. Exit conditions met',
JSONParse : 'JSON could not be parsed during error handling',
legacyParameters : 'You are using legacy API success callback names',
method : 'The method you called is not defined',
missingAction : 'API action used but no url was defined',
missingSerialize : 'jquery-serialize-object is required to add form data to an existing data object',
missingURL : 'No URL specified for api event',
noReturnedValue : 'The beforeSend callback must return a settings object, beforeSend ignored.',
noStorage : 'Caching responses locally requires session storage',
parseError : 'There was an error parsing your request',
requiredParameter : 'Missing a required URL parameter: ',
statusMessage : 'Server gave an error: ',
timeout : 'Your request timed out'
},
regExp : {
required : /\{\$*[A-z0-9]+\}/g,
optional : /\{\/\$*[A-z0-9]+\}/g,
},
className: {
loading : 'loading',
error : 'error'
},
selector: {
disabled : '.disabled',
form : 'form'
},
metadata: {
action : 'action',
url : 'url'
}
};
})( jQuery, window, document );
================================================
FILE: parrot/semantic/src/definitions/behaviors/form.js
================================================
/*!
* # Semantic UI - Form Validation
* http://github.com/semantic-org/semantic-ui/
*
*
* Released under the MIT license
* http://opensource.org/licenses/MIT
*
*/
;(function ($, window, document, undefined) {
'use strict';
window = (typeof window != 'undefined' && window.Math == Math)
? window
: (typeof self != 'undefined' && self.Math == Math)
? self
: Function('return this')()
;
$.fn.form = function(parameters) {
var
$allModules = $(this),
moduleSelector = $allModules.selector || '',
time = new Date().getTime(),
performance = [],
query = arguments[0],
legacyParameters = arguments[1],
methodInvoked = (typeof query == 'string'),
queryArguments = [].slice.call(arguments, 1),
returnedValue
;
$allModules
.each(function() {
var
$module = $(this),
element = this,
formErrors = [],
keyHeldDown = false,
// set at run-time
$field,
$group,
$message,
$prompt,
$submit,
$clear,
$reset,
settings,
validation,
metadata,
selector,
className,
regExp,
error,
namespace,
moduleNamespace,
eventNamespace,
instance,
module
;
module = {
initialize: function() {
// settings grabbed at run time
module.get.settings();
if(methodInvoked) {
if(instance === undefined) {
module.instantiate();
}
module.invoke(query);
}
else {
if(instance !== undefined) {
instance.invoke('destroy');
}
module.verbose('Initializing form validation', $module, settings);
module.bindEvents();
module.set.defaults();
module.instantiate();
}
},
instantiate: function() {
module.verbose('Storing instance of module', module);
instance = module;
$module
.data(moduleNamespace, module)
;
},
destroy: function() {
module.verbose('Destroying previous module', instance);
module.removeEvents();
$module
.removeData(moduleNamespace)
;
},
refresh: function() {
module.verbose('Refreshing selector cache');
$field = $module.find(selector.field);
$group = $module.find(selector.group);
$message = $module.find(selector.message);
$prompt = $module.find(selector.prompt);
$submit = $module.find(selector.submit);
$clear = $module.find(selector.clear);
$reset = $module.find(selector.reset);
},
submit: function() {
module.verbose('Submitting form', $module);
$module
.submit()
;
},
attachEvents: function(selector, action) {
action = action || 'submit';
$(selector)
.on('click' + eventNamespace, function(event) {
module[action]();
event.preventDefault();
})
;
},
bindEvents: function() {
module.verbose('Attaching form events');
$module
.on('submit' + eventNamespace, module.validate.form)
.on('blur' + eventNamespace, selector.field, module.event.field.blur)
.on('click' + eventNamespace, selector.submit, module.submit)
.on('click' + eventNamespace, selector.reset, module.reset)
.on('click' + eventNamespace, selector.clear, module.clear)
;
if(settings.keyboardShortcuts) {
$module
.on('keydown' + eventNamespace, selector.field, module.event.field.keydown)
;
}
$field
.each(function() {
var
$input = $(this),
type = $input.prop('type'),
inputEvent = module.get.changeEvent(type, $input)
;
$(this)
.on(inputEvent + eventNamespace, module.event.field.change)
;
})
;
},
clear: function() {
$field
.each(function () {
var
$field = $(this),
$element = $field.parent(),
$fieldGroup = $field.closest($group),
$prompt = $fieldGroup.find(selector.prompt),
defaultValue = $field.data(metadata.defaultValue) || '',
isCheckbox = $element.is(selector.uiCheckbox),
isDropdown = $element.is(selector.uiDropdown),
isErrored = $fieldGroup.hasClass(className.error)
;
if(isErrored) {
module.verbose('Resetting error on field', $fieldGroup);
$fieldGroup.removeClass(className.error);
$prompt.remove();
}
if(isDropdown) {
module.verbose('Resetting dropdown value', $element, defaultValue);
$element.dropdown('clear');
}
else if(isCheckbox) {
$field.prop('checked', false);
}
else {
module.verbose('Resetting field value', $field, defaultValue);
$field.val('');
}
})
;
},
reset: function() {
$field
.each(function () {
var
$field = $(this),
$element = $field.parent(),
$fieldGroup = $field.closest($group),
$prompt = $fieldGroup.find(selector.prompt),
defaultValue = $field.data(metadata.defaultValue),
isCheckbox = $element.is(selector.uiCheckbox),
isDropdown = $element.is(selector.uiDropdown),
isErrored = $fieldGroup.hasClass(className.error)
;
if(defaultValue === undefined) {
return;
}
if(isErrored) {
module.verbose('Resetting error on field', $fieldGroup);
$fieldGroup.removeClass(className.error);
$prompt.remove();
}
if(isDropdown) {
module.verbose('Resetting dropdown value', $element, defaultValue);
$element.dropdown('restore defaults');
}
else if(isCheckbox) {
module.verbose('Resetting checkbox value', $element, defaultValue);
$field.prop('checked', defaultValue);
}
else {
module.verbose('Resetting field value', $field, defaultValue);
$field.val(defaultValue);
}
})
;
},
determine: {
isValid: function() {
var
allValid = true
;
$.each(validation, function(fieldName, field) {
if( !( module.validate.field(field, fieldName, true) ) ) {
allValid = false;
}
});
return allValid;
}
},
is: {
bracketedRule: function(rule) {
return (rule.type && rule.type.match(settings.regExp.bracket));
},
shorthandFields: function(fields) {
var
fieldKeys = Object.keys(fields),
firstRule = fields[fieldKeys[0]]
;
return module.is.shorthandRules(firstRule);
},
// duck type rule test
shorthandRules: function(rules) {
return (typeof rules == 'string' || $.isArray(rules));
},
empty: function($field) {
if(!$field || $field.length === 0) {
return true;
}
else if($field.is('input[type="checkbox"]')) {
return !$field.is(':checked');
}
else {
return module.is.blank($field);
}
},
blank: function($field) {
return $.trim($field.val()) === '';
},
valid: function(field) {
var
allValid = true
;
if(field) {
module.verbose('Checking if field is valid', field);
return module.validate.field(validation[field], field, false);
}
else {
module.verbose('Checking if form is valid');
$.each(validation, function(fieldName, field) {
if( !module.is.valid(fieldName) ) {
allValid = false;
}
});
return allValid;
}
}
},
removeEvents: function() {
$module
.off(eventNamespace)
;
$field
.off(eventNamespace)
;
$submit
.off(eventNamespace)
;
$field
.off(eventNamespace)
;
},
event: {
field: {
keydown: function(event) {
var
$field = $(this),
key = event.which,
isInput = $field.is(selector.input),
isCheckbox = $field.is(selector.checkbox),
isInDropdown = ($field.closest(selector.uiDropdown).length > 0),
keyCode = {
enter : 13,
escape : 27
}
;
if( key == keyCode.escape) {
module.verbose('Escape key pressed blurring field');
$field
.blur()
;
}
if(!event.ctrlKey && key == keyCode.enter && isInput && !isInDropdown && !isCheckbox) {
if(!keyHeldDown) {
$field
.one('keyup' + eventNamespace, module.event.field.keyup)
;
module.submit();
module.debug('Enter pressed on input submitting form');
}
keyHeldDown = true;
}
},
keyup: function() {
keyHeldDown = false;
},
blur: function(event) {
var
$field = $(this),
$fieldGroup = $field.closest($group),
validationRules = module.get.validation($field)
;
if( $fieldGroup.hasClass(className.error) ) {
module.debug('Revalidating field', $field, validationRules);
if(validationRules) {
module.validate.field( validationRules );
}
}
else if(settings.on == 'blur') {
if(validationRules) {
module.validate.field( validationRules );
}
}
},
change: function(event) {
var
$field = $(this),
$fieldGroup = $field.closest($group),
validationRules = module.get.validation($field)
;
if(validationRules && (settings.on == 'change' || ( $fieldGroup.hasClass(className.error) && settings.revalidate) )) {
clearTimeout(module.timer);
module.timer = setTimeout(function() {
module.debug('Revalidating field', $field, module.get.validation($field));
module.validate.field( validationRules );
}, settings.delay);
}
}
}
},
get: {
ancillaryValue: function(rule) {
if(!rule.type || (!rule.value && !module.is.bracketedRule(rule))) {
return false;
}
return (rule.value !== undefined)
? rule.value
: rule.type.match(settings.regExp.bracket)[1] + ''
;
},
ruleName: function(rule) {
if( module.is.bracketedRule(rule) ) {
return rule.type.replace(rule.type.match(settings.regExp.bracket)[0], '');
}
return rule.type;
},
changeEvent: function(type, $input) {
if(type == 'checkbox' || type == 'radio' || type == 'hidden' || $input.is('select')) {
return 'change';
}
else {
return module.get.inputEvent();
}
},
inputEvent: function() {
return (document.createElement('input').oninput !== undefined)
? 'input'
: (document.createElement('input').onpropertychange !== undefined)
? 'propertychange'
: 'keyup'
;
},
fieldsFromShorthand: function(fields) {
var
fullFields = {}
;
$.each(fields, function(name, rules) {
if(typeof rules == 'string') {
rules = [rules];
}
fullFields[name] = {
rules: []
};
$.each(rules, function(index, rule) {
fullFields[name].rules.push({ type: rule });
});
});
return fullFields;
},
prompt: function(rule, field) {
var
ruleName = module.get.ruleName(rule),
ancillary = module.get.ancillaryValue(rule),
$field = module.get.field(field.identifier),
value = $field.val(),
prompt = $.isFunction(rule.prompt)
? rule.prompt(value)
: rule.prompt || settings.prompt[ruleName] || settings.text.unspecifiedRule,
requiresValue = (prompt.search('{value}') !== -1),
requiresName = (prompt.search('{name}') !== -1),
$label,
name
;
if(requiresValue) {
prompt = prompt.replace('{value}', $field.val());
}
if(requiresName) {
$label = $field.closest(selector.group).find('label').eq(0);
name = ($label.length == 1)
? $label.text()
: $field.prop('placeholder') || settings.text.unspecifiedField
;
prompt = prompt.replace('{name}', name);
}
prompt = prompt.replace('{identifier}', field.identifier);
prompt = prompt.replace('{ruleValue}', ancillary);
if(!rule.prompt) {
module.verbose('Using default validation prompt for type', prompt, ruleName);
}
return prompt;
},
settings: function() {
if($.isPlainObject(parameters)) {
var
keys = Object.keys(parameters),
isLegacySettings = (keys.length > 0)
? (parameters[keys[0]].identifier !== undefined && parameters[keys[0]].rules !== undefined)
: false,
ruleKeys
;
if(isLegacySettings) {
// 1.x (ducktyped)
settings = $.extend(true, {}, $.fn.form.settings, legacyParameters);
validation = $.extend({}, $.fn.form.settings.defaults, parameters);
module.error(settings.error.oldSyntax, element);
module.verbose('Extending settings from legacy parameters', validation, settings);
}
else {
// 2.x
if(parameters.fields && module.is.shorthandFields(parameters.fields)) {
parameters.fields = module.get.fieldsFromShorthand(parameters.fields);
}
settings = $.extend(true, {}, $.fn.form.settings, parameters);
validation = $.extend({}, $.fn.form.settings.defaults, settings.fields);
module.verbose('Extending settings', validation, settings);
}
}
else {
settings = $.fn.form.settings;
validation = $.fn.form.settings.defaults;
module.verbose('Using default form validation', validation, settings);
}
// shorthand
namespace = settings.namespace;
metadata = settings.metadata;
selector = settings.selector;
className = settings.className;
regExp = settings.regExp;
error = settings.error;
moduleNamespace = 'module-' + namespace;
eventNamespace = '.' + namespace;
// grab instance
instance = $module.data(moduleNamespace);
// refresh selector cache
module.refresh();
},
field: function(identifier) {
module.verbose('Finding field with identifier', identifier);
identifier = module.escape.string(identifier);
if($field.filter('#' + identifier).length > 0 ) {
return $field.filter('#' + identifier);
}
else if( $field.filter('[name="' + identifier +'"]').length > 0 ) {
return $field.filter('[name="' + identifier +'"]');
}
else if( $field.filter('[name="' + identifier +'[]"]').length > 0 ) {
return $field.filter('[name="' + identifier +'[]"]');
}
else if( $field.filter('[data-' + metadata.validate + '="'+ identifier +'"]').length > 0 ) {
return $field.filter('[data-' + metadata.validate + '="'+ identifier +'"]');
}
return $('<input/>');
},
fields: function(fields) {
var
$fields = $()
;
$.each(fields, function(index, name) {
$fields = $fields.add( module.get.field(name) );
});
return $fields;
},
validation: function($field) {
var
fieldValidation,
identifier
;
if(!validation) {
return false;
}
$.each(validation, function(fieldName, field) {
identifier = field.identifier || fieldName;
if( module.get.field(identifier)[0] == $field[0] ) {
field.identifier = identifier;
fieldValidation = field;
}
});
return fieldValidation || false;
},
value: function (field) {
var
fields = [],
results
;
fields.push(field);
results = module.get.values.call(element, fields);
return results[field];
},
values: function (fields) {
var
$fields = $.isArray(fields)
? module.get.fields(fields)
: $field,
values = {}
;
$fields.each(function(index, field) {
var
$field = $(field),
type = $field.prop('type'),
name = $field.prop('name'),
value = $field.val(),
isCheckbox = $field.is(selector.checkbox),
isRadio = $field.is(selector.radio),
isMultiple = (name.indexOf('[]') !== -1),
isChecked = (isCheckbox)
? $field.is(':checked')
: false
;
if(name) {
if(isMultiple) {
name = name.replace('[]', '');
if(!values[name]) {
values[name] = [];
}
if(isCheckbox) {
if(isChecked) {
values[name].push(value || true);
}
else {
values[name].push(false);
}
}
else {
values[name].push(value);
}
}
else {
if(isRadio) {
if(values[name] === undefined || values[name] == false) {
values[name] = (isChecked)
? value || true
: false
;
}
}
else if(isCheckbox) {
if(isChecked) {
values[name] = value || true;
}
else {
values[name] = false;
}
}
else {
values[name] = value;
}
}
}
});
return values;
}
},
has: {
field: function(identifier) {
module.verbose('Checking for existence of a field with identifier', identifier);
identifier = module.escape.string(identifier);
if(typeof identifier !== 'string') {
module.error(error.identifier, identifier);
}
if($field.filter('#' + identifier).length > 0 ) {
return true;
}
else if( $field.filter('[name="' + identifier +'"]').length > 0 ) {
return true;
}
else if( $field.filter('[data-' + metadata.validate + '="'+ identifier +'"]').length > 0 ) {
return true;
}
return false;
}
},
escape: {
string: function(text) {
text = String(text);
return text.replace(regExp.escape, '\\$&');
}
},
add: {
// alias
rule: function(name, rules) {
module.add.field(name, rules);
},
field: function(name, rules) {
var
newValidation = {}
;
if(module.is.shorthandRules(rules)) {
rules = $.isArray(rules)
? rules
: [rules]
;
newValidation[name] = {
rules: []
};
$.each(rules, function(index, rule) {
newValidation[name].rules.push({ type: rule });
});
}
else {
newValidation[name] = rules;
}
validation = $.extend({}, validation, newValidation);
module.debug('Adding rules', newValidation, validation);
},
fields: function(fields) {
var
newValidation
;
if(fields && module.is.shorthandFields(fields)) {
newValidation = module.get.fieldsFromShorthand(fields);
}
else {
newValidation = fields;
}
validation = $.extend({}, validation, newValidation);
},
prompt: function(identifier, errors) {
var
$field = module.get.field(identifier),
$fieldGroup = $field.closest($group),
$prompt = $fieldGroup.children(selector.prompt),
promptExists = ($prompt.length !== 0)
;
errors = (typeof errors == 'string')
? [errors]
: errors
;
module.verbose('Adding field error state', identifier);
$fieldGroup
.addClass(className.error)
;
if(settings.inline) {
if(!promptExists) {
$prompt = settings.templates.prompt(errors);
$prompt
.appendTo($fieldGroup)
;
}
$prompt
.html(errors[0])
;
if(!promptExists) {
if(settings.transition && $.fn.transition !== undefined && $module.transition('is supported')) {
module.verbose('Displaying error with css transition', settings.transition);
$prompt.transition(settings.transition + ' in', settings.duration);
}
else {
module.verbose('Displaying error with fallback javascript animation');
$prompt
.fadeIn(settings.duration)
;
}
}
else {
module.verbose('Inline errors are disabled, no inline error added', identifier);
}
}
},
errors: function(errors) {
module.debug('Adding form error messages', errors);
module.set.error();
$message
.html( settings.templates.error(errors) )
;
}
},
remove: {
rule: function(field, rule) {
var
rules = $.isArray(rule)
? rule
: [rule]
;
if(rule == undefined) {
module.debug('Removed all rules');
validation[field].rules = [];
return;
}
if(validation[field] == undefined || !$.isArray(validation[field].rules)) {
return;
}
$.each(validation[field].rules, function(index, rule) {
if(rules.indexOf(rule.type) !== -1) {
module.debug('Removed rule', rule.type);
validation[field].rules.splice(index, 1);
}
});
},
field: function(field) {
var
fields = $.isArray(field)
? field
: [field]
;
$.each(fields, function(index, field) {
module.remove.rule(field);
});
},
// alias
rules: function(field, rules) {
if($.isArray(field)) {
$.each(fields, function(index, field) {
module.remove.rule(field, rules);
});
}
else {
module.remove.rule(field, rules);
}
},
fields: function(fields) {
module.remove.field(fields);
},
prompt: function(identifier) {
var
$field = module.get.field(identifier),
$fieldGroup = $field.closest($group),
$prompt = $fieldGroup.children(selector.prompt)
;
$fieldGroup
.removeClass(className.error)
;
if(settings.inline && $prompt.is(':visible')) {
module.verbose('Removing prompt for field', identifier);
if(settings.transition && $.fn.transition !== undefined && $module.transition('is supported')) {
$prompt.transition(settings.transition + ' out', settings.duration, function() {
$prompt.remove();
});
}
else {
$prompt
.fadeOut(settings.duration, function(){
$prompt.remove();
})
;
}
}
}
},
set: {
success: function() {
$module
.removeClass(className.error)
.addClass(className.success)
;
},
defaults: function () {
$field
.each(function () {
var
$field = $(this),
isCheckbox = ($field.filter(selector.checkbox).length > 0),
value = (isCheckbox)
? $field.is(':checked')
: $field.val()
;
$field.data(metadata.defaultValue, value);
})
;
},
error: function() {
$module
.removeClass(className.success)
.addClass(className.error)
;
},
value: function (field, value) {
var
fields = {}
;
fields[field] = value;
return module.set.values.call(element, fields);
},
values: function (fields) {
if($.isEmptyObject(fields)) {
return;
}
$.each(fields, function(key, value) {
var
$field = module.get.field(key),
$element = $field.parent(),
isMultiple = $.isArray(value),
isCheckbox = $element.is(selector.uiCheckbox),
isDropdown = $element.is(selector.uiDropdown),
isRadio = ($field.is(selector.radio) && isCheckbox),
fieldExists = ($field.length > 0),
$multipleField
;
if(fieldExists) {
if(isMultiple && isCheckbox) {
module.verbose('Selecting multiple', value, $field);
$element.checkbox('uncheck');
$.each(value, function(index, value) {
$multipleField = $field.filter('[value="' + value + '"]');
$element = $multipleField.parent();
if($multipleField.length > 0) {
$element.checkbox('check');
}
});
}
else if(isRadio) {
module.verbose('Selecting radio value', value, $field);
$field.filter('[value="' + value + '"]')
.parent(selector.uiCheckbox)
.checkbox('check')
;
}
else if(isCheckbox) {
module.verbose('Setting checkbox value', value, $element);
if(value === true) {
$element.checkbox('check');
}
else {
$element.checkbox('uncheck');
}
}
else if(isDropdown) {
module.verbose('Setting dropdown value', value, $element);
$element.dropdown('set selected', value);
}
else {
module.verbose('Setting field value', value, $field);
$field.val(value);
}
}
});
}
},
validate: {
form: function(event, ignoreCallbacks) {
var
values = module.get.values(),
apiRequest
;
// input keydown event will fire submit repeatedly by browser default
if(keyHeldDown) {
return false;
}
// reset errors
formErrors = [];
if( module.determine.isValid() ) {
module.debug('Form has no validation errors, submitting');
module.set.success();
if(ignoreCallbacks !== true) {
return settings.onSuccess.call(element, event, values);
}
}
else {
module.debug('Form has errors');
module.set.error();
if(!settings.inline) {
module.add.errors(formErrors);
}
// prevent ajax submit
if($module.data('moduleApi') !== undefined) {
event.stopImmediatePropagation();
}
if(ignoreCallbacks !== true) {
return settings.onFailure.call(element, formErrors, values);
}
}
},
// takes a validation object and returns whether field passes validation
field: function(field, fieldName, showErrors) {
showErrors = (showErrors !== undefined)
? showErrors
: true
;
if(typeof field == 'string') {
module.verbose('Validating field', field);
fieldName = field;
field = validation[field];
}
var
identifier = field.identifier || fieldName,
$field = module.get.field(identifier),
$dependsField = (field.depends)
? module.get.field(field.depends)
: false,
fieldValid = true,
fieldErrors = []
;
if(!field.identifier) {
module.debug('Using field name as identifier', identifier);
field.identifier = identifier;
}
if($field.prop('disabled')) {
module.debug('Field is disabled. Skipping', identifier);
fieldValid = true;
}
else if(field.optional && module.is.blank($field)){
module.debug('Field is optional and blank. Skipping', identifier);
fieldValid = true;
}
else if(field.depends && module.is.empty($dependsField)) {
module.debug('Field depends on another value that is not present or empty. Skipping', $dependsField);
fieldValid = true;
}
else if(field.rules !== undefined) {
$.each(field.rules, function(index, rule) {
if( module.has.field(identifier) && !( module.validate.rule(field, rule) ) ) {
module.debug('Field is invalid', identifier, rule.type);
fieldErrors.push(module.get.prompt(rule, field));
fieldValid = false;
}
});
}
if(fieldValid) {
if(showErrors) {
module.remove.prompt(identifier, fieldErrors);
settings.onValid.call($field);
}
}
else {
if(showErrors) {
formErrors = formErrors.concat(fieldErrors);
module.add.prompt(identifier, fieldErrors);
settings.onInvalid.call($field, fieldErrors);
}
return false;
}
return true;
},
// takes validation rule and returns whether field passes rule
rule: function(field, rule) {
var
$field = module.get.field(field.identifier),
type = rule.type,
value = $field.val(),
isValid = true,
ancillary = module.get.ancillaryValue(rule),
ruleName = module.get.ruleName(rule),
ruleFunction = settings.rules[ruleName]
;
if( !$.isFunction(ruleFunction) ) {
module.error(error.noRule, ruleName);
return;
}
// cast to string avoiding encoding special values
value = (value === undefined || value === '' || value === null)
? ''
: $.trim(value + '')
;
return ruleFunction.call($field, value, ancillary);
}
},
setting: function(name, value) {
if( $.isPlainObject(name) ) {
$.extend(true, settings, name);
}
else if(value !== undefined) {
settings[name] = value;
}
else {
return settings[name];
}
},
internal: function(name, value) {
if( $.isPlainObject(name) ) {
$.extend(true, module, name);
}
else if(value !== undefined) {
module[name] = value;
}
else {
return module[name];
}
},
debug: function() {
if(!settings.silent && settings.debug) {
if(settings.performance) {
module.performance.log(arguments);
}
else {
module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
module.debug.apply(console, arguments);
}
}
},
verbose: function() {
if(!settings.silent && settings.verbose && settings.debug) {
if(settings.performance) {
module.performance.log(arguments);
}
else {
module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
module.verbose.apply(console, arguments);
}
}
},
error: function() {
if(!settings.silent) {
module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
module.error.apply(console, arguments);
}
},
performance: {
log: function(message) {
var
currentTime,
executionTime,
previousTime
;
if(settings.performance) {
currentTime = new Date().getTime();
previousTime = time || currentTime;
executionTime = currentTime - previousTime;
time = currentTime;
performance.push({
'Name' : message[0],
'Arguments' : [].slice.call(message, 1) || '',
'Element' : element,
'Execution Time' : executionTime
});
}
clearTimeout(module.performance.timer);
module.performance.timer = setTimeout(module.performance.display, 500);
},
display: function() {
var
title = settings.name + ':',
totalTime = 0
;
time = false;
clearTimeout(module.performance.timer);
$.each(performance, function(index, data) {
totalTime += data['Execution Time'];
});
title += ' ' + totalTime + 'ms';
if(moduleSelector) {
title += ' \'' + moduleSelector + '\'';
}
if($allModules.length > 1) {
title += ' ' + '(' + $allModules.length + ')';
}
if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
console.groupCollapsed(title);
if(console.table) {
console.table(performance);
}
else {
$.each(performance, function(index, data) {
console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
});
}
console.groupEnd();
}
performance = [];
}
},
invoke: function(query, passedArguments, context) {
var
object = instance,
maxDepth,
found,
response
;
passedArguments = passedArguments || queryArguments;
context = element || context;
if(typeof query == 'string' && object !== undefined) {
query = query.split(/[\. ]/);
maxDepth = query.length - 1;
$.each(query, function(depth, value) {
var camelCaseValue = (depth != maxDepth)
? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
: query
;
if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
object = object[camelCaseValue];
}
else if( object[camelCaseValue] !== undefined ) {
found = object[camelCaseValue];
return false;
}
else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
object = object[value];
}
else if( object[value] !== undefined ) {
found = object[value];
return false;
}
else {
return false;
}
});
}
if( $.isFunction( found ) ) {
response = found.apply(context, passedArguments);
}
else if(found !== undefined) {
response = found;
}
if($.isArray(returnedValue)) {
returnedValue.push(response);
}
else if(returnedValue !== undefined) {
returnedValue = [returnedValue, response];
}
else if(response !== undefined) {
returnedValue = response;
}
return found;
}
};
module.initialize();
})
;
return (returnedValue !== undefined)
? returnedValue
: this
;
};
$.fn.form.settings = {
name : 'Form',
namespace : 'form',
debug : false,
verbose : false,
performance : true,
fields : false,
keyboardShortcuts : true,
on : 'submit',
inline : false,
delay : 200,
revalidate : true,
transition : 'scale',
duration : 200,
onValid : function() {},
onInvalid : function() {},
onSuccess : function() { return true; },
onFailure : function() { return false; },
metadata : {
defaultValue : 'default',
validate : 'validate'
},
regExp: {
htmlID : /^[a-zA-Z][\w:.-]*$/g,
bracket : /\[(.*)\]/i,
decimal : /^\d+\.?\d*$/,
email : /^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i,
escape : /[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,
flags : /^\/(.*)\/(.*)?/,
integer : /^\-?\d+$/,
number : /^\-?\d*(\.\d+)?$/,
url : /(https?:\/\/(?:www\.|(?!www))[^\s\.]+\.[^\s]{2,}|www\.[^\s]+\.[^\s]{2,})/i
},
text: {
unspecifiedRule : 'Please enter a valid value',
unspecifiedField : 'This field'
},
prompt: {
empty : '{name} must have a value',
checked : '{name} must be checked',
email : '{name} must be a valid e-mail',
url : '{name} must be a valid url',
regExp : '{name} is not formatted correctly',
integer : '{name} must be an integer',
decimal : '{name} must be a decimal number',
number : '{name} must be set to a number',
is : '{name} must be "{ruleValue}"',
isExactly : '{name} must be exactly "{ruleValue}"',
not : '{name} cannot be set to "{ruleValue}"',
notExactly : '{name} cannot be set to exactly "{ruleValue}"',
contain : '{name} must contain "{ruleValue}"',
containExactly : '{name} must contain exactly "{ruleValue}"',
doesntContain : '{name} cannot contain "{ruleValue}"',
doesntContainExactly : '{name} cannot contain exactly "{ruleValue}"',
minLength : '{name} must be at least {ruleValue} characters',
length : '{name} must be at least {ruleValue} characters',
exactLength : '{name} must be exactly {ruleValue} characters',
maxLength : '{name} cannot be longer than {ruleValue} characters',
match : '{name} must match {ruleValue} field',
different : '{name} must have a different value than {ruleValue} field',
creditCard : '{name} must be a valid credit card number',
minCount : '{name} must have at least {ruleValue} choices',
exactCount : '{name} must have exactly {ruleValue} choices',
maxCount : '{name} must have {ruleValue} or less choices'
},
selector : {
checkbox : 'input[type="checkbox"], input[type="radio"]',
clear : '.clear',
field : 'input, textarea, select',
group : '.field',
input : 'input',
message : '.error.message',
prompt : '.prompt.label',
radio : 'input[type="radio"]',
reset : '.reset:not([type="reset"])',
submit : '.submit:not([type="submit"])',
uiCheckbox : '.ui.checkbox',
uiDropdown : '.ui.dropdown'
},
className : {
error : 'error',
label : 'ui prompt label',
pressed : 'down',
success : 'success'
},
error: {
identifier : 'You must specify a string identifier for each field',
method : 'The method you called is not defined.',
noRule : 'There is no rule matching the one you specified',
oldSyntax : 'Starting in 2.0 forms now only take a single settings object. Validation settings converted to new syntax automatically.'
},
templates: {
// template that produces error message
error: function(errors) {
var
html = '<ul class="list">'
;
$.each(errors, function(index, value) {
html += '<li>' + value + '</li>';
});
html += '</ul>';
return $(html);
},
// template that produces label
prompt: function(errors) {
return $('<div/>')
.addClass('ui basic red pointing prompt label')
.html(errors[0])
;
}
},
rules: {
// is not empty or blank string
empty: function(value) {
return !(value === undefined || '' === value || $.isArray(value) && value.length === 0);
},
// checkbox checked
checked: function() {
return ($(this).filter(':checked').length > 0);
},
// is most likely an email
email: function(value){
return $.fn.form.settings.regExp.email.test(value);
},
// value is most likely url
url: function(value) {
return $.fn.form.settings.regExp.url.test(value);
},
// matches specified regExp
regExp: function(value, regExp) {
if(regExp instanceof RegExp) {
return value.match(regExp);
}
var
regExpParts = regExp.match($.fn.form.settings.regExp.flags),
flags
;
// regular expression specified as /baz/gi (flags)
if(regExpParts) {
regExp = (regExpParts.length >= 2)
? regExpParts[1]
: regExp
;
flags = (regExpParts.length >= 3)
? regExpParts[2]
: ''
;
}
return value.match( new RegExp(regExp, flags) );
},
// is valid integer or matches range
integer: function(value, range) {
var
intRegExp = $.fn.form.settings.regExp.integer,
min,
max,
parts
;
if( !range || ['', '..'].indexOf(range) !== -1) {
// do nothing
}
else if(range.indexOf('..') == -1) {
if(intRegExp.test(range)) {
min = max = range - 0;
}
}
else {
parts = range.split('..', 2);
if(intRegExp.test(parts[0])) {
min = parts[0] - 0;
}
if(intRegExp.test(parts[1])) {
max = parts[1] - 0;
}
}
return (
intRegExp.test(value) &&
(min === undefined || value >= min) &&
(max === undefined || value <= max)
);
},
// is valid number (with decimal)
decimal: function(value) {
return $.fn.form.settings.regExp.decimal.test(value);
},
// is valid number
number: function(value) {
return $.fn.form.settings.regExp.number.test(value);
},
// is value (case insensitive)
is: function(value, text) {
text = (typeof text == 'string')
? text.toLowerCase()
: text
;
value = (typeof value == 'string')
? value.toLowerCase()
: value
;
return (value == text);
},
// is value
isExactly: function(value, text) {
return (value == text);
},
// value is not another value (case insensitive)
not: function(value, notValue) {
value = (typeof value == 'string')
? value.toLowerCase()
: value
;
notValue = (typeof notValue == 'string')
? notValue.toLowerCase()
: notValue
;
return (value != notValue);
},
// value is not another value (case sensitive)
notExactly: function(value, notValue) {
return (value != notValue);
},
// value contains text (insensitive)
contains: function(value, text) {
// escape regex characters
text = text.replace($.fn.form.settings.regExp.escape, "\\$&");
return (value.search( new RegExp(text, 'i') ) !== -1);
},
// value contains text (case sensitive)
containsExactly: function(value, text) {
// escape regex characters
text = text.replace($.fn.form.settings.regExp.escape, "\\$&");
return (value.search( new RegExp(text) ) !== -1);
},
// value contains text (insensitive)
doesntContain: function(value, text) {
// escape regex characters
text = text.replace($.fn.form.settings.regExp.escape, "\\$&");
return (value.search( new RegExp(text, 'i') ) === -1);
},
// value contains text (case sensitive)
doesntContainExactly: function(value, text) {
// escape regex characters
text = text.replace($.fn.form.settings.regExp.escape, "\\$&");
return (value.search( new RegExp(text) ) === -1);
},
// is at least string length
minLength: function(value, requiredLength) {
return (value !== undefined)
? (value.length >= requiredLength)
: false
;
},
// see rls notes for 2.0.6 (this is a duplicate of minLength)
length: function(value, requiredLength) {
return (value !== undefined)
? (value.length >= requiredLength)
: false
;
},
// is exactly length
exactLength: function(value, requiredLength) {
return (value !== undefined)
? (value.length == requiredLength)
: false
;
},
// is less than length
maxLength: function(value, maxLength) {
return (value !== undefined)
? (value.length <= maxLength)
: false
;
},
// matches another field
match: function(value, identifier) {
var
$form = $(this),
matchingValue
;
if( $('[data-validate="'+ identifier +'"]').length > 0 ) {
matchingValue = $('[data-validate="'+ identifier +'"]').val();
}
else if($('#' + identifier).length > 0) {
matchingValue = $('#' + identifier).val();
}
else if($('[name="' + identifier +'"]').length > 0) {
matchingValue = $('[name="' + identifier + '"]').val();
}
else if( $('[name="' + identifier +'[]"]').length > 0 ) {
matchingValue = $('[name="' + identifier +'[]"]');
}
return (matchingValue !== undefined)
? ( value.toString() == matchingValue.toString() )
: false
;
},
// different than another field
different: function(value, identifier) {
// use either id or name of field
var
$form = $(this),
matchingValue
;
if( $('[data-validate="'+ identifier +'"]').length > 0 ) {
matchingValue = $('[data-validate="'+ identifier +'"]').val();
}
else if($('#' + identifier).length > 0) {
matchingValue = $('#' + identifier).val();
}
else if($('[name="' + identifier +'"]').length > 0) {
matchingValue = $('[name="' + identifier + '"]').val();
}
else if( $('[name="' + identifier +'[]"]').length > 0 ) {
matchingValue = $('[name="' + identifier +'[]"]');
}
return (matchingValue !== undefined)
? ( value.toString() !== matchingValue.toString() )
: false
;
},
creditCard: function(cardNumber, cardTypes) {
var
cards = {
visa: {
pattern : /^4/,
length : [16]
},
amex: {
pattern : /^3[47]/,
length : [15]
},
mastercard: {
pattern : /^5[1-5]/,
length : [16]
},
discover: {
pattern : /^(6011|622(12[6-9]|1[3-9][0-9]|[2-8][0-9]{2}|9[0-1][0-9]|92[0-5]|64[4-9])|65)/,
length : [16]
},
unionPay: {
pattern : /^(62|88)/,
length : [16, 17, 18, 19]
},
jcb: {
pattern : /^35(2[89]|[3-8][0-9])/,
length : [16]
},
maestro: {
pattern : /^(5018|5020|5038|6304|6759|676[1-3])/,
length : [12, 13, 14, 15, 16, 17, 18, 19]
},
dinersClub: {
pattern : /^(30[0-5]|^36)/,
length : [14]
},
laser: {
pattern : /^(6304|670[69]|6771)/,
length : [16, 17, 18, 19]
},
visaElectron: {
pattern : /^(4026|417500|4508|4844|491(3|7))/,
length : [16]
}
},
valid = {},
validCard = false,
requiredTypes = (typeof cardTypes == 'string')
? cardTypes.split(',')
: false,
unionPay,
validation
;
if(typeof cardNumber !== 'string' || cardNumber.length === 0) {
return;
}
// allow dashes in card
cardNumber = cardNumber.replace(/[\-]/g, '');
// verify card types
if(requiredTypes) {
$.each(requiredTypes, function(index, type){
// verify each card type
validation = cards[type];
if(validation) {
valid = {
length : ($.inArray(cardNumber.length, validation.length) !== -1),
pattern : (cardNumber.search(validation.pattern) !== -1)
};
if(valid.length && valid.pattern) {
validCard = true;
}
}
});
if(!validCard) {
return false;
}
}
// skip luhn for UnionPay
unionPay = {
number : ($.inArray(cardNumber.length, cards.unionPay.length) !== -1),
pattern : (cardNumber.search(cards.unionPay.pattern) !== -1)
};
if(unionPay.number && unionPay.pattern) {
return true;
}
// verify luhn, adapted from <https://gist.github.com/2134376>
var
length = cardNumber.length,
multiple = 0,
producedValue = [
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
[0, 2, 4, 6, 8, 1, 3, 5, 7, 9]
],
sum = 0
;
while (length--) {
sum += producedValue[multiple][parseInt(cardNumber.charAt(length), 10)];
multiple ^= 1;
}
return (sum % 10 === 0 && sum > 0);
},
minCount: function(value, minCount) {
if(minCount == 0) {
return true;
}
if(minCount == 1) {
return (value !== '');
}
return (value.split(',').length >= minCount);
},
exactCount: function(value, exactCount) {
if(exactCount == 0) {
return (value === '');
}
if(exactCount == 1) {
return (value !== '' && value.search(',') === -1);
}
return (value.split(',').length == exactCount);
},
maxCount: function(value, maxCount) {
if(maxCount == 0) {
return false;
}
if(maxCount == 1) {
return (value.search(',') === -1);
}
return (value.split(',').length <= maxCount);
}
}
};
})( jQuery, window, document );
================================================
FILE: parrot/semantic/src/definitions/behaviors/visibility.js
================================================
/*!
* # Semantic UI - Visibility
* http://github.com/semantic-org/semantic-ui/
*
*
* Released under the MIT license
* http://opensource.org/licenses/MIT
*
*/
;(function ($, window, document, undefined) {
'use strict';
window = (typeof window != 'undefined' && window.Math == Math)
? window
: (typeof self != 'undefined' && self.Math == Math)
? self
: Function('return this')()
;
$.fn.visibility = function(parameters) {
var
$allModules = $(this),
moduleSelector = $allModules.selector || '',
time = new Date().getTime(),
performance = [],
query = arguments[0],
methodInvoked = (typeof query == 'string'),
queryArguments = [].slice.call(arguments, 1),
returnedValue,
moduleCount = $allModules.length,
loadedCount = 0
;
$allModules
.each(function() {
var
settings = ( $.isPlainObject(parameters) )
? $.extend(true, {}, $.fn.visibility.settings, parameters)
: $.extend({}, $.fn.visibility.settings),
className = settings.className,
namespace = settings.namespace,
error = settings.error,
metadata = settings.metadata,
eventNamespace = '.' + namespace,
moduleNamespace = 'module-' + namespace,
$window = $(window),
$module = $(this),
$context = $(settings.context),
$placeholder,
selector = $module.selector || '',
instance = $module.data(moduleNamespace),
requestAnimationFrame = window.requestAnimationFrame
|| window.mozRequestAnimationFrame
|| window.webkitRequestAnimationFrame
|| window.msRequestAnimationFrame
|| function(callback) { setTimeout(callback, 0); },
element = this,
disabled = false,
contextObserver,
observer,
module
;
module = {
initialize: function() {
module.debug('Initializing', settings);
module.setup.cache();
if( module.should.trackChanges() ) {
if(settings.type == 'image') {
module.setup.image();
}
if(settings.type == 'fixed') {
module.setup.fixed();
}
if(settings.observeChanges) {
module.observeChanges();
}
module.bind.events();
}
module.save.position();
if( !module.is.visible() ) {
module.error(error.visible, $module);
}
if(settings.initialCheck) {
module.checkVisibility();
}
module.instantiate();
},
instantiate: function() {
module.debug('Storing instance', module);
$module
.data(moduleNamespace, module)
;
instance = module;
},
destroy: function() {
module.verbose('Destroying previous module');
if(observer) {
observer.disconnect();
}
if(contextObserver) {
contextObserver.disconnect();
}
$window
.off('load' + eventNamespace, module.event.load)
.off('resize' + eventNamespace, module.event.resize)
;
$context
.off('scroll' + eventNamespace, module.event.scroll)
.off('scrollchange' + eventNamespace, module.event.scrollchange)
;
if(settings.type == 'fixed') {
module.resetFixed();
module.remove.placeholder();
}
$module
.off(eventNamespace)
.removeData(moduleNamespace)
;
},
observeChanges: function() {
if('MutationObserver' in window) {
contextObserver = new MutationObserver(module.event.contextChanged);
observer = new MutationObserver(module.event.changed);
contextObserver.observe(document, {
childList : true,
subtree : true
});
observer.observe(element, {
childList : true,
subtree : true
});
module.debug('Setting up mutation observer', observer);
}
},
bind: {
events: function() {
module.verbose('Binding visibility events to scroll and resize');
if(settings.refreshOnLoad) {
$window
.on('load' + eventNamespace, module.event.load)
;
}
$window
.on('resize' + eventNamespace, module.event.resize)
;
// pub/sub pattern
$context
.off('scroll' + eventNamespace)
.on('scroll' + eventNamespace, module.event.scroll)
.on('scrollchange' + eventNamespace, module.event.scrollchange)
;
}
},
event: {
changed: function(mutations) {
module.verbose('DOM tree modified, updating visibility calculations');
module.timer = setTimeout(function() {
module.verbose('DOM tree modified, updating sticky menu');
module.refresh();
}, 100);
},
contextChanged: function(mutations) {
[].forEach.call(mutations, function(mutation) {
if(mutation.removedNodes) {
[].forEach.call(mutation.removedNodes, function(node) {
if(node == element || $(node).find(element).length > 0) {
module.debug('Element removed from DOM, tearing down events');
module.destroy();
}
});
}
});
},
resize: function() {
module.debug('Window resized');
if(settings.refreshOnResize) {
requestAnimationFrame(module.refresh);
}
},
load: function() {
module.debug('Page finished loading');
requestAnimationFrame(module.refresh);
},
// publishes scrollchange event on one scroll
scroll: function() {
if(settings.throttle) {
clearTimeout(module.timer);
module.timer = setTimeout(function() {
$context.triggerHandler('scrollchange' + eventNamespace, [ $context.scrollTop() ]);
}, settings.throttle);
}
else {
requestAnimationFrame(function() {
$context.triggerHandler('scrollchange' + eventNamespace, [ $context.scrollTop() ]);
});
}
},
// subscribes to scrollchange
scrollchange: function(event, scrollPosition) {
module.checkVisibility(scrollPosition);
},
},
precache: function(images, callback) {
if (!(images instanceof Array)) {
images = [images];
}
var
imagesLength = images.length,
loadedCounter = 0,
cache = [],
cacheImage = document.createElement('img'),
handleLoad = function() {
loadedCounter++;
if (loadedCounter >= images.length) {
if ($.isFunction(callback)) {
callback();
}
}
}
;
while (imagesLength--) {
cacheImage = document.createElement('img');
cacheImage.onload = handleLoad;
cacheImage.onerror = handleLoad;
cacheImage.src = images[imagesLength];
cache.push(cacheImage);
}
},
enableCallbacks: function() {
module.debug('Allowing callbacks to occur');
disabled = false;
},
disableCallbacks: function() {
module.debug('Disabling all callbacks temporarily');
disabled = true;
},
should: {
trackChanges: function() {
if(methodInvoked) {
module.debug('One time query, no need to bind events');
return false;
}
module.debug('Callbacks being attached');
return true;
}
},
setup: {
cache: function() {
module.cache = {
occurred : {},
screen : {},
element : {},
};
},
image: function() {
var
src = $module.data(metadata.src)
;
if(src) {
module.verbose('Lazy loading image', src);
settings.once = true;
settings.observeChanges = false;
// show when top visible
settings.onOnScreen = function() {
module.debug('Image on screen', element);
module.precache(src, function() {
module.set.image(src, function() {
loadedCount++;
if(loadedCount == moduleCount) {
settings.onAllLoaded.call(this);
}
settings.onLoad.call(this);
});
});
};
}
},
fixed: function() {
module.debug('Setting up fixed');
settings.once = false;
settings.observeChanges = false;
settings.initialCheck = true;
settings.refreshOnLoad = true;
if(!parameters.transition) {
settings.transition = false;
}
module.create.placeholder();
module.debug('Added placeholder', $placeholder);
settings.onTopPassed = function() {
module.debug('Element passed, adding fixed position', $module);
module.show.placeholder();
module.set.fixed();
if(settings.transition) {
if($.fn.transition !== undefined) {
$module.transition(settings.transition, settings.duration);
}
}
};
settings.onTopPassedReverse = function() {
module.debug('Element returned to position, removing fixed', $module);
module.hide.placeholder();
module.remove.fixed();
};
}
},
create: {
placeholder: function() {
module.verbose('Creating fixed position placeholder');
$placeholder = $module
.clone(false)
.css('display', 'none')
.addClass(className.placeholder)
.insertAfter($module)
;
}
},
show: {
placeholder: function() {
module.verbose('Showing placeholder');
$placeholder
.css('display', 'block')
.css('visibility', 'hidden')
;
}
},
hide: {
placeholder: function() {
module.verbose('Hiding placeholder');
$placeholder
.css('display', 'none')
.css('visibility', '')
;
}
},
set: {
fixed: function() {
module.verbose('Setting element to fixed position');
$module
.addClass(className.fixed)
.css({
position : 'fixed',
top : settings.offset + 'px',
left : 'auto',
zIndex : settings.zIndex
})
;
settings.onFixed.call(element);
},
image: function(src, callback) {
$module
.attr('src', src)
;
if(settings.transition) {
if( $.fn.transition !== undefined) {
if($module.hasClass(className.visible)) {
module.debug('Transition already occurred on this image, skipping animation');
return;
}
$module.transition(settings.transition, settings.duration, callback);
}
else {
$module.fadeIn(settings.duration, callback);
}
}
else {
$module.show();
}
}
},
is: {
onScreen: function() {
var
calculations = module.get.elementCalculations()
;
return calculations.onScreen;
},
offScreen: function() {
var
calculations = module.get.elementCalculations()
;
return calculations.offScreen;
},
visible: function() {
if(module.cache && module.cache.element) {
return !(module.cache.element.width === 0 && module.cache.element.offset.top === 0);
}
return false;
},
verticallyScrollableContext: function() {
var
overflowY = ($context.get(0) !== window)
? $context.css('overflow-y')
: false
;
return (overflowY == 'auto' || overflowY == 'scroll');
},
horizontallyScrollableContext: function() {
var
overflowX = ($context.get(0) !== window)
? $context.css('overflow-x')
: false
;
return (overflowX == 'auto' || overflowX == 'scroll');
}
},
refresh: function() {
module.debug('Refreshing constants (width/height)');
if(settings.type == 'fixed') {
module.resetFixed();
}
module.reset();
module.save.position();
if(settings.checkOnRefresh) {
module.checkVisibility();
}
settings.onRefresh.call(element);
},
resetFixed: function () {
module.remove.fixed();
module.remove.occurred();
},
reset: function() {
module.verbose('Resetting all cached values');
if( $.isPlainObject(module.cache) ) {
module.cache.screen = {};
module.cache.element = {};
}
},
checkVisibility: function(scroll) {
module.verbose('Checking visibility of element', module.cache.element);
if( !disabled && module.is.visible() ) {
// save scroll position
module.save.scroll(scroll);
// update calculations derived from scroll
module.save.calculations();
// percentage
module.passed();
// reverse (must be first)
module.passingReverse();
module.topVisibleReverse();
module.bottomVisibleReverse();
module.topPassedReverse();
module.bottomPassedReverse();
// one time
module.onScreen();
module.offScreen();
module.passing();
module.topVisible();
module.bottomVisible();
module.topPassed();
module.bottomPassed();
// on update callback
if(settings.onUpdate) {
settings.onUpdate.call(element, module.get.elementCalculations());
}
}
},
passed: function(amount, newCallback) {
var
calculations = module.get.elementCalculations(),
amountInPixels
;
// assign callback
if(amount && newCallback) {
settings.onPassed[amount] = newCallback;
}
else if(amount !== undefined) {
return (module.get.pixelsPassed(amount) > calculations.pixelsPassed);
}
else if(calculations.passing) {
$.each(settings.onPassed, function(amount, callback) {
if(calculations.bottomVisible || calculations.pixelsPassed > module.get.pixelsPassed(amount)) {
module.execute(callback, amount);
}
else if(!settings.once) {
module.remove.occurred(callback);
}
});
}
},
onScreen: function(newCallback) {
var
calculations = module.get.elementCalculations(),
callback = newCallback || settings.onOnScreen,
callbackName = 'onScreen'
;
if(newCallback) {
module.debug('Adding callback for onScreen', newCallback);
settings.onOnScreen = newCallback;
}
if(calculations.onScreen) {
module.execute(callback, callbackName);
}
else if(!settings.once) {
module.remove.occurred(callbackName);
}
if(newCallback !== undefined) {
return calculations.onOnScreen;
}
},
offScreen: function(newCallback) {
var
calculations = module.get.elementCalculations(),
callback = newCallback || settings.onOffScreen,
callbackName = 'offScreen'
;
if(newCallback) {
module.debug('Adding callback for offScreen', newCallback);
settings.onOffScreen = newCallback;
}
if(calculations.offScreen) {
module.execute(callback, callbackName);
}
else if(!settings.once) {
module.remove.occurred(callbackName);
}
if(newCallback !== undefined) {
return calculations.onOffScreen;
}
},
passing: function(newCallback) {
var
calculations = module.get.elementCalculations(),
callback = newCallback || settings.onPassing,
callbackName = 'passing'
;
if(newCallback) {
module.debug('Adding callback for passing', newCallback);
settings.onPassing = newCallback;
}
if(calculations.passing) {
module.execute(callback, callbackName);
}
else if(!settings.once) {
module.remove.occurred(callbackName);
}
if(newCallback !== undefined) {
return calculations.passing;
}
},
topVisible: function(newCallback) {
var
calculations = module.get.elementCalculations(),
callback = newCallback || settings.onTopVisible,
callbackName = 'topVisible'
;
if(newCallback) {
module.debug('Adding callback for top visible', newCallback);
settings.onTopVisible = newCallback;
}
if(calculations.topVisible) {
module.execute(callback, callbackName);
}
else if(!settings.once) {
module.remove.occurred(callbackName);
}
if(newCallback === undefined) {
return calculations.topVisible;
}
},
bottomVisible: function(newCallback) {
var
calculations = module.get.elementCalculations(),
callback = newCallback || settings.onBottomVisible,
callbackName = 'bottomVisible'
;
if(newCallback) {
module.debug('Adding callback for bottom visible', newCallback);
settings.onBottomVisible = newCallback;
}
if(calculations.bottomVisible) {
module.execute(callback, callbackName);
}
else if(!settings.once) {
module.remove.occurred(callbackName);
}
if(newCallback === undefined) {
return calculations.bottomVisible;
}
},
topPassed: function(newCallback) {
var
calculations = module.get.elementCalculations(),
callback = newCallback || settings.onTopPassed,
callbackName = 'topPassed'
;
if(newCallback) {
module.debug('Adding callback for top passed', newCallback);
settings.onTopPassed = newCallback;
}
if(calculations.topPassed) {
module.execute(callback, callbackName);
}
else if(!settings.once) {
module.remove.occurred(callbackName);
}
gitextract_tafhqydv/
├── .gitignore
├── LICENSE
├── README.md
├── captainkube/
│ ├── .dockerignore
│ ├── .draft-tasks.toml
│ ├── .draftignore
│ ├── Dockerfile
│ ├── cd-pipeline.yml
│ ├── charts/
│ │ └── captainkube/
│ │ ├── .helmignore
│ │ ├── Chart.yaml
│ │ ├── templates/
│ │ │ ├── NOTES.txt
│ │ │ ├── _helpers.tpl
│ │ │ ├── deployment.yaml
│ │ │ └── secret.yaml
│ │ └── values.yaml
│ ├── ci-pipeline.yml
│ ├── draft.toml
│ └── main.go
├── common/
│ ├── cd-steps-template.yml
│ ├── cd-vars-template.yml
│ ├── ci-steps-template.yml
│ └── ci-vars-template.yml
├── nodebrady/
│ ├── .dockerignore
│ ├── .draft-tasks.toml
│ ├── .draftignore
│ ├── .editorconfig
│ ├── .jshintrc
│ ├── Dockerfile
│ ├── app.js
│ ├── cd-pipeline.yml
│ ├── charts/
│ │ └── nodebrady/
│ │ ├── .helmignore
│ │ ├── Chart.yaml
│ │ ├── templates/
│ │ │ ├── NOTES.txt
│ │ │ ├── _helpers.tpl
│ │ │ ├── deployment.yaml
│ │ │ ├── ingress.yaml
│ │ │ ├── secret.yaml
│ │ │ └── service.yaml
│ │ └── values.yaml
│ ├── ci-pipeline.yml
│ ├── controllers/
│ │ └── messages.js
│ ├── draft.toml
│ ├── package.json
│ ├── public/
│ │ ├── scripts/
│ │ │ └── .gitkeep
│ │ └── styles/
│ │ └── main.css
│ ├── test/
│ │ └── routeSpec.js
│ └── views/
│ ├── layout.html
│ └── list.html
├── parrot/
│ ├── .dockerignore
│ ├── .draft-tasks.toml
│ ├── .draftignore
│ ├── .vscode/
│ │ ├── launch.json
│ │ └── tasks.json
│ ├── Controllers/
│ │ ├── ClusterStatusController.cs
│ │ ├── HomeController.cs
│ │ └── test.json
│ ├── Dockerfile
│ ├── Hubs/
│ │ └── Daemon.cs
│ ├── Models/
│ │ ├── ErrorViewModel.cs
│ │ └── Pod.cs
│ ├── NOTICE
│ ├── Program.cs
│ ├── Startup.cs
│ ├── Views/
│ │ ├── Home/
│ │ │ └── Index.cshtml
│ │ ├── Shared/
│ │ │ ├── Error.cshtml
│ │ │ ├── _Layout.cshtml
│ │ │ └── _ValidationScriptsPartial.cshtml
│ │ ├── _ViewImports.cshtml
│ │ └── _ViewStart.cshtml
│ ├── appsettings.Development.json
│ ├── appsettings.json
│ ├── bundleconfig.json
│ ├── cd-pipeline.yml
│ ├── charts/
│ │ └── parrot/
│ │ ├── .helmignore
│ │ ├── Chart.yaml
│ │ ├── templates/
│ │ │ ├── NOTES.txt
│ │ │ ├── _helpers.tpl
│ │ │ ├── deployment.yaml
│ │ │ ├── ingress.yaml
│ │ │ ├── secret.yaml
│ │ │ └── service.yaml
│ │ └── values.yaml
│ ├── ci-pipeline.yml
│ ├── draft.toml
│ ├── package.json
│ ├── parrot.csproj
│ ├── semantic/
│ │ ├── gulpfile.js
│ │ ├── src/
│ │ │ ├── definitions/
│ │ │ │ ├── behaviors/
│ │ │ │ │ ├── api.js
│ │ │ │ │ ├── form.js
│ │ │ │ │ └── visibility.js
│ │ │ │ ├── collections/
│ │ │ │ │ ├── breadcrumb.less
│ │ │ │ │ ├── form.less
│ │ │ │ │ ├── grid.less
│ │ │ │ │ ├── menu.less
│ │ │ │ │ ├── message.less
│ │ │ │ │ └── table.less
│ │ │ │ ├── elements/
│ │ │ │ │ ├── button.less
│ │ │ │ │ ├── container.less
│ │ │ │ │ ├── divider.less
│ │ │ │ │ ├── flag.less
│ │ │ │ │ ├── header.less
│ │ │ │ │ ├── icon.less
│ │ │ │ │ ├── image.less
│ │ │ │ │ ├── input.less
│ │ │ │ │ ├── label.less
│ │ │ │ │ ├── list.less
│ │ │ │ │ ├── loader.less
│ │ │ │ │ ├── rail.less
│ │ │ │ │ ├── reveal.less
│ │ │ │ │ ├── segment.less
│ │ │ │ │ └── step.less
│ │ │ │ ├── globals/
│ │ │ │ │ ├── reset.less
│ │ │ │ │ ├── site.js
│ │ │ │ │ └── site.less
│ │ │ │ ├── modules/
│ │ │ │ │ ├── accordion.js
│ │ │ │ │ ├── accordion.less
│ │ │ │ │ ├── checkbox.js
│ │ │ │ │ ├── checkbox.less
│ │ │ │ │ ├── dimmer.js
│ │ │ │ │ ├── dimmer.less
│ │ │ │ │ ├── dropdown.js
│ │ │ │ │ ├── dropdown.less
│ │ │ │ │ ├── embed.js
│ │ │ │ │ ├── embed.less
│ │ │ │ │ ├── modal.js
│ │ │ │ │ ├── modal.less
│ │ │ │ │ ├── nag.js
│ │ │ │ │ ├── nag.less
│ │ │ │ │ ├── popup.js
│ │ │ │ │ ├── popup.less
│ │ │ │ │ ├── progress.js
│ │ │ │ │ ├── progress.less
│ │ │ │ │ ├── rating.js
│ │ │ │ │ ├── rating.less
│ │ │ │ │ ├── search.js
│ │ │ │ │ ├── search.less
│ │ │ │ │ ├── shape.js
│ │ │ │ │ ├── shape.less
│ │ │ │ │ ├── sidebar.js
│ │ │ │ │ ├── sidebar.less
│ │ │ │ │ ├── sticky.js
│ │ │ │ │ ├── sticky.less
│ │ │ │ │ ├── tab.js
│ │ │ │ │ ├── tab.less
│ │ │ │ │ ├── transition.js
│ │ │ │ │ └── transition.less
│ │ │ │ └── views/
│ │ │ │ ├── ad.less
│ │ │ │ ├── card.less
│ │ │ │ ├── comment.less
│ │ │ │ ├── feed.less
│ │ │ │ ├── item.less
│ │ │ │ └── statistic.less
│ │ │ ├── semantic.less
│ │ │ ├── site/
│ │ │ │ ├── collections/
│ │ │ │ │ ├── breadcrumb.overrides
│ │ │ │ │ ├── breadcrumb.variables
│ │ │ │ │ ├── form.overrides
│ │ │ │ │ ├── form.variables
│ │ │ │ │ ├── grid.overrides
│ │ │ │ │ ├── grid.variables
│ │ │ │ │ ├── menu.overrides
│ │ │ │ │ ├── menu.variables
│ │ │ │ │ ├── message.overrides
│ │ │ │ │ ├── message.variables
│ │ │ │ │ ├── table.overrides
│ │ │ │ │ └── table.variables
│ │ │ │ ├── elements/
│ │ │ │ │ ├── button.overrides
│ │ │ │ │ ├── button.variables
│ │ │ │ │ ├── container.overrides
│ │ │ │ │ ├── container.variables
│ │ │ │ │ ├── divider.overrides
│ │ │ │ │ ├── divider.variables
│ │ │ │ │ ├── flag.overrides
│ │ │ │ │ ├── flag.variables
│ │ │ │ │ ├── header.overrides
│ │ │ │ │ ├── header.variables
│ │ │ │ │ ├── icon.overrides
│ │ │ │ │ ├── icon.variables
│ │ │ │ │ ├── image.overrides
│ │ │ │ │ ├── image.variables
│ │ │ │ │ ├── input.overrides
│ │ │ │ │ ├── input.variables
│ │ │ │ │ ├── label.overrides
│ │ │ │ │ ├── label.variables
│ │ │ │ │ ├── list.overrides
│ │ │ │ │ ├── list.variables
│ │ │ │ │ ├── loader.overrides
│ │ │ │ │ ├── loader.variables
│ │ │ │ │ ├── rail.overrides
│ │ │ │ │ ├── rail.variables
│ │ │ │ │ ├── reveal.overrides
│ │ │ │ │ ├── reveal.variables
│ │ │ │ │ ├── segment.overrides
│ │ │ │ │ ├── segment.variables
│ │ │ │ │ ├── step.overrides
│ │ │ │ │ └── step.variables
│ │ │ │ ├── globals/
│ │ │ │ │ ├── reset.overrides
│ │ │ │ │ ├── reset.variables
│ │ │ │ │ ├── site.overrides
│ │ │ │ │ └── site.variables
│ │ │ │ ├── modules/
│ │ │ │ │ ├── accordion.overrides
│ │ │ │ │ ├── accordion.variables
│ │ │ │ │ ├── chatroom.overrides
│ │ │ │ │ ├── chatroom.variables
│ │ │ │ │ ├── checkbox.overrides
│ │ │ │ │ ├── checkbox.variables
│ │ │ │ │ ├── dimmer.overrides
│ │ │ │ │ ├── dimmer.variables
│ │ │ │ │ ├── dropdown.overrides
│ │ │ │ │ ├── dropdown.variables
│ │ │ │ │ ├── embed.overrides
│ │ │ │ │ ├── embed.variables
│ │ │ │ │ ├── modal.overrides
│ │ │ │ │ ├── modal.variables
│ │ │ │ │ ├── nag.overrides
│ │ │ │ │ ├── nag.variables
│ │ │ │ │ ├── popup.overrides
│ │ │ │ │ ├── popup.variables
│ │ │ │ │ ├── progress.overrides
│ │ │ │ │ ├── progress.variables
│ │ │ │ │ ├── rating.overrides
│ │ │ │ │ ├── rating.variables
│ │ │ │ │ ├── search.overrides
│ │ │ │ │ ├── search.variables
│ │ │ │ │ ├── shape.overrides
│ │ │ │ │ ├── shape.variables
│ │ │ │ │ ├── sidebar.overrides
│ │ │ │ │ ├── sidebar.variables
│ │ │ │ │ ├── sticky.overrides
│ │ │ │ │ ├── sticky.variables
│ │ │ │ │ ├── tab.overrides
│ │ │ │ │ ├── tab.variables
│ │ │ │ │ ├── transition.overrides
│ │ │ │ │ └── transition.variables
│ │ │ │ └── views/
│ │ │ │ ├── ad.overrides
│ │ │ │ ├── ad.variables
│ │ │ │ ├── card.overrides
│ │ │ │ ├── card.variables
│ │ │ │ ├── comment.overrides
│ │ │ │ ├── comment.variables
│ │ │ │ ├── feed.overrides
│ │ │ │ ├── feed.variables
│ │ │ │ ├── item.overrides
│ │ │ │ ├── item.variables
│ │ │ │ ├── statistic.overrides
│ │ │ │ └── statistic.variables
│ │ │ ├── theme.config
│ │ │ ├── theme.less
│ │ │ └── themes/
│ │ │ ├── amazon/
│ │ │ │ ├── elements/
│ │ │ │ │ ├── button.overrides
│ │ │ │ │ └── button.variables
│ │ │ │ └── globals/
│ │ │ │ └── site.variables
│ │ │ ├── basic/
│ │ │ │ ├── collections/
│ │ │ │ │ ├── table.overrides
│ │ │ │ │ └── table.variables
│ │ │ │ ├── elements/
│ │ │ │ │ ├── button.overrides
│ │ │ │ │ ├── button.variables
│ │ │ │ │ ├── icon.overrides
│ │ │ │ │ ├── icon.variables
│ │ │ │ │ ├── step.overrides
│ │ │ │ │ └── step.variables
│ │ │ │ ├── globals/
│ │ │ │ │ ├── reset.overrides
│ │ │ │ │ └── reset.variables
│ │ │ │ ├── modules/
│ │ │ │ │ ├── progress.overrides
│ │ │ │ │ └── progress.variables
│ │ │ │ └── views/
│ │ │ │ ├── card.overrides
│ │ │ │ └── card.variables
│ │ │ ├── bookish/
│ │ │ │ └── elements/
│ │ │ │ ├── header.overrides
│ │ │ │ └── header.variables
│ │ │ ├── bootstrap3/
│ │ │ │ └── elements/
│ │ │ │ ├── button.overrides
│ │ │ │ └── button.variables
│ │ │ ├── chubby/
│ │ │ │ ├── collections/
│ │ │ │ │ ├── form.overrides
│ │ │ │ │ ├── form.variables
│ │ │ │ │ ├── menu.overrides
│ │ │ │ │ └── menu.variables
│ │ │ │ ├── elements/
│ │ │ │ │ ├── button.overrides
│ │ │ │ │ ├── button.variables
│ │ │ │ │ ├── header.overrides
│ │ │ │ │ └── header.variables
│ │ │ │ ├── modules/
│ │ │ │ │ ├── accordion.overrides
│ │ │ │ │ └── accordion.variables
│ │ │ │ └── views/
│ │ │ │ ├── comment.overrides
│ │ │ │ └── comment.variables
│ │ │ ├── classic/
│ │ │ │ ├── collections/
│ │ │ │ │ ├── table.overrides
│ │ │ │ │ └── table.variables
│ │ │ │ ├── elements/
│ │ │ │ │ ├── button.overrides
│ │ │ │ │ ├── button.variables
│ │ │ │ │ ├── header.overrides
│ │ │ │ │ └── header.variables
│ │ │ │ ├── modules/
│ │ │ │ │ ├── progress.overrides
│ │ │ │ │ └── progress.variables
│ │ │ │ └── views/
│ │ │ │ ├── card.overrides
│ │ │ │ └── card.variables
│ │ │ ├── colored/
│ │ │ │ └── modules/
│ │ │ │ ├── checkbox.overrides
│ │ │ │ └── checkbox.variables
│ │ │ ├── default/
│ │ │ │ ├── collections/
│ │ │ │ │ ├── breadcrumb.overrides
│ │ │ │ │ ├── breadcrumb.variables
│ │ │ │ │ ├── form.overrides
│ │ │ │ │ ├── form.variables
│ │ │ │ │ ├── grid.overrides
│ │ │ │ │ ├── grid.variables
│ │ │ │ │ ├── menu.overrides
│ │ │ │ │ ├── menu.variables
│ │ │ │ │ ├── message.overrides
│ │ │ │ │ ├── message.variables
│ │ │ │ │ ├── table.overrides
│ │ │ │ │ └── table.variables
│ │ │ │ ├── elements/
│ │ │ │ │ ├── button.overrides
│ │ │ │ │ ├── button.variables
│ │ │ │ │ ├── container.overrides
│ │ │ │ │ ├── container.variables
│ │ │ │ │ ├── divider.overrides
│ │ │ │ │ ├── divider.variables
│ │ │ │ │ ├── flag.overrides
│ │ │ │ │ ├── flag.variables
│ │ │ │ │ ├── header.overrides
│ │ │ │ │ ├── header.variables
│ │ │ │ │ ├── icon.overrides
│ │ │ │ │ ├── icon.variables
│ │ │ │ │ ├── image.overrides
│ │ │ │ │ ├── image.variables
│ │ │ │ │ ├── input.overrides
│ │ │ │ │ ├── input.variables
│ │ │ │ │ ├── label.overrides
│ │ │ │ │ ├── label.variables
│ │ │ │ │ ├── list.overrides
│ │ │ │ │ ├── list.variables
│ │ │ │ │ ├── loader.overrides
│ │ │ │ │ ├── loader.variables
│ │ │ │ │ ├── rail.overrides
│ │ │ │ │ ├── rail.variables
│ │ │ │ │ ├── reveal.overrides
│ │ │ │ │ ├── reveal.variables
│ │ │ │ │ ├── segment.overrides
│ │ │ │ │ ├── segment.variables
│ │ │ │ │ ├── step.overrides
│ │ │ │ │ └── step.variables
│ │ │ │ ├── globals/
│ │ │ │ │ ├── reset.overrides
│ │ │ │ │ ├── reset.variables
│ │ │ │ │ ├── site.overrides
│ │ │ │ │ └── site.variables
│ │ │ │ ├── modules/
│ │ │ │ │ ├── accordion.overrides
│ │ │ │ │ ├── accordion.variables
│ │ │ │ │ ├── chatroom.overrides
│ │ │ │ │ ├── chatroom.variables
│ │ │ │ │ ├── checkbox.overrides
│ │ │ │ │ ├── checkbox.variables
│ │ │ │ │ ├── dimmer.overrides
│ │ │ │ │ ├── dimmer.variables
│ │ │ │ │ ├── dropdown.overrides
│ │ │ │ │ ├── dropdown.variables
│ │ │ │ │ ├── embed.overrides
│ │ │ │ │ ├── embed.variables
│ │ │ │ │ ├── modal.overrides
│ │ │ │ │ ├── modal.variables
│ │ │ │ │ ├── nag.overrides
│ │ │ │ │ ├── nag.variables
│ │ │ │ │ ├── popup.overrides
│ │ │ │ │ ├── popup.variables
│ │ │ │ │ ├── progress.overrides
│ │ │ │ │ ├── progress.variables
│ │ │ │ │ ├── rating.overrides
│ │ │ │ │ ├── rating.variables
│ │ │ │ │ ├── search.overrides
│ │ │ │ │ ├── search.variables
│ │ │ │ │ ├── shape.overrides
│ │ │ │ │ ├── shape.variables
│ │ │ │ │ ├── sidebar.overrides
│ │ │ │ │ ├── sidebar.variables
│ │ │ │ │ ├── sticky.overrides
│ │ │ │ │ ├── sticky.variables
│ │ │ │ │ ├── tab.overrides
│ │ │ │ │ ├── tab.variables
│ │ │ │ │ ├── transition.overrides
│ │ │ │ │ └── transition.variables
│ │ │ │ └── views/
│ │ │ │ ├── ad.overrides
│ │ │ │ ├── ad.variables
│ │ │ │ ├── card.overrides
│ │ │ │ ├── card.variables
│ │ │ │ ├── comment.overrides
│ │ │ │ ├── comment.variables
│ │ │ │ ├── feed.overrides
│ │ │ │ ├── feed.variables
│ │ │ │ ├── item.overrides
│ │ │ │ ├── item.variables
│ │ │ │ ├── statistic.overrides
│ │ │ │ └── statistic.variables
│ │ │ ├── duo/
│ │ │ │ └── elements/
│ │ │ │ ├── loader.overrides
│ │ │ │ └── loader.variables
│ │ │ ├── fixed-width/
│ │ │ │ ├── collections/
│ │ │ │ │ ├── grid.overrides
│ │ │ │ │ └── grid.variables
│ │ │ │ └── modules/
│ │ │ │ ├── modal.overrides
│ │ │ │ └── modal.variables
│ │ │ ├── flat/
│ │ │ │ ├── collections/
│ │ │ │ │ ├── form.overrides
│ │ │ │ │ └── form.variables
│ │ │ │ └── globals/
│ │ │ │ ├── site.overrides
│ │ │ │ └── site.variables
│ │ │ ├── github/
│ │ │ │ ├── collections/
│ │ │ │ │ ├── breadcrumb.variables
│ │ │ │ │ ├── form.overrides
│ │ │ │ │ ├── form.variables
│ │ │ │ │ ├── grid.variables
│ │ │ │ │ ├── menu.overrides
│ │ │ │ │ ├── menu.variables
│ │ │ │ │ ├── message.overrides
│ │ │ │ │ ├── message.variables
│ │ │ │ │ └── table.variables
│ │ │ │ ├── elements/
│ │ │ │ │ ├── button.overrides
│ │ │ │ │ ├── button.variables
│ │ │ │ │ ├── header.variables
│ │ │ │ │ ├── icon.overrides
│ │ │ │ │ ├── icon.variables
│ │ │ │ │ ├── image.variables
│ │ │ │ │ ├── input.overrides
│ │ │ │ │ ├── input.variables
│ │ │ │ │ ├── label.overrides
│ │ │ │ │ ├── label.variables
│ │ │ │ │ ├── segment.overrides
│ │ │ │ │ ├── segment.variables
│ │ │ │ │ ├── step.overrides
│ │ │ │ │ └── step.variables
│ │ │ │ ├── globals/
│ │ │ │ │ └── site.variables
│ │ │ │ └── modules/
│ │ │ │ ├── dropdown.overrides
│ │ │ │ ├── dropdown.variables
│ │ │ │ └── popup.variables
│ │ │ ├── gmail/
│ │ │ │ └── collections/
│ │ │ │ ├── message.overrides
│ │ │ │ └── message.variables
│ │ │ ├── instagram/
│ │ │ │ └── views/
│ │ │ │ ├── card.overrides
│ │ │ │ └── card.variables
│ │ │ ├── material/
│ │ │ │ ├── collections/
│ │ │ │ │ ├── menu.overrides
│ │ │ │ │ └── menu.variables
│ │ │ │ ├── elements/
│ │ │ │ │ ├── button.overrides
│ │ │ │ │ ├── button.variables
│ │ │ │ │ ├── header.overrides
│ │ │ │ │ ├── header.variables
│ │ │ │ │ ├── icon.overrides
│ │ │ │ │ └── icon.variables
│ │ │ │ ├── globals/
│ │ │ │ │ ├── site.overrides
│ │ │ │ │ └── site.variables
│ │ │ │ └── modules/
│ │ │ │ ├── dropdown.overrides
│ │ │ │ ├── dropdown.variables
│ │ │ │ ├── modal.overrides
│ │ │ │ └── modal.variables
│ │ │ ├── pulsar/
│ │ │ │ └── elements/
│ │ │ │ ├── loader.overrides
│ │ │ │ └── loader.variables
│ │ │ ├── raised/
│ │ │ │ └── elements/
│ │ │ │ ├── button.overrides
│ │ │ │ └── button.variables
│ │ │ ├── resetcss/
│ │ │ │ └── globals/
│ │ │ │ ├── reset.overrides
│ │ │ │ └── reset.variables
│ │ │ ├── round/
│ │ │ │ └── elements/
│ │ │ │ ├── button.overrides
│ │ │ │ └── button.variables
│ │ │ ├── rtl/
│ │ │ │ └── globals/
│ │ │ │ ├── site.overrides
│ │ │ │ └── site.variables
│ │ │ ├── striped/
│ │ │ │ └── modules/
│ │ │ │ ├── progress.overrides
│ │ │ │ └── progress.variables
│ │ │ ├── timeline/
│ │ │ │ └── views/
│ │ │ │ ├── feed.overrides
│ │ │ │ └── feed.variables
│ │ │ └── twitter/
│ │ │ └── elements/
│ │ │ ├── button.overrides
│ │ │ └── button.variables
│ │ └── tasks/
│ │ ├── README.md
│ │ ├── admin/
│ │ │ ├── components/
│ │ │ │ ├── create.js
│ │ │ │ ├── init.js
│ │ │ │ └── update.js
│ │ │ ├── distributions/
│ │ │ │ ├── create.js
│ │ │ │ ├── init.js
│ │ │ │ └── update.js
│ │ │ ├── publish.js
│ │ │ ├── register.js
│ │ │ └── release.js
│ │ ├── build/
│ │ │ ├── assets.js
│ │ │ ├── css.js
│ │ │ └── javascript.js
│ │ ├── build.js
│ │ ├── check-install.js
│ │ ├── clean.js
│ │ ├── collections/
│ │ │ ├── README.md
│ │ │ ├── admin.js
│ │ │ ├── build.js
│ │ │ ├── internal.js
│ │ │ └── rtl.js
│ │ ├── config/
│ │ │ ├── admin/
│ │ │ │ ├── github.js
│ │ │ │ ├── oauth.example.js
│ │ │ │ ├── release.js
│ │ │ │ └── templates/
│ │ │ │ ├── README.md
│ │ │ │ ├── bower.json
│ │ │ │ ├── component-package.js
│ │ │ │ ├── composer.json
│ │ │ │ ├── css-package.js
│ │ │ │ ├── less-package.js
│ │ │ │ └── package.json
│ │ │ ├── defaults.js
│ │ │ ├── docs.js
│ │ │ ├── npm/
│ │ │ │ └── gulpfile.js
│ │ │ ├── project/
│ │ │ │ ├── config.js
│ │ │ │ ├── install.js
│ │ │ │ └── release.js
│ │ │ ├── tasks.js
│ │ │ └── user.js
│ │ ├── docs/
│ │ │ ├── build.js
│ │ │ ├── metadata.js
│ │ │ └── serve.js
│ │ ├── install.js
│ │ ├── rtl/
│ │ │ ├── build.js
│ │ │ └── watch.js
│ │ ├── version.js
│ │ └── watch.js
│ ├── semantic.json
│ └── wwwroot/
│ ├── scripts/
│ │ ├── daemon.js
│ │ └── knockout-3.4.2.js
│ └── semantic/
│ ├── components/
│ │ ├── accordion.css
│ │ ├── accordion.js
│ │ ├── ad.css
│ │ ├── api.js
│ │ ├── breadcrumb.css
│ │ ├── button.css
│ │ ├── card.css
│ │ ├── checkbox.css
│ │ ├── checkbox.js
│ │ ├── comment.css
│ │ ├── container.css
│ │ ├── dimmer.css
│ │ ├── dimmer.js
│ │ ├── divider.css
│ │ ├── dropdown.css
│ │ ├── dropdown.js
│ │ ├── embed.css
│ │ ├── embed.js
│ │ ├── feed.css
│ │ ├── flag.css
│ │ ├── form.css
│ │ ├── form.js
│ │ ├── grid.css
│ │ ├── header.css
│ │ ├── icon.css
│ │ ├── image.css
│ │ ├── input.css
│ │ ├── item.css
│ │ ├── label.css
│ │ ├── list.css
│ │ ├── loader.css
│ │ ├── menu.css
│ │ ├── message.css
│ │ ├── modal.css
│ │ ├── modal.js
│ │ ├── nag.css
│ │ ├── nag.js
│ │ ├── popup.css
│ │ ├── popup.js
│ │ ├── progress.css
│ │ ├── progress.js
│ │ ├── rail.css
│ │ ├── rating.css
│ │ ├── rating.js
│ │ ├── reset.css
│ │ ├── reveal.css
│ │ ├── search.css
│ │ ├── search.js
│ │ ├── segment.css
│ │ ├── shape.css
│ │ ├── shape.js
│ │ ├── sidebar.css
│ │ ├── sidebar.js
│ │ ├── site.css
│ │ ├── site.js
│ │ ├── statistic.css
│ │ ├── step.css
│ │ ├── sticky.css
│ │ ├── sticky.js
│ │ ├── tab.css
│ │ ├── tab.js
│ │ ├── table.css
│ │ ├── transition.css
│ │ ├── transition.js
│ │ └── visibility.js
│ ├── semantic.css
│ └── semantic.js
└── phippy/
├── .dockerignore
├── .draft-tasks.toml
├── .draftignore
├── Dockerfile
├── cd-pipeline.yml
├── charts/
│ └── phippy/
│ ├── .helmignore
│ ├── Chart.yaml
│ ├── templates/
│ │ ├── NOTES.txt
│ │ ├── _helpers.tpl
│ │ ├── deployment.yaml
│ │ ├── ingress.yaml
│ │ ├── secret.yaml
│ │ └── service.yaml
│ └── values.yaml
├── ci-pipeline.yml
├── composer.json
├── composer.phar
├── draft.toml
└── index.php
SYMBOL INDEX (141 symbols across 15 files)
FILE: captainkube/main.go
type Pod (line 18) | type Pod struct
function main (line 27) | func main() {
function runhealthz (line 37) | func runhealthz() {
function runinformer (line 56) | func runinformer(done chan struct{}) {
function pingparrot (line 127) | func pingparrot(pod *v1.Pod, state string) {
FILE: parrot/Controllers/ClusterStatusController.cs
class ClusterStatusController (line 15) | [Route("api/[controller]")]
method ClusterStatusController (line 19) | public ClusterStatusController(ILogger<ClusterStatusController> logger...
method Get (line 28) | [HttpGet]
method Delete (line 34) | [HttpDelete]
method Post (line 49) | [HttpPost]
FILE: parrot/Controllers/HomeController.cs
class HomeController (line 11) | public class HomeController : Controller
method Index (line 13) | public IActionResult Index()
method Error (line 18) | public IActionResult Error()
FILE: parrot/Hubs/Daemon.cs
class DaemonHub (line 10) | public class DaemonHub : Hub
method DaemonHub (line 15) | static DaemonHub()
method OnConnectedAsync (line 23) | public override Task OnConnectedAsync()
method AddPod (line 29) | public void AddPod(Pod pod)
method RemovePod (line 37) | public void RemovePod(Pod pod)
method UpdatePod (line 43) | public void UpdatePod(Pod pod)
method clearClusterView (line 51) | public void clearClusterView()
method updateClusterView (line 57) | public void updateClusterView(Pod pod)
FILE: parrot/Models/ErrorViewModel.cs
class ErrorViewModel (line 5) | public class ErrorViewModel
FILE: parrot/Models/Pod.cs
class Pod (line 5) | public class Pod
method ToString (line 18) | public override string ToString() {
FILE: parrot/Program.cs
class Program (line 6) | public class Program
method Main (line 8) | public static void Main(string[] args)
method CreateHostBuilder (line 13) | public static IHostBuilder CreateHostBuilder(string[] args) =>
FILE: parrot/Startup.cs
class Startup (line 9) | public class Startup
method Startup (line 11) | public Startup(IConfiguration configuration)
method ConfigureServices (line 19) | public void ConfigureServices(IServiceCollection services)
method Configure (line 27) | public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
FILE: parrot/semantic/tasks/admin/components/init.js
function setupRepo (line 96) | function setupRepo() {
function initRepo (line 105) | function initRepo() {
function createRepo (line 115) | function createRepo() {
function addRemote (line 126) | function addRemote() {
function pullFiles (line 133) | function pullFiles() {
function resetFiles (line 140) | function resetFiles() {
function nextRepo (line 147) | function nextRepo() {
FILE: parrot/semantic/tasks/admin/components/update.js
function setConfig (line 104) | function setConfig() {
function commitFiles (line 116) | function commitFiles() {
function pushFiles (line 138) | function pushFiles() {
function getSHA (line 147) | function getSHA() {
function createRelease (line 155) | function createRelease(version) {
function nextRepo (line 165) | function nextRepo() {
FILE: parrot/semantic/tasks/admin/distributions/init.js
function setupRepo (line 95) | function setupRepo() {
function initRepo (line 104) | function initRepo() {
function createRepo (line 114) | function createRepo() {
function addRemote (line 125) | function addRemote() {
function pullFiles (line 132) | function pullFiles() {
function resetFiles (line 139) | function resetFiles() {
function nextRepo (line 146) | function nextRepo() {
FILE: parrot/semantic/tasks/admin/distributions/update.js
function setConfig (line 100) | function setConfig() {
function commitFiles (line 111) | function commitFiles() {
function pushFiles (line 133) | function pushFiles() {
function getSHA (line 142) | function getSHA() {
function createRelease (line 150) | function createRelease(version) {
function nextRepo (line 160) | function nextRepo() {
FILE: parrot/semantic/tasks/docs/metadata.js
function startsWith (line 21) | function startsWith(str, prefix) {
function inArray (line 25) | function inArray(needle, haystack) {
function parser (line 39) | function parser(file, callback) {
FILE: parrot/wwwroot/scripts/daemon.js
function PodCardsViewModel (line 21) | function PodCardsViewModel() {
function startConnection (line 28) | function startConnection() {
FILE: parrot/wwwroot/scripts/knockout-3.4.2.js
function J (line 7) | function J(a,c){return null===a||typeof a in R?a===c:!1}
function S (line 7) | function S(b,c){var d;return function(){d||(d=a.a.setTimeout(function(){...
function T (line 7) | function T(b,c){var d;return function(){clearTimeout(d);d=a.a.setTimeout...
function U (line 7) | function U(a,
function V (line 8) | function V(a,c){null!==c&&c.k&&c.k()}
function W (line 8) | function W(a,c){var d=this.Mc,e=d[s];e.T||(this.ob&&this.Oa[c]?(d.Sb(c,a...
function K (line 8) | function K(b,c,d,e){a.d[b]={init:function(b,g,h,l,m){var k,r;a.m(functio...
function b (line 9) | function b(a,b){for(var c in a)a.hasOwnProperty(c)&&b(c,a[c])}
function c (line 9) | function c(a,b){if(b)for(var c in b)b.hasOwnProperty(c)&&(a[c]=b[c]);ret...
function d (line 9) | function d(a,b){a.__proto__=
function e (line 10) | function e(b,c,d,e){var m=b[c].match(r)||[];a.a.r(d.match(r),function(b)...
function a (line 25) | function a(b,g){var h=b[d];if(!h||"null"===h||!e[h]){if(!g)return n;h=b[...
function b (line 26) | function b(b,c){var e=a.a.e.get(b,d);e===n&&c&&(e=[],a.a.e.set(b,d,e));r...
function c (line 26) | function c(d){var e=b(d,!1);if(e)for(var e=e.slice(0),l=0;l<e.length;l++...
function b (line 30) | function b(c,e){if(c)if(8==c.nodeType){var f=a.N.pc(c.nodeValue);null!=f...
function b (line 32) | function b(){if(e)for(var b=
function c (line 33) | function c(){b();g=e=d.length=0}
function b (line 39) | function b(a){d.push(e);e=a}
function c (line 39) | function c(){e=d.pop()}
function c (line 40) | function c(){if(0<arguments.length)return c.Ua(c[F],arguments[0])&&(c.ia...
function d (line 45) | function d(){if(!e){e=!0;l=b.notifySubscribers;b.notifySubscribers=funct...
function k (line 46) | function k(a,b,c){return m[m.length]={status:a,value:b,index:c}}
function e (line 47) | function e(){if(0<arguments.length){if("function"===typeof f)f.apply(g.s...
function b (line 55) | function b(a,f,g){g=g||new d;a=f(a);if("object"!=typeof a||null===a||a==...
function c (line 56) | function c(a,b){if(a instanceof Array){for(var c=0;c<a.length;c++)b(c);"...
function d (line 56) | function d(){this.keys=[];this.Lb=[]}
function b (line 59) | function b(b){b=a.a.cb(b);123===b.charCodeAt(0)&&(b=b.slice(1,-1));var c...
function k (line 61) | function k(b,e){var m;if(!A){var l=a.getBindingHandler(b);if(l&&l.prepro...
function b (line 63) | function b(a){return 8==a.nodeType&&g.test(f?a.text:a.nodeValue)}
function c (line 63) | function c(a){return 8==a.nodeType&&h.test(f?a.text:a.nodeValue)}
function d (line 63) | function d(a,d){for(var e=a,f=1,l=[];e=e.nextSibling;){if(c(e)&&(f--,0==...
function e (line 63) | function e(a,b){var c=d(a,b);return c?0<c.length?c[c.length-
function b (line 69) | function b(a){return function(){return a}}
function c (line 69) | function c(a){return a()}
function d (line 69) | function d(b){return a.a.Ea(a.l.w(b),function(a,c){return function(){ret...
function e (line 69) | function e(c,e,k){return"function"===typeof c?d(c.bind(null,e,k)):a.a.Ea...
function f (line 69) | function f(a,b){return d(this.getBindings.bind(this,a,b))}
function g (line 69) | function g(b,c,d){var e,k=a.f.firstChild(c),f=a.S.instance,m=f.preproces...
function h (line 70) | function h(b,c,d){var e=!0,k=1===c.nodeType;k&&a.f.oc(c);if(k&&d||a.S.in...
function l (line 70) | function l(b){var c=[],d={},e=[];a.a.D(b,function X(k){if(!d[k]){var f=a...
function m (line 71) | function m(b,d,e,k){var m=a.a.e.get(b,q);if(!d){if(m)throw Error("You ca...
function k (line 73) | function k(b){return b&&b instanceof a.R?b:new a.R(b)}
function f (line 73) | function f(){var k=g?b():b,m=a.a.c(k);c?(c.Q&&c.Q(),a.a.extend(l,c),l.Q=...
function m (line 74) | function m(){return h&&!a.a.Tb(h)}
function c (line 77) | function c(c,e){var m=f.hasOwnProperty(c)?f[c]:b,k;m?m.Y(e):(m=f[c]=new ...
function d (line 77) | function d(a,b){e("getConfig",[a],function(c){c?e("loadComponent",
function e (line 78) | function e(c,d,f,k){k||(k=a.g.loaders.slice(0));var g=k.shift();if(g){va...
function b (line 79) | function b(b,c,d,e){function g(){0===--y&&e(h)}var h={},y=2,v=d.template...
function c (line 79) | function c(a,b,d){if("function"===typeof b)d(function(a){return new b(a)});
function d (line 80) | function d(b){switch(a.a.A(b)){case "script":return a.a.na(b.text);case ...
function e (line 80) | function e(a){return x.DocumentFragment?a instanceof DocumentFragment:a&...
function f (line 80) | function f(a,b,c){"string"===typeof b.require?
function g (line 81) | function g(a){return function(b){throw Error("Component '"+a+"': "+b);}}
function b (line 83) | function b(b,e){var f=b.getAttribute("params");if(f){var f=c.parseBindin...
function c (line 85) | function c(b,c,d){c=c.template;if(!c)throw Error("Component '"+b+"' has ...
function d (line 85) | function d(a,b,c,d){var e=a.createViewModel;return e?e.call(a,
function k (line 86) | function k(){var a=r&&r.dispose;"function"===typeof a&&a.call(r);q=r=null}
function e (line 88) | function e(){var e=b.checked,f=p?g():e;if(!a.xa.Va()&&(!l||e)){var h=a.l...
function f (line 88) | function f(){var d=a.a.c(c());b.checked=k?0<=a.a.o(d,g()):h?d:g()===d}
function e (line 92) | function e(e){b.__ko_hasfocusUpdating=!0;var f=b.ownerDocument;if("activ...
function e (line 94) | function e(){return a.a.Ma(b.options,function(a){return a.selected})}
function f (line 94) | function f(a,b,c){var d=typeof b;return"function"==d?b(a):"string"==d?a[...
function g (line 94) | function g(c,e){if(A&&k)a.j.ja(b,a.a.c(d.get("value")),!0);else if(p.len...
function l (line 100) | function l(c,d){a.a.q(b,c,d)}
function h (line 100) | function h(){var c=a.a.c(d());if(null===c||c===n)c="";u!==n&&c===u?a.a.s...
function y (line 100) | function y(){t||(u=b.value,t=a.a.setTimeout(v,4))}
function v (line 100) | function v(){clearTimeout(t);u=t=n;var c=b.value;s!==c&&(s=c,a.h.Ga(d(),...
function b (line 106) | function b(b,c,d,h){b=a.h.Ab(b);for(var l=a.h.va,m=0;m<b.length;m++){var...
function b (line 110) | function b(b,c,d){var e;for(c=a.f.nextSibling(c);b&&(e=b)!==c;)b=a.f.nex...
function c (line 110) | function c(c,d){if(c.length){var e=c[0],f=c[c.length-1],g=e.parentNode,h=
function d (line 111) | function d(a){return a.nodeType?a:0<a.length?a[0]:null}
function e (line 111) | function e(b,e,f,h,q){q=q||{};var p=(b&&d(b)||f||{}).ownerDocument,n=q.t...
function f (line 112) | function f(b,c,d){return a.I(b)?b():"function"===typeof b?b(c,d):b}
function p (line 114) | function p(a,b){c(b,t);g.afterRender&&g.afterRender(b,a);t=null}
function s (line 114) | function s(a,c){t=q.createChildContext(a,g.as,function(a){a.$index=c});v...
function b (line 117) | function b(b,d,e,f,g){var h=Math.min,l=Math.max,m=[],k,n=b.length,q,p=d....
function b (line 118) | function b(b,c,d,h,l){var m=[],k=a.B(function(){var k=c(d,l,a.a.Ba(m,b))...
function m (line 119) | function m(b,c){w=q[c];u!==c&&(D[b]=w);w.tb(u++);a.a.Ba(w.ea,e);t.push(w...
function k (line 119) | function k(b,c){if(b)for(var d=0,e=c.length;d<e;d++)c[d]&&a.a.r(c[d].ea,...
Condensed preview — 591 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (5,470K chars).
[
{
"path": ".gitignore",
"chars": 5582,
"preview": "## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n##\n## G"
},
{
"path": "LICENSE",
"chars": 1162,
"preview": " MIT License\n\n Copyright (c) Microsoft Corporation. All rights reserved.\n\n Permission is hereby granted, free o"
},
{
"path": "README.md",
"chars": 12027,
"preview": "# Phippy and Friends\n\nThe [Children's Guide to Kubernetes](https://azure.microsoft.com/en-us/resources/videos/the-illust"
},
{
"path": "captainkube/.dockerignore",
"chars": 51,
"preview": "Dockerfile\ndraft.toml\nchart/\nNOTICE\nGodeps/\nvendor/"
},
{
"path": "captainkube/.draft-tasks.toml",
"chars": 0,
"preview": ""
},
{
"path": "captainkube/.draftignore",
"chars": 25,
"preview": "*.swp\n*.tmp\n*.temp\n.git*\n"
},
{
"path": "captainkube/Dockerfile",
"chars": 441,
"preview": "# Build\nFROM golang:1.14.4 as builder\n\nWORKDIR /build\nCOPY main.go .\n# temporary workaroud for https://github.com/Azure/"
},
{
"path": "captainkube/cd-pipeline.yml",
"chars": 908,
"preview": "trigger: none\npr: none\n\nvariables:\n- template: ../common/cd-vars-template.yml\n parameters:\n projectName: captainku"
},
{
"path": "captainkube/charts/captainkube/.helmignore",
"chars": 333,
"preview": "# Patterns to ignore when building packages.\n# This supports shell glob matching, relative path matching, and\n# negation"
},
{
"path": "captainkube/charts/captainkube/Chart.yaml",
"chars": 153,
"preview": "apiVersion: v1\ndescription: This app represents Captain Kube, who is taking care of all the containers in the cluster.\nn"
},
{
"path": "captainkube/charts/captainkube/templates/NOTES.txt",
"chars": 248,
"preview": "Tail the logs of the lighthouse pod\n\n- kubectl logs -f --namespace {{ .Release.Namespace }} \\\n $(kubectl get pods --n"
},
{
"path": "captainkube/charts/captainkube/templates/_helpers.tpl",
"chars": 796,
"preview": "{{/* vim: set filetype=mustache: */}}\n{{/*\nExpand the name of the chart.\n*/}}\n{{- define \"name\" -}}\n{{- default .Chart.N"
},
{
"path": "captainkube/charts/captainkube/templates/deployment.yaml",
"chars": 1037,
"preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: {{ template \"fullname\" . }}\n labels:\n app: {{ template \"fulln"
},
{
"path": "captainkube/charts/captainkube/templates/secret.yaml",
"chars": 214,
"preview": "{{ if .Values.image.private }}\napiVersion: v1\nkind: Secret\nmetadata:\n name: {{ .Chart.Name }}-acr-secret\ntype: kubernet"
},
{
"path": "captainkube/charts/captainkube/values.yaml",
"chars": 73,
"preview": "replicaCount: 1\nimage:\n useImagePullSecrets: false\n pullPolicy: Always\n"
},
{
"path": "captainkube/ci-pipeline.yml",
"chars": 448,
"preview": "trigger:\n batch: true\n branches:\n include: \n - '*'\n paths:\n include: \n - captainkube/\n - common/ci-ste"
},
{
"path": "captainkube/draft.toml",
"chars": 218,
"preview": "[environments]\n [environments.development]\n name = \"captainkube\"\n namespace = \"phippyandfriends\"\n wait = true\n"
},
{
"path": "captainkube/main.go",
"chars": 4478,
"preview": "package main\n\nimport (\n\t\"time\"\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"net/http\"\n\t\"log\"\n\t\"reflect\"\n\n\t\"k8s.io/api/core/v1\"\n\t\"k8s.io/a"
},
{
"path": "common/cd-steps-template.yml",
"chars": 1067,
"preview": "steps:\n- checkout: none\n- task: HelmInstaller@1\n displayName: 'install helm'\n inputs:\n helmVersionToInstall: $(helm"
},
{
"path": "common/cd-vars-template.yml",
"chars": 159,
"preview": "parameters:\n projectName: ''\n\nvariables:\n helmVersion: 3.2.3\n registryServerName: '$(registryName).azurecr.io'\n proj"
},
{
"path": "common/ci-steps-template.yml",
"chars": 1655,
"preview": "steps:\n- bash: |\n cd $(projectName)\n docker build \\\n -t $(registryServerName)/$(imageName):$(imageTag) \\\n "
},
{
"path": "common/ci-vars-template.yml",
"chars": 268,
"preview": "parameters:\n projectName: ''\n\nvariables:\n helmVersion: 3.2.3\n registryServerName: '$(registryName).azurecr.io'\n proj"
},
{
"path": "nodebrady/.dockerignore",
"chars": 63,
"preview": "Dockerfile\ndraft.toml\nchart/\nNOTICE\nnode_modules\nnpm-debug.log\n"
},
{
"path": "nodebrady/.draft-tasks.toml",
"chars": 0,
"preview": ""
},
{
"path": "nodebrady/.draftignore",
"chars": 25,
"preview": "*.swp\n*.tmp\n*.temp\n.git*\n"
},
{
"path": "nodebrady/.editorconfig",
"chars": 214,
"preview": "# http://editorconfig.org\nroot = true\n\n[*]\nindent_style = space\nindent_size = 2\nend_of_line = lf\ncharset = utf-8\ntrim_tr"
},
{
"path": "nodebrady/.jshintrc",
"chars": 389,
"preview": "{\n \"node\": true,\n \"esnext\": true,\n \"bitwise\": true,\n \"camelcase\": true,\n \"curly\": true,\n \"eqeqeq\": tru"
},
{
"path": "nodebrady/Dockerfile",
"chars": 601,
"preview": "# Build\nFROM node:carbon AS base\n\nWORKDIR /app\n\n# Dependencies\nFROM base AS dependencies \n\n# A wildcard is used to ensu"
},
{
"path": "nodebrady/app.js",
"chars": 823,
"preview": "'use strict';\nconst messages = require('./controllers/messages');\nconst compress = require('koa-compress');\nconst logger"
},
{
"path": "nodebrady/cd-pipeline.yml",
"chars": 904,
"preview": "trigger: none\npr: none\n\nvariables:\n- template: ../common/cd-vars-template.yml\n parameters:\n projectName: nodebrady"
},
{
"path": "nodebrady/charts/nodebrady/.helmignore",
"chars": 333,
"preview": "# Patterns to ignore when building packages.\n# This supports shell glob matching, relative path matching, and\n# negation"
},
{
"path": "nodebrady/charts/nodebrady/Chart.yaml",
"chars": 95,
"preview": "apiVersion: v1\ndescription: Azure Brady in his Node.js attire.\nname: nodebrady\nversion: v0.3.0\n"
},
{
"path": "nodebrady/charts/nodebrady/templates/NOTES.txt",
"chars": 248,
"preview": "Tail the logs of the lighthouse pod\n\n- kubectl logs -f --namespace {{ .Release.Namespace }} \\\n $(kubectl get pods --n"
},
{
"path": "nodebrady/charts/nodebrady/templates/_helpers.tpl",
"chars": 796,
"preview": "{{/* vim: set filetype=mustache: */}}\n{{/*\nExpand the name of the chart.\n*/}}\n{{- define \"name\" -}}\n{{- default .Chart.N"
},
{
"path": "nodebrady/charts/nodebrady/templates/deployment.yaml",
"chars": 915,
"preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: {{ template \"fullname\" . }}\n labels:\n app: {{ template \"fulln"
},
{
"path": "nodebrady/charts/nodebrady/templates/ingress.yaml",
"chars": 647,
"preview": "{{ if .Values.ingress.enabled }}\napiVersion: extensions/v1beta1\nkind: Ingress\nmetadata:\n name: {{ template \"fullname\" ."
},
{
"path": "nodebrady/charts/nodebrady/templates/secret.yaml",
"chars": 214,
"preview": "{{ if .Values.image.private }}\napiVersion: v1\nkind: Secret\nmetadata:\n name: {{ .Chart.Name }}-acr-secret\ntype: kubernet"
},
{
"path": "nodebrady/charts/nodebrady/templates/service.yaml",
"chars": 443,
"preview": "apiVersion: v1\nkind: Service\nmetadata:\n name: {{ template \"fullname\" . }}\n labels:\n app: {{ template \"fullname\" . }"
},
{
"path": "nodebrady/charts/nodebrady/values.yaml",
"chars": 239,
"preview": "replicaCount: 1\nimage:\n useImagePullSecrets: false\n pullPolicy: Always\nservice:\n internalPort: 3000\n externalPort: 8"
},
{
"path": "nodebrady/ci-pipeline.yml",
"chars": 444,
"preview": "trigger:\n batch: true\n branches:\n include: \n - '*'\n paths:\n include: \n - nodebrady/\n - common/ci-steps"
},
{
"path": "nodebrady/controllers/messages.js",
"chars": 1378,
"preview": "'use strict';\nconst views = require('co-views');\nconst parse = require('co-body');\nconst messages = [\n { id: 0,\n mes"
},
{
"path": "nodebrady/draft.toml",
"chars": 216,
"preview": "[environments]\n [environments.development]\n name = \"nodebrady\"\n namespace = \"phippyandfriends\"\n wait = true\n "
},
{
"path": "nodebrady/package.json",
"chars": 444,
"preview": "{\n \"name\": \"nodebrady\",\n \"version\": \"0.0.1\",\n \"private\": true,\n \"scripts\": {\n \"start\": \"node app.js\",\n \"test\":"
},
{
"path": "nodebrady/public/scripts/.gitkeep",
"chars": 0,
"preview": ""
},
{
"path": "nodebrady/public/styles/main.css",
"chars": 315,
"preview": "ul {\n\tmargin: 100px auto 0;\n\tlist-style: none;\n\twidth: 700px;\n\tfont: 30px helvetica;\n\tfont-weight: 100;\n}\n\nli {\n margin"
},
{
"path": "nodebrady/test/routeSpec.js",
"chars": 694,
"preview": "/*global describe, it*/\n'use strict';\nconst superagent = require('supertest');\nconst app = require('../app');\nconst requ"
},
{
"path": "nodebrady/views/layout.html",
"chars": 298,
"preview": "<!DOCTYPE html>\n<html>\n<head>\n\t<title>{% block title %}Messages{% endblock %}</title>\n <link rel=\"stylesheet\" type=\"tex"
},
{
"path": "nodebrady/views/list.html",
"chars": 475,
"preview": "{% extends 'layout.html' %}\n\n{% block title %}Messages{% endblock %}\n\n{% block content %}\n <ul class=\"messages\">\n {%"
},
{
"path": "parrot/.dockerignore",
"chars": 57,
"preview": "Dockerfile\ndraft.toml\nchart/\nNOTICE\nbin/\nobj/\n!published/"
},
{
"path": "parrot/.draft-tasks.toml",
"chars": 0,
"preview": ""
},
{
"path": "parrot/.draftignore",
"chars": 25,
"preview": "*.swp\n*.tmp\n*.temp\n.git*\n"
},
{
"path": "parrot/.vscode/launch.json",
"chars": 1617,
"preview": "{\n // Use IntelliSense to find out which attributes exist for C# debugging\n // Use hover for the description of the "
},
{
"path": "parrot/.vscode/tasks.json",
"chars": 318,
"preview": "{\n \"version\": \"2.0.0\",\n \"tasks\": [\n {\n \"label\": \"build\",\n \"command\": \"dotnet\",\n "
},
{
"path": "parrot/Controllers/ClusterStatusController.cs",
"chars": 2021,
"preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Diagnostics;\r\nusing System.IO;\r\nusing System.Linq;\r\nusin"
},
{
"path": "parrot/Controllers/HomeController.cs",
"chars": 546,
"preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Diagnostics;\r\nusing System.Linq;\r\nusing System.Threading"
},
{
"path": "parrot/Controllers/test.json",
"chars": 3884,
"preview": "\"metadata\": {\n \"name\": \"nodeapp-nodeapp-66845c9868-phvqv\",\n \"generateName\": \"nodeapp-nodeapp-66845c9868-\",\n \"na"
},
{
"path": "parrot/Dockerfile",
"chars": 403,
"preview": "FROM mcr.microsoft.com/dotnet/core/sdk:3.1.301-alpine AS build-env\nWORKDIR /app\n\n# Copy csproj and restore as distinct l"
},
{
"path": "parrot/Hubs/Daemon.cs",
"chars": 2185,
"preview": "using System.Threading.Tasks;\nusing System.Collections;\nusing System.Linq;\nusing System.Collections.Generic;\nusing Micro"
},
{
"path": "parrot/Models/ErrorViewModel.cs",
"chars": 214,
"preview": "using System;\r\n\r\nnamespace parrot.Models\r\n{\r\n public class ErrorViewModel\r\n {\r\n public string RequestId { g"
},
{
"path": "parrot/Models/Pod.cs",
"chars": 710,
"preview": "using System;\n\nnamespace parrot.Models\n{\n public class Pod\n {\n public string Name { get; set; }\n pub"
},
{
"path": "parrot/NOTICE",
"chars": 1082,
"preview": "MIT License:\n\nCopyright (C) 2017 Cloudbase Solutions, Srl\n\nPermission is hereby granted, free of charge, to any person o"
},
{
"path": "parrot/Program.cs",
"chars": 534,
"preview": "using Microsoft.AspNetCore.Hosting;\r\nusing Microsoft.Extensions.Hosting;\r\n\r\nnamespace parrot\r\n{\r\n public class Progr"
},
{
"path": "parrot/Startup.cs",
"chars": 1517,
"preview": "using Microsoft.AspNetCore.Builder;\r\nusing Microsoft.AspNetCore.Hosting;\r\nusing Microsoft.Extensions.Configuration;\r\nus"
},
{
"path": "parrot/Views/Home/Index.cshtml",
"chars": 839,
"preview": "@{\r\n ViewData[\"Title\"] = \"parrot\";\r\n}\r\n\r\n<ul id=\"pods\">\r\n</ul>\r\n\r\n<div class=\"ui link cards\" id=\"podcards\" data-bind"
},
{
"path": "parrot/Views/Shared/Error.cshtml",
"chars": 867,
"preview": "@model ErrorViewModel\r\n@{\r\n ViewData[\"Title\"] = \"Error\";\r\n}\r\n\r\n<h1 class=\"text-danger\">Error.</h1>\r\n<h2 class=\"text-"
},
{
"path": "parrot/Views/Shared/_Layout.cshtml",
"chars": 1462,
"preview": "<!DOCTYPE html>\r\n<html>\r\n<head>\r\n <meta charset=\"utf-8\" />\r\n <meta name=\"viewport\" content=\"width=device-width, i"
},
{
"path": "parrot/Views/Shared/_ValidationScriptsPartial.cshtml",
"chars": 1172,
"preview": "<environment include=\"Development\">\r\n <script src=\"~/lib/jquery-validation/dist/jquery.validate.js\"></script>\r\n <s"
},
{
"path": "parrot/Views/_ViewImports.cshtml",
"chars": 91,
"preview": "@using parrot\r\n@using parrot.Models\r\n@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers\r\n"
},
{
"path": "parrot/Views/_ViewStart.cshtml",
"chars": 33,
"preview": "@{\r\n Layout = \"_Layout\";\r\n}\r\n"
},
{
"path": "parrot/appsettings.Development.json",
"chars": 176,
"preview": "{\r\n \"Logging\": {\r\n \"IncludeScopes\": false,\r\n \"LogLevel\": {\r\n \"Default\": \"Debug\",\r\n \"System\": \"Informat"
},
{
"path": "parrot/appsettings.json",
"chars": 111,
"preview": "{\r\n \"Logging\": {\r\n \"IncludeScopes\": false,\r\n \"LogLevel\": {\r\n \"Default\": \"Warning\"\r\n }\r\n }\r\n}\r\n"
},
{
"path": "parrot/bundleconfig.json",
"chars": 626,
"preview": "// Configure bundling and minification for the project.\r\n// More info at https://go.microsoft.com/fwlink/?LinkId=808241"
},
{
"path": "parrot/cd-pipeline.yml",
"chars": 898,
"preview": "trigger: none\npr: none\n\nvariables:\n- template: ../common/cd-vars-template.yml\n parameters:\n projectName: parrot\n "
},
{
"path": "parrot/charts/parrot/.helmignore",
"chars": 333,
"preview": "# Patterns to ignore when building packages.\n# This supports shell glob matching, relative path matching, and\n# negation"
},
{
"path": "parrot/charts/parrot/Chart.yaml",
"chars": 145,
"preview": "apiVersion: v1\ndescription: Parrot is Captain Kube's sidekick, who shows everything the captain's doing on-screen. \nname"
},
{
"path": "parrot/charts/parrot/templates/NOTES.txt",
"chars": 248,
"preview": "Tail the logs of the lighthouse pod\n\n- kubectl logs -f --namespace {{ .Release.Namespace }} \\\n $(kubectl get pods --n"
},
{
"path": "parrot/charts/parrot/templates/_helpers.tpl",
"chars": 796,
"preview": "{{/* vim: set filetype=mustache: */}}\n{{/*\nExpand the name of the chart.\n*/}}\n{{- define \"name\" -}}\n{{- default .Chart.N"
},
{
"path": "parrot/charts/parrot/templates/deployment.yaml",
"chars": 925,
"preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: {{ template \"fullname\" . }}\n labels:\n app: {{ template \"fulln"
},
{
"path": "parrot/charts/parrot/templates/ingress.yaml",
"chars": 647,
"preview": "{{ if .Values.ingress.enabled }}\napiVersion: extensions/v1beta1\nkind: Ingress\nmetadata:\n name: {{ template \"fullname\" ."
},
{
"path": "parrot/charts/parrot/templates/secret.yaml",
"chars": 214,
"preview": "{{ if .Values.image.private }}\napiVersion: v1\nkind: Secret\nmetadata:\n name: {{ .Chart.Name }}-acr-secret\ntype: kubernet"
},
{
"path": "parrot/charts/parrot/templates/service.yaml",
"chars": 518,
"preview": "apiVersion: v1\nkind: Service\nmetadata:\n name: {{ template \"fullname\" . }}\n labels:\n app: {{ template \"fullname\" . }"
},
{
"path": "parrot/charts/parrot/values.yaml",
"chars": 259,
"preview": "replicaCount: 1\nimage:\n useImagePullSecrets: false\n pullPolicy: Always\nservice:\n internalPort: 80\n externalPort: 80\n"
},
{
"path": "parrot/ci-pipeline.yml",
"chars": 430,
"preview": "trigger:\n batch: true\n branches:\n include: \n - '*'\n paths:\n include: \n - parrot/\n - common/ci-steps-te"
},
{
"path": "parrot/draft.toml",
"chars": 213,
"preview": "[environments]\n [environments.development]\n name = \"parrot\"\n namespace = \"phippyandfriends\"\n wait = true\n w"
},
{
"path": "parrot/package.json",
"chars": 288,
"preview": "{\n \"name\": \"parrot\",\n \"version\": \"1.0.0\",\n \"description\": \"\",\n \"main\": \"index.js\",\n \"scripts\": {\n \"test\": \"echo "
},
{
"path": "parrot/parrot.csproj",
"chars": 469,
"preview": "<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n\n <PropertyGroup>\n <TargetFramework>netcoreapp3.1</TargetFramework>\n </Proper"
},
{
"path": "parrot/semantic/gulpfile.js",
"chars": 1925,
"preview": "/*******************************\n Set-up\n*******************************/\n\nvar\n gulp = require('gulp"
},
{
"path": "parrot/semantic/src/definitions/behaviors/api.js",
"chars": 39779,
"preview": "/*!\n * # Semantic UI - API\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license\n * htt"
},
{
"path": "parrot/semantic/src/definitions/behaviors/form.js",
"chars": 55906,
"preview": "/*!\n * # Semantic UI - Form Validation\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT li"
},
{
"path": "parrot/semantic/src/definitions/behaviors/visibility.js",
"chars": 42863,
"preview": "/*!\n * # Semantic UI - Visibility\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license"
},
{
"path": "parrot/semantic/src/definitions/collections/breadcrumb.less",
"chars": 2103,
"preview": "/*!\n * # Semantic UI - Breadcrumb\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license"
},
{
"path": "parrot/semantic/src/definitions/collections/form.less",
"chars": 27067,
"preview": "/*!\n * # Semantic UI - Form\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license\n * ht"
},
{
"path": "parrot/semantic/src/definitions/collections/grid.less",
"chars": 68576,
"preview": "/*!\n * # Semantic UI - Grid\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license\n * ht"
},
{
"path": "parrot/semantic/src/definitions/collections/menu.less",
"chars": 43280,
"preview": "/*\n * # Semantic - Menu\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Copyright 2015 Contributor\n * Released u"
},
{
"path": "parrot/semantic/src/definitions/collections/message.less",
"chars": 8828,
"preview": "/*!\n * # Semantic UI - Message\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license\n *"
},
{
"path": "parrot/semantic/src/definitions/collections/table.less",
"chars": 24750,
"preview": "/*!\n * # Semantic UI - Table\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license\n * h"
},
{
"path": "parrot/semantic/src/definitions/elements/button.less",
"chars": 100521,
"preview": "/*!\n * # Semantic UI - Button\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license\n * "
},
{
"path": "parrot/semantic/src/definitions/elements/container.less",
"chars": 3162,
"preview": "/*!\n * # Semantic UI - Container\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license\n"
},
{
"path": "parrot/semantic/src/definitions/elements/divider.less",
"chars": 4815,
"preview": "/*!\n * # Semantic UI - Divider\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license\n *"
},
{
"path": "parrot/semantic/src/definitions/elements/flag.less",
"chars": 895,
"preview": "/*!\n * # Semantic UI - Flag\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license\n * ht"
},
{
"path": "parrot/semantic/src/definitions/elements/header.less",
"chars": 13383,
"preview": "/*!\n * # Semantic UI - Header\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license\n * "
},
{
"path": "parrot/semantic/src/definitions/elements/icon.less",
"chars": 8663,
"preview": "/*!\n * # Semantic UI - Icon\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license\n * ht"
},
{
"path": "parrot/semantic/src/definitions/elements/image.less",
"chars": 5759,
"preview": "/*!\n * # Semantic UI - Image\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license\n * h"
},
{
"path": "parrot/semantic/src/definitions/elements/input.less",
"chars": 11637,
"preview": "/*!\n * # Semantic UI - Input\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license\n * h"
},
{
"path": "parrot/semantic/src/definitions/elements/label.less",
"chars": 28211,
"preview": "/*!\n * # Semantic UI - Label\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license\n * h"
},
{
"path": "parrot/semantic/src/definitions/elements/list.less",
"chars": 22368,
"preview": "/*!\n * # Semantic UI - List\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license\n * ht"
},
{
"path": "parrot/semantic/src/definitions/elements/loader.less",
"chars": 6054,
"preview": "/*!\n * # Semantic UI - Loader\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license\n * "
},
{
"path": "parrot/semantic/src/definitions/elements/rail.less",
"chars": 2684,
"preview": "/*!\n * # Semantic UI - Rail\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license\n * ht"
},
{
"path": "parrot/semantic/src/definitions/elements/reveal.less",
"chars": 6041,
"preview": "/*!\n * # Semantic UI - Reveal\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license\n * "
},
{
"path": "parrot/semantic/src/definitions/elements/segment.less",
"chars": 15442,
"preview": "/*!\n * # Semantic UI - Segment\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license\n *"
},
{
"path": "parrot/semantic/src/definitions/elements/step.less",
"chars": 11386,
"preview": "/*!\n * # Semantic UI - Step\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license\n * ht"
},
{
"path": "parrot/semantic/src/definitions/globals/reset.less",
"chars": 733,
"preview": "/*!\n * # Semantic UI - Reset\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license\n * h"
},
{
"path": "parrot/semantic/src/definitions/globals/site.js",
"chars": 14111,
"preview": "/*!\n * # Semantic UI - Site\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license\n * ht"
},
{
"path": "parrot/semantic/src/definitions/globals/site.less",
"chars": 3786,
"preview": "/*!\n * # Semantic UI - Site\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license\n * ht"
},
{
"path": "parrot/semantic/src/definitions/modules/accordion.js",
"chars": 20171,
"preview": "/*!\n * # Semantic UI - Accordion\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license\n"
},
{
"path": "parrot/semantic/src/definitions/modules/accordion.less",
"chars": 4873,
"preview": "/*!\r\n * # Semantic UI - Accordion\r\n * http://github.com/semantic-org/semantic-ui/\r\n *\r\n *\r\n * Released under the MIT lic"
},
{
"path": "parrot/semantic/src/definitions/modules/checkbox.js",
"chars": 26075,
"preview": "/*!\n * # Semantic UI - Checkbox\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license\n "
},
{
"path": "parrot/semantic/src/definitions/modules/checkbox.less",
"chars": 12945,
"preview": "/*!\n * # Semantic UI - Checkbox\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license\n "
},
{
"path": "parrot/semantic/src/definitions/modules/dimmer.js",
"chars": 21339,
"preview": "/*!\n * # Semantic UI - Dimmer\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license\n * "
},
{
"path": "parrot/semantic/src/definitions/modules/dimmer.less",
"chars": 4226,
"preview": "/*!\n * # Semantic UI - Dimmer\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license\n * "
},
{
"path": "parrot/semantic/src/definitions/modules/dropdown.js",
"chars": 141229,
"preview": "/*!\n * # Semantic UI - Dropdown\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license\n "
},
{
"path": "parrot/semantic/src/definitions/modules/dropdown.less",
"chars": 31311,
"preview": "/*!\n * # Semantic UI - Dropdown\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license\n "
},
{
"path": "parrot/semantic/src/definitions/modules/embed.js",
"chars": 19895,
"preview": "/*!\n * # Semantic UI - Embed\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license\n * h"
},
{
"path": "parrot/semantic/src/definitions/modules/embed.less",
"chars": 2734,
"preview": "/*!\n * # Semantic UI - Video\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license\n * h"
},
{
"path": "parrot/semantic/src/definitions/modules/modal.js",
"chars": 29786,
"preview": "/*!\n * # Semantic UI - Modal\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license\n * h"
},
{
"path": "parrot/semantic/src/definitions/modules/modal.less",
"chars": 11834,
"preview": "/*!\n * # Semantic UI - Modal\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license\n * h"
},
{
"path": "parrot/semantic/src/definitions/modules/nag.js",
"chars": 15040,
"preview": "/*!\n * # Semantic UI - Nag\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license\n * htt"
},
{
"path": "parrot/semantic/src/definitions/modules/nag.less",
"chars": 2464,
"preview": "/*!\n * # Semantic UI - Nag\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license\n * htt"
},
{
"path": "parrot/semantic/src/definitions/modules/popup.js",
"chars": 50492,
"preview": "/*!\n * # Semantic UI - Popup\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license\n * h"
},
{
"path": "parrot/semantic/src/definitions/modules/popup.less",
"chars": 14883,
"preview": "/*!\n * # Semantic UI - Popup\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license\n * h"
},
{
"path": "parrot/semantic/src/definitions/modules/progress.js",
"chars": 30267,
"preview": "/*!\n * # Semantic UI - Progress\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license\n "
},
{
"path": "parrot/semantic/src/definitions/modules/progress.less",
"chars": 10283,
"preview": "/*!\n * # Semantic UI - Progress Bar\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT licen"
},
{
"path": "parrot/semantic/src/definitions/modules/rating.js",
"chars": 14355,
"preview": "/*!\n * # Semantic UI - Rating\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license\n * "
},
{
"path": "parrot/semantic/src/definitions/modules/rating.less",
"chars": 3599,
"preview": "/*!\n * # Semantic UI - Rating\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license\n * "
},
{
"path": "parrot/semantic/src/definitions/modules/search.js",
"chars": 49690,
"preview": "/*!\n * # Semantic UI - Search\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license\n * "
},
{
"path": "parrot/semantic/src/definitions/modules/search.less",
"chars": 9435,
"preview": "/*!\n * # Semantic UI - Search\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license\n * "
},
{
"path": "parrot/semantic/src/definitions/modules/shape.js",
"chars": 28946,
"preview": "/*!\n * # Semantic UI - Shape\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license\n * h"
},
{
"path": "parrot/semantic/src/definitions/modules/shape.less",
"chars": 2403,
"preview": "/*!\n * # Semantic UI - Shape\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license\n * h"
},
{
"path": "parrot/semantic/src/definitions/modules/sidebar.js",
"chars": 33449,
"preview": "/*!\n * # Semantic UI - Sidebar\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license\n *"
},
{
"path": "parrot/semantic/src/definitions/modules/sidebar.less",
"chars": 10545,
"preview": "/*!\n * # Semantic UI - Sidebar\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license\n *"
},
{
"path": "parrot/semantic/src/definitions/modules/sticky.js",
"chars": 30849,
"preview": "/*!\n * # Semantic UI - Sticky\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license\n * "
},
{
"path": "parrot/semantic/src/definitions/modules/sticky.less",
"chars": 1189,
"preview": "/*!\n * # Semantic UI - Sticky\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license\n * "
},
{
"path": "parrot/semantic/src/definitions/modules/tab.js",
"chars": 32813,
"preview": "/*!\n * # Semantic UI - Tab\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license\n * htt"
},
{
"path": "parrot/semantic/src/definitions/modules/tab.less",
"chars": 1742,
"preview": "/*!\n * # Semantic UI - Tab\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license\n * htt"
},
{
"path": "parrot/semantic/src/definitions/modules/transition.js",
"chars": 34975,
"preview": "/*!\n * # Semantic UI - Transition\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license"
},
{
"path": "parrot/semantic/src/definitions/modules/transition.less",
"chars": 1441,
"preview": "/*!\n * # Semantic UI - Transition\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license"
},
{
"path": "parrot/semantic/src/definitions/views/ad.less",
"chars": 3882,
"preview": "/*!\n * # Semantic UI - Ad\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Copyright 2013 Contributors\n * Release"
},
{
"path": "parrot/semantic/src/definitions/views/card.less",
"chars": 21596,
"preview": "/*!\n * # Semantic UI - Item\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license\n * ht"
},
{
"path": "parrot/semantic/src/definitions/views/comment.less",
"chars": 5074,
"preview": "/*!\n * # Semantic UI - Comment\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license\n *"
},
{
"path": "parrot/semantic/src/definitions/views/feed.less",
"chars": 5882,
"preview": "/*!\n * # Semantic UI - Feed\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license\n * ht"
},
{
"path": "parrot/semantic/src/definitions/views/item.less",
"chars": 9456,
"preview": "/*!\n * # Semantic UI - Item\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license\n * ht"
},
{
"path": "parrot/semantic/src/definitions/views/statistic.less",
"chars": 12164,
"preview": "/*!\n * # Semantic UI - Statistic\n * http://github.com/semantic-org/semantic-ui/\n *\n *\n * Released under the MIT license\n"
},
{
"path": "parrot/semantic/src/semantic.less",
"chars": 2650,
"preview": "/*\n\n███████╗███████╗███╗ ███╗ █████╗ ███╗ ██╗████████╗██╗ ██████╗ ██╗ ██╗██╗\n██╔════╝██╔════╝████╗ ████║██╔══██"
},
{
"path": "parrot/semantic/src/site/collections/breadcrumb.overrides",
"chars": 90,
"preview": "/*******************************\n Site Overrides\n*******************************/\n"
},
{
"path": "parrot/semantic/src/site/collections/breadcrumb.variables",
"chars": 90,
"preview": "/*******************************\n Site Overrides\n*******************************/\n"
},
{
"path": "parrot/semantic/src/site/collections/form.overrides",
"chars": 90,
"preview": "/*******************************\n Site Overrides\n*******************************/\n"
},
{
"path": "parrot/semantic/src/site/collections/form.variables",
"chars": 94,
"preview": "/*******************************\n User Variable Overrides\n*******************************/\n"
},
{
"path": "parrot/semantic/src/site/collections/grid.overrides",
"chars": 90,
"preview": "/*******************************\n Site Overrides\n*******************************/\n"
},
{
"path": "parrot/semantic/src/site/collections/grid.variables",
"chars": 94,
"preview": "/*******************************\n User Variable Overrides\n*******************************/\n"
},
{
"path": "parrot/semantic/src/site/collections/menu.overrides",
"chars": 89,
"preview": "/*******************************\n Site Overrides\n*******************************/"
},
{
"path": "parrot/semantic/src/site/collections/menu.variables",
"chars": 94,
"preview": "/*******************************\n User Variable Overrides\n*******************************/\n"
},
{
"path": "parrot/semantic/src/site/collections/message.overrides",
"chars": 89,
"preview": "/*******************************\n Site Overrides\n*******************************/\n"
},
{
"path": "parrot/semantic/src/site/collections/message.variables",
"chars": 94,
"preview": "/*******************************\n User Variable Overrides\n*******************************/\n"
},
{
"path": "parrot/semantic/src/site/collections/table.overrides",
"chars": 90,
"preview": "/*******************************\n Site Overrides\n*******************************/\n"
},
{
"path": "parrot/semantic/src/site/collections/table.variables",
"chars": 94,
"preview": "/*******************************\n User Variable Overrides\n*******************************/\n"
},
{
"path": "parrot/semantic/src/site/elements/button.overrides",
"chars": 90,
"preview": "/*******************************\n Site Overrides\n*******************************/\n"
},
{
"path": "parrot/semantic/src/site/elements/button.variables",
"chars": 94,
"preview": "/*******************************\n User Variable Overrides\n*******************************/\n"
},
{
"path": "parrot/semantic/src/site/elements/container.overrides",
"chars": 90,
"preview": "/*******************************\n Site Overrides\n*******************************/\n"
},
{
"path": "parrot/semantic/src/site/elements/container.variables",
"chars": 94,
"preview": "/*******************************\n User Variable Overrides\n*******************************/\n"
},
{
"path": "parrot/semantic/src/site/elements/divider.overrides",
"chars": 90,
"preview": "/*******************************\n Site Overrides\n*******************************/\n"
},
{
"path": "parrot/semantic/src/site/elements/divider.variables",
"chars": 94,
"preview": "/*******************************\n User Variable Overrides\n*******************************/\n"
},
{
"path": "parrot/semantic/src/site/elements/flag.overrides",
"chars": 90,
"preview": "/*******************************\n Site Overrides\n*******************************/\n"
},
{
"path": "parrot/semantic/src/site/elements/flag.variables",
"chars": 63,
"preview": "/*-------------------\n Flag Variables\n--------------------*/\n"
},
{
"path": "parrot/semantic/src/site/elements/header.overrides",
"chars": 90,
"preview": "/*******************************\n Site Overrides\n*******************************/\n"
},
{
"path": "parrot/semantic/src/site/elements/header.variables",
"chars": 94,
"preview": "/*******************************\n User Variable Overrides\n*******************************/\n"
},
{
"path": "parrot/semantic/src/site/elements/icon.overrides",
"chars": 90,
"preview": "/*******************************\n Site Overrides\n*******************************/\n"
},
{
"path": "parrot/semantic/src/site/elements/icon.variables",
"chars": 94,
"preview": "/*******************************\n User Variable Overrides\n*******************************/\n"
},
{
"path": "parrot/semantic/src/site/elements/image.overrides",
"chars": 90,
"preview": "/*******************************\n Site Overrides\n*******************************/\n"
},
{
"path": "parrot/semantic/src/site/elements/image.variables",
"chars": 94,
"preview": "/*******************************\n User Variable Overrides\n*******************************/\n"
},
{
"path": "parrot/semantic/src/site/elements/input.overrides",
"chars": 90,
"preview": "/*******************************\n Site Overrides\n*******************************/\n"
},
{
"path": "parrot/semantic/src/site/elements/input.variables",
"chars": 94,
"preview": "/*******************************\n User Variable Overrides\n*******************************/\n"
},
{
"path": "parrot/semantic/src/site/elements/label.overrides",
"chars": 90,
"preview": "/*******************************\n Site Overrides\n*******************************/\n"
},
{
"path": "parrot/semantic/src/site/elements/label.variables",
"chars": 94,
"preview": "/*******************************\n User Variable Overrides\n*******************************/\n"
},
{
"path": "parrot/semantic/src/site/elements/list.overrides",
"chars": 94,
"preview": "/*******************************\n User Variable Overrides\n*******************************/\n"
},
{
"path": "parrot/semantic/src/site/elements/list.variables",
"chars": 94,
"preview": "/*******************************\n User Variable Overrides\n*******************************/\n"
},
{
"path": "parrot/semantic/src/site/elements/loader.overrides",
"chars": 90,
"preview": "/*******************************\n Site Overrides\n*******************************/\n"
},
{
"path": "parrot/semantic/src/site/elements/loader.variables",
"chars": 94,
"preview": "/*******************************\n User Variable Overrides\n*******************************/\n"
},
{
"path": "parrot/semantic/src/site/elements/rail.overrides",
"chars": 90,
"preview": "/*******************************\n Site Overrides\n*******************************/\n"
},
{
"path": "parrot/semantic/src/site/elements/rail.variables",
"chars": 94,
"preview": "/*******************************\n User Variable Overrides\n*******************************/\n"
},
{
"path": "parrot/semantic/src/site/elements/reveal.overrides",
"chars": 90,
"preview": "/*******************************\n Site Overrides\n*******************************/\n"
},
{
"path": "parrot/semantic/src/site/elements/reveal.variables",
"chars": 94,
"preview": "/*******************************\n User Variable Overrides\n*******************************/\n"
},
{
"path": "parrot/semantic/src/site/elements/segment.overrides",
"chars": 90,
"preview": "/*******************************\n Site Overrides\n*******************************/\n"
},
{
"path": "parrot/semantic/src/site/elements/segment.variables",
"chars": 94,
"preview": "/*******************************\n User Variable Overrides\n*******************************/\n"
},
{
"path": "parrot/semantic/src/site/elements/step.overrides",
"chars": 90,
"preview": "/*******************************\n Site Overrides\n*******************************/\n"
},
{
"path": "parrot/semantic/src/site/elements/step.variables",
"chars": 94,
"preview": "/*******************************\n User Variable Overrides\n*******************************/\n"
},
{
"path": "parrot/semantic/src/site/globals/reset.overrides",
"chars": 90,
"preview": "/*******************************\n Site Overrides\n*******************************/\n"
},
{
"path": "parrot/semantic/src/site/globals/reset.variables",
"chars": 93,
"preview": "/*******************************\n User Global Variables\n*******************************/\n"
},
{
"path": "parrot/semantic/src/site/globals/site.overrides",
"chars": 90,
"preview": "/*******************************\n Site Overrides\n*******************************/\n"
},
{
"path": "parrot/semantic/src/site/globals/site.variables",
"chars": 92,
"preview": "/*******************************\n User Global Variables\n*******************************/"
},
{
"path": "parrot/semantic/src/site/modules/accordion.overrides",
"chars": 89,
"preview": "/*******************************\n User Overrides\n*******************************/\n"
}
]
// ... and 391 more files (download for full content)
About this extraction
This page contains the full source code of the Azure/phippyandfriends GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 591 files (5.0 MB), approximately 1.3M tokens, and a symbol index with 141 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.