├── .DS_Store ├── .env.example ├── .gitignore ├── README.md ├── vk-burst-demo ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── LICENSE.md ├── Makefile ├── README.md ├── aci-frontend │ ├── Dockerfile │ ├── README.md │ └── app │ │ ├── dbAzureBlob.py │ │ ├── requirements.txt │ │ ├── run.py │ │ ├── static │ │ ├── css │ │ │ ├── bootstrap-theme.css │ │ │ ├── bootstrap-theme.css.map │ │ │ ├── bootstrap-theme.min.css │ │ │ ├── bootstrap.css │ │ │ ├── bootstrap.css.map │ │ │ ├── bootstrap.min.css │ │ │ └── jumbotron-narrow.css │ │ ├── dashboard │ │ │ ├── assets │ │ │ │ ├── css │ │ │ │ │ ├── animate.min.css │ │ │ │ │ ├── bootstrap.min.css │ │ │ │ │ ├── demo.css │ │ │ │ │ ├── paper-dashboard.css │ │ │ │ │ └── themify-icons.css │ │ │ │ ├── fonts │ │ │ │ │ ├── themify.eot │ │ │ │ │ ├── themify.svg │ │ │ │ │ ├── themify.ttf │ │ │ │ │ └── themify.woff │ │ │ │ ├── img │ │ │ │ │ ├── Microsoft-Logo-PNG.png │ │ │ │ │ ├── apple-icon.png │ │ │ │ │ ├── background.jpg │ │ │ │ │ ├── faces │ │ │ │ │ │ ├── face-0.jpg │ │ │ │ │ │ ├── face-1.jpg │ │ │ │ │ │ ├── face-2.jpg │ │ │ │ │ │ └── face-3.jpg │ │ │ │ │ ├── favicon.png │ │ │ │ │ ├── new_logo.png │ │ │ │ │ └── tim_80x80.png │ │ │ │ ├── js │ │ │ │ │ ├── bootstrap-checkbox-radio.js │ │ │ │ │ ├── bootstrap-notify.js │ │ │ │ │ ├── bootstrap.min.js │ │ │ │ │ ├── chartist.min.js │ │ │ │ │ ├── demo.js │ │ │ │ │ ├── jquery-1.10.2.js │ │ │ │ │ └── paper-dashboard.js │ │ │ │ └── sass │ │ │ │ │ ├── paper-dashboard.scss │ │ │ │ │ └── paper │ │ │ │ │ ├── _alerts.scss │ │ │ │ │ ├── _buttons.scss │ │ │ │ │ ├── _cards.scss │ │ │ │ │ ├── _chartist.scss │ │ │ │ │ ├── _checkbox-radio.scss │ │ │ │ │ ├── _dropdown.scss │ │ │ │ │ ├── _footers.scss │ │ │ │ │ ├── _inputs.scss │ │ │ │ │ ├── _misc.scss │ │ │ │ │ ├── _mixins.scss │ │ │ │ │ ├── _navbars.scss │ │ │ │ │ ├── _responsive.scss │ │ │ │ │ ├── _sidebar-and-main-panel.scss │ │ │ │ │ ├── _tables.scss │ │ │ │ │ ├── _typography.scss │ │ │ │ │ ├── _variables.scss │ │ │ │ │ └── mixins │ │ │ │ │ ├── _buttons.scss │ │ │ │ │ ├── _cards.scss │ │ │ │ │ ├── _chartist.scss │ │ │ │ │ ├── _icons.scss │ │ │ │ │ ├── _inputs.scss │ │ │ │ │ ├── _labels.scss │ │ │ │ │ ├── _navbars.scss │ │ │ │ │ ├── _sidebar.scss │ │ │ │ │ ├── _tabs.scss │ │ │ │ │ ├── _transparency.scss │ │ │ │ │ └── _vendor-prefixes.scss │ │ │ ├── changelog.txt │ │ │ ├── documentation │ │ │ │ ├── css │ │ │ │ │ └── documentation.css │ │ │ │ └── documentation.html │ │ │ ├── icons.html │ │ │ ├── maps.html │ │ │ ├── notifications.html │ │ │ ├── table.html │ │ │ ├── template.html │ │ │ ├── typography.html │ │ │ ├── upgrade.html │ │ │ └── user.html │ │ ├── fonts │ │ │ ├── glyphicons-halflings-regular.eot │ │ │ ├── glyphicons-halflings-regular.svg │ │ │ ├── glyphicons-halflings-regular.ttf │ │ │ └── glyphicons-halflings-regular.woff │ │ └── js │ │ │ ├── bootstrap.js │ │ │ ├── bootstrap.min.js │ │ │ └── npm.js │ │ ├── templates │ │ ├── index.html │ │ └── test.html │ │ └── test.py ├── aci-webserver │ ├── Dockerfile │ ├── README.md │ ├── app │ │ ├── dbAzureBlob.py │ │ ├── requirements.txt │ │ ├── run.py │ │ ├── templates │ │ │ └── index.html │ │ └── test.py │ └── setupJobserver.ps1 ├── aci-worker │ ├── Dockerfile │ ├── README.md │ ├── app │ │ ├── dbAzureBlob.py │ │ ├── haarcascade_eye.xml │ │ ├── haarcascade_frontalface_default.xml │ │ ├── requirements.txt │ │ └── run.py │ ├── deployment.yaml │ └── metricsCompilation.yaml ├── assignFQDNtoIP.sh ├── buildPush.sh ├── charts │ ├── README.md │ └── fr-demo │ │ ├── Chart.yaml │ │ ├── templates │ │ ├── NOTES.txt │ │ ├── _helpers.tpl │ │ ├── backend-deployment.yaml │ │ ├── backend-ingress.yaml │ │ ├── backend-service.yaml │ │ ├── frontend-deployment.yaml │ │ ├── frontend-ingress.yaml │ │ ├── frontend-service.yaml │ │ ├── ir-aci-deployment.yaml │ │ └── ir-deployment.yaml │ │ └── values.yaml ├── create-aci-connector │ ├── example-aci-connector.yaml │ └── generateManifest.py ├── custom.yaml ├── customUI.yaml ├── customWeb.yaml ├── demo.sh ├── deploy.sh ├── docker-compose.yml └── util.sh ├── vk-computervision ├── Dockerfile ├── front-end.py ├── textanalysis.py └── tweet │ ├── Chart.yaml │ ├── templates │ ├── NOTES.txt │ ├── _helpers.tpl │ ├── deployment.yaml │ ├── ingress.yaml │ └── service.yaml │ └── values.yaml └── vk-tensorflow-demo ├── Fruits demo steps.txt ├── charts └── tensorstuff │ ├── Chart.yaml │ ├── templates │ ├── NOTES.txt │ ├── _helpers.tpl │ ├── aci-worker-deployment.yaml │ ├── deployment.yaml │ ├── ingress.yaml │ ├── service.yaml │ ├── worker-deployment.yaml │ └── worker-service.yaml │ └── values.yaml ├── kubernetes ├── web-deployment.yaml ├── web-ingress.yaml └── web-service.yaml ├── sfdeploy-app.json └── sfdeploy-base.json /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rbitia/aci-demos/b334d304196e99e0ded4406357ff28dd1a78936c/.DS_Store -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | export IP_JOB_SERVER = "" 2 | export AZURE_BLOB_ACCOUNT = "" 3 | export AZURE_BLOB_KEY = "" -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | **/__pycache__/ 3 | **/logs/ 4 | **/jobs.db 5 | .* 6 | aci-webserver/app/__pycache__/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # aci-demos 2 | Demos with ACI 3 | the coolest demos of the land 4 | made by a pm so use with caution ;) 5 | -------------------------------------------------------------------------------- /vk-burst-demo/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [project-title] Changelog 2 | 3 | 4 | # x.y.z (yyyy-mm-dd) 5 | 6 | *Features* 7 | * ... 8 | 9 | *Bug Fixes* 10 | * ... 11 | 12 | *Breaking Changes* 13 | * ... 14 | -------------------------------------------------------------------------------- /vk-burst-demo/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to [project-title] 2 | 3 | This project welcomes contributions and suggestions. Most contributions require you to agree to a 4 | Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us 5 | the rights to use your contribution. For details, visit https://cla.microsoft.com. 6 | 7 | When you submit a pull request, a CLA-bot will automatically determine whether you need to provide 8 | a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions 9 | provided by the bot. You will only need to do this once across all repos using our CLA. 10 | 11 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 12 | For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or 13 | contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. 14 | 15 | - [Code of Conduct](#coc) 16 | - [Issues and Bugs](#issue) 17 | - [Feature Requests](#feature) 18 | - [Submission Guidelines](#submit) 19 | 20 | ## Code of Conduct 21 | Help us keep this project open and inclusive. Please read and follow our [Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 22 | 23 | ## Found an Issue? 24 | If you find a bug in the source code or a mistake in the documentation, you can help us by 25 | [submitting an issue](#submit-issue) to the GitHub Repository. Even better, you can 26 | [submit a Pull Request](#submit-pr) with a fix. 27 | 28 | ## Want a Feature? 29 | You can *request* a new feature by [submitting an issue](#submit-issue) to the GitHub 30 | Repository. If you would like to *implement* a new feature, please submit an issue with 31 | a proposal for your work first, to be sure that we can use it. 32 | 33 | * **Small Features** can be crafted and directly [submitted as a Pull Request](#submit-pr). 34 | 35 | ## Submission Guidelines 36 | 37 | ### Submitting an Issue 38 | Before you submit an issue, search the archive, maybe your question was already answered. 39 | 40 | If your issue appears to be a bug, and hasn't been reported, open a new issue. 41 | Help us to maximize the effort we can spend fixing issues and adding new 42 | features, by not reporting duplicate issues. Providing the following information will increase the 43 | chances of your issue being dealt with quickly: 44 | 45 | * **Overview of the Issue** - if an error is being thrown a non-minified stack trace helps 46 | * **Version** - what version is affected (e.g. 0.1.2) 47 | * **Motivation for or Use Case** - explain what are you trying to do and why the current behavior is a bug for you 48 | * **Browsers and Operating System** - is this a problem with all browsers? 49 | * **Reproduce the Error** - provide a live example or a unambiguous set of steps 50 | * **Related Issues** - has a similar issue been reported before? 51 | * **Suggest a Fix** - if you can't fix the bug yourself, perhaps you can point to what might be 52 | causing the problem (line of code or commit) 53 | 54 | You can file new issues by providing the above information at the corresponding repository's issues link: https://github.com/[organization-name]/[repository-name]/issues/new]. 55 | 56 | ### Submitting a Pull Request (PR) 57 | Before you submit your Pull Request (PR) consider the following guidelines: 58 | 59 | * Search the repository (https://github.com/[organization-name]/[repository-name]/pulls) for an open or closed PR 60 | that relates to your submission. You don't want to duplicate effort. 61 | 62 | * Make your changes in a new git fork: 63 | 64 | * Commit your changes using a descriptive commit message 65 | * Push your fork to GitHub: 66 | * In GitHub, create a pull request 67 | * If we suggest changes then: 68 | * Make the required updates. 69 | * Rebase your fork and force push to your GitHub repository (this will update your Pull Request): 70 | 71 | ```shell 72 | git rebase master -i 73 | git push -f 74 | ``` 75 | 76 | That's it! Thank you for your contribution! 77 | -------------------------------------------------------------------------------- /vk-burst-demo/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. All rights reserved. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /vk-burst-demo/LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. All rights reserved. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE -------------------------------------------------------------------------------- /vk-burst-demo/Makefile: -------------------------------------------------------------------------------- 1 | build: 2 | -rm aci-webserver/app/jobs.db 3 | docker build -t rbitia/aci-webserver:latest aci-webserver/. 4 | docker build -t rbitia/fr-frontend:latest aci-frontend/. 5 | docker build -t rbitia/fr-ir:latest aci-worker/. 6 | 7 | docker push rbitia/aci-webserver:latest 8 | docker push rbitia/fr-frontend:latest 9 | docker push rbitia/fr-ir:latest 10 | 11 | helm del --purge demo 12 | helm install charts/fr-demo --name demo 13 | kubectl get po --watch -------------------------------------------------------------------------------- /vk-burst-demo/README.md: -------------------------------------------------------------------------------- 1 | # aci-demos 2 | 3 | ## Demos with ACI 4 | 5 | Description: Run a facial recognition demo across your AKS cluster and use ACI and the ACI Connector to burst into for on-demand compute. 6 | 7 | Contact ria.bhatia@microsoft.com if you need help! 8 | 9 | steps to deploy dis demo & talking tips 10 | 11 | ### Part 1 Prerequisites 12 | 13 | In order to run this demo, you will need the following: 14 | 15 | - An active [Microsoft Azure](https://azure.microsoft.com/en-us/free "Microsoft Azure") Subscription 16 | - [Azure CLI](https://docs.microsoft.com/en-us/cli/azure/overview?view=azure-cli-latest "Azure CLI") installed 17 | - [Kubernetes CLI (kubectl)](https://kubernetes.io/docs/tasks/tools/install-kubectl/ "Kubernetes CLI (kubectl)") installed 18 | - [Helm client](https://docs.helm.sh/using_helm/#installing-helm) installed 19 | 20 | ### Part 2 Setup 21 | Replace `` with your expected and run following command to create resource group. Then remember the created resource group name. 22 | 23 | ``` 24 | $ az group create --name --location eastus 25 | ``` 26 | 27 | > **Note:** The AKS extending to ACI only support in one location. So far AKS and ACI are both deployed to East US and West Europe. So please create your resource group in East US or West Europe only. 28 | 29 | Replace ``,`` with your expected and run following command to create the AKS. Then remember the AKS name. 30 | 31 | ``` 32 | $ az aks create --resource-group --name --node-count 1 --generate-ssh-keys 33 | ``` 34 | 35 | Replace ``, `` with your created in previous steps and run following command to set the AKS as your current connected cluster. 36 | 37 | ``` 38 | $ az aks get-credentials --resource-group --name 39 | ``` 40 | 41 | Make sure you're connected. 42 | 43 | ``` 44 | $ kubectl get nodes 45 | ``` 46 | 47 | Make sure you have helm installed and initialize this. 48 | ``` 49 | $ helm init 50 | ``` 51 | 52 | Replace `` with yours and run to install kube-lego w/ helm for certs. 53 | 54 | ``` 55 | $ helm install stable/kube-lego --name kube-lego --namespace kube-system --set config.LEGO_EMAIL=,config.LEGO_URL=https://acme-v01.api.letsencrypt.org/directory 56 | ``` 57 | 58 | Install ingress controller w/ helm. 59 | 60 | ``` 61 | $ helm install stable/nginx-ingress --name ingress --namespace kube-system 62 | ``` 63 | 64 | Get the Public IP of the ingress controller. It may take some times for the IP assigned to the services 65 | 66 | ``` 67 | $ kubectl get services --namespace kube-system --watch 68 | ``` 69 | 70 | When the IP assigned, remember the IP address and press Ctrl+Q to exit 71 | 72 | Clone this repo 73 | ``` 74 | $ git clone https://github.com/rbitia/aci-demos.git 75 | ``` 76 | 77 | Change the folder to the root of the source code 78 | ``` 79 | $ cd aci-demo 80 | ``` 81 | 82 | Replace ``, `` with your created in previous steps. Replace `` with your expected and run following shell script to bind FQDN to your IP. Remember the return FQDN name. You will use it to update your configuration file. 83 | 84 | ``` 85 | $ chmod u+x assignFQDNtoIP.sh 86 | $ ./assignFQDNtoIP.sh -g -d -i 87 | ``` 88 | 89 | Edit the values.yaml file and replace all `` with the FQDN name in pervious step. 90 | ``` 91 | $ vim ./charts/fr-demo/values.yaml 92 | ``` 93 | 94 | Start at the top of the aci-demos directory and deploy the Facial Recognition application that consists of a frontend, a backend, and a set of image recognizers. 95 | 96 | ``` 97 | $ helm install charts/fr-demo --name demo 98 | ``` 99 | 100 | Checkout the UI that's generated in the output and see the pictures start to get processed 101 | The rate will be super slow because we have a 1 node AKS cluster running 1 worker pod. 102 | 103 | Deploy the ACI connector : 104 | Replace ``, `` with yours in previous steps and run following command 105 | 106 | ``` 107 | az aks install-connector --resource-group --name --connector-name myaciconnector 108 | ``` 109 | 110 | The connector has been deployed and with a `kubectl get nodes` you can see that the ACI Connector is a new node in your cluster. Now scale up the image recognizer to 10 using the following command 111 | 112 | ``` 113 | $ kubectl scale deploy demo-fr-ir-aci --replicas 10 114 | ``` 115 | Though we are using `kubectl`, the ACI Connector is dispatching pods to Azure Container Instances transparently, via the ACI connector node. 116 | This virtual node has unlimited capacity and a per-second billing model, making it perfect for burst compute scenarios like this one. 117 | If we wait a minute or so for the ACI containers to warm up, we should see image recognizer throughput increase dramatically. 118 | 119 | Check out the dashboard to see throughput it dramatically increase... 120 | 121 | Here we can see throughput really beginning to pick up, thanks to burst capacity provided by ACI. 122 | 123 | This is powerful stuff. Here we can see AKS and ACI combine to provide the best of “serverless” computing – invisible infrastructure and micro-billing – all managed through the open Kubernetes APIs. This kind of innovation – the marriage of containers and serverless computing -- is important for the industry, and Microsoft is working hard to make it a reality. 124 | 125 | 126 | Once you've done all the set up you just need these commands during the live demo: 127 | ``` 128 | $ helm install charts/fr-demo --name demo 129 | $ az aks install-connector --resource-group --name --connector-name myaciconnector 130 | $ kubectl scale deploy demo-fr-ir-aci --replicas 10 131 | ``` 132 | 133 | 134 | ### Part 3 Clean up: 135 | 136 | Replace ``, `` with your created in previous steps. Then run following command to clean up resources 137 | 138 | ``` 139 | $ helm del --purge demo 140 | $ az aks remove-connector --resource-group --name --connector-name myaciconnector 141 | $ az group delete --resource-group --no-wait -y 142 | ``` 143 | -------------------------------------------------------------------------------- /vk-burst-demo/aci-frontend/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:14.04 2 | MAINTAINER Samuel Kreter 3 | 4 | ENV DEBIAN_FRONTEND noninteractive 5 | 6 | RUN apt-get update && apt-get install -y \ 7 | python3-pip python3-dev \ 8 | sqlite3 libsqlite3-dev \ 9 | build-essential libssl-dev libffi-dev 10 | 11 | COPY ./app/requirements.txt . 12 | RUN pip3 install -r ./requirements.txt 13 | 14 | COPY app/ /app 15 | WORKDIR /app 16 | CMD ["python3", "run.py"] 17 | -------------------------------------------------------------------------------- /vk-burst-demo/aci-frontend/README.md: -------------------------------------------------------------------------------- 1 | ## Creating the docker image 2 | 1. Inside the directory run docker build 3 | 4 | `docker build -t .` 5 | 6 | 2. You should now be able to see the docker images using: `docker images` 7 | 8 | ## Running the image 9 | 10 | On Docker host run: `docker run -d -p 80:80 ` 11 | 12 | On Docker machine run: `docker run -d -p 80:80 ` 13 | 14 | Docker compose: `docker-compose up -d` 15 | 16 | 17 | ### Credits 18 | Base image 19 | Source code: https://github.com/p0bailey/docker-flask 20 | DockerHub: https://hub.docker.com/r/p0bailey/docker-flask/ 21 | 22 | 23 | -------------------------------------------------------------------------------- /vk-burst-demo/aci-frontend/app/dbAzureBlob.py: -------------------------------------------------------------------------------- 1 | #By Sam Kreter 2 | #For use by Microsoft and other parties to demo 3 | #Azure Container Service, Azure Container Instances 4 | #and the experimental ACI-connector 5 | import os 6 | from azure.storage.blob import BlockBlobService 7 | import sqlite3 8 | 9 | COPY_PICS_NUM = 1 10 | 11 | class DbAzureBlob: 12 | 13 | def __init__(self): 14 | AZURE_BLOB_ACCOUNT = os.environ.get('AZURE_BLOB_ACCOUNT') 15 | 16 | if not AZURE_BLOB_ACCOUNT: 17 | raise EnvironmentError("Must have env variables AZURE_BLOB_ACCOUNT set for this to work.") 18 | 19 | self.block_blob_service = BlockBlobService(account_name= AZURE_BLOB_ACCOUNT) 20 | 21 | 22 | def getImageFromAzureBlob(self,filename_src, filename_dest): 23 | try: 24 | self.block_blob_service.get_blob_to_path('pictures', filename_src, filename_dest) 25 | return True 26 | except Exception as ex: 27 | print("getImageFromAzureBlob: ") 28 | return False 29 | 30 | 31 | def getAllImagesFromAzureBlob(self,container,dest_folder): 32 | generator = self.block_blob_service.list_blobs('pictures') 33 | 34 | success = [] 35 | 36 | for blob in generator: 37 | try: 38 | self.block_blob_service.get_blob_to_path(container, blob.name, dest_folder + blob.name) 39 | success.append(True) 40 | except Exception as ex: 41 | print("getAllImagesFromAzureBlob: ", ex) 42 | success.append(False) 43 | 44 | return all(success) 45 | 46 | def doubleDatabase(self): 47 | conn = sqlite3.connect('jobs.db') 48 | cursor = conn.execute("SELECT * FROM jobs;") 49 | for row in cursor: 50 | conn.execute("INSERT INTO jobs (filename) \ 51 | VALUES (\"" + row[1] + "\");") 52 | conn.commit() 53 | 54 | def setupDatabase(self): 55 | conn = sqlite3.connect('jobs.db') 56 | 57 | conn.execute('''DROP TABLE IF EXISTS jobs;''') 58 | conn.execute(''' 59 | CREATE TABLE jobs ( 60 | id INTEGER PRIMARY KEY AUTOINCREMENT, 61 | filename NOT NULL, 62 | processed INTEGER DEFAULT 0 NOT NULL, 63 | detected INTEGER DEFAULT NULL 64 | ); 65 | ''') 66 | 67 | conn.execute('DROP TABLE IF EXISTS time;') 68 | conn.execute(''' 69 | CREATE TABLE time ( 70 | id INTEGER PRIMARY KEY, 71 | start_time TEXT, 72 | finish_time TEXT, 73 | finished INTEGER, 74 | started INTEGER 75 | ); 76 | ''') 77 | 78 | conn.execute('INSERT INTO time values(1,"2017-09-23 18:28:24","2017-09-23 18:28:24",0,0);') 79 | 80 | generator = self.block_blob_service.list_blobs('pictures') 81 | for blob in generator: 82 | if(blob.name[:2] == "._"): 83 | blob.name = blob.name[2:] 84 | for i in range(COPY_PICS_NUM): 85 | conn.execute("INSERT INTO jobs (filename) \ 86 | VALUES (\"" + blob.name + "\");") 87 | 88 | conn.commit() 89 | -------------------------------------------------------------------------------- /vk-burst-demo/aci-frontend/app/requirements.txt: -------------------------------------------------------------------------------- 1 | flask 2 | cryptography==2.0.3 3 | azure-storage-blob 4 | -------------------------------------------------------------------------------- /vk-burst-demo/aci-frontend/app/run.py: -------------------------------------------------------------------------------- 1 | #!flask/bin/python 2 | 3 | #By Sam Kreter 4 | #For use by Microsoft and other parties to demo 5 | #Azure Container Service, Azure Container Instances 6 | #and the experimental ACI-connector 7 | from flask import render_template 8 | from flask import Flask 9 | from dbAzureBlob import DbAzureBlob 10 | import requests 11 | import json 12 | 13 | 14 | import os 15 | 16 | app = Flask(__name__) 17 | 18 | 19 | @app.route('/') 20 | def index(): 21 | return render_template('index.html') 22 | 23 | @app.route('/getProgress') 24 | def getProgress(): 25 | res = getRequest(getJobServiceUrl() + "/getProgress") 26 | 27 | if res == False: 28 | print("No Response from Jobserver") 29 | return json.dumps({"error":True}) 30 | 31 | return json.dumps(res) 32 | 33 | @app.route('/resetDb') 34 | def resetDb(): 35 | res = getRequest(getJobServiceUrl() + "/resetDb") 36 | 37 | if res == False: 38 | return json.dumps({"error":True}) 39 | 40 | return json.dumps(res) 41 | 42 | @app.route('/test') 43 | def test(): 44 | res = getRequest("http://api.openweathermap.org/data/2.5/weather?q=London") 45 | if res == False: 46 | print("failed") 47 | 48 | print(res['message']) 49 | 50 | return json.dumps(res) 51 | 52 | def getJobServiceUrl(): 53 | return "http://" + os.getenv('IP_JOB_SERVER', "localhost") + "/api" 54 | 55 | def getRequest(url): 56 | try: 57 | res = requests.get(url) 58 | return json.loads(res.text) 59 | except: 60 | return False 61 | 62 | 63 | 64 | if __name__ == '__main__': 65 | app.run(debug=True, host='0.0.0.0',port=8080) 66 | -------------------------------------------------------------------------------- /vk-burst-demo/aci-frontend/app/static/css/jumbotron-narrow.css: -------------------------------------------------------------------------------- 1 | /* Space out content a bit */ 2 | body { 3 | padding-top: 20px; 4 | padding-bottom: 20px; 5 | } 6 | 7 | /* Everything but the jumbotron gets side spacing for mobile first views */ 8 | .header, 9 | .marketing, 10 | .footer { 11 | padding-right: 15px; 12 | padding-left: 15px; 13 | } 14 | 15 | /* Custom page header */ 16 | .header { 17 | border-bottom: 1px solid #e5e5e5; 18 | } 19 | /* Make the masthead heading the same height as the navigation */ 20 | .header h3 { 21 | padding-bottom: 19px; 22 | margin-top: 0; 23 | margin-bottom: 0; 24 | line-height: 40px; 25 | } 26 | 27 | /* Custom page footer */ 28 | .footer { 29 | padding-top: 19px; 30 | color: #777; 31 | border-top: 1px solid #e5e5e5; 32 | } 33 | 34 | /* Customize container */ 35 | @media (min-width: 768px) { 36 | .container { 37 | max-width: 730px; 38 | } 39 | } 40 | .container-narrow > hr { 41 | margin: 30px 0; 42 | } 43 | 44 | /* Main marketing message and sign up button */ 45 | .jumbotron { 46 | text-align: center; 47 | border-bottom: 1px solid #e5e5e5; 48 | } 49 | .jumbotron .btn { 50 | padding: 14px 24px; 51 | font-size: 21px; 52 | } 53 | 54 | /* Supporting marketing content */ 55 | .marketing { 56 | margin: 40px 0; 57 | } 58 | .marketing p + h4 { 59 | margin-top: 28px; 60 | } 61 | 62 | /* Responsive: Portrait tablets and up */ 63 | @media screen and (min-width: 768px) { 64 | /* Remove the padding we set earlier */ 65 | .header, 66 | .marketing, 67 | .footer { 68 | padding-right: 0; 69 | padding-left: 0; 70 | } 71 | /* Space out the masthead */ 72 | .header { 73 | margin-bottom: 30px; 74 | } 75 | /* Remove the bottom border on the jumbotron for visual effect */ 76 | .jumbotron { 77 | border-bottom: 0; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /vk-burst-demo/aci-frontend/app/static/dashboard/assets/css/demo.css: -------------------------------------------------------------------------------- 1 | @media (min-width: 992px){ 2 | .typo-line{ 3 | padding-left: 140px; 4 | margin-bottom: 40px; 5 | position: relative; 6 | } 7 | 8 | .typo-line .category{ 9 | transform: translateY(-50%); 10 | top: 50%; 11 | left: 0px; 12 | position: absolute; 13 | } 14 | } 15 | 16 | .icon-section { 17 | margin: 0 0 3em; 18 | clear: both; 19 | overflow: hidden; 20 | } 21 | .icon-container { 22 | width: 240px; 23 | padding: .7em 0; 24 | float: left; 25 | position: relative; 26 | text-align: left; 27 | } 28 | .icon-container [class^="ti-"], 29 | .icon-container [class*=" ti-"] { 30 | color: #000; 31 | position: absolute; 32 | margin-top: 3px; 33 | transition: .3s; 34 | } 35 | .icon-container:hover [class^="ti-"], 36 | .icon-container:hover [class*=" ti-"] { 37 | font-size: 2.2em; 38 | margin-top: -5px; 39 | } 40 | .icon-container:hover .icon-name { 41 | color: #000; 42 | } 43 | .icon-name { 44 | color: #aaa; 45 | margin-left: 35px; 46 | font-size: .8em; 47 | transition: .3s; 48 | } 49 | .icon-container:hover .icon-name { 50 | margin-left: 45px; 51 | } 52 | 53 | .places-buttons .btn{ 54 | margin-bottom: 30px 55 | } 56 | .sidebar .nav > li.active-pro{ 57 | position: absolute; 58 | width: 100%; 59 | bottom: 10px; 60 | } 61 | .sidebar .nav > li.active-pro a{ 62 | background: rgba(255, 255, 255, 0.14); 63 | opacity: 1; 64 | color: #FFFFFF; 65 | } 66 | 67 | .table-upgrade td:nth-child(2), 68 | .table-upgrade td:nth-child(3){ 69 | text-align: center; 70 | } 71 | -------------------------------------------------------------------------------- /vk-burst-demo/aci-frontend/app/static/dashboard/assets/fonts/themify.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rbitia/aci-demos/b334d304196e99e0ded4406357ff28dd1a78936c/vk-burst-demo/aci-frontend/app/static/dashboard/assets/fonts/themify.eot -------------------------------------------------------------------------------- /vk-burst-demo/aci-frontend/app/static/dashboard/assets/fonts/themify.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rbitia/aci-demos/b334d304196e99e0ded4406357ff28dd1a78936c/vk-burst-demo/aci-frontend/app/static/dashboard/assets/fonts/themify.ttf -------------------------------------------------------------------------------- /vk-burst-demo/aci-frontend/app/static/dashboard/assets/fonts/themify.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rbitia/aci-demos/b334d304196e99e0ded4406357ff28dd1a78936c/vk-burst-demo/aci-frontend/app/static/dashboard/assets/fonts/themify.woff -------------------------------------------------------------------------------- /vk-burst-demo/aci-frontend/app/static/dashboard/assets/img/Microsoft-Logo-PNG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rbitia/aci-demos/b334d304196e99e0ded4406357ff28dd1a78936c/vk-burst-demo/aci-frontend/app/static/dashboard/assets/img/Microsoft-Logo-PNG.png -------------------------------------------------------------------------------- /vk-burst-demo/aci-frontend/app/static/dashboard/assets/img/apple-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rbitia/aci-demos/b334d304196e99e0ded4406357ff28dd1a78936c/vk-burst-demo/aci-frontend/app/static/dashboard/assets/img/apple-icon.png -------------------------------------------------------------------------------- /vk-burst-demo/aci-frontend/app/static/dashboard/assets/img/background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rbitia/aci-demos/b334d304196e99e0ded4406357ff28dd1a78936c/vk-burst-demo/aci-frontend/app/static/dashboard/assets/img/background.jpg -------------------------------------------------------------------------------- /vk-burst-demo/aci-frontend/app/static/dashboard/assets/img/faces/face-0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rbitia/aci-demos/b334d304196e99e0ded4406357ff28dd1a78936c/vk-burst-demo/aci-frontend/app/static/dashboard/assets/img/faces/face-0.jpg -------------------------------------------------------------------------------- /vk-burst-demo/aci-frontend/app/static/dashboard/assets/img/faces/face-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rbitia/aci-demos/b334d304196e99e0ded4406357ff28dd1a78936c/vk-burst-demo/aci-frontend/app/static/dashboard/assets/img/faces/face-1.jpg -------------------------------------------------------------------------------- /vk-burst-demo/aci-frontend/app/static/dashboard/assets/img/faces/face-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rbitia/aci-demos/b334d304196e99e0ded4406357ff28dd1a78936c/vk-burst-demo/aci-frontend/app/static/dashboard/assets/img/faces/face-2.jpg -------------------------------------------------------------------------------- /vk-burst-demo/aci-frontend/app/static/dashboard/assets/img/faces/face-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rbitia/aci-demos/b334d304196e99e0ded4406357ff28dd1a78936c/vk-burst-demo/aci-frontend/app/static/dashboard/assets/img/faces/face-3.jpg -------------------------------------------------------------------------------- /vk-burst-demo/aci-frontend/app/static/dashboard/assets/img/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rbitia/aci-demos/b334d304196e99e0ded4406357ff28dd1a78936c/vk-burst-demo/aci-frontend/app/static/dashboard/assets/img/favicon.png -------------------------------------------------------------------------------- /vk-burst-demo/aci-frontend/app/static/dashboard/assets/img/new_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rbitia/aci-demos/b334d304196e99e0ded4406357ff28dd1a78936c/vk-burst-demo/aci-frontend/app/static/dashboard/assets/img/new_logo.png -------------------------------------------------------------------------------- /vk-burst-demo/aci-frontend/app/static/dashboard/assets/img/tim_80x80.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rbitia/aci-demos/b334d304196e99e0ded4406357ff28dd1a78936c/vk-burst-demo/aci-frontend/app/static/dashboard/assets/img/tim_80x80.png -------------------------------------------------------------------------------- /vk-burst-demo/aci-frontend/app/static/dashboard/assets/js/bootstrap-checkbox-radio.js: -------------------------------------------------------------------------------- 1 | !function ($) { 2 | 3 | /* CHECKBOX PUBLIC CLASS DEFINITION 4 | * ============================== */ 5 | 6 | var Checkbox = function (element, options) { 7 | this.init(element, options); 8 | } 9 | 10 | Checkbox.prototype = { 11 | 12 | constructor: Checkbox 13 | 14 | , init: function (element, options) { 15 | var $el = this.$element = $(element) 16 | 17 | this.options = $.extend({}, $.fn.checkbox.defaults, options); 18 | $el.before(this.options.template); 19 | this.setState(); 20 | } 21 | 22 | , setState: function () { 23 | var $el = this.$element 24 | , $parent = $el.closest('.checkbox'); 25 | 26 | $el.prop('disabled') && $parent.addClass('disabled'); 27 | $el.prop('checked') && $parent.addClass('checked'); 28 | } 29 | 30 | , toggle: function () { 31 | var ch = 'checked' 32 | , $el = this.$element 33 | , $parent = $el.closest('.checkbox') 34 | , checked = $el.prop(ch) 35 | , e = $.Event('toggle') 36 | 37 | if ($el.prop('disabled') == false) { 38 | $parent.toggleClass(ch) && checked ? $el.removeAttr(ch) : $el.prop(ch, ch); 39 | $el.trigger(e).trigger('change'); 40 | } 41 | } 42 | 43 | , setCheck: function (option) { 44 | var d = 'disabled' 45 | , ch = 'checked' 46 | , $el = this.$element 47 | , $parent = $el.closest('.checkbox') 48 | , checkAction = option == 'check' ? true : false 49 | , e = $.Event(option) 50 | 51 | $parent[checkAction ? 'addClass' : 'removeClass' ](ch) && checkAction ? $el.prop(ch, ch) : $el.removeAttr(ch); 52 | $el.trigger(e).trigger('change'); 53 | } 54 | 55 | } 56 | 57 | 58 | /* CHECKBOX PLUGIN DEFINITION 59 | * ======================== */ 60 | 61 | var old = $.fn.checkbox 62 | 63 | $.fn.checkbox = function (option) { 64 | return this.each(function () { 65 | var $this = $(this) 66 | , data = $this.data('checkbox') 67 | , options = $.extend({}, $.fn.checkbox.defaults, $this.data(), typeof option == 'object' && option); 68 | if (!data) $this.data('checkbox', (data = new Checkbox(this, options))); 69 | if (option == 'toggle') data.toggle() 70 | if (option == 'check' || option == 'uncheck') data.setCheck(option) 71 | else if (option) data.setState(); 72 | }); 73 | } 74 | 75 | $.fn.checkbox.defaults = { 76 | template: '' 77 | } 78 | 79 | 80 | /* CHECKBOX NO CONFLICT 81 | * ================== */ 82 | 83 | $.fn.checkbox.noConflict = function () { 84 | $.fn.checkbox = old; 85 | return this; 86 | } 87 | 88 | 89 | /* CHECKBOX DATA-API 90 | * =============== */ 91 | 92 | $(document).on('click.checkbox.data-api', '[data-toggle^=checkbox], .checkbox', function (e) { 93 | var $checkbox = $(e.target); 94 | if (e.target.tagName != "A") { 95 | e && e.preventDefault() && e.stopPropagation(); 96 | if (!$checkbox.hasClass('checkbox')) $checkbox = $checkbox.closest('.checkbox'); 97 | $checkbox.find(':checkbox').checkbox('toggle'); 98 | } 99 | }); 100 | 101 | $(function () { 102 | $('input[type="checkbox"]').each(function () { 103 | var $checkbox = $(this); 104 | $checkbox.checkbox(); 105 | }); 106 | }); 107 | 108 | }(window.jQuery); 109 | 110 | /* ============================================================= 111 | * flatui-radio v0.0.3 112 | * ============================================================ */ 113 | 114 | !function ($) { 115 | 116 | /* RADIO PUBLIC CLASS DEFINITION 117 | * ============================== */ 118 | 119 | var Radio = function (element, options) { 120 | this.init(element, options); 121 | } 122 | 123 | Radio.prototype = { 124 | 125 | constructor: Radio 126 | 127 | , init: function (element, options) { 128 | var $el = this.$element = $(element) 129 | 130 | this.options = $.extend({}, $.fn.radio.defaults, options); 131 | $el.before(this.options.template); 132 | this.setState(); 133 | } 134 | 135 | , setState: function () { 136 | var $el = this.$element 137 | , $parent = $el.closest('.radio'); 138 | 139 | $el.prop('disabled') && $parent.addClass('disabled'); 140 | $el.prop('checked') && $parent.addClass('checked'); 141 | } 142 | 143 | , toggle: function () { 144 | var d = 'disabled' 145 | , ch = 'checked' 146 | , $el = this.$element 147 | , checked = $el.prop(ch) 148 | , $parent = $el.closest('.radio') 149 | , $parentWrap = $el.closest('form').length ? $el.closest('form') : $el.closest('body') 150 | , $elemGroup = $parentWrap.find(':radio[name="' + $el.attr('name') + '"]') 151 | , e = $.Event('toggle') 152 | 153 | if ($el.prop(d) == false) { 154 | $elemGroup.not($el).each(function () { 155 | var $el = $(this) 156 | , $parent = $(this).closest('.radio'); 157 | 158 | if ($el.prop(d) == false) { 159 | $parent.removeClass(ch) && $el.removeAttr(ch).trigger('change'); 160 | } 161 | }); 162 | 163 | if (checked == false) $parent.addClass(ch) && $el.prop(ch, true); 164 | $el.trigger(e); 165 | 166 | if (checked !== $el.prop(ch)) { 167 | $el.trigger('change'); 168 | } 169 | } 170 | } 171 | 172 | , setCheck: function (option) { 173 | var ch = 'checked' 174 | , $el = this.$element 175 | , $parent = $el.closest('.radio') 176 | , checkAction = option == 'check' ? true : false 177 | , checked = $el.prop(ch) 178 | , $parentWrap = $el.closest('form').length ? $el.closest('form') : $el.closest('body') 179 | , $elemGroup = $parentWrap.find(':radio[name="' + $el['attr']('name') + '"]') 180 | , e = $.Event(option) 181 | 182 | $elemGroup.not($el).each(function () { 183 | var $el = $(this) 184 | , $parent = $(this).closest('.radio'); 185 | 186 | $parent.removeClass(ch) && $el.removeAttr(ch); 187 | }); 188 | 189 | $parent[checkAction ? 'addClass' : 'removeClass'](ch) && checkAction ? $el.prop(ch, ch) : $el.removeAttr(ch); 190 | $el.trigger(e); 191 | 192 | if (checked !== $el.prop(ch)) { 193 | $el.trigger('change'); 194 | } 195 | } 196 | 197 | } 198 | 199 | 200 | /* RADIO PLUGIN DEFINITION 201 | * ======================== */ 202 | 203 | var old = $.fn.radio 204 | 205 | $.fn.radio = function (option) { 206 | return this.each(function () { 207 | var $this = $(this) 208 | , data = $this.data('radio') 209 | , options = $.extend({}, $.fn.radio.defaults, $this.data(), typeof option == 'object' && option); 210 | if (!data) $this.data('radio', (data = new Radio(this, options))); 211 | if (option == 'toggle') data.toggle() 212 | if (option == 'check' || option == 'uncheck') data.setCheck(option) 213 | else if (option) data.setState(); 214 | }); 215 | } 216 | 217 | $.fn.radio.defaults = { 218 | template: '' 219 | } 220 | 221 | 222 | /* RADIO NO CONFLICT 223 | * ================== */ 224 | 225 | $.fn.radio.noConflict = function () { 226 | $.fn.radio = old; 227 | return this; 228 | } 229 | 230 | 231 | /* RADIO DATA-API 232 | * =============== */ 233 | 234 | $(document).on('click.radio.data-api', '[data-toggle^=radio], .radio', function (e) { 235 | var $radio = $(e.target); 236 | e && e.preventDefault() && e.stopPropagation(); 237 | if (!$radio.hasClass('radio')) $radio = $radio.closest('.radio'); 238 | $radio.find(':radio').radio('toggle'); 239 | }); 240 | 241 | $(function () { 242 | $('input[type="radio"]').each(function () { 243 | var $radio = $(this); 244 | $radio.radio(); 245 | }); 246 | }); 247 | 248 | }(window.jQuery); 249 | -------------------------------------------------------------------------------- /vk-burst-demo/aci-frontend/app/static/dashboard/assets/js/paper-dashboard.js: -------------------------------------------------------------------------------- 1 | /*! 2 | 3 | ========================================================= 4 | * Paper Dashboard - v1.1.2 5 | ========================================================= 6 | 7 | * Product Page: http://www.creative-tim.com/product/paper-dashboard 8 | * Copyright 2017 Creative Tim (http://www.creative-tim.com) 9 | * Licensed under MIT (https://github.com/creativetimofficial/paper-dashboard/blob/master/LICENSE.md) 10 | 11 | ========================================================= 12 | 13 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 14 | 15 | */ 16 | 17 | 18 | var fixedTop = false; 19 | var transparent = true; 20 | var navbar_initialized = false; 21 | 22 | $(document).ready(function(){ 23 | window_width = $(window).width(); 24 | 25 | // Init navigation toggle for small screens 26 | if(window_width <= 991){ 27 | pd.initRightMenu(); 28 | } 29 | 30 | // Activate the tooltips 31 | $('[rel="tooltip"]').tooltip(); 32 | 33 | }); 34 | 35 | // activate collapse right menu when the windows is resized 36 | $(window).resize(function(){ 37 | if($(window).width() <= 991){ 38 | pd.initRightMenu(); 39 | } 40 | }); 41 | 42 | pd = { 43 | misc:{ 44 | navbar_menu_visible: 0 45 | }, 46 | checkScrollForTransparentNavbar: debounce(function() { 47 | if($(document).scrollTop() > 381 ) { 48 | if(transparent) { 49 | transparent = false; 50 | $('.navbar-color-on-scroll').removeClass('navbar-transparent'); 51 | $('.navbar-title').removeClass('hidden'); 52 | } 53 | } else { 54 | if( !transparent ) { 55 | transparent = true; 56 | $('.navbar-color-on-scroll').addClass('navbar-transparent'); 57 | $('.navbar-title').addClass('hidden'); 58 | } 59 | } 60 | }), 61 | initRightMenu: function(){ 62 | if(!navbar_initialized){ 63 | $off_canvas_sidebar = $('nav').find('.navbar-collapse').first().clone(true); 64 | 65 | $sidebar = $('.sidebar'); 66 | sidebar_bg_color = $sidebar.data('background-color'); 67 | sidebar_active_color = $sidebar.data('active-color'); 68 | 69 | $logo = $sidebar.find('.logo').first(); 70 | logo_content = $logo[0].outerHTML; 71 | 72 | ul_content = ''; 73 | 74 | // set the bg color and active color from the default sidebar to the off canvas sidebar; 75 | $off_canvas_sidebar.attr('data-background-color',sidebar_bg_color); 76 | $off_canvas_sidebar.attr('data-active-color',sidebar_active_color); 77 | 78 | $off_canvas_sidebar.addClass('off-canvas-sidebar'); 79 | 80 | //add the content from the regular header to the right menu 81 | $off_canvas_sidebar.children('ul').each(function(){ 82 | content_buff = $(this).html(); 83 | ul_content = ul_content + content_buff; 84 | }); 85 | 86 | // add the content from the sidebar to the right menu 87 | content_buff = $sidebar.find('.nav').html(); 88 | ul_content = ul_content + ''+ content_buff; 89 | 90 | ul_content = '' + ul_content + ''; 91 | 92 | navbar_content = logo_content + ul_content; 93 | navbar_content = '' + navbar_content + ''; 94 | 95 | $off_canvas_sidebar.html(navbar_content); 96 | 97 | $('body').append($off_canvas_sidebar); 98 | 99 | $toggle = $('.navbar-toggle'); 100 | 101 | $off_canvas_sidebar.find('a').removeClass('btn btn-round btn-default'); 102 | $off_canvas_sidebar.find('button').removeClass('btn-round btn-fill btn-info btn-primary btn-success btn-danger btn-warning btn-neutral'); 103 | $off_canvas_sidebar.find('button').addClass('btn-simple btn-block'); 104 | 105 | $toggle.click(function (){ 106 | if(pd.misc.navbar_menu_visible == 1) { 107 | $('html').removeClass('nav-open'); 108 | pd.misc.navbar_menu_visible = 0; 109 | $('#bodyClick').remove(); 110 | setTimeout(function(){ 111 | $toggle.removeClass('toggled'); 112 | }, 400); 113 | 114 | } else { 115 | setTimeout(function(){ 116 | $toggle.addClass('toggled'); 117 | }, 430); 118 | 119 | div = ''; 120 | $(div).appendTo("body").click(function() { 121 | $('html').removeClass('nav-open'); 122 | pd.misc.navbar_menu_visible = 0; 123 | $('#bodyClick').remove(); 124 | setTimeout(function(){ 125 | $toggle.removeClass('toggled'); 126 | }, 400); 127 | }); 128 | 129 | $('html').addClass('nav-open'); 130 | pd.misc.navbar_menu_visible = 1; 131 | 132 | } 133 | }); 134 | navbar_initialized = true; 135 | } 136 | 137 | } 138 | } 139 | 140 | 141 | // Returns a function, that, as long as it continues to be invoked, will not 142 | // be triggered. The function will be called after it stops being called for 143 | // N milliseconds. If `immediate` is passed, trigger the function on the 144 | // leading edge, instead of the trailing. 145 | 146 | function debounce(func, wait, immediate) { 147 | var timeout; 148 | return function() { 149 | var context = this, args = arguments; 150 | clearTimeout(timeout); 151 | timeout = setTimeout(function() { 152 | timeout = null; 153 | if (!immediate) func.apply(context, args); 154 | }, wait); 155 | if (immediate && !timeout) func.apply(context, args); 156 | }; 157 | }; 158 | -------------------------------------------------------------------------------- /vk-burst-demo/aci-frontend/app/static/dashboard/assets/sass/paper-dashboard.scss: -------------------------------------------------------------------------------- 1 | /*! 2 | 3 | ========================================================= 4 | * Paper Dashboard - v1.1.2 5 | ========================================================= 6 | 7 | * Product Page: http://www.creative-tim.com/product/paper-dashboard 8 | * Copyright 2017 Creative Tim (http://www.creative-tim.com) 9 | * Licensed under MIT (https://github.com/creativetimofficial/paper-dashboard/blob/master/LICENSE.md) 10 | 11 | ========================================================= 12 | 13 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 14 | 15 | */ 16 | 17 | 18 | @import "paper/variables"; 19 | @import "paper/mixins"; 20 | 21 | @import "paper/typography"; 22 | 23 | // Core CSS 24 | @import "paper/misc"; 25 | @import "paper/sidebar-and-main-panel"; 26 | @import "paper/buttons"; 27 | @import "paper/inputs"; 28 | 29 | @import "paper/alerts"; 30 | @import "paper/tables"; 31 | 32 | @import "paper/checkbox-radio"; 33 | @import "paper/navbars"; 34 | @import "paper/footers"; 35 | 36 | // Fancy Stuff 37 | 38 | @import "paper/dropdown"; 39 | @import "paper/cards"; 40 | @import "paper/chartist"; 41 | @import "paper/responsive"; 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /vk-burst-demo/aci-frontend/app/static/dashboard/assets/sass/paper/_alerts.scss: -------------------------------------------------------------------------------- 1 | .alert{ 2 | border: 0; 3 | border-radius: 0; 4 | color: #FFFFFF; 5 | padding: 10px 15px; 6 | font-size: 14px; 7 | 8 | .container &{ 9 | border-radius: 4px; 10 | 11 | } 12 | .navbar &{ 13 | border-radius: 0; 14 | left: 0; 15 | position: absolute; 16 | right: 0; 17 | top: 85px; 18 | width: 100%; 19 | z-index: 3; 20 | } 21 | .navbar:not(.navbar-transparent) &{ 22 | top: 70px; 23 | } 24 | 25 | span[data-notify="icon"]{ 26 | font-size: 30px; 27 | display: block; 28 | left: 15px; 29 | position: absolute; 30 | top: 50%; 31 | margin-top: -20px; 32 | } 33 | 34 | .close ~ span{ 35 | display: block; 36 | max-width: 89%; 37 | } 38 | 39 | &[data-notify="container"]{ 40 | padding: 10px 10px 10px 20px; 41 | border-radius: $border-radius-base; 42 | } 43 | 44 | &.alert-with-icon{ 45 | padding-left: 65px; 46 | } 47 | } 48 | .alert-info{ 49 | background-color: $bg-info; 50 | color: $info-states-color; 51 | } 52 | .alert-success { 53 | background-color: $bg-success; 54 | color: $success-states-color; 55 | } 56 | .alert-warning { 57 | background-color: $bg-warning; 58 | color: $warning-states-color; 59 | } 60 | .alert-danger { 61 | background-color: $bg-danger; 62 | color: $danger-states-color; 63 | } 64 | 65 | -------------------------------------------------------------------------------- /vk-burst-demo/aci-frontend/app/static/dashboard/assets/sass/paper/_buttons.scss: -------------------------------------------------------------------------------- 1 | .btn, 2 | .navbar .navbar-nav > li > a.btn{ 3 | border-radius: $border-radius-btn-base; 4 | box-sizing: border-box; 5 | border-width: $border-thick; 6 | background-color: $transparent-bg; 7 | font-size: $font-size-base; 8 | font-weight: $font-weight-semi; 9 | 10 | padding: $padding-base-vertical $padding-base-horizontal; 11 | 12 | @include btn-styles($default-color, $default-states-color); 13 | @include transition($fast-transition-time, linear); 14 | 15 | &:hover, 16 | &:focus{ 17 | outline: 0 !important; 18 | } 19 | &:active, 20 | &.active, 21 | .open > &.dropdown-toggle { 22 | @include box-shadow(none); 23 | outline: 0 !important; 24 | } 25 | 26 | &.btn-icon{ 27 | padding: $padding-base-vertical; 28 | } 29 | } 30 | 31 | .btn-group .btn + .btn, 32 | .btn-group .btn + .btn-group, 33 | .btn-group .btn-group + .btn, 34 | .btn-group .btn-group + .btn-group{ 35 | margin-left: -2px; 36 | } 37 | 38 | // Apply the mixin to the buttons 39 | //.btn-default { @include btn-styles($default-color, $default-states-color); } 40 | .navbar .navbar-nav > li > a.btn-primary, .btn-primary { @include btn-styles($primary-color, $primary-states-color); } 41 | .navbar .navbar-nav > li > a.btn-success, .btn-success { @include btn-styles($success-color, $success-states-color); } 42 | .navbar .navbar-nav > li > a.btn-info, .btn-info { @include btn-styles($info-color, $info-states-color); } 43 | .navbar .navbar-nav > li > a.btn-warning, .btn-warning { @include btn-styles($warning-color, $warning-states-color); } 44 | .navbar .navbar-nav > li > a.btn-danger, .btn-danger { @include btn-styles($danger-color, $danger-states-color); } 45 | .btn-neutral { 46 | @include btn-styles($white-color, $white-color); 47 | 48 | &:hover, 49 | &:focus{ 50 | color: $default-color; 51 | } 52 | 53 | &:active, 54 | &.active, 55 | .open > &.dropdown-toggle{ 56 | background-color: $white-color; 57 | color: $default-color; 58 | } 59 | 60 | &.btn-fill{ 61 | color: $default-color; 62 | } 63 | &.btn-fill:hover, 64 | &.btn-fill:focus{ 65 | color: $default-states-color; 66 | } 67 | 68 | &.btn-simple:active, 69 | &.btn-simple.active{ 70 | background-color: transparent; 71 | } 72 | } 73 | 74 | .btn{ 75 | &:disabled, 76 | &[disabled], 77 | &.disabled{ 78 | @include opacity(.5); 79 | } 80 | } 81 | .btn-simple{ 82 | border: $none; 83 | padding: $padding-base-vertical $padding-base-horizontal; 84 | 85 | &.btn-icon{ 86 | padding: $padding-base-vertical; 87 | } 88 | } 89 | .btn-lg{ 90 | @include btn-size($padding-large-vertical, $padding-large-horizontal, $font-size-large, $border-radius-btn-large, $line-height-small); 91 | font-weight: $font-weight-normal; 92 | } 93 | .btn-sm{ 94 | @include btn-size($padding-small-vertical, $padding-small-horizontal, $font-size-small, $border-radius-btn-small, $line-height-small); 95 | } 96 | .btn-xs { 97 | @include btn-size($padding-xs-vertical, $padding-xs-horizontal, $font-size-xs, $border-radius-btn-small, $line-height-small); 98 | } 99 | .btn-wd { 100 | min-width: 140px; 101 | } 102 | 103 | .btn-group.select{ 104 | width: 100%; 105 | } 106 | .btn-group.select .btn{ 107 | text-align: left; 108 | } 109 | .btn-group.select .caret{ 110 | position: absolute; 111 | top: 50%; 112 | margin-top: -1px; 113 | right: 8px; 114 | } 115 | -------------------------------------------------------------------------------- /vk-burst-demo/aci-frontend/app/static/dashboard/assets/sass/paper/_cards.scss: -------------------------------------------------------------------------------- 1 | .card{ 2 | border-radius: $border-radius-extreme; 3 | box-shadow: 0 2px 2px rgba(204, 197, 185, 0.5); 4 | background-color: #FFFFFF; 5 | color: $card-black-color; 6 | margin-bottom: 20px; 7 | position: relative; 8 | z-index: 1; 9 | 10 | .image{ 11 | width: 100%; 12 | overflow: hidden; 13 | height: 260px; 14 | border-radius: $border-radius-extreme $border-radius-extreme 0 0; 15 | position: relative; 16 | -webkit-transform-style: preserve-3d; 17 | -moz-transform-style: preserve-3d; 18 | transform-style: preserve-3d; 19 | 20 | img { 21 | width: 100%; 22 | } 23 | } 24 | .content{ 25 | padding: 15px 15px 10px 15px; 26 | } 27 | .header{ 28 | padding: 20px 20px 0; 29 | } 30 | .description{ 31 | font-size: $font-paragraph; 32 | color: $font-color; 33 | } 34 | 35 | h6{ 36 | font-size: $font-size-small; 37 | margin: 0; 38 | } 39 | .category, 40 | label{ 41 | font-size: $font-size-base; 42 | font-weight: $font-weight-normal; 43 | color: $dark-gray; 44 | margin-bottom: 0px; 45 | i{ 46 | font-size: $font-paragraph; 47 | } 48 | } 49 | 50 | label{ 51 | font-size: 15px; 52 | margin-bottom: 5px; 53 | } 54 | 55 | .title{ 56 | margin: $none; 57 | color: $card-black-color; 58 | font-weight: $font-weight-light; 59 | } 60 | .avatar{ 61 | width: 50px; 62 | height: 50px; 63 | overflow: hidden; 64 | border-radius: 50%; 65 | margin-right: 5px; 66 | } 67 | .footer{ 68 | padding: 0; 69 | line-height: 30px; 70 | 71 | .legend{ 72 | padding: 5px 0; 73 | } 74 | 75 | hr{ 76 | margin-top: 5px; 77 | margin-bottom: 5px; 78 | } 79 | } 80 | .stats{ 81 | color: #a9a9a9; 82 | font-weight: 300; 83 | i{ 84 | margin-right: 2px; 85 | min-width: 15px; 86 | display: inline-block; 87 | } 88 | } 89 | .footer div{ 90 | display: inline-block; 91 | } 92 | 93 | .author{ 94 | font-size: $font-size-small; 95 | font-weight: $font-weight-bold; 96 | text-transform: uppercase; 97 | } 98 | .author i{ 99 | font-size: $font-size-base; 100 | } 101 | 102 | &.card-separator:after{ 103 | height: 100%; 104 | right: -15px; 105 | top: 0; 106 | width: 1px; 107 | background-color: $medium-gray; 108 | content: ""; 109 | position: absolute; 110 | } 111 | 112 | .ct-chart{ 113 | margin: 30px 0 30px; 114 | height: 245px; 115 | } 116 | 117 | .table{ 118 | tbody td:first-child, 119 | thead th:first-child{ 120 | padding-left: 15px; 121 | } 122 | 123 | tbody td:last-child, 124 | thead th:last-child{ 125 | padding-right: 15px; 126 | } 127 | } 128 | 129 | .alert{ 130 | border-radius: $border-radius-base; 131 | position: relative; 132 | 133 | &.alert-with-icon{ 134 | padding-left: 65px; 135 | } 136 | } 137 | .icon-big{ 138 | font-size: 3em; 139 | min-height: 64px; 140 | } 141 | .numbers{ 142 | font-size: 2em; 143 | text-align: right; 144 | p{ 145 | margin: 0; 146 | } 147 | } 148 | ul.team-members{ 149 | li{ 150 | padding: 10px 0px; 151 | &:not(:last-child){ 152 | border-bottom: 1px solid $medium-pale-bg; 153 | } 154 | } 155 | } 156 | } 157 | .card-user{ 158 | .image{ 159 | border-radius: 8px 8px 0 0; 160 | height: 150px; 161 | position: relative; 162 | overflow: hidden; 163 | 164 | img{ 165 | width: 100%; 166 | } 167 | } 168 | .image-plain{ 169 | height: 0; 170 | margin-top: 110px; 171 | } 172 | .author{ 173 | text-align: center; 174 | text-transform: none; 175 | margin-top: -65px; 176 | .title{ 177 | color: $default-states-color; 178 | small{ 179 | color: $card-muted-color; 180 | } 181 | } 182 | } 183 | .avatar{ 184 | width: 100px; 185 | height: 100px; 186 | border-radius: 50%; 187 | position: relative; 188 | margin-bottom: 15px; 189 | 190 | &.border-white{ 191 | border: 5px solid $white-color; 192 | } 193 | &.border-gray{ 194 | border: 5px solid $card-muted-color; 195 | } 196 | } 197 | .title{ 198 | font-weight: 600; 199 | line-height: 24px; 200 | } 201 | .description{ 202 | margin-top: 10px; 203 | } 204 | .content{ 205 | min-height: 200px; 206 | } 207 | 208 | &.card-plain{ 209 | .avatar{ 210 | height: 190px; 211 | width: 190px; 212 | } 213 | } 214 | } 215 | 216 | .card-map{ 217 | .map{ 218 | height: 500px; 219 | padding-top: 20px; 220 | 221 | > div{ 222 | height: 100%; 223 | } 224 | } 225 | } 226 | .card-user, 227 | .card-price{ 228 | .footer{ 229 | padding: 5px 15px 10px; 230 | } 231 | hr{ 232 | margin: 5px 15px; 233 | } 234 | } 235 | .card-plain{ 236 | background-color: transparent; 237 | box-shadow: none; 238 | border-radius: 0; 239 | 240 | .image{ 241 | border-radius: 4px; 242 | } 243 | } 244 | -------------------------------------------------------------------------------- /vk-burst-demo/aci-frontend/app/static/dashboard/assets/sass/paper/_chartist.scss: -------------------------------------------------------------------------------- 1 | @mixin ct-responsive-svg-container($width: 100%, $ratio: $ct-container-ratio) { 2 | display: block; 3 | position: relative; 4 | width: $width; 5 | 6 | &:before { 7 | display: block; 8 | float: left; 9 | content: ""; 10 | width: 0; 11 | height: 0; 12 | padding-bottom: $ratio * 100%; 13 | } 14 | 15 | &:after { 16 | content: ""; 17 | display: table; 18 | clear: both; 19 | } 20 | 21 | > svg { 22 | display: block; 23 | position: absolute; 24 | top: 0; 25 | left: 0; 26 | } 27 | } 28 | 29 | @mixin ct-align-justify($ct-text-align: $ct-text-align, $ct-text-justify: $ct-text-justify) { 30 | -webkit-box-align: $ct-text-align; 31 | -webkit-align-items: $ct-text-align; 32 | -ms-flex-align: $ct-text-align; 33 | align-items: $ct-text-align; 34 | -webkit-box-pack: $ct-text-justify; 35 | -webkit-justify-content: $ct-text-justify; 36 | -ms-flex-pack: $ct-text-justify; 37 | justify-content: $ct-text-justify; 38 | // Fallback to text-align for non-flex browsers 39 | @if($ct-text-justify == 'flex-start') { 40 | text-align: left; 41 | } @else if ($ct-text-justify == 'flex-end') { 42 | text-align: right; 43 | } @else { 44 | text-align: center; 45 | } 46 | } 47 | 48 | @mixin ct-flex() { 49 | // Fallback to block 50 | display: block; 51 | display: -webkit-box; 52 | display: -moz-box; 53 | display: -ms-flexbox; 54 | display: -webkit-flex; 55 | display: flex; 56 | } 57 | 58 | @mixin ct-chart-label($ct-text-color: $ct-text-color, $ct-text-size: $ct-text-size, $ct-text-line-height: $ct-text-line-height) { 59 | fill: $ct-text-color; 60 | color: $ct-text-color; 61 | font-size: $ct-text-size; 62 | line-height: $ct-text-line-height; 63 | } 64 | 65 | @mixin ct-chart-grid($ct-grid-color: $ct-grid-color, $ct-grid-width: $ct-grid-width, $ct-grid-dasharray: $ct-grid-dasharray) { 66 | stroke: $ct-grid-color; 67 | stroke-width: $ct-grid-width; 68 | 69 | @if ($ct-grid-dasharray) { 70 | stroke-dasharray: $ct-grid-dasharray; 71 | } 72 | } 73 | 74 | @mixin ct-chart-point($ct-point-size: $ct-point-size, $ct-point-shape: $ct-point-shape) { 75 | stroke-width: $ct-point-size; 76 | stroke-linecap: $ct-point-shape; 77 | } 78 | 79 | @mixin ct-chart-line($ct-line-width: $ct-line-width, $ct-line-dasharray: $ct-line-dasharray) { 80 | fill: none; 81 | stroke-width: $ct-line-width; 82 | 83 | @if ($ct-line-dasharray) { 84 | stroke-dasharray: $ct-line-dasharray; 85 | } 86 | } 87 | 88 | @mixin ct-chart-area($ct-area-opacity: $ct-area-opacity) { 89 | stroke: none; 90 | fill-opacity: $ct-area-opacity; 91 | } 92 | 93 | @mixin ct-chart-bar($ct-bar-width: $ct-bar-width) { 94 | fill: none; 95 | stroke-width: $ct-bar-width; 96 | } 97 | 98 | @mixin ct-chart-donut($ct-donut-width: $ct-donut-width) { 99 | fill: none; 100 | stroke-width: $ct-donut-width; 101 | } 102 | 103 | @mixin ct-chart-series-color($color) { 104 | .#{$ct-class-point}, .#{$ct-class-line}, .#{$ct-class-bar}, .#{$ct-class-slice-donut} { 105 | stroke: $color; 106 | } 107 | 108 | .#{$ct-class-slice-pie}, .#{$ct-class-area} { 109 | fill: $color; 110 | } 111 | } 112 | 113 | @mixin ct-chart($ct-container-ratio: $ct-container-ratio, $ct-text-color: $ct-text-color, $ct-text-size: $ct-text-size, $ct-grid-color: $ct-grid-color, $ct-grid-width: $ct-grid-width, $ct-grid-dasharray: $ct-grid-dasharray, $ct-point-size: $ct-point-size, $ct-point-shape: $ct-point-shape, $ct-line-width: $ct-line-width, $ct-bar-width: $ct-bar-width, $ct-donut-width: $ct-donut-width, $ct-series-names: $ct-series-names, $ct-series-colors: $ct-series-colors) { 114 | 115 | .#{$ct-class-label} { 116 | @include ct-chart-label($ct-text-color, $ct-text-size); 117 | } 118 | 119 | .#{$ct-class-chart-line} .#{$ct-class-label}, 120 | .#{$ct-class-chart-bar} .#{$ct-class-label} { 121 | @include ct-flex(); 122 | } 123 | 124 | .#{$ct-class-label}.#{$ct-class-horizontal}.#{$ct-class-start} { 125 | @include ct-align-justify(flex-end, flex-start); 126 | // Fallback for browsers that don't support foreignObjects 127 | text-anchor: start; 128 | } 129 | 130 | .#{$ct-class-label}.#{$ct-class-horizontal}.#{$ct-class-end} { 131 | @include ct-align-justify(flex-start, flex-start); 132 | // Fallback for browsers that don't support foreignObjects 133 | text-anchor: start; 134 | } 135 | 136 | .#{$ct-class-label}.#{$ct-class-vertical}.#{$ct-class-start} { 137 | @include ct-align-justify(flex-end, flex-end); 138 | // Fallback for browsers that don't support foreignObjects 139 | text-anchor: end; 140 | } 141 | 142 | .#{$ct-class-label}.#{$ct-class-vertical}.#{$ct-class-end} { 143 | @include ct-align-justify(flex-end, flex-start); 144 | // Fallback for browsers that don't support foreignObjects 145 | text-anchor: start; 146 | } 147 | 148 | .#{$ct-class-chart-bar} .#{$ct-class-label}.#{$ct-class-horizontal}.#{$ct-class-start} { 149 | @include ct-align-justify(flex-end, center); 150 | // Fallback for browsers that don't support foreignObjects 151 | text-anchor: start; 152 | } 153 | 154 | .#{$ct-class-chart-bar} .#{$ct-class-label}.#{$ct-class-horizontal}.#{$ct-class-end} { 155 | @include ct-align-justify(flex-start, center); 156 | // Fallback for browsers that don't support foreignObjects 157 | text-anchor: start; 158 | } 159 | 160 | .#{$ct-class-chart-bar}.#{$ct-class-horizontal-bars} .#{$ct-class-label}.#{$ct-class-horizontal}.#{$ct-class-start} { 161 | @include ct-align-justify(flex-end, flex-start); 162 | // Fallback for browsers that don't support foreignObjects 163 | text-anchor: start; 164 | } 165 | 166 | .#{$ct-class-chart-bar}.#{$ct-class-horizontal-bars} .#{$ct-class-label}.#{$ct-class-horizontal}.#{$ct-class-end} { 167 | @include ct-align-justify(flex-start, flex-start); 168 | // Fallback for browsers that don't support foreignObjects 169 | text-anchor: start; 170 | } 171 | 172 | .#{$ct-class-chart-bar}.#{$ct-class-horizontal-bars} .#{$ct-class-label}.#{$ct-class-vertical}.#{$ct-class-start} { 173 | //@include ct-chart-label($ct-text-color, $ct-text-size, center, $ct-vertical-text-justify); 174 | @include ct-align-justify(center, flex-end); 175 | // Fallback for browsers that don't support foreignObjects 176 | text-anchor: end; 177 | } 178 | 179 | .#{$ct-class-chart-bar}.#{$ct-class-horizontal-bars} .#{$ct-class-label}.#{$ct-class-vertical}.#{$ct-class-end} { 180 | @include ct-align-justify(center, flex-start); 181 | // Fallback for browsers that don't support foreignObjects 182 | text-anchor: end; 183 | } 184 | 185 | .#{$ct-class-grid} { 186 | @include ct-chart-grid($ct-grid-color, $ct-grid-width, $ct-grid-dasharray); 187 | } 188 | 189 | .#{$ct-class-point} { 190 | @include ct-chart-point($ct-point-size, $ct-point-shape); 191 | } 192 | 193 | .#{$ct-class-line} { 194 | @include ct-chart-line($ct-line-width); 195 | } 196 | 197 | .#{$ct-class-area} { 198 | @include ct-chart-area(); 199 | } 200 | 201 | .#{$ct-class-bar} { 202 | @include ct-chart-bar($ct-bar-width); 203 | } 204 | 205 | .#{$ct-class-slice-donut} { 206 | @include ct-chart-donut($ct-donut-width); 207 | } 208 | 209 | @if $ct-include-colored-series { 210 | @for $i from 0 to length($ct-series-names) { 211 | .#{$ct-class-series}-#{nth($ct-series-names, $i + 1)} { 212 | $color: nth($ct-series-colors, $i + 1); 213 | 214 | @include ct-chart-series-color($color); 215 | } 216 | } 217 | } 218 | } 219 | 220 | @if $ct-include-classes { 221 | @include ct-chart(); 222 | 223 | @if $ct-include-alternative-responsive-containers { 224 | @for $i from 0 to length($ct-scales-names) { 225 | .#{nth($ct-scales-names, $i + 1)} { 226 | @include ct-responsive-svg-container($ratio: nth($ct-scales, $i + 1)); 227 | } 228 | } 229 | } 230 | } -------------------------------------------------------------------------------- /vk-burst-demo/aci-frontend/app/static/dashboard/assets/sass/paper/_checkbox-radio.scss: -------------------------------------------------------------------------------- 1 | /* Checkbox and radio */ 2 | .checkbox, 3 | .radio { 4 | margin-bottom: 12px; 5 | padding-left: 30px; 6 | position: relative; 7 | -webkit-transition: color,opacity 0.25s linear; 8 | transition: color,opacity 0.25s linear; 9 | font-size: $font-size-base; 10 | font-weight: normal; 11 | line-height: 1.5; 12 | color: $font-color; 13 | cursor: pointer; 14 | 15 | .icons { 16 | color: $font-color; 17 | display: block; 18 | height: 20px; 19 | left: 0; 20 | position: absolute; 21 | top: 0; 22 | width: 20px; 23 | text-align: center; 24 | line-height: 21px; 25 | font-size: 20px; 26 | cursor: pointer; 27 | -webkit-transition: color,opacity 0.15s linear; 28 | transition: color,opacity 0.15s linear; 29 | 30 | opacity: .50; 31 | } 32 | 33 | 34 | &.checked{ 35 | .icons{ 36 | opacity: 1; 37 | } 38 | } 39 | 40 | input{ 41 | outline: none !important; 42 | display: none; 43 | } 44 | } 45 | 46 | .checkbox, 47 | .radio{ 48 | label{ 49 | padding-left: 10px; 50 | } 51 | } 52 | 53 | .checkbox .icons .first-icon, 54 | .radio .icons .first-icon, 55 | .checkbox .icons .second-icon, 56 | .radio .icons .second-icon { 57 | display: inline-table; 58 | position: absolute; 59 | left: 0; 60 | top: 0; 61 | background-color: transparent; 62 | margin: 0; 63 | @include opacity(1); 64 | } 65 | .checkbox .icons .second-icon, 66 | .radio .icons .second-icon { 67 | @include opacity(0); 68 | } 69 | .checkbox:hover, 70 | .radio:hover { 71 | -webkit-transition: color 0.2s linear; 72 | transition: color 0.2s linear; 73 | } 74 | .checkbox:hover .first-icon, 75 | .radio:hover .first-icon { 76 | @include opacity(0); 77 | } 78 | .checkbox:hover .second-icon, 79 | .radio:hover .second-icon { 80 | @include opacity (1); 81 | } 82 | .checkbox.checked, 83 | .radio.checked { 84 | // color: $info-color; 85 | } 86 | .checkbox.checked .first-icon, 87 | .radio.checked .first-icon { 88 | opacity: 0; 89 | filter: alpha(opacity=0); 90 | } 91 | .checkbox.checked .second-icon, 92 | .radio.checked .second-icon { 93 | opacity: 1; 94 | filter: alpha(opacity=100); 95 | // color: $info-color; 96 | -webkit-transition: color 0.2s linear; 97 | transition: color 0.2s linear; 98 | } 99 | .checkbox.disabled, 100 | .radio.disabled { 101 | cursor: default; 102 | color: $medium-gray; 103 | } 104 | .checkbox.disabled .icons, 105 | .radio.disabled .icons { 106 | color: $medium-gray; 107 | } 108 | .checkbox.disabled .first-icon, 109 | .radio.disabled .first-icon { 110 | opacity: 1; 111 | filter: alpha(opacity=100); 112 | } 113 | .checkbox.disabled .second-icon, 114 | .radio.disabled .second-icon { 115 | opacity: 0; 116 | filter: alpha(opacity=0); 117 | } 118 | .checkbox.disabled.checked .icons, 119 | .radio.disabled.checked .icons { 120 | color: $medium-gray; 121 | } 122 | .checkbox.disabled.checked .first-icon, 123 | .radio.disabled.checked .first-icon { 124 | opacity: 0; 125 | filter: alpha(opacity=0); 126 | } 127 | .checkbox.disabled.checked .second-icon, 128 | .radio.disabled.checked .second-icon { 129 | opacity: 1; 130 | color: $medium-gray; 131 | filter: alpha(opacity=100); 132 | } 133 | -------------------------------------------------------------------------------- /vk-burst-demo/aci-frontend/app/static/dashboard/assets/sass/paper/_dropdown.scss: -------------------------------------------------------------------------------- 1 | .dropdown-menu{ 2 | background-color: $pale-bg; 3 | border: 0 none; 4 | border-radius: $border-radius-extreme; 5 | display: block; 6 | margin-top: 10px; 7 | padding: 0px; 8 | position: absolute; 9 | visibility: hidden; 10 | z-index: 9000; 11 | 12 | @include opacity(0); 13 | @include box-shadow($dropdown-shadow); 14 | 15 | // the style for opening dropdowns on mobile devices; for the desktop version check the _responsive.scss file 16 | .open &{ 17 | @include opacity(1); 18 | visibility: visible; 19 | } 20 | 21 | .divider{ 22 | background-color: $medium-pale-bg; 23 | margin: 0px; 24 | } 25 | 26 | .dropdown-header{ 27 | color: $dark-gray; 28 | font-size: $font-size-small; 29 | padding: $padding-dropdown-vertical $padding-dropdown-horizontal; 30 | } 31 | 32 | // the style for the dropdown menu that appears under select, it is different from the default one 33 | .select &{ 34 | border-radius: $border-radius-bottom; 35 | @include box-shadow(none); 36 | @include transform-origin($select-coordinates); 37 | @include transform-scale(1); 38 | @include transition($fast-transition-time, $transition-linear); 39 | margin-top: -20px; 40 | } 41 | .select.open &{ 42 | margin-top: -1px; 43 | } 44 | 45 | > li > a { 46 | color: $font-color; 47 | font-size: $font-size-base; 48 | padding: $padding-dropdown-vertical $padding-dropdown-horizontal; 49 | @include transition-none(); 50 | 51 | img{ 52 | margin-top: -3px; 53 | } 54 | } 55 | > li > a:focus{ 56 | outline: 0 !important; 57 | } 58 | 59 | .btn-group.select &{ 60 | min-width: 100%; 61 | } 62 | 63 | > li:first-child > a{ 64 | border-top-left-radius: $border-radius-extreme; 65 | border-top-right-radius: $border-radius-extreme; 66 | } 67 | 68 | > li:last-child > a{ 69 | border-bottom-left-radius: $border-radius-extreme; 70 | border-bottom-right-radius: $border-radius-extreme; 71 | } 72 | 73 | .select & > li:first-child > a{ 74 | border-radius: 0; 75 | border-bottom: 0 none; 76 | } 77 | 78 | > li > a:hover, 79 | > li > a:focus { 80 | background-color: $default-color; 81 | color: $fill-font-color; 82 | opacity: 1; 83 | text-decoration: none; 84 | } 85 | 86 | &.dropdown-primary > li > a:hover, 87 | &.dropdown-primary > li > a:focus{ 88 | background-color: $primary-color; 89 | } 90 | &.dropdown-info > li > a:hover, 91 | &.dropdown-info > li > a:focus{ 92 | background-color: $info-color; 93 | } 94 | &.dropdown-success > li > a:hover, 95 | &.dropdown-success > li > a:focus{ 96 | background-color: $success-color; 97 | } 98 | &.dropdown-warning > li > a:hover, 99 | &.dropdown-warning > li > a:focus{ 100 | background-color: $warning-color; 101 | } 102 | &.dropdown-danger > li > a:hover, 103 | &.dropdown-danger > li > a:focus{ 104 | background-color: $danger-color; 105 | } 106 | 107 | } 108 | 109 | //fix bug for the select items in btn-group 110 | .btn-group.select{ 111 | overflow: hidden; 112 | } 113 | .btn-group.select.open{ 114 | overflow: visible; 115 | } 116 | -------------------------------------------------------------------------------- /vk-burst-demo/aci-frontend/app/static/dashboard/assets/sass/paper/_footers.scss: -------------------------------------------------------------------------------- 1 | .footer{ 2 | background-attachment: fixed; 3 | position: relative; 4 | line-height: 20px; 5 | nav { 6 | ul { 7 | list-style: none; 8 | margin: 0; 9 | padding: 0; 10 | font-weight: normal; 11 | li{ 12 | display: inline-block; 13 | padding: 10px 15px; 14 | margin: 15px 3px; 15 | line-height: 20px; 16 | text-align: center; 17 | } 18 | a:not(.btn){ 19 | color: $font-color; 20 | display: block; 21 | margin-bottom: 3px; 22 | 23 | &:focus, 24 | &:hover{ 25 | color: $default-states-color; 26 | } 27 | } 28 | } 29 | } 30 | .copyright{ 31 | color: $font-color; 32 | padding: 10px 15px; 33 | font-size: 14px; 34 | white-space: nowrap; 35 | margin: 15px 3px; 36 | line-height: 20px; 37 | text-align: center; 38 | } 39 | .heart{ 40 | color: $danger-color; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /vk-burst-demo/aci-frontend/app/static/dashboard/assets/sass/paper/_inputs.scss: -------------------------------------------------------------------------------- 1 | .form-control::-moz-placeholder{ 2 | @include placeholder($medium-gray,1); 3 | } 4 | .form-control:-moz-placeholder{ 5 | @include placeholder($medium-gray,1); 6 | } 7 | .form-control::-webkit-input-placeholder{ 8 | @include placeholder($medium-gray,1); 9 | } 10 | .form-control:-ms-input-placeholder{ 11 | @include placeholder($medium-gray,1); 12 | } 13 | 14 | .form-control { 15 | background-color: $gray-input-bg; 16 | border: medium none; 17 | border-radius: $border-radius-base; 18 | color: $font-color; 19 | font-size: $font-size-base; 20 | transition: background-color 0.3s ease 0s; 21 | @include input-size($padding-base-vertical, $padding-base-horizontal, $height-base); 22 | @include box-shadow(none); 23 | 24 | &:focus{ 25 | background-color: $white-bg; 26 | @include box-shadow(none); 27 | outline: 0 !important; 28 | } 29 | 30 | .has-success &, 31 | .has-error &, 32 | .has-success &:focus, 33 | .has-error &:focus{ 34 | @include box-shadow(none); 35 | } 36 | 37 | .has-success &{ 38 | background-color: $success-input-bg; 39 | color: $success-color; 40 | &.border-input{ 41 | border: 1px solid $success-color; 42 | } 43 | } 44 | .has-success &:focus{ 45 | background-color: $white-bg; 46 | } 47 | .has-error &{ 48 | background-color: $danger-input-bg; 49 | color: $danger-color; 50 | &.border-input{ 51 | border: 1px solid $danger-color; 52 | } 53 | } 54 | .has-error &:focus{ 55 | background-color: $white-bg; 56 | } 57 | 58 | & + .form-control-feedback{ 59 | border-radius: $border-radius-large; 60 | font-size: $font-size-base; 61 | margin-top: -7px; 62 | position: absolute; 63 | right: 10px; 64 | top: 50%; 65 | vertical-align: middle; 66 | } 67 | &.border-input{ 68 | border: 1px solid $table-line-color; 69 | } 70 | .open &{ 71 | border-bottom-color: transparent; 72 | } 73 | } 74 | 75 | .input-lg{ 76 | height: 55px; 77 | padding: $padding-large-vertical $padding-large-horizontal; 78 | } 79 | 80 | .has-error{ 81 | .form-control-feedback, .control-label{ 82 | color: $danger-color; 83 | } 84 | } 85 | .has-success{ 86 | .form-control-feedback, .control-label{ 87 | color: $success-color; 88 | } 89 | } 90 | 91 | 92 | .input-group-addon { 93 | background-color: $gray-input-bg; 94 | border: medium none; 95 | border-radius: $border-radius-base; 96 | 97 | 98 | .has-success &, 99 | .has-error &{ 100 | background-color: $white-color; 101 | } 102 | .has-error .form-control:focus + &{ 103 | color: $danger-color; 104 | } 105 | .has-success .form-control:focus + &{ 106 | color: $success-color; 107 | } 108 | .form-control:focus + &, 109 | .form-control:focus ~ &{ 110 | background-color: $white-color; 111 | } 112 | } 113 | .border-input{ 114 | .input-group-addon{ 115 | border: solid 1px $table-line-color; 116 | } 117 | } 118 | .input-group{ 119 | margin-bottom: 15px; 120 | } 121 | .input-group[disabled]{ 122 | .input-group-addon{ 123 | background-color: $light-gray; 124 | } 125 | } 126 | .input-group .form-control:first-child, 127 | .input-group-addon:first-child, 128 | .input-group-btn:first-child > .dropdown-toggle, 129 | .input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle) { 130 | border-right: 0 none; 131 | } 132 | .input-group .form-control:last-child, 133 | .input-group-addon:last-child, 134 | .input-group-btn:last-child > .dropdown-toggle, 135 | .input-group-btn:first-child > .btn:not(:first-child) { 136 | border-left: 0 none; 137 | } 138 | .form-control[disabled], .form-control[readonly], fieldset[disabled] .form-control { 139 | background-color: $light-gray; 140 | cursor: not-allowed; 141 | @include placeholder($dark-gray,1); 142 | } 143 | .form-control[disabled]::-moz-placeholder{ 144 | @include placeholder($dark-gray,1); 145 | } 146 | .form-control[disabled]:-moz-placeholder{ 147 | @include placeholder($medium-gray,1); 148 | } 149 | .form-control[disabled]::-webkit-input-placeholder{ 150 | @include placeholder($medium-gray,1); 151 | } 152 | .form-control[disabled]:-ms-input-placeholder{ 153 | @include placeholder($medium-gray,1); 154 | } 155 | .input-group-btn .btn{ 156 | border-width: $border-thin; 157 | padding: $padding-round-vertical $padding-base-horizontal; 158 | } 159 | .input-group-btn .btn-default:not(.btn-fill){ 160 | border-color: $medium-gray; 161 | } 162 | 163 | .input-group-btn:last-child > .btn{ 164 | margin-left: 0; 165 | } 166 | textarea.form-control{ 167 | max-width: 100%; 168 | padding: 10px 18px; 169 | resize: none; 170 | } 171 | 172 | -------------------------------------------------------------------------------- /vk-burst-demo/aci-frontend/app/static/dashboard/assets/sass/paper/_misc.scss: -------------------------------------------------------------------------------- 1 | /* General overwrite */ 2 | body{ 3 | color: $font-color; 4 | font-size: $font-size-base; 5 | font-family: 'Muli', Arial, sans-serif; 6 | .wrapper{ 7 | min-height: 100vh; 8 | position: relative; 9 | } 10 | } 11 | a{ 12 | color: $info-color; 13 | 14 | &:hover, &:focus{ 15 | color: $info-states-color; 16 | text-decoration: none; 17 | } 18 | } 19 | 20 | a:focus, a:active, 21 | button::-moz-focus-inner, 22 | input::-moz-focus-inner, 23 | select::-moz-focus-inner, 24 | input[type="file"] > input[type="button"]::-moz-focus-inner{ 25 | outline:0 !important; 26 | } 27 | .ui-slider-handle:focus, 28 | .navbar-toggle, 29 | input:focus, 30 | button:focus { 31 | outline : 0 !important; 32 | } 33 | 34 | /* Animations */ 35 | .form-control, 36 | .input-group-addon, 37 | .tagsinput, 38 | .navbar, 39 | .navbar .alert{ 40 | @include transition($general-transition-time, $transition-linear); 41 | } 42 | 43 | .sidebar .nav a, 44 | .table > tbody > tr .td-actions .btn{ 45 | @include transition($fast-transition-time, $transition-ease-in); 46 | } 47 | 48 | .btn{ 49 | @include transition($ultra-fast-transition-time, $transition-ease-in); 50 | } 51 | .fa{ 52 | width: 21px; 53 | text-align: center; 54 | } 55 | .fa-base{ 56 | font-size: 1.25em !important; 57 | } 58 | 59 | .margin-top{ 60 | margin-top: 50px; 61 | } 62 | hr{ 63 | border-color: $medium-pale-bg; 64 | } 65 | .wrapper{ 66 | position: relative; 67 | top: 0; 68 | height: 100vh; 69 | } 70 | -------------------------------------------------------------------------------- /vk-burst-demo/aci-frontend/app/static/dashboard/assets/sass/paper/_mixins.scss: -------------------------------------------------------------------------------- 1 | //Utilities 2 | 3 | @import "mixins/transparency"; 4 | @import "mixins/vendor-prefixes"; 5 | 6 | 7 | //Components 8 | 9 | @import "mixins/buttons"; 10 | @import "mixins/inputs"; 11 | @import "mixins/labels"; 12 | @import "mixins/tabs"; 13 | @import "mixins/navbars"; 14 | @import "mixins/icons"; 15 | @import "mixins/cards"; 16 | @import "mixins/chartist"; 17 | @import "mixins/sidebar"; -------------------------------------------------------------------------------- /vk-burst-demo/aci-frontend/app/static/dashboard/assets/sass/paper/_navbars.scss: -------------------------------------------------------------------------------- 1 | .nav { 2 | > li{ 3 | > a:hover, 4 | > a:focus{ 5 | background-color: transparent; 6 | } 7 | } 8 | } 9 | .navbar{ 10 | border: $none; 11 | border-radius: 0; 12 | font-size: $font-size-navbar; 13 | z-index: 3; 14 | 15 | .navbar-brand{ 16 | font-weight: $font-weight-bold; 17 | margin: $navbar-margin-brand; 18 | padding: $navbar-padding-brand; 19 | font-size: $font-size-large-navbar; 20 | } 21 | .navbar-nav{ 22 | > li > a { 23 | line-height: 1.42857; 24 | margin: $navbar-margin-a; 25 | padding: $navbar-padding-a; 26 | 27 | i, 28 | p{ 29 | display: inline-block; 30 | margin: 0; 31 | } 32 | i{ 33 | position: relative; 34 | top: 1px; 35 | } 36 | } 37 | > li > a.btn{ 38 | margin: $navbar-margin-a-btn; 39 | padding: $padding-base-vertical $padding-base-horizontal; 40 | } 41 | } 42 | .btn{ 43 | margin: $navbar-margin-btn; 44 | font-size: $font-size-base; 45 | } 46 | .btn-simple{ 47 | font-size: $font-size-medium; 48 | } 49 | } 50 | 51 | .navbar-nav > li > .dropdown-menu{ 52 | border-radius: $border-radius-extreme; 53 | margin-top: -5px; 54 | } 55 | 56 | .navbar-default { 57 | background-color: $bg-nude; 58 | border-bottom: 1px solid $medium-gray; 59 | 60 | .brand{ 61 | color: $font-color !important; 62 | } 63 | .navbar-nav{ 64 | > li > a:not(.btn){ 65 | color: $dark-gray; 66 | } 67 | 68 | > .active > a, 69 | > .active > a:not(.btn):hover, 70 | > .active > a:not(.btn):focus, 71 | > li > a:not(.btn):hover, 72 | > li > a:not(.btn):focus { 73 | background-color: transparent; 74 | border-radius: 3px; 75 | color: $info-color; 76 | @include opacity(1); 77 | } 78 | 79 | > .dropdown > a:hover .caret, 80 | > .dropdown > a:focus .caret { 81 | border-bottom-color: $info-color; 82 | border-top-color: $info-color; 83 | 84 | } 85 | 86 | > .open > a, 87 | > .open > a:hover, 88 | > .open > a:focus{ 89 | background-color: transparent; 90 | color: $info-color; 91 | } 92 | 93 | .navbar-toggle:hover,.navbar-toggle:focus { 94 | background-color: transparent; 95 | } 96 | 97 | } 98 | 99 | &:not(.navbar-transparent) .btn-default:hover{ 100 | color: $info-color; 101 | border-color: $info-color; 102 | } 103 | &:not(.navbar-transparent) .btn-neutral, 104 | &:not(.navbar-transparent) .btn-neutral:hover, 105 | &:not(.navbar-transparent) .btn-neutral:active{ 106 | color: $dark-gray; 107 | } 108 | } 109 | 110 | .navbar-form{ 111 | @include box-shadow(none); 112 | .form-control{ 113 | @include light-form(); 114 | height: 22px; 115 | font-size: $font-size-navbar; 116 | line-height: $line-height-general; 117 | color: $light-gray; 118 | } 119 | .navbar-transparent & .form-control, 120 | [class*="navbar-ct"] & .form-control{ 121 | color: $white-color; 122 | border: $none; 123 | border-bottom: 1px solid rgba($white-color,.6); 124 | } 125 | 126 | } 127 | 128 | .navbar-ct-primary{ 129 | @include navbar-color($bg-primary); 130 | } 131 | .navbar-ct-info{ 132 | @include navbar-color($bg-info); 133 | } 134 | .navbar-ct-success{ 135 | @include navbar-color($bg-success); 136 | } 137 | .navbar-ct-warning{ 138 | @include navbar-color($bg-warning); 139 | } 140 | .navbar-ct-danger{ 141 | @include navbar-color($bg-danger); 142 | } 143 | 144 | .navbar-transparent{ 145 | padding-top: 15px; 146 | background-color: transparent; 147 | border-bottom: 1px solid transparent; 148 | } 149 | 150 | .navbar-toggle{ 151 | margin-top: 19px; 152 | margin-bottom: 19px; 153 | border: $none; 154 | 155 | .icon-bar { 156 | background-color: $white-color; 157 | } 158 | .navbar-collapse, 159 | .navbar-form { 160 | border-color: transparent; 161 | } 162 | 163 | &.navbar-default .navbar-toggle:hover, 164 | &.navbar-default .navbar-toggle:focus { 165 | background-color: transparent; 166 | } 167 | } 168 | 169 | .navbar-transparent, [class*="navbar-ct"]{ 170 | 171 | .navbar-brand{ 172 | 173 | @include opacity(.9); 174 | 175 | &:focus, 176 | 177 | &:hover{ 178 | 179 | background-color: transparent; 180 | 181 | @include opacity(1); 182 | 183 | } 184 | 185 | } 186 | 187 | .navbar-brand:not([class*="text"]){ 188 | 189 | color: $white-color; 190 | 191 | } 192 | 193 | .navbar-nav{ 194 | 195 | > li > a:not(.btn){ 196 | 197 | color: $white-color; 198 | 199 | border-color: $white-color; 200 | 201 | @include opacity(0.8); 202 | 203 | } 204 | 205 | > .active > a:not(.btn), 206 | 207 | > .active > a:hover:not(.btn), 208 | 209 | > .active > a:focus:not(.btn), 210 | 211 | > li > a:hover:not(.btn), 212 | 213 | > li > a:focus:not(.btn){ 214 | 215 | background-color: transparent; 216 | 217 | border-radius: 3px; 218 | 219 | color: $white-color; 220 | 221 | @include opacity(1); 222 | 223 | } 224 | 225 | .nav > li > a.btn:hover{ 226 | 227 | background-color: transparent; 228 | 229 | } 230 | 231 | > .dropdown > a .caret, 232 | 233 | > .dropdown > a:hover .caret, 234 | 235 | > .dropdown > a:focus .caret{ 236 | 237 | border-bottom-color: $white-color; 238 | 239 | border-top-color: $white-color; 240 | 241 | } 242 | 243 | > .open > a, 244 | 245 | > .open > a:hover, 246 | 247 | > .open > a:focus { 248 | 249 | background-color: transparent; 250 | 251 | color: $white-color; 252 | 253 | @include opacity(1); 254 | 255 | } 256 | 257 | } 258 | 259 | .btn-default{ 260 | 261 | color: $white-color; 262 | 263 | border-color: $white-color; 264 | 265 | } 266 | 267 | .btn-default.btn-fill{ 268 | 269 | color: $dark-gray; 270 | 271 | background-color: $white-color; 272 | 273 | @include opacity(.9); 274 | 275 | } 276 | 277 | .btn-default.btn-fill:hover, 278 | 279 | .btn-default.btn-fill:focus, 280 | 281 | .btn-default.btn-fill:active, 282 | 283 | .btn-default.btn-fill.active, 284 | 285 | .open .dropdown-toggle.btn-fill.btn-default{ 286 | 287 | border-color: $white-color; 288 | 289 | @include opacity(1); 290 | 291 | } 292 | 293 | } 294 | -------------------------------------------------------------------------------- /vk-burst-demo/aci-frontend/app/static/dashboard/assets/sass/paper/_sidebar-and-main-panel.scss: -------------------------------------------------------------------------------- 1 | .sidebar{ 2 | position: absolute; 3 | top: 0; 4 | bottom: 0; 5 | left: 0; 6 | z-index: 1; 7 | background-size: cover; 8 | background-position: center center; 9 | .sidebar-wrapper{ 10 | position: relative; 11 | max-height: none; 12 | min-height: 100%; 13 | overflow: hidden; 14 | width: 260px; 15 | z-index: 4; 16 | box-shadow: inset -1px 0px 0px 0px $medium-gray; 17 | } 18 | .sidebar-background{ 19 | position: absolute; 20 | z-index: 1; 21 | height: 100%; 22 | width: 100%; 23 | display: block; 24 | top: 0; 25 | left: 0; 26 | background-size: cover; 27 | background-position: center center; 28 | } 29 | 30 | } 31 | .sidebar, 32 | .off-canvas-sidebar{ 33 | width: 260px; 34 | display: block; 35 | font-weight: 200; 36 | 37 | .logo{ 38 | padding: 18px 0px; 39 | margin: 0 20px; 40 | 41 | p{ 42 | float: left; 43 | font-size: 20px; 44 | margin: 10px 10px; 45 | line-height: 20px; 46 | } 47 | 48 | .simple-text{ 49 | text-transform: uppercase; 50 | padding: $padding-small-vertical $padding-zero; 51 | display: block; 52 | font-size: $font-size-large; 53 | text-align: center; 54 | font-weight: $font-weight-normal; 55 | line-height: 30px; 56 | } 57 | } 58 | 59 | .nav{ 60 | margin-top: 20px; 61 | 62 | li{ 63 | > a{ 64 | margin: 10px 0px; 65 | padding-left: 25px; 66 | padding-right: 25px; 67 | 68 | opacity: .7; 69 | } 70 | 71 | &:hover > a{ 72 | opacity: 1; 73 | } 74 | 75 | &.active > a{ 76 | color: $primary-color; 77 | opacity: 1; 78 | 79 | &:before{ 80 | border-right: 17px solid $medium-gray; 81 | border-top: 17px solid transparent; 82 | border-bottom: 17px solid transparent; 83 | content: ""; 84 | display: inline-block; 85 | position: absolute; 86 | right: 0; 87 | top: 8px; 88 | } 89 | 90 | &:after{ 91 | border-right: 17px solid $bg-nude; 92 | border-top: 17px solid transparent; 93 | border-bottom: 17px solid transparent; 94 | content: ""; 95 | display: inline-block; 96 | position: absolute; 97 | right: -1px; 98 | top: 8px; 99 | } 100 | } 101 | } 102 | 103 | p{ 104 | margin: 0; 105 | line-height: 30px; 106 | font-size: 12px; 107 | font-weight: 600; 108 | text-transform: uppercase; 109 | } 110 | 111 | i{ 112 | font-size: 24px; 113 | float: left; 114 | margin-right: 15px; 115 | line-height: 30px; 116 | width: 30px; 117 | text-align: center; 118 | } 119 | } 120 | 121 | &:after, 122 | &:before{ 123 | display: block; 124 | content: ""; 125 | position: absolute; 126 | width: 100%; 127 | height: 100%; 128 | top: 0; 129 | left: 0; 130 | z-index: 2; 131 | background: $white-background-color; 132 | } 133 | 134 | &, 135 | &[data-background-color="white"]{ 136 | @include sidebar-background-color($white-background-color, $default-color); 137 | } 138 | &[data-background-color="black"]{ 139 | @include sidebar-background-color($black-background-color, $white-color); 140 | } 141 | 142 | &[data-active-color="primary"]{ 143 | @include sidebar-active-color($primary-color); 144 | } 145 | &[data-active-color="info"]{ 146 | @include sidebar-active-color($info-color); 147 | } 148 | &[data-active-color="success"]{ 149 | @include sidebar-active-color($success-color); 150 | } 151 | &[data-active-color="warning"]{ 152 | @include sidebar-active-color($warning-color); 153 | } 154 | &[data-active-color="danger"]{ 155 | @include sidebar-active-color($danger-color); 156 | } 157 | 158 | } 159 | 160 | .main-panel{ 161 | background-color: $bg-nude; 162 | position: relative; 163 | z-index: 2; 164 | float: right; 165 | width: $sidebar-width; 166 | min-height: 100%; 167 | 168 | > .content{ 169 | padding: 30px 15px; 170 | min-height: calc(100% - 123px); 171 | } 172 | 173 | > .footer{ 174 | border-top: 1px solid rgba(0, 0, 0, 0.1); 175 | } 176 | 177 | .navbar{ 178 | margin-bottom: 0; 179 | } 180 | } 181 | 182 | .sidebar, 183 | .main-panel{ 184 | overflow: auto; 185 | max-height: 100%; 186 | height: 100%; 187 | -webkit-transition-property: top,bottom; 188 | transition-property: top,bottom; 189 | -webkit-transition-duration: .2s,.2s; 190 | transition-duration: .2s,.2s; 191 | -webkit-transition-timing-function: linear,linear; 192 | transition-timing-function: linear,linear; 193 | -webkit-overflow-scrolling: touch; 194 | } 195 | -------------------------------------------------------------------------------- /vk-burst-demo/aci-frontend/app/static/dashboard/assets/sass/paper/_tables.scss: -------------------------------------------------------------------------------- 1 | .table{ 2 | thead, 3 | tbody, 4 | tfoot{ 5 | tr > th, 6 | tr > td{ 7 | border-top: 1px solid $table-line-color; 8 | } 9 | } 10 | > thead > tr > th{ 11 | border-bottom-width: 0; 12 | font-size: $font-size-h5; 13 | font-weight: $font-weight-light; 14 | } 15 | 16 | .radio, 17 | .checkbox{ 18 | margin-top: 0; 19 | margin-bottom: 22px; 20 | padding: 0; 21 | width: 15px; 22 | } 23 | > thead > tr > th, 24 | > tbody > tr > th, 25 | > tfoot > tr > th, 26 | > thead > tr > td, 27 | > tbody > tr > td, 28 | > tfoot > tr > td{ 29 | padding: 12px; 30 | vertical-align: middle; 31 | } 32 | 33 | .th-description{ 34 | max-width: 150px; 35 | } 36 | .td-price{ 37 | font-size: 26px; 38 | font-weight: $font-weight-light; 39 | margin-top: 5px; 40 | text-align: right; 41 | } 42 | .td-total{ 43 | font-weight: $font-weight-bold; 44 | font-size: $font-size-h5; 45 | padding-top: 20px; 46 | text-align: right; 47 | } 48 | 49 | .td-actions .btn{ 50 | 51 | &.btn-sm, 52 | &.btn-xs{ 53 | padding-left: 3px; 54 | padding-right: 3px; 55 | } 56 | } 57 | 58 | > tbody > tr{ 59 | position: relative; 60 | } 61 | } 62 | .table-striped{ 63 | tbody > tr:nth-of-type(2n+1) { 64 | background-color: #fff; 65 | } 66 | tbody > tr:nth-of-type(2n) { 67 | background-color: $pale-bg; 68 | } 69 | > thead > tr > th, 70 | > tbody > tr > th, 71 | > tfoot > tr > th, 72 | > thead > tr > td, 73 | > tbody > tr > td, 74 | > tfoot > tr > td{ 75 | padding: 15px 8px; 76 | } 77 | } -------------------------------------------------------------------------------- /vk-burst-demo/aci-frontend/app/static/dashboard/assets/sass/paper/_typography.scss: -------------------------------------------------------------------------------- 1 | h1, .h1, h2, .h2, h3, .h3, h4, .h4, h5, .h5, h6, .h6, p, .navbar, .brand, a, .td-name, td{ 2 | -moz-osx-font-smoothing: grayscale; 3 | -webkit-font-smoothing: antialiased; 4 | font-family: 'Muli', "Helvetica", Arial, sans-serif; 5 | } 6 | 7 | h1, .h1, h2, .h2, h3, .h3, h4, .h4{ 8 | font-weight: $font-weight-normal; 9 | margin: $margin-large-vertical 0 $margin-base-vertical; 10 | } 11 | 12 | h1, .h1 { 13 | font-size: $font-size-h1; 14 | } 15 | h2, .h2{ 16 | font-size: $font-size-h2; 17 | } 18 | h3, .h3{ 19 | font-size: $font-size-h3; 20 | line-height: 1.4; 21 | margin: 20px 0 10px; 22 | } 23 | h4, .h4{ 24 | font-size: $font-size-h4; 25 | font-weight: $font-weight-bold; 26 | line-height: 1.2em; 27 | } 28 | h5, .h5 { 29 | font-size: $font-size-h5; 30 | font-weight: $font-weight-normal; 31 | line-height: 1.4em; 32 | margin-bottom: 15px; 33 | } 34 | h6, .h6{ 35 | font-size: $font-size-h6; 36 | font-weight: $font-weight-bold; 37 | text-transform: uppercase; 38 | } 39 | p{ 40 | font-size: $font-paragraph; 41 | line-height: $line-height-general; 42 | } 43 | 44 | h1 small, h2 small, h3 small, h4 small, h5 small, h6 small, .h1 small, .h2 small, .h3 small, .h4 small, .h5 small, .h6 small, h1 .small, h2 .small, h3 .small, h4 .small, h5 .small, h6 .small, .h1 .small, .h2 .small, .h3 .small, .h4 .small, .h5 .small, .h6 .small { 45 | color: $dark-gray; 46 | font-weight: $font-weight-light; 47 | line-height: $line-height-general; 48 | } 49 | 50 | h1 small, h2 small, h3 small, h1 .small, h2 .small, h3 .small { 51 | font-size: 60%; 52 | } 53 | .title-uppercase{ 54 | text-transform: uppercase; 55 | } 56 | blockquote{ 57 | font-style: italic; 58 | } 59 | blockquote small{ 60 | font-style: normal; 61 | } 62 | .text-muted{ 63 | color: $medium-gray; 64 | } 65 | .text-primary, .text-primary:hover{ 66 | color: $primary-states-color; 67 | } 68 | .text-info, .text-info:hover{ 69 | color: $info-states-color; 70 | } 71 | .text-success, .text-success:hover{ 72 | color: $success-states-color; 73 | } 74 | .text-warning, .text-warning:hover{ 75 | color: $warning-states-color; 76 | } 77 | .text-danger, .text-danger:hover{ 78 | color: $danger-states-color; 79 | } 80 | .glyphicon{ 81 | line-height: 1; 82 | } 83 | strong{ 84 | color: $default-states-color; 85 | } 86 | .icon-primary{ 87 | color: $primary-color; 88 | } 89 | .icon-info{ 90 | color: $info-color; 91 | } 92 | .icon-success{ 93 | color: $success-color; 94 | } 95 | .icon-warning{ 96 | color: $warning-color; 97 | } 98 | .icon-danger{ 99 | color: $danger-color; 100 | } 101 | .chart-legend{ 102 | .text-primary, .text-primary:hover{ 103 | color: $primary-color; 104 | } 105 | .text-info, .text-info:hover{ 106 | color: $info-color; 107 | } 108 | .text-success, .text-success:hover{ 109 | color: $success-color; 110 | } 111 | .text-warning, .text-warning:hover{ 112 | color: $warning-color; 113 | } 114 | .text-danger, .text-danger:hover{ 115 | color: $danger-color; 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /vk-burst-demo/aci-frontend/app/static/dashboard/assets/sass/paper/mixins/_buttons.scss: -------------------------------------------------------------------------------- 1 | // Mixin for generating new styles 2 | @mixin btn-styles($btn-color, $btn-states-color) { 3 | border-color: $btn-color; 4 | color: $btn-color; 5 | 6 | &:hover, 7 | &:focus, 8 | &:active, 9 | &.active, 10 | .open > &.dropdown-toggle { 11 | background-color: $btn-color; 12 | color: $fill-font-color; 13 | border-color: $btn-color; 14 | .caret{ 15 | border-top-color: $fill-font-color; 16 | } 17 | } 18 | 19 | &.disabled, 20 | &:disabled, 21 | &[disabled], 22 | fieldset[disabled] & { 23 | &, 24 | &:hover, 25 | &:focus, 26 | &.focus, 27 | &:active, 28 | &.active { 29 | background-color: $transparent-bg; 30 | border-color: $btn-color; 31 | } 32 | } 33 | 34 | 35 | &.btn-fill { 36 | color: $white-color; 37 | background-color: $btn-color; 38 | @include opacity(1); 39 | 40 | &:hover, 41 | &:focus, 42 | &:active, 43 | &.active, 44 | .open > &.dropdown-toggle{ 45 | background-color: $btn-states-color; 46 | color: $white-color; 47 | border-color: $btn-states-color; 48 | } 49 | 50 | .caret{ 51 | border-top-color: $white-color; 52 | } 53 | } 54 | 55 | &.btn-simple { 56 | &:hover, 57 | &:focus, 58 | &:active, 59 | &.active, 60 | .open > &.dropdown-toggle{ 61 | background-color: $transparent-bg; 62 | color: $btn-states-color; 63 | } 64 | 65 | .caret{ 66 | border-top-color: $white-color; 67 | } 68 | } 69 | 70 | .caret{ 71 | border-top-color: $btn-color; 72 | } 73 | } 74 | 75 | 76 | @mixin btn-size($padding-vertical, $padding-horizontal, $font-size, $border, $line-height){ 77 | font-size: $font-size; 78 | border-radius: $border; 79 | padding: $padding-vertical $padding-horizontal; 80 | 81 | &.btn-simple{ 82 | padding: $padding-vertical + 2 $padding-horizontal; 83 | } 84 | 85 | } -------------------------------------------------------------------------------- /vk-burst-demo/aci-frontend/app/static/dashboard/assets/sass/paper/mixins/_cards.scss: -------------------------------------------------------------------------------- 1 | @mixin filter($color){ 2 | @if $color == #FFFFFF{ 3 | background-color: rgba($color,.91); 4 | } @else { 5 | background-color: rgba($color,.69); 6 | } 7 | } 8 | 9 | -------------------------------------------------------------------------------- /vk-burst-demo/aci-frontend/app/static/dashboard/assets/sass/paper/mixins/_chartist.scss: -------------------------------------------------------------------------------- 1 | // Scales for responsive SVG containers 2 | $ct-scales: ((1), (15/16), (8/9), (5/6), (4/5), (3/4), (2/3), (5/8), (1/1.618), (3/5), (9/16), (8/15), (1/2), (2/5), (3/8), (1/3), (1/4)) !default; 3 | $ct-scales-names: (ct-square, ct-minor-second, ct-major-second, ct-minor-third, ct-major-third, ct-perfect-fourth, ct-perfect-fifth, ct-minor-sixth, ct-golden-section, ct-major-sixth, ct-minor-seventh, ct-major-seventh, ct-octave, ct-major-tenth, ct-major-eleventh, ct-major-twelfth, ct-double-octave) !default; 4 | 5 | // Class names to be used when generating CSS 6 | $ct-class-chart: ct-chart !default; 7 | $ct-class-chart-line: ct-chart-line !default; 8 | $ct-class-chart-bar: ct-chart-bar !default; 9 | $ct-class-horizontal-bars: ct-horizontal-bars !default; 10 | $ct-class-chart-pie: ct-chart-pie !default; 11 | $ct-class-chart-donut: ct-chart-donut !default; 12 | $ct-class-label: ct-label !default; 13 | $ct-class-series: ct-series !default; 14 | $ct-class-line: ct-line !default; 15 | $ct-class-point: ct-point !default; 16 | $ct-class-area: ct-area !default; 17 | $ct-class-bar: ct-bar !default; 18 | $ct-class-slice-pie: ct-slice-pie !default; 19 | $ct-class-slice-donut: ct-slice-donut !default; 20 | $ct-class-grid: ct-grid !default; 21 | $ct-class-vertical: ct-vertical !default; 22 | $ct-class-horizontal: ct-horizontal !default; 23 | $ct-class-start: ct-start !default; 24 | $ct-class-end: ct-end !default; 25 | 26 | // Container ratio 27 | $ct-container-ratio: (1/1.618) !default; 28 | 29 | // Text styles for labels 30 | $ct-text-color: rgba(0, 0, 0, 0.4) !default; 31 | $ct-text-size: 0.9em !default; 32 | $ct-text-align: flex-start !default; 33 | $ct-text-justify: flex-start !default; 34 | $ct-text-line-height: 1; 35 | 36 | // Grid styles 37 | $ct-grid-color: rgba(0, 0, 0, 0.2) !default; 38 | $ct-grid-dasharray: 2px !default; 39 | $ct-grid-width: 1px !default; 40 | 41 | // Line chart properties 42 | $ct-line-width: 4px !default; 43 | $ct-line-dasharray: false !default; 44 | $ct-point-size: 10px !default; 45 | // Line chart point, can be either round or square 46 | $ct-point-shape: round !default; 47 | // Area fill transparency between 0 and 1 48 | $ct-area-opacity: 0.7 !default; 49 | 50 | // Bar chart bar width 51 | $ct-bar-width: 10px !default; 52 | 53 | // Donut width (If donut width is to big it can cause issues where the shape gets distorted) 54 | $ct-donut-width: 60px !default; 55 | 56 | // If set to true it will include the default classes and generate CSS output. If you're planning to use the mixins you 57 | // should set this property to false 58 | $ct-include-classes: true !default; 59 | 60 | // If this is set to true the CSS will contain colored series. You can extend or change the color with the 61 | // properties below 62 | $ct-include-colored-series: $ct-include-classes !default; 63 | 64 | // If set to true this will include all responsive container variations using the scales defined at the top of the script 65 | $ct-include-alternative-responsive-containers: $ct-include-classes !default; 66 | 67 | // Series names and colors. This can be extended or customized as desired. Just add more series and colors. 68 | $ct-series-names: (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) !default; 69 | $ct-series-colors: ( 70 | $info-color, 71 | $warning-color, 72 | $danger-color, 73 | $success-color, 74 | $primary-color, 75 | rgba($info-color,.8), 76 | rgba($success-color,.8), 77 | rgba($warning-color,.8), 78 | rgba($danger-color,.8), 79 | rgba($primary-color,.8), 80 | rgba($info-color,.6), 81 | rgba($success-color,.6), 82 | rgba($warning-color,.6), 83 | rgba($danger-color,.6), 84 | rgba($primary-color,.6) 85 | 86 | ) !default; 87 | 88 | // Paper Kit Colors 89 | 90 | .ct-blue{ 91 | stroke: $primary-color !important; 92 | } 93 | .ct-azure{ 94 | stroke: $info-color !important; 95 | } 96 | .ct-green{ 97 | stroke: $success-color !important; 98 | } 99 | .ct-orange{ 100 | stroke: $warning-color !important; 101 | } 102 | .ct-red{ 103 | stroke: $danger-color !important; 104 | } -------------------------------------------------------------------------------- /vk-burst-demo/aci-frontend/app/static/dashboard/assets/sass/paper/mixins/_icons.scss: -------------------------------------------------------------------------------- 1 | @mixin icon-background ($icon-url){ 2 | background-image : url($icon-url); 3 | 4 | } 5 | 6 | @mixin icon-shape ($size, $padding, $border-radius) { 7 | height: $size; 8 | width: $size; 9 | padding: $padding; 10 | border-radius: $border-radius; 11 | display: inline-table; 12 | 13 | } -------------------------------------------------------------------------------- /vk-burst-demo/aci-frontend/app/static/dashboard/assets/sass/paper/mixins/_inputs.scss: -------------------------------------------------------------------------------- 1 | @mixin input-size($padding-vertical, $padding-horizontal, $height){ 2 | padding: $padding-vertical $padding-horizontal; 3 | height: $height; 4 | } 5 | 6 | @mixin placeholder($color, $opacity){ 7 | color: $color; 8 | @include opacity(1); 9 | } 10 | 11 | @mixin light-form(){ 12 | border-radius: 0; 13 | border:0; 14 | padding: 0; 15 | background-color: transparent; 16 | 17 | } -------------------------------------------------------------------------------- /vk-burst-demo/aci-frontend/app/static/dashboard/assets/sass/paper/mixins/_labels.scss: -------------------------------------------------------------------------------- 1 | @mixin label-style(){ 2 | padding: $padding-label-vertical $padding-label-horizontal; 3 | border: 1px solid $default-color; 4 | border-radius: $border-radius-small; 5 | color: $default-color; 6 | font-weight: $font-weight-semi; 7 | font-size: $font-size-small; 8 | text-transform: uppercase; 9 | display: inline-block; 10 | vertical-align: middle; 11 | } 12 | 13 | @mixin label-color($color){ 14 | border-color: $color; 15 | color: $color; 16 | } 17 | @mixin label-color-fill($color){ 18 | border-color: $color; 19 | color: $white-color; 20 | background-color: $color; 21 | } -------------------------------------------------------------------------------- /vk-burst-demo/aci-frontend/app/static/dashboard/assets/sass/paper/mixins/_navbars.scss: -------------------------------------------------------------------------------- 1 | @mixin navbar-color($color){ 2 | background-color: $color; 3 | } 4 | 5 | @mixin center-item(){ 6 | left: 0; 7 | right: 0; 8 | margin-right: auto; 9 | margin-left: auto; 10 | position: absolute; 11 | } -------------------------------------------------------------------------------- /vk-burst-demo/aci-frontend/app/static/dashboard/assets/sass/paper/mixins/_sidebar.scss: -------------------------------------------------------------------------------- 1 | @mixin sidebar-background-color($background-color, $font-color){ 2 | &:after, 3 | &:before{ 4 | background-color: $background-color; 5 | } 6 | 7 | .logo{ 8 | border-bottom: 1px solid rgba($font-color,.3); 9 | 10 | p{ 11 | color: $font-color; 12 | } 13 | 14 | .simple-text{ 15 | color: $font-color; 16 | } 17 | } 18 | 19 | .nav{ 20 | li:not(.active){ 21 | > a{ 22 | color: $font-color; 23 | } 24 | } 25 | .divider{ 26 | background-color: rgba($font-color,.2); 27 | } 28 | 29 | } 30 | 31 | } 32 | 33 | @mixin sidebar-active-color($font-color){ 34 | .nav{ 35 | li{ 36 | &.active > a{ 37 | color: $font-color; 38 | opacity: 1; 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /vk-burst-demo/aci-frontend/app/static/dashboard/assets/sass/paper/mixins/_tabs.scss: -------------------------------------------------------------------------------- 1 | @mixin pill-style($color){ 2 | border: 1px solid $color; 3 | color: $color; 4 | } -------------------------------------------------------------------------------- /vk-burst-demo/aci-frontend/app/static/dashboard/assets/sass/paper/mixins/_transparency.scss: -------------------------------------------------------------------------------- 1 | // Opacity 2 | 3 | @mixin opacity($opacity) { 4 | opacity: $opacity; 5 | // IE8 filter 6 | $opacity-ie: ($opacity * 100); 7 | filter: #{alpha(opacity=$opacity-ie)}; 8 | } 9 | 10 | @mixin black-filter($opacity){ 11 | top: 0; 12 | left: 0; 13 | height: 100%; 14 | width: 100%; 15 | position: absolute; 16 | background-color: rgba(17,17,17,$opacity); 17 | display: block; 18 | content: ""; 19 | z-index: 1; 20 | } -------------------------------------------------------------------------------- /vk-burst-demo/aci-frontend/app/static/dashboard/assets/sass/paper/mixins/_vendor-prefixes.scss: -------------------------------------------------------------------------------- 1 | // User select 2 | // For selecting text on the page 3 | 4 | @mixin user-select($select) { 5 | -webkit-user-select: $select; 6 | -moz-user-select: $select; 7 | -ms-user-select: $select; // IE10+ 8 | user-select: $select; 9 | } 10 | 11 | @mixin box-shadow($shadow...) { 12 | -webkit-box-shadow: $shadow; // iOS <4.3 & Android <4.1 13 | box-shadow: $shadow; 14 | } 15 | 16 | // Box sizing 17 | @mixin box-sizing($boxmodel) { 18 | -webkit-box-sizing: $boxmodel; 19 | -moz-box-sizing: $boxmodel; 20 | box-sizing: $boxmodel; 21 | } 22 | 23 | 24 | @mixin transition($time, $type){ 25 | -webkit-transition: all $time $type; 26 | -moz-transition: all $time $type; 27 | -o-transition: all $time $type; 28 | -ms-transition: all $time $type; 29 | transition: all $time $type; 30 | } 31 | 32 | @mixin transition-none(){ 33 | -webkit-transition: none; 34 | -moz-transition: none; 35 | -o-transition: none; 36 | -ms-transition: none; 37 | transition: none; 38 | } 39 | 40 | @mixin transform-scale($value){ 41 | -webkit-transform: scale($value); 42 | -moz-transform: scale($value); 43 | -o-transform: scale($value); 44 | -ms-transform: scale($value); 45 | transform: scale($value); 46 | } 47 | 48 | @mixin transform-translate-x($value){ 49 | -webkit-transform: translate3d($value, 0, 0); 50 | -moz-transform: translate3d($value, 0, 0); 51 | -o-transform: translate3d($value, 0, 0); 52 | -ms-transform: translate3d($value, 0, 0); 53 | transform: translate3d($value, 0, 0); 54 | } 55 | 56 | @mixin transform-origin($coordinates){ 57 | -webkit-transform-origin: $coordinates; 58 | -moz-transform-origin: $coordinates; 59 | -o-transform-origin: $coordinates; 60 | -ms-transform-origin: $coordinates; 61 | transform-origin: $coordinates; 62 | } 63 | 64 | @mixin icon-gradient ($top-color, $bottom-color){ 65 | background: $top-color; 66 | background: -moz-linear-gradient(top, $top-color 0%, $bottom-color 100%); 67 | background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,$top-color), color-stop(100%,$bottom-color)); 68 | background: -webkit-linear-gradient(top, $top-color 0%,$bottom-color 100%); 69 | background: -o-linear-gradient(top, $top-color 0%,$bottom-color 100%); 70 | background: -ms-linear-gradient(top, $top-color 0%,$bottom-color 100%); 71 | background: linear-gradient(to bottom, $top-color 0%,$bottom-color 100%); 72 | background-size: 150% 150%; 73 | } 74 | 75 | @mixin radial-gradient($extern-color, $center-color){ 76 | background: $extern-color; 77 | background: -moz-radial-gradient(center, ellipse cover, $center-color 0%, $extern-color 100%); /* FF3.6+ */ 78 | background: -webkit-gradient(radial, center center, 0px, center center, 100%, color-stop(0%,$center-color), color-stop(100%,$extern-color)); /* Chrome,Safari4+ */ 79 | background: -webkit-radial-gradient(center, ellipse cover, $center-color 0%,$extern-color 100%); /* Chrome10+,Safari5.1+ */ 80 | background: -o-radial-gradient(center, ellipse cover, $center-color 0%,$extern-color 100%); /* Opera 12+ */ 81 | background: -ms-radial-gradient(center, ellipse cover, $center-color 0%,$extern-color 100%); /* IE10+ */ 82 | background: radial-gradient(ellipse at center, $center-color 0%,$extern-color 100%); /* W3C */ 83 | background-size: 550% 450%; 84 | } 85 | 86 | @mixin vertical-align { 87 | position: relative; 88 | top: 50%; 89 | -webkit-transform: translateY(-50%); 90 | -ms-transform: translateY(-50%); 91 | transform: translateY(-50%); 92 | } 93 | 94 | @mixin rotate-180(){ 95 | filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2); 96 | -webkit-transform: rotate(180deg); 97 | -ms-transform: rotate(180deg); 98 | transform: rotate(180deg); 99 | } 100 | 101 | @mixin bar-animation($type){ 102 | -webkit-animation: $type 500ms linear 0s; 103 | -moz-animation: $type 500ms linear 0s; 104 | animation: $type 500ms 0s; 105 | -webkit-animation-fill-mode: forwards; 106 | -moz-animation-fill-mode: forwards; 107 | animation-fill-mode: forwards; 108 | } 109 | 110 | @mixin topbar-x-rotation(){ 111 | @keyframes topbar-x { 112 | 0% {top: 0px; transform: rotate(0deg); } 113 | 45% {top: 6px; transform: rotate(145deg); } 114 | 75% {transform: rotate(130deg); } 115 | 100% {transform: rotate(135deg); } 116 | } 117 | @-webkit-keyframes topbar-x { 118 | 0% {top: 0px; -webkit-transform: rotate(0deg); } 119 | 45% {top: 6px; -webkit-transform: rotate(145deg); } 120 | 75% {-webkit-transform: rotate(130deg); } 121 | 100% { -webkit-transform: rotate(135deg); } 122 | } 123 | @-moz-keyframes topbar-x { 124 | 0% {top: 0px; -moz-transform: rotate(0deg); } 125 | 45% {top: 6px; -moz-transform: rotate(145deg); } 126 | 75% {-moz-transform: rotate(130deg); } 127 | 100% { -moz-transform: rotate(135deg); } 128 | } 129 | } 130 | 131 | @mixin topbar-back-rotation(){ 132 | @keyframes topbar-back { 133 | 0% { top: 6px; transform: rotate(135deg); } 134 | 45% { transform: rotate(-10deg); } 135 | 75% { transform: rotate(5deg); } 136 | 100% { top: 0px; transform: rotate(0); } 137 | } 138 | 139 | @-webkit-keyframes topbar-back { 140 | 0% { top: 6px; -webkit-transform: rotate(135deg); } 141 | 45% { -webkit-transform: rotate(-10deg); } 142 | 75% { -webkit-transform: rotate(5deg); } 143 | 100% { top: 0px; -webkit-transform: rotate(0); } 144 | } 145 | 146 | @-moz-keyframes topbar-back { 147 | 0% { top: 6px; -moz-transform: rotate(135deg); } 148 | 45% { -moz-transform: rotate(-10deg); } 149 | 75% { -moz-transform: rotate(5deg); } 150 | 100% { top: 0px; -moz-transform: rotate(0); } 151 | } 152 | } 153 | 154 | @mixin bottombar-x-rotation(){ 155 | @keyframes bottombar-x { 156 | 0% {bottom: 0px; transform: rotate(0deg);} 157 | 45% {bottom: 6px; transform: rotate(-145deg);} 158 | 75% {transform: rotate(-130deg);} 159 | 100% {transform: rotate(-135deg);} 160 | } 161 | @-webkit-keyframes bottombar-x { 162 | 0% {bottom: 0px; -webkit-transform: rotate(0deg);} 163 | 45% {bottom: 6px; -webkit-transform: rotate(-145deg);} 164 | 75% {-webkit-transform: rotate(-130deg);} 165 | 100% {-webkit-transform: rotate(-135deg);} 166 | } 167 | @-moz-keyframes bottombar-x { 168 | 0% {bottom: 0px; -moz-transform: rotate(0deg);} 169 | 45% {bottom: 6px; -moz-transform: rotate(-145deg);} 170 | 75% {-moz-transform: rotate(-130deg);} 171 | 100% {-moz-transform: rotate(-135deg);} 172 | } 173 | } 174 | 175 | @mixin bottombar-back-rotation{ 176 | @keyframes bottombar-back { 177 | 0% { bottom: 6px;transform: rotate(-135deg);} 178 | 45% { transform: rotate(10deg);} 179 | 75% { transform: rotate(-5deg);} 180 | 100% { bottom: 0px;transform: rotate(0);} 181 | } 182 | @-webkit-keyframes bottombar-back { 183 | 0% {bottom: 6px;-webkit-transform: rotate(-135deg);} 184 | 45% {-webkit-transform: rotate(10deg);} 185 | 75% {-webkit-transform: rotate(-5deg);} 186 | 100% {bottom: 0px;-webkit-transform: rotate(0);} 187 | } 188 | @-moz-keyframes bottombar-back { 189 | 0% {bottom: 6px;-moz-transform: rotate(-135deg);} 190 | 45% {-moz-transform: rotate(10deg);} 191 | 75% {-moz-transform: rotate(-5deg);} 192 | 100% {bottom: 0px;-moz-transform: rotate(0);} 193 | } 194 | 195 | } 196 | 197 | 198 | -------------------------------------------------------------------------------- /vk-burst-demo/aci-frontend/app/static/dashboard/changelog.txt: -------------------------------------------------------------------------------- 1 | V1.0, 29.03.2016 Original Release 2 | 3 | V1.1.0, 30 Sept 2016 - New Page 4 | - added Upgrade to PRO page for those who want to upsell inside the dashboard 5 | 6 | V1.1.1, 8 Feb 2017 7 | - switched to MIT license -------------------------------------------------------------------------------- /vk-burst-demo/aci-frontend/app/static/dashboard/documentation/css/documentation.css: -------------------------------------------------------------------------------- 1 | .nav-mobile-menu{ 2 | position: relative; 3 | z-index: 2; 4 | } 5 | .nav-mobile-menu li a p{ 6 | font-size: 12px; 7 | } 8 | 9 | .nav-mobile-menu .btn-simple, 10 | .nav-mobile-menu .btn-simple:hover, 11 | .nav-mobile-menu .btn-simple:focus{ 12 | color: #66615B; 13 | } 14 | .nav-mobile-menu .navbar-title{ 15 | display: none; 16 | } 17 | .navbar .navbar-nav > li > a.btn{ 18 | margin: 17px 3px; 19 | padding: 7px 18px; 20 | } 21 | .tim-row{ 22 | margin-bottom: 40px; 23 | } 24 | pre.prettyprint{ 25 | background-color: #eee; 26 | border: 0px; 27 | margin-bottom: 0; 28 | margin-top: 20px; 29 | padding: 20px; 30 | text-align: left; 31 | } 32 | .navbar-title{ 33 | height: 100%; 34 | padding-top: 5px; 35 | } 36 | .atv, .str{ 37 | color: #05AE0E; 38 | } 39 | .tag, .pln, .kwd{ 40 | color: #3472F7; 41 | } 42 | .atn{ 43 | color: #2C93FF; 44 | } 45 | .pln{ 46 | color: #333; 47 | } 48 | .com{ 49 | color: #999; 50 | } 51 | .navbar-title .image-container{ 52 | height: 40px; 53 | width: 40px; 54 | display: inline-block; 55 | top: -3px; 56 | position: relative; 57 | } 58 | .navbar-title img { 59 | width: 100%; 60 | } 61 | .space-top{ 62 | margin-top: 50px; 63 | } 64 | .btn-primary .caret{ 65 | border-top-color: #3472F7; 66 | color: #3472F7; 67 | } 68 | .area-line{ 69 | border: 1px solid #999; 70 | border-left: 0; 71 | border-right: 0; 72 | color: #666; 73 | display: block; 74 | margin-top: 20px; 75 | padding: 8px 0; 76 | text-align: center; 77 | } 78 | .area-line a{ 79 | color: #666; 80 | } 81 | .container-fluid{ 82 | padding-right: 15px; 83 | padding-left: 15px; 84 | } 85 | .logo-container .logo{ 86 | overflow: hidden; 87 | border-radius: 50%; 88 | border: 1px solid #333333; 89 | width: 50px; 90 | float: left; 91 | } 92 | .header-wrapper { 93 | position: relative; 94 | height: 500px; 95 | } 96 | 97 | .header-wrapper .navbar { 98 | border-radius: 0; 99 | /*position: absolute;*/ 100 | width: 100%; 101 | z-index: 1031; 102 | } 103 | .header-wrapper .header { 104 | background-color: #ff8f5e; 105 | background-position: center center; 106 | background-size: cover; 107 | height: 450px; 108 | overflow: hidden; 109 | position: absolute; 110 | width: 100%; 111 | z-index: 1; 112 | } 113 | .header-wrapper .header .filter::after { 114 | /* background: rgba(0, 0, 0, 0) linear-gradient(to bottom, #9368e9 0%, #943bea 100%) repeat scroll 0 0 / 150% 150%; */ 115 | content: ""; 116 | display: block; 117 | height: 450px; 118 | left: 0; 119 | opacity: 0.77; 120 | position: absolute; 121 | top: 0; 122 | width: 100%; 123 | z-index: 2; 124 | } 125 | .header-wrapper .title-container{ 126 | color: #fff; 127 | position: relative; 128 | top: 120px; 129 | z-index: 3; 130 | 131 | } 132 | .logo-container .brand{ 133 | font-size: 18px; 134 | color: #FFFFFF; 135 | line-height: 20px; 136 | float: left; 137 | margin-left: 10px; 138 | margin-top: 5px; 139 | width: 50px; 140 | height: 50px; 141 | } 142 | .logo-container{ 143 | margin-top: 10px; 144 | margin-left: 15px; 145 | } 146 | .logo-container .logo img{ 147 | width: 100%; 148 | } 149 | .title-container img{ 150 | width: 100px; 151 | height: 100px; 152 | } 153 | .navbar-small .logo-container .brand{ 154 | color: #333333; 155 | } 156 | .navbar-default.navbar-transparent .navbar-nav>li>a{ 157 | color: #FFFFFF; 158 | } 159 | .navbar-default .logo-container .brand{ 160 | color: #444; 161 | } 162 | .navbar-default.navbar-transparent .logo-container .brand{ 163 | color: #FFFFFF !important; 164 | } 165 | .navbar-center{ 166 | float: none; 167 | display: inline-block; 168 | margin-top: -16px; 169 | } 170 | .navbar.navbar-transparent{ 171 | background-color: transparent; 172 | box-shadow: none; 173 | color: #fff; 174 | border: 0; 175 | padding-top: 0px; 176 | } 177 | .fixed-section{ 178 | max-height: 80vh; 179 | overflow: scroll; 180 | top: 110px; 181 | } 182 | .fixed-section ul li{ 183 | list-style: none; 184 | } 185 | .fixed-section li a{ 186 | font-size: 14px; 187 | padding: 2px; 188 | display: block; 189 | color: #666666; 190 | } 191 | .fixed-section li a.active{ 192 | color: #00bbff; 193 | } 194 | .fixed-section.float{ 195 | position: fixed; 196 | top: 100px; 197 | width: 200px; 198 | margin-top: 0; 199 | } 200 | .copyright { 201 | color: #777777; 202 | padding: 10px 15px; 203 | font-size: 14px; 204 | margin: 15px 3px; 205 | line-height: 20px; 206 | text-align: center; 207 | } 208 | 209 | .table-bigboy .img-container{ 210 | width: 130px; 211 | height: 85px; 212 | } 213 | 214 | .table-bigboy .td-name{ 215 | min-width: 170px; 216 | } 217 | #buttons-row .btn{ 218 | margin-bottom: 15px; 219 | } 220 | @media (max-width: 991px) { 221 | .fixed-section.affix { 222 | position: relative; 223 | margin-bottom: 100px; 224 | } 225 | 226 | .tim-row .nav.nav-pills{ 227 | margin-bottom: 25px; 228 | } 229 | 230 | .nav-mobile-menu .navbar-title{ 231 | display: none; 232 | } 233 | 234 | } 235 | 236 | @media (max-width: 1199px) { 237 | 238 | .navbar .navbar-brand { 239 | height: 50px; 240 | padding: 10px 15px; 241 | } 242 | 243 | } 244 | 245 | @media (max-width: 768px) { 246 | .footer .copyright { 247 | display: inline-block; 248 | text-align: center; 249 | padding: 10px 0; 250 | float: none !important; 251 | width: 100%; 252 | } 253 | } 254 | 255 | @media (max-width: 830px){ 256 | .main-raised{ 257 | margin-left: 10px; 258 | margin-right: 10px; 259 | } 260 | } 261 | -------------------------------------------------------------------------------- /vk-burst-demo/aci-frontend/app/static/dashboard/maps.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Paper Dashboard by Creative Tim 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 42 | 43 | 44 | 45 | 46 | Creative Tim 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | Dashboard 55 | 56 | 57 | 58 | 59 | 60 | User Profile 61 | 62 | 63 | 64 | 65 | 66 | Table List 67 | 68 | 69 | 70 | 71 | 72 | Typography 73 | 74 | 75 | 76 | 77 | 78 | Icons 79 | 80 | 81 | 82 | 83 | 84 | Maps 85 | 86 | 87 | 88 | 89 | 90 | Notifications 91 | 92 | 93 | 94 | 95 | 96 | Upgrade to PRO 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | Toggle navigation 109 | 110 | 111 | 112 | 113 | Maps 114 | 115 | 116 | 117 | 118 | 119 | 120 | Stats 121 | 122 | 123 | 124 | 125 | 126 | 5 127 | Notifications 128 | 129 | 130 | 131 | Notification 1 132 | Notification 2 133 | Notification 3 134 | Notification 4 135 | Another notification 136 | 137 | 138 | 139 | 140 | 141 | Settings 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | Google Maps 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 224 | 225 | 226 | -------------------------------------------------------------------------------- /vk-burst-demo/aci-frontend/app/static/dashboard/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Paper Dashboard by Creative Tim 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 42 | 43 | 44 | 45 | 46 | Creative Tim 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | Dashboard 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | Toggle navigation 68 | 69 | 70 | 71 | 72 | Template 73 | 74 | 75 | 76 | 77 | 78 | 79 | Stats 80 | 81 | 82 | 83 | 84 | 85 | 5 86 | Notifications 87 | 88 | 89 | 90 | Notification 1 91 | Notification 2 92 | Notification 3 93 | Notification 4 94 | Another notification 95 | 96 | 97 | 98 | 99 | 100 | Settings 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | -------------------------------------------------------------------------------- /vk-burst-demo/aci-frontend/app/static/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rbitia/aci-demos/b334d304196e99e0ded4406357ff28dd1a78936c/vk-burst-demo/aci-frontend/app/static/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /vk-burst-demo/aci-frontend/app/static/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rbitia/aci-demos/b334d304196e99e0ded4406357ff28dd1a78936c/vk-burst-demo/aci-frontend/app/static/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /vk-burst-demo/aci-frontend/app/static/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rbitia/aci-demos/b334d304196e99e0ded4406357ff28dd1a78936c/vk-burst-demo/aci-frontend/app/static/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /vk-burst-demo/aci-frontend/app/static/js/npm.js: -------------------------------------------------------------------------------- 1 | // This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment. 2 | require('../../js/transition.js') 3 | require('../../js/alert.js') 4 | require('../../js/button.js') 5 | require('../../js/carousel.js') 6 | require('../../js/collapse.js') 7 | require('../../js/dropdown.js') 8 | require('../../js/modal.js') 9 | require('../../js/tooltip.js') 10 | require('../../js/popover.js') 11 | require('../../js/scrollspy.js') 12 | require('../../js/tab.js') 13 | require('../../js/affix.js') -------------------------------------------------------------------------------- /vk-burst-demo/aci-frontend/app/test.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from hello import app 4 | 5 | 6 | class TestPost(unittest.TestCase): 7 | def test_post(self): 8 | 9 | self.test_app = app.test_client() 10 | 11 | response = self.test_app.get('/', content_type='html/text') 12 | self.assertEqual(response.status_code, 200) 13 | 14 | if __name__ == '__main__': 15 | unittest.main() 16 | -------------------------------------------------------------------------------- /vk-burst-demo/aci-webserver/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:14.04 2 | MAINTAINER Samuel Kreter 3 | 4 | ENV DEBIAN_FRONTEND noninteractive 5 | 6 | RUN apt-get update && apt-get install -y \ 7 | python3-pip python3-dev \ 8 | sqlite3 libsqlite3-dev \ 9 | build-essential libssl-dev libffi-dev 10 | 11 | 12 | COPY ./app/requirements.txt . 13 | RUN pip3 install -r ./requirements.txt 14 | 15 | COPY app/ /app 16 | WORKDIR /app 17 | 18 | CMD ["python3", "run.py"] 19 | -------------------------------------------------------------------------------- /vk-burst-demo/aci-webserver/README.md: -------------------------------------------------------------------------------- 1 | ## Creating the docker image 2 | 1. Inside the directory run docker build 3 | 4 | `docker build -t .` 5 | 6 | 2. You should now be able to see the docker images using: `docker images` 7 | 8 | ## Running the image 9 | 10 | On Docker host run: `docker run -d -p 80:80 ` 11 | 12 | On Docker machine run: `docker run -d -p 80:80 ` 13 | 14 | Docker compose: `docker-compose up -d` 15 | 16 | 17 | ### Credits 18 | Base image 19 | Source code: https://github.com/p0bailey/docker-flask 20 | DockerHub: https://hub.docker.com/r/p0bailey/docker-flask/ 21 | 22 | 23 | -------------------------------------------------------------------------------- /vk-burst-demo/aci-webserver/app/dbAzureBlob.py: -------------------------------------------------------------------------------- 1 | #By Sam Kreter 2 | #For use by Microsoft and other parties to demo 3 | #Azure Container Service, Azure Container Instances 4 | #and the experimental ACI-connector 5 | import os 6 | from azure.storage.blob import BlockBlobService 7 | import sqlite3 8 | 9 | 10 | COPY_PICS_NUM = 1 11 | DATABASE_NAME = os.getenv('DB_PATH', "") + 'jobs.db' 12 | 13 | class DbAzureBlob: 14 | 15 | def __init__(self): 16 | AZURE_BLOB_ACCOUNT = os.environ.get('AZURE_BLOB_ACCOUNT') 17 | 18 | if not AZURE_BLOB_ACCOUNT: 19 | raise EnvironmentError("Must have env variables AZURE_BLOB_ACCOUNT set for this to work.") 20 | 21 | self.block_blob_service = BlockBlobService(account_name= AZURE_BLOB_ACCOUNT) 22 | 23 | 24 | def getImageFromAzureBlob(self,filename_src, filename_dest): 25 | try: 26 | self.block_blob_service.get_blob_to_path('pictures', filename_src, filename_dest) 27 | return True 28 | except Exception as ex: 29 | print("getImageFromAzureBlob: ", ex) 30 | return False 31 | 32 | 33 | def getAllImagesFromAzureBlob(self,container,dest_folder): 34 | generator = self.block_blob_service.list_blobs('pictures') 35 | 36 | success = [] 37 | 38 | for blob in generator: 39 | try: 40 | self.block_blob_service.get_blob_to_path(container, blob.name, dest_folder + blob.name) 41 | success.append(True) 42 | except Exception as ex: 43 | print("getAllImagesFromAzureBlob: ", ex) 44 | success.append(False) 45 | 46 | return all(success) 47 | 48 | def doubleDatabase(self): 49 | conn = sqlite3.connect(DATABASE_NAME) 50 | cursor = conn.execute("SELECT * FROM jobs;") 51 | for row in cursor: 52 | conn.execute("INSERT INTO jobs (filename) \ 53 | VALUES (\"" + row[1] + "\");") 54 | conn.commit() 55 | 56 | def setupDatabase(self): 57 | conn = sqlite3.connect(DATABASE_NAME) 58 | print("Reseting the database") 59 | 60 | conn.execute('''DROP TABLE IF EXISTS jobs;''') 61 | conn.execute(''' 62 | CREATE TABLE jobs ( 63 | id INTEGER PRIMARY KEY AUTOINCREMENT, 64 | filename NOT NULL, 65 | processed INTEGER DEFAULT 0 NOT NULL, 66 | detected INTEGER DEFAULT NULL, 67 | start_time INTEGER DEFAULT NULL, 68 | end_time INTEGER DEFAULT NULL, 69 | worker_id TEXT DEFAULT NULL, 70 | processed_time DEFAULT NULL 71 | ); 72 | ''') 73 | 74 | conn.commit() 75 | 76 | generator = self.block_blob_service.list_blobs('pictures') 77 | for blob in generator: 78 | if(blob.name[:2] == "._"): 79 | blob.name = blob.name[2:] 80 | for i in range(COPY_PICS_NUM): 81 | conn.execute("INSERT INTO jobs (filename) \ 82 | VALUES (\"" + blob.name + "\");") 83 | 84 | conn.commit() 85 | -------------------------------------------------------------------------------- /vk-burst-demo/aci-webserver/app/requirements.txt: -------------------------------------------------------------------------------- 1 | flask 2 | jsonify 3 | flask-cors 4 | cryptography==2.0.3 5 | azure-storage-blob -------------------------------------------------------------------------------- /vk-burst-demo/aci-webserver/app/run.py: -------------------------------------------------------------------------------- 1 | #!flask/bin/python 2 | 3 | #By Sam Kreter 4 | #For use by Microsoft and other parties to demo 5 | #Azure Container Service, Azure Container Instances 6 | #and the experimental ACI-connector 7 | from flask import Flask, render_template, request, Response 8 | from flask_cors import CORS 9 | import json 10 | import sqlite3 11 | import requests 12 | from datetime import datetime 13 | from datetime import timedelta 14 | import os 15 | from dbAzureBlob import DbAzureBlob, DATABASE_NAME 16 | 17 | import logging 18 | from logging.handlers import RotatingFileHandler 19 | import urllib 20 | 21 | app = Flask(__name__) 22 | 23 | @app.route('/api') 24 | def index(): 25 | dbHelper = DbAzureBlob() 26 | 27 | if not os.path.isfile(DATABASE_NAME): 28 | print("reseting") 29 | dbHelper.setupDatabase() 30 | 31 | conn = sqlite3.connect(DATABASE_NAME) 32 | 33 | row = conn.execute("SELECT * FROM jobs WHERE processed = 0 ORDER BY RANDOM() LIMIT 1").fetchone() 34 | 35 | if(row == None ): 36 | return json.dumps({ 37 | 'filename':"NULL", 38 | 'processed':1, 39 | }) 40 | 41 | id = row[0] 42 | filename = row[1] 43 | conn.close() 44 | 45 | return Response(json.dumps({'id': id, 'filename': filename, 'processed': 0 }), status=200, mimetype='application/json') 46 | 47 | @app.route('/api/test') 48 | def liveTest(): 49 | return Response(json.dumps({'status': 'ok!'}), status=200, mimetype='application/json') 50 | 51 | @app.route('/api/processed') 52 | def processed(): 53 | if not os.path.isfile(DATABASE_NAME): 54 | DbAzureBlob().setupDatabase() 55 | 56 | conn = sqlite3.connect(DATABASE_NAME) 57 | id = request.args.get('id') 58 | filename = urllib.parse.unquote(request.args.get('filename')) 59 | detected = request.args.get('detected') 60 | start_time = request.args.get('start_time') 61 | end_time = request.args.get('end_time') 62 | worker_id = request.args.get('worker_id') 63 | if(filename == None or detected == None): 64 | return json.dumps({"success":True,"status_code":200}) 65 | 66 | conn.execute("UPDATE jobs set detected = ? , start_time = ? , end_time = ? , worker_id = ? where filename = ?", (str2bool(detected), start_time, end_time, worker_id, filename ) ) 67 | 68 | conn.commit() 69 | 70 | conn.close() 71 | return json.dumps({"success":True,"status_code":200}) 72 | 73 | 74 | @app.route('/api/resetDb') 75 | def resetDb(): 76 | ''' Use to delete the cache db and start the process again''' 77 | os.remove(DATABASE_NAME) 78 | 79 | return json.dumps({"success":True,"status_code":200}) 80 | 81 | 82 | @app.route('/api/reuseDb') 83 | def reuseDb(): 84 | 85 | if not os.path.isfile(DATABASE_NAME): 86 | return request.args.get('callback') + "(" + json.dumps({"success":False}) + ")" 87 | 88 | conn = sqlite3.connect(DATABASE_NAME) 89 | conn.execute("UPDATE jobs set detected = NULL, start_time = NULL, end_time = NULL, processed = 0, worker_id = NULL, processed_time = NULL;" ) 90 | conn.commit() 91 | 92 | return json.dumps({"success": True}) 93 | #return request.args.get('callback') + "(" + json.dumps({"success":True}) + ")" 94 | 95 | @app.route('/api/getFile') 96 | def getFile(): 97 | if not os.path.isfile(DATABASE_NAME): 98 | DbAzureBlob().setupDatabase() 99 | 100 | conn = sqlite3.connect(DATABASE_NAME) 101 | 102 | timeout_time = datetime.utcnow() - timedelta(seconds=45) 103 | row = conn.execute("SELECT * FROM jobs WHERE processed = 0 or (processed = 1 and detected is NULL and processed_time < ?) ORDER BY RANDOM() LIMIT 1 ;", (timeout_time,)).fetchone() 104 | 105 | if(row == None ): 106 | return json.dumps({ 107 | 'filename':"NULL", 108 | 'processed':1, 109 | }) 110 | 111 | id = row[0] 112 | filename = row[1] 113 | 114 | conn.execute("UPDATE jobs set processed = 1, processed_time = ? where id = ? ;", (datetime.utcnow(), id)) 115 | conn.commit() 116 | 117 | conn.close() 118 | 119 | return Response(json.dumps({'id': id, 'filename': filename, 'processed': 0}), status=200, mimetype='application/json') 120 | 121 | 122 | @app.route('/api/getProgress') 123 | def getProgress(): 124 | if not os.path.isfile(DATABASE_NAME): 125 | DbAzureBlob().setupDatabase() 126 | req_start_time = datetime.utcnow() 127 | 128 | TIME_SPAN = 30 129 | processed_count = 0 130 | total_time = 0 131 | current_time = datetime.utcnow() 132 | 133 | conn = sqlite3.connect(DATABASE_NAME) 134 | total_rows = conn.execute("SELECT COUNT(*) FROM jobs").fetchone()[0] 135 | rows = conn.execute("SELECT * FROM jobs WHERE detected IS NOT NULL;").fetchall() 136 | if len(rows) > 0 : 137 | time_range = conn.execute("SELECT MIN(start_time), MAX(end_time) from jobs WHERE detected IS NOT NULL;").fetchone() 138 | start_time = datetime.strptime(time_range[0], '%Y-%m-%d %H:%M:%S.%f') 139 | interval_start_time = current_time - timedelta(seconds=TIME_SPAN) 140 | processed_count = conn.execute("SELECT COUNT(*) FROM jobs WHERE detected IS NOT NULL AND end_time > ? ;", (str(interval_start_time),)).fetchone()[0] 141 | conn.close() 142 | 143 | speed = processed_count / TIME_SPAN 144 | 145 | if (len(rows) == 0): 146 | total_time = 0 147 | elif (len(rows) != total_rows): 148 | total_time = (current_time - start_time).total_seconds() 149 | else: 150 | total_time = (datetime.strptime(time_range[1], '%Y-%m-%d %H:%M:%S.%f') - start_time).total_seconds() 151 | 152 | pictures = [] 153 | 154 | for row in rows: 155 | obj = { 156 | "filename": row[1], 157 | "detected": row[3] 158 | } 159 | pictures.append(obj) 160 | 161 | data = { 162 | "success": True, 163 | "pictures": pictures, 164 | "speed": speed, 165 | "speed_time": str(current_time), 166 | "total_period": int(total_time) 167 | } 168 | 169 | json_data = json.dumps(data) 170 | 171 | req_end_time = datetime.utcnow() 172 | print("request spend: " + str((req_start_time - req_end_time).total_seconds())) 173 | return json_data 174 | 175 | def str2bool(v): 176 | return v.lower() in ("yes", "true", "t", "1") 177 | 178 | 179 | if __name__ == '__main__': 180 | app.run(debug=True,host='0.0.0.0',port=8000) 181 | 182 | 183 | -------------------------------------------------------------------------------- /vk-burst-demo/aci-webserver/app/test.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from hello import app 4 | 5 | 6 | class TestPost(unittest.TestCase): 7 | def test_post(self): 8 | 9 | self.test_app = app.test_client() 10 | 11 | response = self.test_app.get('/', content_type='html/text') 12 | self.assertEqual(response.status_code, 200) 13 | 14 | if __name__ == '__main__': 15 | unittest.main() 16 | -------------------------------------------------------------------------------- /vk-burst-demo/aci-webserver/setupJobserver.ps1: -------------------------------------------------------------------------------- 1 | docker stop $(docker ps -a -q) 2 | docker rm $(docker ps -a -q) 3 | docker build -t jobserver . 4 | docker run -p 80:80 --env-file ../.env -v ./logs/:/var/log/uwsgi/app/ jobserver 5 | 6 | -------------------------------------------------------------------------------- /vk-burst-demo/aci-worker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:14.04 2 | 3 | MAINTAINER Ria Bhatia 4 | 5 | RUN apt-get update \ 6 | && apt-get upgrade -y \ 7 | && apt-get install -y unzip wget build-essential \ 8 | cmake git pkg-config libswscale-dev \ 9 | python3-dev python3-numpy python3-pip \ 10 | libtbb2 libtbb-dev libjpeg-dev libffi-dev \ 11 | libpng-dev libtiff-dev libjasper-dev libssl-dev \ 12 | python-opencv 13 | 14 | RUN PYTHONPATH=/usr/lib/python3.0 15 | RUN export $PYTHONPATH 16 | RUN #!/bin/bash ~/.bashrc 17 | 18 | RUN cd \ 19 | && wget https://github.com/opencv/opencv/archive/3.1.0.zip \ 20 | && unzip 3.1.0.zip \ 21 | && cd opencv-3.1.0 \ 22 | && mkdir build \ 23 | && cd build \ 24 | && cmake .. \ 25 | && make -j3 \ 26 | && make install \ 27 | && cd \ 28 | && rm 3.1.0.zip \ 29 | && rm -rf opencv-3.1.0 30 | 31 | COPY ./app/requirements.txt . 32 | RUN pip3 install -r ./requirements.txt 33 | 34 | COPY app/ /app 35 | WORKDIR /app 36 | CMD ["python3", "run.py"] 37 | -------------------------------------------------------------------------------- /vk-burst-demo/aci-worker/README.md: -------------------------------------------------------------------------------- 1 | 2 | Create Docker Image 3 | 4 | `docker build -t imagerec .` 5 | 6 | Run the image in a container 7 | 8 | `docker run imagerec` 9 | -------------------------------------------------------------------------------- /vk-burst-demo/aci-worker/app/dbAzureBlob.py: -------------------------------------------------------------------------------- 1 | #By Sam Kreter 2 | #For use by Microsoft and other parties to demo 3 | #Azure Container Service, Azure Container Instances 4 | #and the experimental ACI-connector 5 | import os 6 | from azure.storage.blob import BlockBlobService 7 | import sqlite3 8 | 9 | 10 | COPY_PICS_NUM = 1 11 | 12 | class DbAzureBlob: 13 | 14 | def __init__(self): 15 | AZURE_BLOB_ACCOUNT = os.environ.get('AZURE_BLOB_ACCOUNT') 16 | 17 | if not AZURE_BLOB_ACCOUNT: 18 | raise EnvironmentError("Must have env variables AZURE_BLOB_ACCOUNT set for this to work.") 19 | 20 | self.block_blob_service = BlockBlobService(account_name= AZURE_BLOB_ACCOUNT) 21 | 22 | 23 | def getImageFromAzureBlob(self,filename_src, filename_dest): 24 | try: 25 | self.block_blob_service.get_blob_to_path('pictures', filename_src, filename_dest) 26 | return True 27 | except Exception as ex: 28 | print("getImageFromAzureBlob: ", ex) 29 | return False 30 | 31 | 32 | def getAllImagesFromAzureBlob(self,container,dest_folder): 33 | generator = self.block_blob_service.list_blobs('pictures') 34 | 35 | success = [] 36 | 37 | for blob in generator: 38 | try: 39 | self.block_blob_service.get_blob_to_path(container, blob.name, dest_folder + blob.name) 40 | success.append(True) 41 | except Exception as ex: 42 | print("getAllImagesFromAzureBlob: ", ex) 43 | success.append(False) 44 | 45 | return all(success) 46 | 47 | def doubleDatabase(self): 48 | conn = sqlite3.connect('jobs.db') 49 | cursor = conn.execute("SELECT * FROM jobs;") 50 | for row in cursor: 51 | conn.execute("INSERT INTO jobs (filename) \ 52 | VALUES (\"" + row[1] + "\");") 53 | conn.commit() 54 | 55 | def setupDatabase(self): 56 | conn = sqlite3.connect('jobs.db') 57 | 58 | conn.execute('''DROP TABLE IF EXISTS jobs;''') 59 | conn.execute(''' 60 | CREATE TABLE jobs ( 61 | id INTEGER PRIMARY KEY AUTOINCREMENT, 62 | filename NOT NULL, 63 | processed INTEGER DEFAULT 0 NOT NULL, 64 | detected INTEGER DEFAULT NULL 65 | ); 66 | ''') 67 | 68 | conn.execute('DROP TABLE IF EXISTS time;') 69 | conn.execute(''' 70 | CREATE TABLE time ( 71 | id INTEGER PRIMARY KEY, 72 | start_time TEXT, 73 | end_time TEXT, 74 | finished INTEGER, 75 | started INTEGER 76 | ); 77 | ''') 78 | 79 | conn.execute('INSERT INTO time values(1,"2017-09-23 18:28:24","2017-09-23 18:28:24",0,0);') 80 | 81 | generator = self.block_blob_service.list_blobs('pictures') 82 | for blob in generator: 83 | if(blob.name[:2] == "._"): 84 | blob.name = blob.name[2:] 85 | for i in range(COPY_PICS_NUM): 86 | conn.execute("INSERT INTO jobs (filename) \ 87 | VALUES (\"" + blob.name + "\");") 88 | 89 | conn.commit() 90 | -------------------------------------------------------------------------------- /vk-burst-demo/aci-worker/app/requirements.txt: -------------------------------------------------------------------------------- 1 | pillow 2 | image 3 | cryptography==2.0.3 4 | azure-storage-blob 5 | -------------------------------------------------------------------------------- /vk-burst-demo/aci-worker/app/run.py: -------------------------------------------------------------------------------- 1 | 2 | #By Ria Bhatia 3 | #Helpful sources: OpenCV tutorials 4 | #For use by Microsoft and other parties to demo 5 | #Azure Container Service, Azure Container Instances 6 | #and the experimental ACI-connector 7 | 8 | import sys 9 | import numpy as np 10 | import cv2 11 | from PIL import Image 12 | import glob 13 | import os 14 | import socket 15 | import time 16 | import datetime 17 | import requests 18 | import urllib.parse 19 | 20 | from dbAzureBlob import DbAzureBlob 21 | 22 | PICTURE_DIR = "" 23 | 24 | start_time = datetime.datetime.utcnow() # Start the timer 25 | 26 | def detect(img, cascade, eyeCascade): # Figure out if the image has a face 27 | rects, eyes = [], [] 28 | try: 29 | rects = cascade.detectMultiScale(img, scaleFactor=1.3, minNeighbors=4, minSize=(30, 30),flags=cv2.CASCADE_SCALE_IMAGE) 30 | print ("rects", rects) 31 | for (x,y,w,h) in rects: 32 | roi_gray = gray[y:y+h, x:x+w] 33 | eyes = eyeCascade.detectMultiScale(roi_gray) 34 | print("eyes:", eyes) 35 | if len(eyes): 36 | return True # face found 37 | 38 | except Exception as e: 39 | print(e) 40 | 41 | return False # no face found 42 | 43 | 44 | def getFilename(url): 45 | try: 46 | r = requests.get(url + "/getFile") 47 | except: 48 | print('url is false') 49 | return False 50 | 51 | if(r == None): 52 | print('Worker: No Request') 53 | return False 54 | 55 | if(r.status_code != 200): 56 | print('Worker: Status code not 200') 57 | return False 58 | 59 | return r.json() 60 | 61 | #grab the filename request 62 | def sendRes(url, filename, detected, start_time, end_time): 63 | try: 64 | r = requests.get(url + "/processed", params={ 65 | "detected":detected, 66 | "filename":urllib.parse.quote(filename), 67 | "start_time": start_time, 68 | "end_time": end_time, 69 | "worker_id": socket.gethostname() 70 | }) 71 | except: 72 | print("Failed to send response") 73 | 74 | #make a request 75 | jobserver_url = "http://" + os.getenv('IP_JOB_SERVER', "localhost") + "/api" 76 | print("JOB SERVER URL: ", jobserver_url) 77 | 78 | counter = 0 79 | 80 | dbHelper = DbAzureBlob() 81 | 82 | while True: 83 | response = getFilename(jobserver_url) 84 | 85 | if(response == False): 86 | print("Failed to get response from jobserver") 87 | time.sleep(5) 88 | continue 89 | 90 | if(response['processed'] == 1): 91 | print("response is processed") 92 | time.sleep(5) 93 | 94 | filename = response['filename'] 95 | 96 | if (filename == "NULL"): 97 | print("Get empty image url") 98 | time.sleep(5) 99 | continue 100 | 101 | realFilename = filename 102 | 103 | if(filename[:2] == "._"): 104 | filename = filename[2:] 105 | 106 | process_start_time = datetime.datetime.utcnow() 107 | 108 | if(not dbHelper.getImageFromAzureBlob(filename, PICTURE_DIR + filename)): 109 | msg = "Failed to get image " + filename 110 | print(msg) 111 | sleep(5) 112 | continue 113 | 114 | download_end_time = datetime.datetime.utcnow() 115 | print("Got image: ", filename, " from blob " + "in " + str((download_end_time - process_start_time).total_seconds())) 116 | img = cv2.imread(PICTURE_DIR + filename) 117 | os.remove(PICTURE_DIR + filename) 118 | 119 | if img is None: 120 | print("Image is none!") 121 | continue 122 | 123 | cascade = cv2.CascadeClassifier('./haarcascade_frontalface_default.xml') 124 | eyeCascade = cv2.CascadeClassifier('./haarcascade_eye.xml') 125 | gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 126 | gray = cv2.equalizeHist(gray) 127 | face = detect(gray, cascade, eyeCascade) 128 | 129 | detect_end_time = datetime.datetime.utcnow() 130 | print("face found:" + str(face) + " in: ", realFilename, " spend:" + str((detect_end_time - process_start_time).total_seconds())) 131 | sendRes(jobserver_url,realFilename, face , process_start_time, detect_end_time) 132 | -------------------------------------------------------------------------------- /vk-burst-demo/aci-worker/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1beta1 2 | kind: Deployment 3 | metadata: 4 | name: facial-recognition 5 | namespace: default 6 | spec: 7 | replicas: 100 8 | template: 9 | metadata: 10 | labels: 11 | app: facial-recognition 12 | spec: 13 | containers: 14 | - name: facial-recognition 15 | image: rbitia/aci-demo:latest 16 | imagePullPolicy: Always 17 | dnsPolicy: ClusterFirst 18 | # Tolerate the ACI taint to get the scheduler to schedule it. 19 | tolerations: 20 | - key: azure.com/aci 21 | effect: NoSchedule 22 | -------------------------------------------------------------------------------- /vk-burst-demo/aci-worker/metricsCompilation.yaml: -------------------------------------------------------------------------------- 1 | kind: Service 2 | apiVersion: v1 3 | metadata: 4 | name: aci-demo-service 5 | spec: 6 | selector: 7 | app: collectionApp 8 | ports: 9 | -name: http 10 | protocol: TCP 11 | port: 80 12 | targetPort:9376 13 | -------------------------------------------------------------------------------- /vk-burst-demo/assignFQDNtoIP.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | while getopts "g:d:i:" opt; do 4 | case $opt in 5 | g) 6 | echo "Resource Group is $OPTARG" 7 | RESOURCEGROUP=$OPTARG 8 | ;; 9 | d) 10 | echo "DNS name is $OPTARG" 11 | DNSNAME=$OPTARG 12 | ;; 13 | i) 14 | echo "IP is $OPTARG" 15 | IP=$OPTARG 16 | ;; 17 | \?) 18 | echo "Invalid option: -$OPTARG" 19 | ;; 20 | esac 21 | done 22 | 23 | # Get resource group and public ip name 24 | RESOURCEGROUP=$(az network public-ip list --query "[?ipAddress!=null]|[?contains(ipAddress, '$IP')].[resourceGroup]" --output tsv) 25 | PIPNAME=$(az network public-ip list --query "[?ipAddress!=null]|[?contains(ipAddress, '$IP')].[name]" --output tsv) 26 | 27 | # Update public ip address with dns name 28 | echo "Start assigning domain name to IP $IP..." 29 | az network public-ip update --resource-group $RESOURCEGROUP --name $PIPNAME --dns-name $DNSNAME >/dev/null 30 | 31 | az network public-ip list --query "[?ipAddress=='$IP']|[0].dnsSettings.fqdn" 32 | -------------------------------------------------------------------------------- /vk-burst-demo/buildPush.sh: -------------------------------------------------------------------------------- 1 | rm aci-webserver/app/jobs.db 2 | docker build -t rbitia/aci-webserver:latest aci-webserver/. 3 | docker build -t rbitia/fr-frontend:latest aci-frontend/. 4 | docker build -t rbitia/fr-ir:latest aci-worker/. 5 | 6 | docker push rbitia/aci-webserver:latest 7 | docker push rbitia/fr-frontend:latest 8 | docker push rbitia/fr-ir:latest 9 | 10 | helm del --purge demo 11 | helm install charts/fr-demo --name demo 12 | kubectl get po --watch 13 | -------------------------------------------------------------------------------- /vk-burst-demo/charts/README.md: -------------------------------------------------------------------------------- 1 | # Helm Charts 2 | 3 | ## Prerequisites: 4 | 5 | - You have an ACS cluster set up, and `kubectl` is pointing to it 6 | - You have installed `aci-connector` and verified that it is working 7 | - You have Helm installed, and have run `helm init` on your cluster 8 | - Because of a bug in ACS, you might have to do this: 9 | 10 | ``` 11 | $ export TILLER_NAMESPACE=aci-demo 12 | $ kubectl create namespace aci-demo 13 | $ helm init 14 | ``` 15 | 16 | ## Install Demo 17 | 18 | Assuming you are starting at the top of the aci-demos repository: 19 | 20 | 21 | ``` 22 | $ helm inspect values charts/aci-demo > custom.yaml 23 | $ # edit custom.yaml 24 | $ helm install -n aci-demo -f custom.yaml charts/aci-demo 25 | ``` 26 | 27 | Read the output of that command carefully! It will tell you how to connect to 28 | the UI. 29 | 30 | ## See what you've done 31 | 32 | You should have two deployments: 33 | 34 | ``` 35 | $ kubectl get deploy 36 | ``` 37 | 38 | You should have one service: 39 | 40 | ``` 41 | $ kubectl get service 42 | ``` 43 | 44 | You should have 20 pods, all running in ACI 45 | 46 | ``` 47 | $ kubectl get pod 48 | $ az container list 49 | ``` 50 | 51 | You can see all the details with: 52 | 53 | ``` 54 | $ helm get aci-demo 55 | ``` 56 | 57 | ## Destroying the Demo 58 | 59 | ``` 60 | $ helm delete --purge aci-demo 61 | ``` 62 | -------------------------------------------------------------------------------- /vk-burst-demo/charts/fr-demo/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | description: A Helm chart for Kubernetes 3 | name: fr 4 | version: 0.1.0 5 | -------------------------------------------------------------------------------- /vk-burst-demo/charts/fr-demo/templates/NOTES.txt: -------------------------------------------------------------------------------- 1 | 1. Get the application URL by running these commands: 2 | {{- if .Values.frontend.ingress.enabled }} 3 | {{- range .Values.frontend.ingress.hosts }} 4 | https://{{ . }} 5 | {{- end }} 6 | {{- else if contains "NodePort" .Values.frontend.service.type }} 7 | export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "fullname" . }}-frontend) 8 | export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") 9 | echo http://$NODE_IP:$NODE_PORT 10 | {{- else if contains "LoadBalancer" .Values.frontend.service.type }} 11 | NOTE: It may take a few minutes for the LoadBalancer IP to be available. 12 | You can watch the status of by running 'kubectl get svc -w {{ template "fullname" . }}-frontend' 13 | export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "fullname" . }}-frontend -o jsonpath='{.status.loadBalancer.ingress[0].ip}') 14 | echo http://$SERVICE_IP:{{ .Values.frontend.service.externalPort }} 15 | {{- else if contains "ClusterIP" .Values.frontend.service.type }} 16 | export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "name" . }}-frontend,release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") 17 | echo "Visit http://127.0.0.1:8080 to use your application" 18 | kubectl port-forward $POD_NAME 8080:{{ .Values.frontend.service.externalPort }} 19 | {{- end }} 20 | -------------------------------------------------------------------------------- /vk-burst-demo/charts/fr-demo/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* vim: set filetype=mustache: */}} 2 | {{/* 3 | Expand the name of the chart. 4 | */}} 5 | {{- define "name" -}} 6 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} 7 | {{- end -}} 8 | 9 | {{/* 10 | Create a default fully qualified app name. 11 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 12 | */}} 13 | {{- define "fullname" -}} 14 | {{- $name := default .Chart.Name .Values.nameOverride -}} 15 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} 16 | {{- end -}} 17 | -------------------------------------------------------------------------------- /vk-burst-demo/charts/fr-demo/templates/backend-deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: extensions/v1beta1 2 | kind: Deployment 3 | metadata: 4 | name: {{ template "fullname" . }}-backend 5 | labels: 6 | app: {{ template "name" . }} 7 | chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} 8 | release: {{ .Release.Name }} 9 | heritage: {{ .Release.Service }} 10 | spec: 11 | replicas: {{ .Values.backend.replicaCount }} 12 | template: 13 | metadata: 14 | labels: 15 | app: {{ template "name" . }}-backend 16 | release: {{ .Release.Name }} 17 | spec: 18 | containers: 19 | - name: {{ .Chart.Name }} 20 | image: "{{ .Values.backend.image.repository }}:{{ .Values.backend.image.tag }}" 21 | imagePullPolicy: "{{ .Values.backend.image.pullPolicy }}" 22 | env: 23 | - name: AZURE_BLOB_ACCOUNT 24 | value: "{{ .Values.imageRecognizer.azureBlob.storageAccount }}" 25 | - name: DB_PATH 26 | value: "/app_db/" 27 | volumeMounts: 28 | - mountPath: /app_db 29 | name: db-volume 30 | ports: 31 | - containerPort: {{ .Values.backend.service.internalPort }} 32 | livenessProbe: 33 | httpGet: 34 | path: /api/test 35 | port: {{ .Values.backend.service.internalPort }} 36 | readinessProbe: 37 | httpGet: 38 | path: /api 39 | port: {{ .Values.backend.service.internalPort }} 40 | resources: 41 | {{ toYaml .Values.backend.resources | indent 12 }} 42 | volumes: 43 | - name: db-volume 44 | emptyDir: {} 45 | {{- if .Values.backend.nodeSelector }} 46 | nodeSelector: 47 | {{ toYaml .Values.backend.nodeSelector | indent 8 }} 48 | {{- end }} 49 | -------------------------------------------------------------------------------- /vk-burst-demo/charts/fr-demo/templates/backend-ingress.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.backend.ingress.enabled -}} 2 | {{- $serviceName := include "fullname" . -}} 3 | {{- $servicePort := .Values.backend.service.externalPort -}} 4 | apiVersion: extensions/v1beta1 5 | kind: Ingress 6 | metadata: 7 | name: {{ template "fullname" . }}-backend 8 | labels: 9 | app: {{ template "name" . }}-backend 10 | chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} 11 | release: {{ .Release.Name }} 12 | heritage: {{ .Release.Service }} 13 | annotations: 14 | {{- range $key, $value := .Values.backend.ingress.annotations }} 15 | {{ $key }}: {{ $value | quote }} 16 | {{- end }} 17 | spec: 18 | rules: 19 | - http: 20 | paths: 21 | - path: /api 22 | backend: 23 | serviceName: {{ $serviceName }}-backend 24 | servicePort: {{ $servicePort }} 25 | {{- range $host := .Values.backend.ingress.hosts }} 26 | host: {{ $host }} 27 | {{- end }} 28 | {{- if .Values.backend.ingress.tls }} 29 | tls: 30 | {{ toYaml .Values.backend.ingress.tls | indent 4 }} 31 | {{- end -}} 32 | {{- end -}} 33 | -------------------------------------------------------------------------------- /vk-burst-demo/charts/fr-demo/templates/backend-service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ template "fullname" . }}-backend 5 | labels: 6 | app: {{ template "name" . }} 7 | chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} 8 | release: {{ .Release.Name }} 9 | heritage: {{ .Release.Service }} 10 | spec: 11 | type: {{ .Values.backend.service.type }} 12 | ports: 13 | - port: {{ .Values.backend.service.externalPort }} 14 | targetPort: {{ .Values.backend.service.internalPort }} 15 | protocol: TCP 16 | name: {{ .Values.backend.service.name }} 17 | selector: 18 | app: {{ template "name" . }}-backend 19 | release: {{ .Release.Name }} 20 | -------------------------------------------------------------------------------- /vk-burst-demo/charts/fr-demo/templates/frontend-deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: extensions/v1beta1 2 | kind: Deployment 3 | metadata: 4 | name: {{ template "fullname" . }}-frontend 5 | labels: 6 | app: {{ template "name" . }} 7 | chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} 8 | release: {{ .Release.Name }} 9 | heritage: {{ .Release.Service }} 10 | spec: 11 | replicas: {{ .Values.frontend.replicaCount }} 12 | template: 13 | metadata: 14 | labels: 15 | app: {{ template "name" . }}-frontend 16 | release: {{ .Release.Name }} 17 | spec: 18 | containers: 19 | - name: {{ .Chart.Name }} 20 | image: "{{ .Values.frontend.image.repository }}:{{ .Values.frontend.image.tag }}" 21 | imagePullPolicy: "{{ .Values.frontend.image.pullPolicy }}" 22 | env: 23 | - name: IP_JOB_SERVER 24 | value: "{{ template "fullname" . }}-backend:{{ .Values.backend.service.externalPort }}" 25 | - name: AZURE_BLOB_ACCOUNT 26 | value: acidemopictures 27 | ports: 28 | - containerPort: {{ .Values.frontend.service.internalPort }} 29 | livenessProbe: 30 | httpGet: 31 | path: / 32 | port: {{ .Values.frontend.service.internalPort }} 33 | readinessProbe: 34 | httpGet: 35 | path: / 36 | port: {{ .Values.frontend.service.internalPort }} 37 | resources: 38 | {{ toYaml .Values.frontend.resources | indent 12 }} 39 | {{- if .Values.frontend.nodeSelector }} 40 | nodeSelector: 41 | {{ toYaml .Values.frontend.nodeSelector | indent 8 }} 42 | {{- end }} 43 | -------------------------------------------------------------------------------- /vk-burst-demo/charts/fr-demo/templates/frontend-ingress.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.frontend.ingress.enabled -}} 2 | {{- $serviceName := include "fullname" . -}} 3 | {{- $servicePort := .Values.frontend.service.externalPort -}} 4 | apiVersion: extensions/v1beta1 5 | kind: Ingress 6 | metadata: 7 | name: {{ template "fullname" . }}-frontend 8 | labels: 9 | app: {{ template "name" . }}-frontend 10 | chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} 11 | release: {{ .Release.Name }} 12 | heritage: {{ .Release.Service }} 13 | annotations: 14 | {{- range $key, $value := .Values.frontend.ingress.annotations }} 15 | {{ $key }}: {{ $value | quote }} 16 | {{- end }} 17 | spec: 18 | rules: 19 | - http: 20 | paths: 21 | - path: / 22 | backend: 23 | serviceName: {{ $serviceName }}-frontend 24 | servicePort: {{ $servicePort }} 25 | {{- range $host := .Values.frontend.ingress.hosts }} 26 | host: {{ $host }} 27 | {{- end }} 28 | {{- if .Values.frontend.ingress.tls }} 29 | tls: 30 | {{ toYaml .Values.frontend.ingress.tls | indent 4 }} 31 | {{- end -}} 32 | {{- end -}} 33 | -------------------------------------------------------------------------------- /vk-burst-demo/charts/fr-demo/templates/frontend-service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ template "fullname" . }}-frontend 5 | labels: 6 | app: {{ template "name" . }} 7 | chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} 8 | release: {{ .Release.Name }} 9 | heritage: {{ .Release.Service }} 10 | spec: 11 | type: {{ .Values.frontend.service.type }} 12 | ports: 13 | - port: {{ .Values.frontend.service.externalPort }} 14 | targetPort: {{ .Values.frontend.service.internalPort }} 15 | protocol: TCP 16 | name: {{ .Values.frontend.service.name }} 17 | selector: 18 | app: {{ template "name" . }}-frontend 19 | release: {{ .Release.Name }} 20 | -------------------------------------------------------------------------------- /vk-burst-demo/charts/fr-demo/templates/ir-aci-deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1beta1 2 | kind: Deployment 3 | metadata: 4 | name: {{ include "fullname" . }}-ir-aci 5 | labels: 6 | app: {{ template "name" . }} 7 | chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} 8 | release: {{ .Release.Name }} 9 | heritage: {{ .Release.Service }} 10 | spec: 11 | replicas: {{ .Values.imageRecognizer.replicaCount.aci }} 12 | template: 13 | metadata: 14 | labels: 15 | app: {{ include "fullname" . }}-ir-aci 16 | spec: 17 | containers: 18 | - name: {{ include "fullname" . }}-ir-aci 19 | image: "{{ .Values.imageRecognizer.image.repository }}:{{ .Values.imageRecognizer.image.tag }}" 20 | imagePullPolicy: "{{ .Values.imageRecognizer.image.pullPolicy }}" 21 | env: 22 | - name: IP_JOB_SERVER 23 | value: "{{ if .Values.backend.ingress.hostIP }} 24 | {{- .Values.backend.ingress.hostIP -}} 25 | {{ else }} 26 | {{- index .Values.backend.ingress.hosts 0 -}} 27 | {{ end -}} 28 | :{{- .Values.backend.service.externalPort -}}" 29 | - name: AZURE_BLOB_ACCOUNT 30 | value: "{{ .Values.imageRecognizer.azureBlob.storageAccount }}" 31 | - name: PYTHONUNBUFFERED 32 | value: "0" 33 | resources: 34 | requests: 35 | memory: 1.5G 36 | cpu: 1 37 | volumeMounts: 38 | - mountPath: /Pics 39 | name: pic-volume 40 | volumes: 41 | - name: pic-volume 42 | emptyDir: {} 43 | dnsPolicy: ClusterFirst 44 | nodeName: virtual-kubelet-myaciconnector-linux 45 | tolerations: 46 | - key: azure.com/aci 47 | effect: NoSchedule 48 | -------------------------------------------------------------------------------- /vk-burst-demo/charts/fr-demo/templates/ir-deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1beta1 2 | kind: Deployment 3 | metadata: 4 | name: {{ include "fullname" . }}-ir 5 | labels: 6 | app: {{ template "name" . }} 7 | chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} 8 | release: {{ .Release.Name }} 9 | heritage: {{ .Release.Service }} 10 | spec: 11 | replicas: {{ .Values.imageRecognizer.replicaCount.pods }} 12 | template: 13 | metadata: 14 | labels: 15 | app: {{ include "fullname" . }}-ir 16 | spec: 17 | containers: 18 | - name: {{ include "fullname" . }}-ir 19 | image: "{{ .Values.imageRecognizer.image.repository }}:{{ .Values.imageRecognizer.image.tag }}" 20 | imagePullPolicy: "{{ .Values.imageRecognizer.image.pullPolicy }}" 21 | env: 22 | - name: IP_JOB_SERVER 23 | value: "{{ template "fullname" . }}-backend:{{ .Values.backend.service.externalPort }}" 24 | - name: SERVER_PATH 25 | value: "" 26 | - name: AZURE_BLOB_ACCOUNT 27 | value: "{{ .Values.imageRecognizer.azureBlob.storageAccount }}" 28 | - name: PYTHONUNBUFFERED 29 | value: "0" 30 | volumeMounts: 31 | - mountPath: /Pics 32 | name: pic-volume 33 | volumes: 34 | - name: pic-volume 35 | emptyDir: {} 36 | dnsPolicy: ClusterFirst 37 | -------------------------------------------------------------------------------- /vk-burst-demo/charts/fr-demo/values.yaml: -------------------------------------------------------------------------------- 1 | # Settings for the facial image recognizer 2 | imageRecognizer: 3 | replicaCount: 4 | pods: 1 5 | aci: 0 6 | image: 7 | repository: rbitia/fr-ir 8 | tag: latest 9 | pullPolicy: Always 10 | resources: 11 | limits: 12 | cpu: 500m 13 | memory: 1.5G 14 | requests: 15 | cpu: 500m 16 | memory: 1.5G 17 | azureBlob: 18 | storageAccount: acidemopictures 19 | 20 | # Settings for the Facial Recognizer UI 21 | frontend: 22 | replicaCount: 1 23 | image: 24 | repository: rbitia/fr-frontend 25 | tag: latest 26 | pullPolicy: Always 27 | service: 28 | name: frontend 29 | type: ClusterIP 30 | externalPort: 8080 31 | internalPort: 8080 32 | ingress: 33 | enabled: true 34 | # Used to create an Ingress record. 35 | # When use IP access, comment hosts node 36 | hosts: 37 | - fi.rbitia.com 38 | annotations: 39 | kubernetes.io/ingress.class: nginx 40 | kubernetes.io/tls-acme: "true" 41 | nginx.ingress.kubernetes.io/ssl-redirect: "false" 42 | tls: 43 | # Secrets must be manually created in the namespace. 44 | - secretName: fi-rbitia-com 45 | hosts: 46 | - fi.rbitia.com 47 | resources: {} 48 | # We usually recommend not to specify default resources and to leave this as a conscious 49 | # choice for the user. This also increases chances charts run on environments with little 50 | # resources, such as Minikube. If you do want to specify resources, uncomment the following 51 | # lines, adjust them as necessary, and remove the curly braces after 'resources:'. 52 | #limits: 53 | # cpu: 100m 54 | # memory: 128Mi 55 | # requests: 56 | # cpu: 100m 57 | # memory: 128Mi 58 | 59 | 60 | # Settings for Facial Recognizer Backend 61 | backend: 62 | replicaCount: 1 63 | image: 64 | repository: rbitia/aci-webserver 65 | tag: latest 66 | pullPolicy: Always 67 | service: 68 | name: backend 69 | type: ClusterIP 70 | externalPort: 80 71 | internalPort: 8000 72 | ingress: 73 | enabled: true 74 | # When use domain access, comment hostIP node and use hosts node 75 | # hostIP: 40.121.216.148 76 | # Used to create an Ingress record. 77 | hosts: 78 | - fi-backend.rbitia.com 79 | annotations: 80 | kubernetes.io/ingress.class: nginx 81 | kubernetes.io/tls-acme: "true" 82 | nginx.ingress.kubernetes.io/ssl-redirect: "false" 83 | # tls: 84 | # # Secrets must be manually created in the namespace. 85 | # - secretName: fr-backend-dev 86 | # hosts: 87 | # - bk.sleepless.tk 88 | resources: {} 89 | # We usually recommend not to specify default resources and to leave this as a conscious 90 | # choice for the user. This also increases chances charts run on environments with little 91 | # resources, such as Minikube. If you do want to specify resources, uncomment the following 92 | # lines, adjust them as necessary, and remove the curly braces after 'resources:'. 93 | # limits: 94 | # cpu: 100m 95 | # memory: 128Mi 96 | # requests: 97 | # cpu: 100m 98 | # memory: 128Mi 99 | -------------------------------------------------------------------------------- /vk-burst-demo/create-aci-connector/example-aci-connector.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: extensions/v1beta1 2 | kind: Deployment 3 | metadata: 4 | name: aci-connector 5 | namespace: default 6 | spec: 7 | replicas: 1 8 | template: 9 | metadata: 10 | labels: 11 | app: aci-connector 12 | spec: 13 | containers: 14 | - name: aci-connector 15 | image: microsoft/aci-connector-k8s:latest 16 | imagePullPolicy: Always 17 | env: 18 | - name: AZURE_CLIENT_ID 19 | value: 20 | - name: AZURE_CLIENT_KEY 21 | value: 22 | - name: AZURE_TENANT_ID 23 | value: 24 | - name: AZURE_SUBSCRIPTION_ID 25 | value: 26 | - name: ACI_RESOURCE_GROUP 27 | value: 28 | -------------------------------------------------------------------------------- /vk-burst-demo/create-aci-connector/generateManifest.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import json 3 | import os 4 | import subprocess 5 | 6 | DEFAULT_LOCATION = "westus" 7 | BASE_CONFIG_FILE = "example-aci-connector.yaml" 8 | 9 | def main(): 10 | """ Auto generate the yml file with the needed credentials""" 11 | 12 | parser = argparse.ArgumentParser( 13 | formatter_class=argparse.RawTextHelpFormatter, 14 | description='''Automatically generate the connector yaml file with the needed credentials. Either create a resource 15 | REQUIREMENTS: 16 | 1) Azure CLI is installed 17 | 2) The desired subscription Id is set as current in the CLI or is provided with the -s flag''', 18 | epilog='''Example: 19 | python generateManifest.py --create-group --resource-group myResourceGroup --helm''') 20 | 21 | parser.add_argument( 22 | "-cr", 23 | "--create-group", 24 | action='store_true', 25 | help="Creates a resource group. Must provide resource group name with (-g) and location (-l)" 26 | ) 27 | parser.add_argument("--helm", help="Output Helm installation all command", type=bool, const=True, nargs='?') 28 | parser.add_argument("-g", "--resource-group", help="Name of resource group", required=True) 29 | parser.add_argument("-s", "--subscription-id", help="Subscription ID") 30 | parser.add_argument("-l", "--location", help="Resource Location") 31 | parser.add_argument("-f", "--file", help="filename for the output file") 32 | 33 | args = parser.parse_args() 34 | 35 | if not os.path.isfile(BASE_CONFIG_FILE): 36 | print("Could not find base configuration file: ", BASE_CONFIG_FILE) 37 | 38 | resource_group = args.resource_group 39 | 40 | if (args.create_group): 41 | 42 | print("Creating Resource Group ", resource_group) 43 | 44 | if (args.location): 45 | location = args.location 46 | else: 47 | print("Using defalut location: " + DEFAULT_LOCATION) 48 | location = DEFAULT_LOCATION 49 | 50 | response = json.loads( 51 | subprocess.check_output( 52 | "az group create -n " + resource_group + " -l " + location, 53 | shell=True 54 | )) 55 | 56 | if(response['properties']['provisioningState'] != 'Succeeded'): 57 | print("An Error occured while creating the resource group: ", resource_group) 58 | exit(-1) 59 | 60 | subscription_id = response['id'].split('/')[2] 61 | 62 | else: 63 | resource_group = args.resource_group 64 | if(resource_group == None): 65 | print("Must provide a resource group name") 66 | exit(-1) 67 | 68 | subscription_id = args.subscription_id 69 | if(subscription_id == None): 70 | print("Must provide a subscription Id unless you create a new resource group") 71 | exit(-1) 72 | 73 | print("Creating Service Principal") 74 | app_info = json.loads( 75 | subprocess.check_output( 76 | "az ad sp create-for-rbac --role=Contributor --scopes /subscriptions/" + subscription_id + "/", 77 | shell=True 78 | ).decode("utf-8") 79 | ) 80 | 81 | try: 82 | replacements = { 83 | "": app_info['appId'], 84 | "": app_info['password'], 85 | "": app_info['tenant'], 86 | "": subscription_id, 87 | "": resource_group 88 | } 89 | except: 90 | print("Unable to create a service principal") 91 | exit(-1) 92 | 93 | if (args.helm): 94 | print("Run the following command to install the ACI connector:") 95 | print("-----Begin Command----") 96 | print("helm install --name my-release --set env.azureClientId=%s,env.azureClientKey=%s,env.azureTenantId=%s,env.azureSubscriptionId=%s,env.aciResourceGroup=%s,env.aciRegion=%s ../charts/aci-connector" % (app_info['appId'], app_info['password'], app_info['tenant'], subscription_id, resource_group, location)) 97 | print("-----End Command----") 98 | else: 99 | with open('example-aci-connector.yaml', 'r') as file: 100 | filedata = file.read() 101 | 102 | for key, value in replacements.items(): 103 | filedata = filedata.replace(key, value) 104 | 105 | filename = args.file 106 | if (filename == None): 107 | filename = "aci-connector.yaml" 108 | 109 | with open(filename, 'w') as file: 110 | file.write(filedata) 111 | 112 | if __name__ == '__main__': 113 | main() 114 | -------------------------------------------------------------------------------- /vk-burst-demo/custom.yaml: -------------------------------------------------------------------------------- 1 | 2 | # Settings for the facial image recognizer 3 | imageRecognizer: 4 | image: "rbitia/aci-demo:latest" 5 | # I cut this from 100 because that was taking a long time to spin up and delete. 6 | # You can override this on the CLI with `--set imageRecognizer.replicas=100` 7 | replicas: 1 8 | inClusterReplicas: 2 9 | webServerIP: 13.90.143.52 10 | webServerPort: 80 11 | 12 | 13 | # If you decide to use an Ingress instead ofa LoadBalancer service, enable this. 14 | ingress: 15 | enabled: false 16 | # Used to create an Ingress record. 17 | hosts: 18 | - chart-example.local 19 | annotations: 20 | # kubernetes.io/ingress.class: nginx 21 | # kubernetes.io/tls-acme: "true" 22 | tls: 23 | # Secrets must be manually created in the namespace. 24 | # - secretName: chart-example-tls 25 | # hosts: 26 | # - chart-example.local 27 | resources: {} 28 | 29 | -------------------------------------------------------------------------------- /vk-burst-demo/customUI.yaml: -------------------------------------------------------------------------------- 1 | # Settings for the UI 2 | ui: 3 | replicaCount: 1 4 | image: "rbitia/aci-ui:latest" 5 | pullPolicy: Always 6 | service: 7 | name: facial-recognition 8 | type: LoadBalancer 9 | externalPort: 80 10 | internalPort: 80 11 | webServerIP: 13.90.143.52 12 | webServerPort: 80 13 | 14 | 15 | # If you decide to use an Ingress instead ofa LoadBalancer service, enable this. 16 | ingress: 17 | enabled: false 18 | # Used to create an Ingress record. 19 | hosts: 20 | - chart-example.local 21 | annotations: 22 | # kubernetes.io/ingress.class: nginx 23 | # kubernetes.io/tls-acme: "true" 24 | tls: 25 | # Secrets must be manually created in the namespace. 26 | # - secretName: chart-example-tls 27 | # hosts: 28 | # - chart-example.local 29 | resources: {} 30 | 31 | -------------------------------------------------------------------------------- /vk-burst-demo/customWeb.yaml: -------------------------------------------------------------------------------- 1 | webserver: 2 | replicaCount: 1 3 | image: "rbitia/aci-webserver:latest" 4 | service: 5 | name: web-server 6 | type: LoadBalancer 7 | externalPort: 80 8 | internalPort: 80 9 | 10 | # If you decide to use an Ingress instead ofa LoadBalancer service, enable this. 11 | ingress: 12 | enabled: false 13 | # Used to create an Ingress record. 14 | hosts: 15 | - chart-example.local 16 | annotations: 17 | # kubernetes.io/ingress.class: nginx 18 | # kubernetes.io/tls-acme: "true" 19 | tls: 20 | # Secrets must be manually created in the namespace. 21 | # - secretName: chart-example-tls 22 | # hosts: 23 | # - chart-example.local 24 | resources: {} 25 | 26 | -------------------------------------------------------------------------------- /vk-burst-demo/demo.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | . ./util.sh 4 | 5 | run "helm install charts/fr-demo --name demo" 6 | 7 | run "kubectl get po -o wide" 8 | 9 | run "cd $GOPATH/src/github.com/Azure/aci-connector-k8s" 10 | 11 | run "helm install charts/aci-connector --name aci-connector --namespace kube-system -f myvalues.yaml" 12 | 13 | run "kubectl get nodes" 14 | 15 | run "kubectl get po -o wide" -------------------------------------------------------------------------------- /vk-burst-demo/deploy.sh: -------------------------------------------------------------------------------- 1 | helm del --purge demo 2 | helm install charts/fr-demo --name demo 3 | kubectl get po --watch -------------------------------------------------------------------------------- /vk-burst-demo/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | services: 3 | jobserver: 4 | build: ./aci-job-server/ 5 | ports: 6 | - '3000:80' 7 | volumes: 8 | - './aci-job-server/logs/:/var/log/uwsgi/app/' 9 | env_file: 10 | - ./.env 11 | aci-worker: 12 | build: ./imageRecognition/ 13 | ports: 14 | - '8000:80' 15 | depends_on: 16 | - jobserver 17 | env_file: 18 | - ./.env 19 | aci-ui: 20 | build: ./demo-aci-image/ 21 | ports: 22 | - "8080:8080" 23 | depends_on: 24 | - jobserver 25 | volumes: 26 | - './demo-aci-image/logs/:/var/log/uwsgi/app/' 27 | env_file: 28 | - ./.env -------------------------------------------------------------------------------- /vk-burst-demo/util.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2016 The Kubernetes Authors. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | readonly reset=$(tput sgr0) 17 | readonly green=$(tput bold; tput setaf 2) 18 | readonly yellow=$(tput bold; tput setaf 3) 19 | readonly blue=$(tput bold; tput setaf 6) 20 | readonly timeout=$(if [ "$(uname)" == "Darwin" ]; then echo "1"; else echo "0.1"; fi) 21 | 22 | function desc() { 23 | maybe_first_prompt 24 | echo "$blue# $@$reset" 25 | prompt 26 | } 27 | 28 | function prompt() { 29 | echo -n "$yellow\$ $reset" 30 | } 31 | 32 | started="" 33 | function maybe_first_prompt() { 34 | if [ -z "$started" ]; then 35 | prompt 36 | started=true 37 | fi 38 | } 39 | 40 | # After a `run` this variable will hold the stdout of the command that was run. 41 | # If the command was interactive, this will likely be garbage. 42 | DEMO_RUN_STDOUT="" 43 | 44 | function run() { 45 | maybe_first_prompt 46 | rate=25 47 | if [ -n "$DEMO_RUN_FAST" ]; then 48 | rate=1000 49 | fi 50 | echo "$green$1$reset" | pv -qL $rate 51 | if [ -n "$DEMO_RUN_FAST" ]; then 52 | sleep 0.5 53 | fi 54 | OFILE="$(mktemp -t $(basename $0).XXXXXX)" 55 | eval "$1" 56 | r=$? 57 | read -d '' -t "${timeout}" -n 10000 # clear stdin 58 | prompt 59 | if [ -z "$DEMO_AUTO_RUN" ]; then 60 | read -s 61 | fi 62 | DEMO_RUN_STDOUT="$(tail -n +2 $OFILE | sed 's/\r//g')" 63 | return $r 64 | } 65 | 66 | function relative() { 67 | for arg; do 68 | echo "$(realpath $(dirname $(which $0)))/$arg" | sed "s|$(realpath $(pwd))|.|" 69 | done 70 | } 71 | 72 | # SSH_NODE=$(kubectl get nodes | tail -1 | cut -f1 -d' ') 73 | 74 | trap "echo" EXIT -------------------------------------------------------------------------------- /vk-computervision/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:2.7-alpine3.8 2 | WORKDIR app 3 | ADD . /app 4 | RUN pip install python-twitter 5 | CMD ["python", "textanalysis.py"] 6 | -------------------------------------------------------------------------------- /vk-computervision/front-end.py: -------------------------------------------------------------------------------- 1 | from flask import Flask 2 | from flask import request 3 | import textanalysis, emoji 4 | app = Flask(__name__) 5 | 6 | @app.route('/', methods=['GET', 'POST']) #allow both GET and POST requests 7 | def form_example(): 8 | if request.method == 'POST': #this block is only entered when the form is submitted 9 | handle = request.form.get('handle') 10 | avg = textanalysis.main(handle) 11 | if avg <= .3: 12 | emojiThing = ":fearful:" 13 | elif avg <= .5: 14 | emojiThing = ":expressionless:" 15 | elif avg <= 1: 16 | emojiThing = ":yum:" 17 | return '''Your twitter handle is: {} 18 | The avg sentiment of your tweets is: {}'''.format(handle, avg) 19 | 20 | return ''' 21 | Twitter Handle: 22 | 23 | ''' 24 | if __name__ == '__main__': 25 | app.run(debug=True, port=5001) #run app in debug mode on port 5000 -------------------------------------------------------------------------------- /vk-computervision/textanalysis.py: -------------------------------------------------------------------------------- 1 | import httplib, urllib, base64, twitter, os 2 | from pprint import pprint 3 | import json 4 | 5 | def sentiment(scoreArray): 6 | headers = { 7 | # Request headers 8 | 'Content-Type': 'application/json', 9 | 'Ocp-Apim-Subscription-Key': '', 10 | } 11 | params = urllib.urlencode({ 12 | }) 13 | with open('tweetOutput.json', 'r') as f: 14 | body= f.read() 15 | #print (str(body)) 16 | t= open("tweetScores.json","w+") 17 | try: 18 | conn = httplib.HTTPSConnection('eastus.api.cognitive.microsoft.com') 19 | conn.request("POST", "/text/analytics/v2.0/sentiment?%s" % params, body, headers) 20 | f.close() 21 | response = conn.getresponse() 22 | data = response.read() 23 | scoreData = json.loads(data) 24 | t.write(json.dumps(scoreData)) 25 | #pprint(scoreData) 26 | num = 0 27 | while num< 19: 28 | scoreArray.append(scoreData['documents'][num]['score']) 29 | print scoreArray[num] 30 | num = num + 1 31 | conn.close() 32 | except Exception as e: 33 | print str(e) 34 | #print scoreArray 35 | return scoreArray 36 | 37 | def tweets(handle): 38 | api = twitter.Api(consumer_key='2sEZ4ECzxAit4ijPiApU0DZyK', 39 | consumer_secret='bgb3CaTh0QENGuMT1MTp4VzXO1dBKnkivZ4cc5EfepBs0X3Lf6', 40 | access_token_key='54722501-nGzzqpFE0HVNMKs4lD5PZJ7dHoebP8TTTxCGNypNi', 41 | access_token_secret='W1C1ZVk3dNFyurCxs8LYtWlm6bed2ZZ8hNvEGlspJtZr5') 42 | twitterURL= "https://api.twitter.com/1.1/statuses/home_timeline.json" 43 | user = handle 44 | index = 0 45 | statuses = api.GetUserTimeline(screen_name=user) 46 | f= open("tweetOutput.json","w+") 47 | f.write("{\n\"documents\": [\n" ) 48 | tweets = [i.AsDict() for i in statuses] 49 | count = 0 50 | for t in tweets: 51 | #print( t['text']) 52 | number = str(index) 53 | distweet=t['text'] 54 | distweet= distweet.encode('ascii', 'ignore').decode('ascii') 55 | okay = json.dumps(distweet) 56 | if index < 20: 57 | f.write("\n{\n\"language\": \"en\", \n\"id\": \""+ number + "\",\n\"text\":" + okay +"\n},") 58 | if index == 20: 59 | f.write("\n{\n\"language\": \"en\", \n\"id\": \""+ number + "\",\n\"text\":" + okay +"\n}") 60 | index = index + 1 61 | #print(f.read)) 62 | f.write("\n]\n}") 63 | def calculateAveTweetScore(scoreArray): 64 | i= 0 65 | disAvg = 0 66 | #print len(scoreArray) 67 | while i 8 | http: 9 | paths: 10 | - path: / 11 | backend: 12 | serviceName: web 13 | servicePort: 80 -------------------------------------------------------------------------------- /vk-tensorflow-demo/kubernetes/web-service.yaml: -------------------------------------------------------------------------------- 1 | kind: Service 2 | apiVersion: v1 3 | metadata: 4 | name: web 5 | spec: 6 | selector: 7 | app: web 8 | ports: 9 | - protocol: TCP 10 | port: 80 11 | targetPort: 80 -------------------------------------------------------------------------------- /vk-tensorflow-demo/sfdeploy-app.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "location": { 6 | "type": "string", 7 | "defaultValue": "eastus", 8 | "metadata": { 9 | "description": "Location of the resources." 10 | } 11 | }, 12 | "workerReplicas": { 13 | "type": "int", 14 | "defaultValue": 1 15 | }, 16 | "webImage": { 17 | "type": "string", 18 | "defaultValue": "anthonychu/imageclassifierweb:0.7" 19 | }, 20 | "workerImage": { 21 | "type": "string", 22 | "defaultValue": "anthonychu/imageclassifierworker:0.2" 23 | } 24 | }, 25 | "resources": [ 26 | { 27 | "apiVersion": "2018-03-01-privatepreview", 28 | "name": "ImageClassifier", 29 | "type": "Microsoft.ServiceFabric/applications", 30 | "location": "[parameters('location')]", 31 | "dependsOn": [ 32 | ], 33 | "properties": { 34 | "description": "Image Classifier App", 35 | "services": [ 36 | { 37 | "name": "ImageClassifierWeb", 38 | "properties": { 39 | "description": "Image Classifier Web service", 40 | "osType": "linux", 41 | "codePackages": [ 42 | { 43 | "name": "ImageClassifierWeb.Code", 44 | "image": "[parameters('webImage')]", 45 | "endpoints": [ 46 | { 47 | "name": "Endpoint1", 48 | "port": 80 49 | } 50 | ], 51 | "resources": { 52 | "requests": { 53 | "cpu": 1, 54 | "memoryInGB": 1 55 | } 56 | } 57 | } 58 | ], 59 | "replicaCount": 1, 60 | "networkRefs": [ 61 | { 62 | "name": "[resourceId('Microsoft.ServiceFabric/networks', 'ImageClassifierNetwork')]" 63 | } 64 | ] 65 | } 66 | }, 67 | { 68 | "name": "ImageClassifierWorker", 69 | "properties": { 70 | "description": "Image Classifier Worker service", 71 | "osType": "linux", 72 | "codePackages": [ 73 | { 74 | "name": "ImageClassifierWorker.Code", 75 | "image": "[parameters('workerImage')]", 76 | "volumeRefs": [ 77 | { 78 | "name": "[resourceId('Microsoft.ServiceFabric/volumes', 'fruitshare')]", 79 | "destinationPath": "/app/assets/images" 80 | } 81 | ], 82 | "environmentVariables": [ 83 | { 84 | "name": "API_BASE_URL", 85 | "value": "http://ImageClassifierWeb" 86 | } 87 | ], 88 | "resources": { 89 | "requests": { 90 | "cpu": 0.5, 91 | "memoryInGB": 0.5 92 | } 93 | } 94 | } 95 | ], 96 | "replicaCount": "[parameters('workerReplicas')]", 97 | "networkRefs": [ 98 | { 99 | "name": "[resourceId('Microsoft.ServiceFabric/networks', 'ImageClassifierNetwork')]" 100 | } 101 | ] 102 | } 103 | } 104 | ] 105 | } 106 | } 107 | ] 108 | } 109 | -------------------------------------------------------------------------------- /vk-tensorflow-demo/sfdeploy-base.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "location": { 6 | "type": "string", 7 | "defaultValue": "eastus", 8 | "metadata": { 9 | "description": "Location of the resources." 10 | } 11 | }, 12 | "shareName": { 13 | "type": "string", 14 | "defaultValue": "fruit" 15 | }, 16 | "accountName": { 17 | "type": "string", 18 | "defaultValue": "sbzfileshare" 19 | }, 20 | "accountKey": { 21 | "type": "securestring", 22 | "defaultValue": "OmTO0iwiaVeP/My0I1z+czEbpxQ5GUi/FOuA0voH4sxxWIwP9QT7kTPY28DniZ4VJfCU1Kpyn8qbcWXqRYtXnA==" 23 | } 24 | }, 25 | "resources": [ 26 | { 27 | "apiVersion": "2018-03-01-privatepreview", 28 | "name": "fruitshare", 29 | "type": "Microsoft.ServiceFabric/volumes", 30 | "location": "[parameters('location')]", 31 | "properties": { 32 | "description": "File share backed by Azure Files storage.", 33 | "provider": "SFAzureFile", 34 | "azureFileParameters": { 35 | "shareName": "[parameters('shareName')]", 36 | "accountName": "[parameters('accountName')]", 37 | "accountKey": "[parameters('accountKey')]" 38 | } 39 | } 40 | }, 41 | { 42 | "apiVersion": "2018-03-01-privatepreview", 43 | "name": "ImageClassifierNetwork", 44 | "type": "Microsoft.ServiceFabric/networks", 45 | "location": "[parameters('location')]", 46 | "dependsOn": [], 47 | "properties": { 48 | "description": "Private network for application", 49 | "addressPrefix": "10.0.0.4/22", 50 | "ingressConfig": { 51 | "qosLevel": "bronze", 52 | "layer4": [ 53 | { 54 | "publicPort": "80", 55 | "applicationName": "ImageClassifier", 56 | "serviceName": "ImageClassifierWeb", 57 | "endpointName": "Endpoint1" 58 | } 59 | ] 60 | } 61 | } 62 | } 63 | ] 64 | } 65 | --------------------------------------------------------------------------------
Dashboard
User Profile
Table List
Typography
Icons
Maps
Notifications
Upgrade to PRO
Stats
5
Settings