{"id":19099434,"url":"https://github.com/TheCodeTraveler/Perfect-Gift","last_synced_at":"2025-09-08T04:31:41.671Z","repository":{"id":68231128,"uuid":"228705381","full_name":"TheCodeTraveler/Perfect-Gift","owner":"TheCodeTraveler","description":"A serverless function to verify a perfectly wrapped gift. The solution to #25DaysOfServerless Day 18.","archived":false,"fork":false,"pushed_at":"2020-10-22T22:26:44.000Z","size":61,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-09-07T04:39:11.960Z","etag":null,"topics":["azure-cli","azure-functions","computer-vision","serverless","storage"],"latest_commit_sha":null,"homepage":"https://25daysofserverless.com/calendar/18","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/TheCodeTraveler.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-12-17T21:33:17.000Z","updated_at":"2020-10-22T22:26:47.000Z","dependencies_parsed_at":null,"dependency_job_id":"ba470daf-2e28-41b8-b6a6-6bcfca1727ed","html_url":"https://github.com/TheCodeTraveler/Perfect-Gift","commit_stats":null,"previous_names":["thecodetraveler/perfect-gift","brminnick/perfect-gift"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/TheCodeTraveler/Perfect-Gift","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheCodeTraveler%2FPerfect-Gift","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheCodeTraveler%2FPerfect-Gift/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheCodeTraveler%2FPerfect-Gift/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheCodeTraveler%2FPerfect-Gift/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/TheCodeTraveler","download_url":"https://codeload.github.com/TheCodeTraveler/Perfect-Gift/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheCodeTraveler%2FPerfect-Gift/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":274134642,"owners_count":25228198,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-08T02:00:09.813Z","response_time":121,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["azure-cli","azure-functions","computer-vision","serverless","storage"],"created_at":"2024-11-09T03:50:05.394Z","updated_at":"2025-09-08T04:31:41.658Z","avatar_url":"https://github.com/TheCodeTraveler.png","language":"C#","readme":"[![](https://res.cloudinary.com/jen-looper/image/upload/v1576271295/images/challenge-18_hraoqx.jpg)](https://25daysofserverless.com/calendar/18)\n\n\nThe challenge on [Day 18](https://25daysofserverless.com/calendar/18) of [#25DaysOfServerless](https://25daysofserverless.com) is to ensure that each gift is perfectly wrapped according to the following rules\n\n1. Placed in a box\n2. Box is wrapped\n3. A bow / ribbon placed on top\n\nLet's accomplish this using [Azure Blob Storage](https://azure.microsoft.com/services/storage/blobs?WT.mc_id=mobile-0000-bramin), [Azure Computer Vision API](https://azure.microsoft.com/services/cognitive-services/computer-vision?WT.mc_id=mobile-0000-bramin), and [Azure Functions](https://docs.microsoft.com/azure/azure-functions/?WT.mc_id=mobile-0000-bramin).\n\n## Example\n\nUsing this [example of a perfectly wrapped gift](https://user-images.githubusercontent.com/13558917/70572373-88876980-1b54-11ea-8cd5-af07306b6d19.jpg), the Computer Vision API confirms the following **Tags**:\n\n- Box\n- Gift Wrapping\n- Ribbon\n- Present\n\n[![Computer Vision Results Example](https://user-images.githubusercontent.com/13558917/70573740-71964680-1b57-11ea-9126-e71f2de14a45.png)](https://azure.microsoft.com/services/cognitive-services/computer-vision?WT.mc_id=mobile-0000-bramin)\n\n## Creating the Solution\n\n### Step 0: Install Tools\n\nIn this step, we will install the necessary commandline tools in order to complete the solution.\n\n1 - Install .NET Core v3.1\n\n- In a browser, navigate to the [Download .NET Core Website](https://dotnet.microsoft.com/download/dotnet-core/3.1?WT.mc_id=mobile-0000-bramin)\n- On the **Download .NET Core Website**, install .NET Core 3.1\n\n2 - Install the [Azure CLI](https://docs.microsoft.com/cli/azure/install-azure-cli?view=azure-cli-latest\u0026WT.mc_id=mobile-0000-bramin)\n\n  - (Windows) [Download the MSI Installer](https://aka.ms/installazurecliwindows)\n\n  - (macOS) In the terminal, enter the following command:\n\n```bash\nbrew update \u0026\u0026 brew install azure-cli\n```\n\n 3 - Install [Azure Functions Core Tools v3.x](https://docs.microsoft.com/azure/azure-functions/functions-run-local?WT.mc_id=mobile-0000-bramin#v3)\n\n  - (Windows) In the terminal, enter the following command:\n\n```bash\nnpm install -g azure-functions-core-tools@3\n```\n\n  - (macOS) In the terminal, enter the following command:\n\n```bash\nbrew tap azure/functions\nbrew install azure-functions-core-tools@3\n# if upgrading on a machine that has 2.x installed\nbrew link --overwrite azure-functions-core-tools@3\n```\n\n4 - Install Git Command Line Tools\n\n  - In a browser, navigate to the [Git Downloads Page](https://git-scm.com/downloads)\n  - On the **Git Downloads Page**, install git for your specific operating system\n\n### Step 1: Downloading the Solution Repo\n\nIn this step, we will fork and clone the solution repo to our local machine.\n\n0 - Star the [Solution Repo](https://github.com/brminnick/Perfect-Gift)\n\u003e **Note** Starring the repo will help it become more discoverable, helping more devs find the solution\n\n  - In a browser, navigate to the [Perfect-Gift repo](https://github.com/brminnick/Perfect-Gift)\n  - In the browser, tt the top of the page, click **Star**\n![GitHub Star](https://user-images.githubusercontent.com/13558917/71127002-02e06b00-219f-11ea-9c10-347049d4fcf7.png)\n\n1 - Fork the [Solution Repo](https://github.com/brminnick/Perfect-Gift)\n  \n  - In a browser, navigate to the [Perfect-Gift repo](https://github.com/brminnick/Perfect-Gift)\n  - In the browser, tt the top of the page, click **Star**\n![GitHub Fork](https://user-images.githubusercontent.com/13558917/71126991-fa883000-219e-11ea-9da5-26a6f893b439.png)\n\n2 - Clone the newly Forked Repo\n\n  - In the terminal, enter the following command:\n\n```bash\ngit clone https://github.com/[your github user name]/Perfect-Gift\n```\n\u003e **Note** Replace `[your github user name]` with your [GitHub User name](https://stackoverflow.com/a/19077217/5953643)\n\n### Step 2: Log into Azure CLI\n\n1 - In the terminal, enter the following command to login into Azure CLI:\n\n```bash\naz login\n```\n\n\u003e **Note:** Stand by until the Azure CLI opens your browser to the Azure Login page\n\n### Step 3: Create Azure Resources\n\nIn this step, we'll generate the following Azure Resources:\n\n- Azure Resource Group\n  - This is a folder in azure that will hold our resources\n- [Azure Blob Storage](https://azure.microsoft.com/services/storage/blobs?WT.mc_id=mobile-0000-bramin)\n  - This is where we'll upload and store the images of our gifts\n- [Computer Vision API](https://azure.microsoft.com/services/cognitive-services/computer-vision?WT.mc_id=mobile-0000-bramin) Key\n  - This API will use machine learning to confirm that our gift has been perfectly wrapped\n- [Azure Functions](https://docs.microsoft.com/azure/azure-functions/?WT.mc_id=mobile-0000-bramin)\n  - This server less function will run each time a new photo is uploaded to Azure Blob Storage to confirm that the image contains a perfectly wrapped gift\n\n1 - In the terminal, enter the following command to create an Azure Resource Group\n\n```bash\naz group create --name PerfectGift --location EastUS\n```\n\n2 - In the terminal, enter the following command to create a free Computer Vision resource\n\n```bash\naz cognitiveservices account create --resource-group PerfectGift --name PerfectGiftComputerVision --sku F0 --kind ComputerVision --location EastUS\n```\n\n3 - In the terminal, in the JSON response, note the value of **endpoint**\n\n\u003e **Note:** For the EastUS, the endpoint should be `https://eastus.api.cognitive.microsoft.com`. We will use this value later in our serverless function.\n\n4 - In the terminal, enter the following command to retrieve the newly generated Computer Vision API Key\n\n```bash\naz cognitiveservices account keys list --resource-group PerfectGift --name PerfectGiftComputerVision\n```\n\n5 - In the terminal, in the JSON response, note the value of **key1**\n\n\u003e **Note:** The JSON response will provide two keys. Both keys are valid, and we'll be using **key1** for our serverless function.\n\u003e ```json\n\u003e {\n\u003e   \"key1\": \"[YOUR API KEY]\",\n\u003e   \"key2\": \"[YOUR API KEY]\"\n\u003e }\n\u003e ```\n\n6 - In the terminal, enter the following command to create an Azure Storage account:\n\n```bash\naz storage account create --name giftstorage[YOUR NAME] --location EastUS --resource-group PerfectGift --sku Standard_LRS\n```\n\n\u003e **Note:** Replace `[Your Name]` with your name to ensure the storage account name is unique, e.g. `giftstoragebrandon`\n\n7 - In the terminal, enter the following command retrive the Azure Storage Connection String\n\n```bash\naz storage account show-connection-string --name giftstorage[YOUR NAME]\n```\n\n\u003e **Note:** Replace `[Your Name]` with your name\n\n8 - In the terminal, in the JSON response, copy the value of **connectionString**\n\u003e **Note:** We will use **connectionString** in the next step to create a new storage container\n\n9 - In the terminal, enter the following command to create container called `gifts` in our Azure Storage account:\n\n```bash\naz storage container create --name gifts --connection-string \"[YOUR CONNECTION STRING]\"\n```\n\n\u003e **Note:** Replace `[YOUR CONNECTION STRING]` with the vaulue of **connectionString** retreived in the previous step, e.g. az `storage container create --name gifts --connection-string \"abc123def456ghi789==\"`\n\n10 - In the terminal, enter the following command to create an Azure Function App:\n\n```bash\naz functionapp create --resource-group PerfectGift --consumption-plan-location EastUS --name PerfectGift-[Your Name] --storage-account  giftstorage[YOUR NAME] --runtime dotnet\n```\n\n\u003e **Note:** Replace `[Your Name]` with your name to ensure the function app name is unique, e.g. `PerfectGift-Brandon`\n\n11 - In the terminal, enter the following to set the Azure Functions Runtime to v3:\n\n```bash\naz functionapp config appsettings set --resource-group PerfectGift --name PerfectGift-Brandon --settings \"FUNCTIONS_EXTENSION_VERSION=~3\"\n```\n\n12 - In the terminal, enter the following to add the Computer Vision API **key** and **endpoint** to the newly created Azure Function App:\n\n```bash\naz functionapp config appsettings set --resource-group PerfectGift --name PerfectGift-[YOUR NAME] --settings \"VisionApiKey=[YOUR API KEY]\" \"VisionApiBaseUrl=[YOUR COMPUTER VISION ENDPOINT]\"\n```\n\n\u003e **Note:** Replace `[YOUR NAME]` with your name, replace `[YOUR API KEY]` with the value of **key1** and replace `[YOUR COMPUTER VISION ENDPOINT]` with the value of **endpoint**\n\u003e e.g. `az functionapp config appsettings set --resource-group PerfectGift --name PerfectGift-Brandon --settings \"VisionApiKey=abc123\" \"VisionApiBaseUrl=https://eastus.api.cognitive.microsoft.com\"`\n\n### Step 4: Publish Azure Function\n\nIn this step, we will publish the solution found in `PerfectGift.csproj` to Azure.\n\n1 - In the terminal, enter the following command to navigate to the folder containing `PerfectGift.csproj` in the cloned solution repo\n\n  - (Windows)\n\n```bash\ncd [Path to cloned solution repo]\\Perfect-Gift\\PerfectGift\\\n```\n\n  - (macOS)\n\n```bash\ncd [Path to cloned solution repo]/Perfect-Gift/PerfectGift\n```\n\n2 - In the terminal, enter the following command to publish `PerfectGift.csproj` to our Azure Function App:\n\n```bash\nfunc azure functionapp publish PerfectGift-[YOUR NAME]\n```\n\n\u003e **Note:** Replace `[YOUR NAME]` with your name\n\n### Step 5: Upload Perfectly Wrapped Gift Images\n\nOur serverless functon is now ready to verify our gift images!\n\nIn this step, we will upload images to Azure Blob Storage and confirm that our serverless function automatically verifies the image is a perfectly wrapped gift. If the image is not of a perfectly wrapped gift, it will automatically be removed from Azure Blob Storage.\n\n1 - Download this sample image of a [perfectly wrapped gift](https://user-images.githubusercontent.com/13558917/70572373-88876980-1b54-11ea-8cd5-af07306b6d19.jpg)\n\n2 - Move \u0026 rename the downloaded image of a perfectly wrapped gift:\n\n  - (Windows) Save the file as C:\\Downloads\\gift.jpg\n  - (macOS) Save the file as ~/Download/gift.jpg\n\n3 - In the terminal, enter the following command to upload our image of a perfectly wrapped gift\n\n```bash\naz storage blob upload --container-name gifts --connection-string \"[YOUR CONNECTION STRING]\" --file [FILE PATH TO GIFT IMAGE] --name Gift1\n```\n\n\u003e **Note:** Replace `[YOUR CONNECTION STRING]` with the value of **connectionString** and replace `[FILE PATH TO GIFT IMAGE]` with the file path to your wrapped gift image\n\u003e e.g. `az storage blob upload --container-name gifts --connection-string \"abc123def456ghi789==\" --file cd:\\Downloads\\gift.jpg --name Gift1`\n\n4 - In the terminal, enter the following command to confirm the image has been **not** been deleted from storage:\n\n```bash\naz storage blob list --container-name gifts --connection-string \"[YOUR CONNECTION STRING]\"\n```\n\n\u003e **Note:** Replace `[YOUR CONNECTION STRING]` with the value of **connectionString** and replace `[FILE PATH TO GIFT IMAGE]` with the file path to your wrapped gift image\n\u003e e.g. `az storage blob list --container-name gifts --connection-string \"abc123def456ghi789==\"`\n\n5 - In the JSON response, confirm **\"name\": \"Gift1\"**\n\n6 - Download this sample image of a [wrapped gift missing a bow](https://user-images.githubusercontent.com/13558917/71133980-696e8480-21b1-11ea-942e-93508643f1e7.jpg)\n\n7 - Move \u0026 rename the downloaded image of a wrapped gift missing a bow:\n\n  - (Windows) Save the file as C:\\Downloads\\nobow.jpg\n  - (macOS) Save the file as ~/Download/nobow.jpg\n\n8. In the terminal, enter the following command to upload our image of a perfectly wrapped gift\n\n```bash\naz storage blob list --container-name gifts --connection-string \"[YOUR CONNECTION STRING]\" --file [FILE PATH TO NO BOW GIFT IMAGE] --name Gift2\n```\n\n\u003e **Note:** Replace `[YOUR CONNECTION STRING]` with the value of **connectionString** and replace `[FILE PATH TO GIFT IMAGE]` with the file path to your wrapped gift image\n\u003e\n\u003e e.g. `az storage blob upload --container-name gifts --connection-string \"abc123def456ghi789==\" --file cd:\\Downloads\\nobow.jpg --name Gift2`\n\n9 - In the terminal, enter the following command to confirm the image has been **not** been deleted from storage:\n\n```bash\naz storage blob list --container-name gifts --connection-string \"[YOUR CONNECTION STRING]\"\n```\n\n\u003e **Note:** Replace `[YOUR CONNECTION STRING]` with the value of **connectionString** and replace `[FILE PATH TO GIFT IMAGE]` with the file path to your wrapped gift image\n\u003e\n\u003e e.g. `az storage blob list --container-name gifts --connection-string \"abc123def456ghi789==\"`\n\n10 - In the JSON response, confirm that **\"name\": \"Gift2\"** does **not** exist\n\n\u003e **Note:** It may take a minute for the Blob Trigger Function to analyze the uploaded image. \n\u003e\n\u003eIf **\"name\": \"Gift2\"** does still exist, run `az storage blob list --container-name gifts --connection-string \"[YOUR CONNECTION STRING]\"` again in a few minutes \n\n### Step 6: Celebrate 🎉 \n\nWe now have a working Blob Trigger that automatically verifies our gifts have been perfectly wrapped!\n\nWe have successfully completed the [Day 18 Challenge](https://25daysofserverless.com/calendar/18) of [#25DaysOfServerless](https://25daysofserverless.com)!\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FTheCodeTraveler%2FPerfect-Gift","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FTheCodeTraveler%2FPerfect-Gift","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FTheCodeTraveler%2FPerfect-Gift/lists"}