text:
# Repurpose PIC-IoT Wx Development Board to Connect to Azure through IoT Hub Device Provisioning Service (DPS) with "Plug and Play" Model Interface

## Introduction

 This document describes how to connect the PIC-IoT Wx Development Board (featuring a 16-bit PIC24F MCU, ATECC608A secure element, and ATWINC1510 Wi-Fi module) to an Azure IoT Hub via Device Provisioning Service (DPS) while leveraging Microsoft’s Azure IoT Embedded C SDK. The PIC-IoT is provisioned for use with Azure using self-signed X.509 certificate-based authentication.

## Table of Contents

- [Repurpose PIC-IoT Wx Development Board to Connect to Azure through IoT Hub Device Provisioning Service (DPS)](#repurpose-pic-iot-wx-development-board-to-connect-to-azure-through-iot-hub-device-provisioning-service-dps)
  - [Introduction](#introduction)
  - [Table of Contents](#table-of-contents)
  - [Background Knowledge](#background-knowledge)
    - [PIC-IoT Wx Development Board Overview & Features (SMART \| CONNECTED \| SECURE)](#pic-iot-wx-development-board-overview--features-smart--connected--secure)
    - [Microchip “Provisioning” vs. Microsoft “Provisioning”](#microchip-provisioning-vs-microsoft-provisioning)
    - [High Level Architecture between the Client (PIC-IoT) and the Cloud (Azure)](#high-level-architecture-between-the-client-pic-iot-and-the-cloud-azure)
    - [Azure IoT Embedded C SDK](#azure-iot-embedded-c-sdk)
    - [TLS connection](#tls-connection)
    - [MQTT Connection](#mqtt-connection)
  - [Checklist](#checklist)
  - [Procedure](#instruction)
    - [Section 1: Prepare your development environment](#step-1-prepare-your-development-environment)
      - [1. Set up Microchip’s MPLAB X IDE Tool Chain](#1-set-up-microchips-mplab-x-ide-tool-chain)
      - [2. Set up Azure cloud resources](#2-set-up-azure-cloud-resources)
      - [3. Set up Git](#3-set-up-git)
    - [Section 2: Prepare your PIC-IoT board to connect to Azure](#step-2-prepare-your-pic-iot-board-to-connect-to-azure)
    - [Section 3: Enroll device into DPS](#step-3-enroll-device-into-dps)
      - [1. Preparing your environment for the certification verifying process:](#1-preparing-your-environment-for-the-certification-verifying-process)
      - [2. In Azure portal, upload the root CA cert “root-ca.pem” in DPS and do proof-of-possession for X.509 CA certificates with your Device Provisioning Service](#2-in-azure-portal-upload-the-root-ca-cert-root-capem-in-dps-and-do-proof-of-possession-for-x509-ca-certificates-with-your-device-provisioning-service)
        - [a. Register the public part of an X.509 certificate and get a verification code](#a-register-the-public-part-of-an-x509-certificate-and-get-a-verification-code)
        - [b. Digitally sign the verification code to create a verification certificate](#b-digitally-sign-the-verification-code-to-create-a-verification-certificate)
        - [c. Upload the signed verification certificate to DPS](#c-upload-the-signed-verification-certificate-to-dps)
        - [STOP! Quick summary of this step](#stop-quick-summary-of-this-step)
      - [3. Add a new enrollment group using the signer-ca.pem file](#3-add-a-new-enrollment-group-using-the-signer-capem-file)
      - [STOP! Sanity checks:](#stop-sanity-checks)
    - [Section 4: Connect the PIC-IoT device to Azure](#step-4-connect-the-pic-iot-device-to-azure)
    - [Section 5: Verify the connection between PIC-IoT and Azure](#step-5-verify-the-connection-between-pic-iot-and-azure)
    - [Section 6: View PIC-IoT board telemetry on Azure IoT Explorer](#step-6-view-pic-iot-board-telemetry-on-azure-iot-explorer)
  - [Future Considerations](#further-consideration)
  - [Conclusion](#conclusion)

## Background Knowledge

### PIC-IoT Wx Development Board Overview & Features (SMART \| CONNECTED \| SECURE)

 Download the [PIC-IoT Wx HW User Guide](http://ww1.microchip.com/downloads/en/DeviceDoc/PIC-IoT-Wx-Hardware-User-Guide-DS50002964A.pdf) for more details

### Microchip “Provisioning” vs. Microsoft “Provisioning”

The term “provisioning” will be use throughout this document (e.g. IoT
Provisioning Tool, provisioning key, provisioning device, device
provisioning service, etc.). On the Microchip side, the provisioning
process is to securely inject certificates into the hardware. From the
context of Microsoft, provisioning is defined in the relationship
between the hardware and the cloud, Azure. [Azure IoT Hub Device
Provisioning Service
(DPS)](https://docs.microsoft.com/azure/iot-dps/#:~:text=The%20IoT%20Hub%20Device%20Provisioning%20Service%20%28DPS%29%20is,of%20devices%20in%20a%20secure%20and%20scalable%20manner.)
allows the hardware to be provisioned securely to the right IoT Hub.

### High Level Architecture between the Client (PIC-IoT) and the Cloud (Azure)

This high-level architecture description summarizes the interactions
between the PIC-IoT board and Azure. These are the top six major puzzle
pieces that make up this enablement work of connecting PIC-IoT to Azure
through DPS using X.509-based authentication:

- ATECC608A: a secure element from the Microchip CryptoAuthentication
    portfolio. It securely stores a private key that is used to
    authenticate the hardware with cloud providers to uniquely identify
    every board <https://www.microchip.com/wwwproducts/en/ATECC608A>

- ATWINC1510: a low-power consumption Wi-Fi module that has access to
    the device certificate, signer CA certificate, and public key for
    mutual TLS handshaking between the board and the cloud
    <https://www.microchip.com/wwwproducts/en/ATWINC1510>

- IoT Provisioning Tool: Microchip-provided tool for provisioning
    self-signed certificate utilizing the unique serial number and
    private key stored in the ATECC608A secure element.

- Azure IoT Embedded C SDK: Microsoft-provided API designed to
    allow small, low-cost embedded IoT devices to communicate with Azure
    services, serving as translation logic between the application code
    and transport client

- Azure IoT Hub: IoT Hub is a managed service, hosted in the cloud,
    that acts as a central message hub for bi-directional communication
    between your IoT application and the devices it manages

- Device Provisioning Service (DPS): a helper service for IoT Hub that
    enables zero-touch, just-in-time provisioning to the right IoT hub
    without requiring human intervention, allowing customers to
    provision millions of devices in a secure and scalable manner

In a nutshell, we will use Microchip’s IoT Provisioning Tool to send a
Certificate Signing Request (CSR) to the ATECC608A to generate a
self-signed certificate chain which is then obtained by the ATWINC1510
Wi-Fi module to perform a TLS mutual handshake between the client
(PIC-IoT board) and the server (Azure), specifically using DPS.

Once successful, the PIC-IoT board will be provisioned to the correct
IoT Hub that is pre-linked to DPS during the setup process. We can then
leverage the Azure IoT Explorer which is a graphical tool for
interacting with and testing your IoT devices. Note that the ATECC608A
only contains the private key. The self-signed certificate chain
including root CA, signer CA (or intermediate CA), and device CA is
stored in the ATWINC1510 Wi-Fi module used for the TLS handshake.

### Azure IoT Embedded C SDK

This is the high-level view of the Embedded C SDK which translates the application code into an Azure-friendly logic that can be easily understood by Azure IoT Hub. Note that Microsoft is only responsible for the logic in the green box; it is up to the IoT Developer to provide the remaining layers of application code, Transport Client, TLS, and Socket. In the provided demo project, Microchip provides the layers in blue. Please the [Azure SDK for Embedded C](https://github.com/Azure/azure-sdk-for-c/tree/78a280b7160201cf10a106e8499e03eec88ea582) document for more details.

### TLS connection

The TLS connection performs both authentication and encryption.
Authentication consists of two parts:

- Server authentication; the board authenticates the server
- Client authentication; the server authenticates the board

Server authentication happens transparently to the user since the
ATWINC1510 on the PIC-IoT board comes preloaded with the required CA
certificate. During client authentication the client private key must be
used, but since this is stored inside the ATECC608A chip and cannot be extracted, all calculations must be done inside the ATECC608A. The ATWINC1510 library offers an API to delegate the TLS calculations to the main application. The main
application will in turn call the ATECC608A library API’s to perform the
calculations. Before the TLS connection is complete, a shared secret key
must be negotiated between the server and the client. This key is used
to encrypt all future communications during the connection.

### MQTT Connection

After successfully connecting on the TLS level, the board starts
establishing the MQTT connection. Since the TLS handles authentication
and security, MQTT does not have to provide a username or password.

## Checklist

Here are major steps of this project.  Set up Microchip’s MPLAB X IDE Tool Chain

- [MPLAB X IDE V5.30 or
    later](https://www.microchip.com/mplab/mplab-x-ide)

- [XC16 Compiler v1.50 or
    later](https://www.microchip.com/mplab/compilers)

- MPLAB Code Configurator 3.95 or later (once you finish the
    installation of the previous items, launch MPLAB X IDE > click on
    Tools > Plugins Download > search for MPLAB Code Configurator
    and install it)

#### 2. Set up Azure Cloud resources

- [Create an Azure free account for 30 day
    trial](https://azure.microsoft.com/en-us/free/)
    As a result, you should be able to access to Azure Portal by the end of this section.

- [Set up Azure IoT Hub and Device Provisioning Service (DPS) in Azure
    Portal](https://docs.microsoft.com/azure/iot-dps/quick-setup-auto-provision)
    As a result, you should be able to 1) create an IoT Hub, 2) create a Device Provisioning Service, and 3) link your DPS to your IoT Hub.

-  [Install Azure IoT Explorer](https://docs.microsoft.com/azure/iot-pnp/howto-install-iot-explorer#install-azure-iot-explorer) (make sure to download \*.msi file of the release 0.12.1 or later). The Azure IoT explorer is a graphical tool for interacting with and testing your IoT device on Azure. View [this GitHub](https://github.com/Azure/azure-iot-explorer) for more details.

#### 3. Set up Git

- Install latest version of [Git](https://git-scm.com/download/win)
- Verify that you have accessed to Git Bash by going to Start menu > type "Git Bash", a window like this will pop-out:

### Section 2: Prepare your PIC-IoT board to Connect to Azure

This section serves two purposes:

1. Update the internal firmware of the ATWINC1510 Wi-Fi module on the PIC-IoT to enable mutual TLS handshake between client’s ECC and server’s RSA.

2. Provision the PIC-IoT board by securely inject certificates into the hardware. Perform this section to create a self-signed certificate chain which acts as a device unique ID to enroll into DPS. The final result is the ATWINC1510 obtains the device certificate, CA certificate, and CA public key. The device certificate is based on a key pair that has previously been generated and is already pre-programmed in the ATECC608A. The device certificate is the client certificate used by the TLS layer for the client authentication (“device” and “client” are used interchangeably in this document). The end goals of the provisioning process include the following:
    - The PC running the Python script requests and receives a Certificate Signing Request (CSR) based on the key pair stored in the ATECC608A
    - The signer CA generates the certificate and returns it alongside with its own certificate and public key to the MCU; the two (signer and device) certificates are stored in the ATWINC1510

Procedure:

1. Download the [Microchip IoT Provisioning Tool v1.4.0](http://www.microchip.com/mymicrochip/filehandler.aspx?ddocname=en1001525)

2. Unzip the downloaded folder and follow the instructions in the "README.txt" file to perform WINC FW upgrade and board provisioning.

   - Launch PowerShell: click on Start > type “PowerShell” in the Search field > Open
   - Go to the directory where the “iotprovision-azure” executable file resides
   - Type the following command (this should generate and write all the certs to your disk):

        ```shell
        iotprovision-bin.exe -c azure -m custom
        ```

3. Take note of the generated cert location mentioned in the output message starting with “Saving to your …[your path]\.microchip-iot\MCHP3261021800001185.”. These certs will be used in IoT Hub DPS enrollment in the next step:
    - root-ca.crt (or .key): self-signed root CA cert
    - signer-ca.crt (or .key) (aka. intermediate CA) is a uniquely generated by the root cert, which is then used to generate device cert in [your-path]\.microchip-iot\MCHP<xxxxxxxxxxxxxxxx>\device.crt

**STOP! Knowledge backfill:** to understand the steps approaching
in the upcoming session, please take some time review the document
[Conceptual understanding of X.509 CA certificates in the IoT
industry](https://docs.microsoft.com/azure/iot-hub/iot-hub-x509ca-concept)
which describes the value of using X.509 certificate authority (CA)
certificates in IoT device manufacturing and authentication to IoT
Hub.

### Section 3: Enroll Device into DPS

#### 1. Set up certificates for the verification process:

- Go to generated cert location in the previous step at `\[your
    path]\.microchip-iot`

- Copy `*.crt` files and rename them to `*.pem`. (Note: DPS only accepts
    \*.pem or \*.cer file formats. If choosing \*.cer file, only base-64
    encoded certificate)

#### 2. In Azure portal, upload the root CA cert “root-ca.pem” in DPS and do proof-of-possession for X.509 CA certificates with your Device Provisioning Service

##### a. Register the public part of an X.509 certificate and get a verification code

Follow the “Register the public part of an X.509 certificate and get a verification code” section in [this document](https://docs.microsoft.com/azure/iot-dps/how-to-verify-certificates).
Again, the verification code is generated by encrypting the public key
portion of your X.509 certification. It will be used to validate the
uploaded certificate ownership. So make sure to copy the generated
verification code to notepad for next step.

##### b. Digitally sign the verification code to create a verification certificate

 Now that you've registered your root CA with Azure IoT Hub, you'll
need to prove that you actually own it by:

1. Generating the Certificate Signing Request (CSR) using the
    verification code.
2. Generating a verification certificate using CSR above

Once this done, you can upload your verification certificate to DPS to finish the [proof of possession](https://tools.ietf.org/html/rfc5280#section-3.1).

Procedure:

1. Open the Git Bash: Start menu > type “Git Bash”, a window like this will pop out:

2. Change to your generated certification folder:

    ```bash
    cd drive\[your path\.microchip-iot

    Example: cd /C/Users/john5/Azure/.microchip-iot
    ```

3. **Generate a certification signing request (CSR)** by entering the below command. CSR is generated by encrypting these two key inputs:

    - The `root-ca.key` generated in previous step by Microchip IoT Provisioning tool. This will be used in the openssl command line below.
    - The `Verification Code` generated from DPS in previous step. You will be asked to provide this during the process of creating the CSR.

    **Note**: Once you enter to command below, you will then be asked to enter information that will be used to will be incorporated into your certificate request. Enter verification code (generated from Azure portal) when prompt for CommonName. For the rest, you can enter anything you want.

    ```bash
    openssl req -new -key root-ca.key -out azure_root_ca_verification.csr
    ```

    As the result, you should see the file `azure_root_ca_verification.csr` appear in the \\.microchip-iot folder:

4. Generate a verification certificate by executing the following command:

    ```bash
    openssl x509 -req -in azure_root_ca_verification.csr -CA root-ca.crt -CAkey root-ca.key -CAcreateserial -out azure_signer_verification.cer -days 365 -sha256
    ```

    As the result, you should see the file `azure_signer_verification.cer` appear in the \\.microchip-iot folder:

##### c. Upload the signed verification certificate to DPS

Follow the “Upload the signed verification certificate” section in
[this document](https://docs.microsoft.com/azure/iot-dps/how-to-verify-certificates).  As a result, the status of your uploaded certification should be “Verified” as shown below (make sure to refresh the page to see the updated change in status).

##### STOP! Quick summary of this step

At this point, you have verified your X.509 CA certificate in DPS. To link all the above sub-steps and understand why this step is significant, it is recommended to download and read [this document](https://docs.microsoft.com/azure/iot-dps/how-to-verify-certificates).

#### 3. Add a new enrollment group using the "signer-ca.pem" file

a. In the Azure portal, navigate to your DPS > Manage enrollments >
Select “Enrollment Groups” tab:

b. Add enrollment group > Enter “Group name” > Choose Certificate
as “Attestation Type” > Choose “False” for IoT Edge Device >
Choose “Intermediate Certificate” as Certificate Type > Upload
\[path]\.microchip-iot\signer-ca.pem to Primary Certificate >
select “Evenly weighted distribution” for how you want to assign
devices to hub > select your IoT Hub that this new enrollment group
can assign to > leave the rest as their existing defaults > hit
“Save”.

Once this has been done, your enrollment group name should show up in the Enrollment Groups tab:

#### STOP! Sanity checks:

At this point, you have successfully created an enrollment group in DPS. However, as we have not yet programmed the PIC-IoT board with
the demo firmware, the device should not show up anywhere in Azure.
This can be verified in both DPS and in IoT Hub.

1. In your DPS, Enrollment Group’s Registration Records should be empty.
This can be verified by clicking on your newly enrolled group >
Registration Records > observe that no device shows up.

2. In your IoT Hub, your device ID should not show up in the IoT Devices.
This can be verified by clicking on your IoT Hub that links to your
DPS > click “IoT devices” (on the left-hand side under “Explorers”
> observe that your PIC-IoT device ID (e.g. “sn01237F696BEB9C89FE”) does
not show up.

### Section 4: Connect the PIC-IoT Device to Azure IoT Hub

In this section, we will flash the PIC-IoT board and connect it to Azure.

1. Clone/download the MPLAB X demo project
    by issuing the following commands in a Command Prompt or PowerShell
    window:

    ```bash
    git clone https://github.com/Azure-Samples/Microchip-PIC-IoT-Wx.git
    cd Microchip-PIC-IoT-Wx
    git submodule update --init
    ```

2. Launch the MPLAB X IDE and navigate to the main toolbar's "File -> Open Project" operation to load the demo project folder (\*.X) located
    at:

    ```bash
    [path]\Microchip-PIC-IoT-Wx\AzureIotPnpDps
    ```

   If the "load error" message in red appears, click on the “Resolve DFP for configuration: default” link:

3. Set the AzureIotPnpDps project as the main (currently focused/active) project by right-clicking on it and selecting "Set as Main Project"

4. Modify `AzureIotPnPDps/Header Files/platform/config/conf_winc.h` with your
    wireless router’s SSID and password (keeping the surrounding quotation marks for each); for example

    ```c
    #define CFG_MAIN_WLAN_SSID "MY_WIFI_AP_SSID"
    #define CFG_MAIN_WLAN_PSK  "MY_WIFI_AP_PSWD"
    ```

    > [!TIP]
    > You may also configure WiFi SSID and WiFI Password through CLI

5. Verify the project properties are set correctly before building the
   project:

    - Connect the board to PC, then make sure “CURIOSITY” device shows up as a disk drive in a File Explorer window

    - Right-click the project AzureIotPnPDps > select “Properties” > Verify
    that all Configuration settings are at least the minimum versions as
    shown in the below screenshot (and that your PIC-IoT board is
    selected as the Connected Hardware Tool). If any changes were made in the project properties window,
    make sure to hit the “Apply” button before hitting “OK”.

6. Build the project and set up a Command Line Interface (CLI) to the board:

    - Open a serial terminal (e.g. PuTTY, TeraTerm, etc.) and connect to the COM port corresponding to your board at 9600 baud (e.g. open PuTTY Configuration window > choose “session” > choose “Serial”> Enter the right COMx port). You can find the COM info by opening your PC’s Device Manager > expand Ports(COM & LPT) > take note of Curiosity Virtual COM Port.

    - Right-click the AzureIotPnPDps project and select “Make and Program Device”.  This operation will automatically clean and build the project before attempting to program the target device. After the “BUILD SUCCESSFUL” message appears in the Output window, the application HEX file will be programmed onto the PIC-IoT board. Once programming has finished, the board will automatically reset and start running its application code.

7. In the terminal emulator window, hit [RETURN] to get the list of available commands for the Command Line Interface (CLI).  The Command Line Interface allows you to send simple ASCII-string commands to set or get the user-configurable operating parameters of the application while it is running.  The CLI prompt is simply the '.' character

8. Look up the ID Scope corresponding to your DPS in the Microsoft Azure Portal.  This value is displayed in a web browser when clicking on "Overview" on the DPS resource page (the DPS was created earlier using a web page on the Azure Portal).  The ID Scope is programmed/saved into the PIC-IoT board in the next step using a CLI command (allowing you to change the ID Scope for the board without having to reprogram the MCU's application firmware)

9. In the terminal emulator window, confirm that “local echo” is enabled in the terminal settings.  At the CLI prompt, type in the command "idscope <MY_ID_SCOPE>" to set the ID Scope (which gets saved in the ATECC608A secure element on the PIC-IoT board) and then hit [ENTER].  To confirm it was set correctly, the ID Scope can be read out from the board by issuing the "idscope" command (i.e. without specifying an ID Scope value as the parameter on the command line)

10. At the CLI prompt, type in the command "reset" and hit [ENTER] to restart the application using the updated ID Scope to establish a connection to your DPS.

11.	Wait for the PIC-IoT board to connect to your DPS and stabilize (allow up to 2 minutes); eventually the Blue and Green LEDs should both stay constantly on (which signifies a successful & stable DPS connection).  If the Red LED comes on and stays lit, then something was incorrectly programmed (e.g. application firmware, Wi-Fi credentials, ID Scope).  If the Blue LED is not constantly on, then there is an issue with connecting to your wireless access point.

12. To enable the “full” debug messaging output to the terminal emulator window, execute the command "debug 4" on the Command Line Interface (CLI).  To disable the debug messages at any time, execute the command "debug 0" (debug levels range from 0 to 4).  The CLI is always active, even while debug messages are being continuously displayed on the terminal window.

### Section 5: Verify the Connection between PIC-IoT and Azure

A successful PIC-IoT to Azure DPS connection can be verified two ways:

1) Correct device ID shows up in the DPS enrollment
2) Correct device ID shows up in the IoT Hub

Procedure:

1. Verify in the Azure Device Provisioning Service

    - In the Azure Portal, go to your DPS > click “Manage enrollments” > under Enrollment Group, click “your group name” > click “Registration Records” > device should show up with the IoT Hub info that it got assigned to

2. In the Azure Portal, go to your IoT Hub > click “IoT
    Devices” > click “Refresh” > device should show up with the
    Status “Enabled” and Authentication Type of “SelfSigned”

### Section 6: PIC-IoT Board Interaction with Azure IoT Explorer

 Once the PIC-IoT connection to Azure has been verified in the previous section, the device can be monitored & controlled using Microsoft's Azure IoT Explorer. The Azure IoT Explorer is a graphical tool for interacting with and testing your IoT device on Azure. View [this document](https://docs.microsoft.com/azure/iot-pnp/howto-install-iot-explorer#install-azure-iot-explorer) for more details.

1. Connect Azure IoT Explorer to IoT Hub by providing your IoT Hub’s connection string.

    From the Azure Portal: click on your IoT Hub >Shared access polices > iothubowner > connection string-primary key > Copy to clipboard

2. Launch Azure IoT Explorer: Click on “Add connection” > paste the
    Connection String > Save

3. In the Azure IoT Explorer window, click on the "Home" link near the top of the window

4. On the left-hand side of the Azure IoT Explorer window, click on "IoT Plug and Play Settings"

5. Please make sure "Public repository" is in the list

    If "Public repository" is not listed, add it from "Add" menu

6. Click on "Save"

7. On the left-hand side of the IoT Explorer window, click on "IoT hubs"

8. Verify that the name of your IoT hub is displayed, then click on "View devices in this hub"

9. Verify that your device ID is displayed (and status is enabled), then click on it

10. On the left-hand side of the IoT Explorer window, click on "IoT Plug and Play components"

11.	Click on "Default component" near the bottom of the IoT Explorer window

12.	Click on "Properties (read-only)" near the top of the IoT Explorer window

13.	Confirm that the “Enum” value of each LED matches the state observed on the PIC-IoT board (1 = On, 2 = Off, 3 = Blinking) and note the maximum temperature reading since device reset (maxTempSinceLastReboot)

14.	Click on "Properties (writable)" near the top of the IoT Explorer window

15. Click on the input field labeled "led_yellow" and select "Blink"

16. Click on "Update desired value"

17. Observe the notification that the request to write the property was accepted by your device, and that the Yellow LED on the PIC-IoT board is blinking/toggling/flashing

18. Click on "Commands" near the top of the IoT Explorer window

19. To set up the getMaxMinReport command, hover the mouse near the right corners of the since input field until the little triangle shows up and then click on it

20. When the calendar window pops up, select today’s date

21. Type in the current time

22. Click on "Send command"

23. Confirm that the command was successfully invoked and that both the max & min temperatures are reported in the message that appears in the pop-up window (once the message window disappears, it can be read again by clicking on "Notifications")

24. Click on "Telemetry" near the top of the IoT Explorer window and then click on "Start"

25. Observe the telemetry data (for the temperature and light sensors) is updating every few seconds

26. Increase the ambient light shining on top of the board and observe that the value of the light sensor increases within a few seconds

27. On the PIC-IoT Wx development board, press and release user buttons SW0 and/or SW1

28. Observe the button event message (telemetry) that is generated each time a user button has been pressed/released

29. Click on "Commands" near the top of the IoT Explorer window

30. Click on the input field for "delay" and type "PT10S", then click "Send command".  Confirm that the command was successfully invoked via a notification message, and then the board resets itself in approximately 10 seconds (the LEDs on the board will cycle and re-initialize)

31. Experiment with the CLI commands to control the LED’s from the terminal emulator window by issuing the led command (usage: "led [led],[state]")
[led] : {1 = blue, 2 = green, 3 = yellow, 4 = red}
[state] : {1 = on, 2 = off, 3 = start blinking, 4 = stop blinking}

## Future Considerations

Instead of connecting to IoT Hub and viewing the telemetry on Azure IoT
Explorer, the PIC-IoT board can be provisioned to connect to Azure IoT Central instead, which has a built-in dashboard to monitor the telemetry. Using IoT Central should be strongly considered for future projects.

## Conclusion

You are now able to connect PIC-IoT to Azure using self-signed cert base
authentication and have deeper knowledge of how all the pieces of the puzzle
fit together from the ATECC608A secure element, ATWINC1510 Wi-Fi, Azure
Embedded C SDK, and Azure IoT Hub/DPS. Let’s start thinking out of the
box and see how you can apply this project to provision securely and
quickly a massive number of Microchip devices to Azure and safely manage
them through the whole device life cycle.


text:
---
title: Virtual users on vsftpd
description: A guide to configure Vsftpd on Linux for virtual users and separated chroot directories
author: Matteo Mattei
layout: post
permalink: /virtual-users-on-vsftpd/
categories:
  - linux
  - ftp
  - virtual
  - vsftp
---
![VSFTPD logo](/public/posts_images/vsftpd_logo.jpg)
I am usually to configure [*vsftp*](http://vsftpd.beasts.org) on web servers to allow FTP access based on domains. Few days ago my client asked me to create multiple FTP users for a single domain every one with a different root folder into that domain.

This is my usual configuration of my **/etc/vsftpd.conf**

```
listen=YES
anonymous_enable=NO
local_enable=YES
virtual_use_local_privs=YES
write_enable=YES
connect_from_port_20=YES
xferlog_enable=YES
pam_service_name=vsftpd
guest_enable=YES
guest_username=www-data
user_sub_token=$USER
local_root=/var/www/$USER
chroot_local_user=YES
hide_ids=YES
force_dot_files=YES
ftpd_banner=Welcome to my private FTP service.
local_umask=022
```

and this is my **/etc/pam.d/vsftpd**

```
auth required pam_pwdfile.so pwdfile /etc/ftpd.passwd
account required pam_permit.so
```

The first time I have created the file **/etc/ftpd.passwd** in this way:

```
htpasswd -c -d -b /etc/ftpd.passwd domain1.com <password>
```

For the next users simply avoid the "**-c**" parameter:

```
htpasswd -d -b /etc/ftpd.passwd domain2.com <password>
```

With this simple configuration all users have these credentials:

 - host: domain1.com
 - username: domain1.com
 - password: password
 - port: 21
 - Root folder: /var/www/domain1/

Now the point is: how can we create multiple users for a single domain each one with a different root folder?
The answer is pretty simple, follow me!

Create the folder **/var/www/users** and add the following line at the end of */etc/vsftpd.conf*

```
user_config_dir=/var/www/users
```

Inside the folder */var/www/users* create a file for each virtual user (for example the user **user1.domain1.com**) containing a line with the root directory for that user:

```
echo "local_root=/var/www/domain1.com/pub/user1" > /var/www/users/user1.domain1.com
```

Now add the new user/password in */etc/ftpd.passwd* as usual:

```
htpasswd -d -b /etc/ftpd.passwd user1.domain1.com <password>
```

Restart vsftpd server and test your new configuration!

license: MIT

branch_name: refs/heads/master

extension: md

license_type: permissive


text:
---
layout: post
title: "Start with what you know"
excerpt: "Learning something brand new? Think again, it's probably got
some overlap to skills you already have. Here's one way I approach
learning to make it a more effective, intentional process."
tags: learning
---

<div class="alert alert-info">
  This post isn't directly or exclusively about Rails. It's from a
  writing idea I had a few months ago, to share more general thoughts
  on being a good software developer, teammate, and communicator. I
  abandoned the project, but liked this piece, and wanted to share it.
  Expect a few more similar to this in the future. I hope you find it
  useful!
</div>

The next time you need to learn something new, start with what you know.
Then apply that to learning the new thing.

Let’s take the approach I took to learn test-driven development on
Rails. At the time, TDD was still a new concept to me, but I’d written
and released a handful of Rails apps, and manually tested each one
through the browser. More importantly, these were real apps with real
users. If something was broken, I’d hear about it fast!

But manual testing and releasing software into the wild without a safety
net don’t scale, and I knew that. So I took what I had—reasonably sound
software that I trusted—and applied it to what I needed to learn.

Starting small, I focused on simple, tiny tests that covered
functionality that obviously worked in my applications: data entry
validations, relations across different classes of objects, string
manipulations. If the tests failed, I could be reasonably certain that
it wasn’t the application’s fault; it was the test. And if I wasn’t so
certain, double-checking my work was as simple as loading an object into
the Rails console and experimenting with it.

Once I’d mastered these simple tests, I gradually moved to more complex
examples that took inputs from different sources, requiring several
objects to play nice together, and eventually full-stack tests
interacting not just with Rails, but with front-end code, external APIs,
and the rest of what’s considered a full web stack.

As an added bonus, as I mastered each layer of testing, I improved my
apps’ test coverage. Again, these were real, production apps, not toys
never intended for public consumption. I delivered value as I learned.

It's not just for testing--I'm using this approach now, as I need to
get more comfortable with modern front-end development after a few
years focusing more on the back-end. Tools like Webpack and Tailwind
CSS are new to me, but they're just different, more efficient ways to
accomplish things I already know how to do.

Technology moves quickly, but don’t discount what you already know.
Look for ways to apply that knowledge to what you need to learn next,
and build new skills on top of it, deliberately.

repository: everydayrails/everyday-rails

branch_name: refs/heads/main

extension: markdown

gha_language: HTML

repo_name: everydayrails/everyday-rails


text:
[com.github.salomonbrys.kodein](../index.md) / [CInstance](index.md) / [fullDescription](.)

# fullDescription

`val fullDescription: String`

Overrides [Provider.fullDescription](../-provider/full-description.md)

The description of this factory (using full type names), *used for debug print only*.

repository: hakanerp/Kodein

repo_name: hakanerp/Kodein


text:
---
# Course title, summary, and position.
linktitle: "glide.discovery.use_probe_results_cache"
summary: ""
weight: 1
# Page metadata.
title: "glide.discovery.use_probe_results_cache"
date: "2018-09-09T00:00:00Z"
lastmod: "2018-09-09T00:00:00Z"
draft: false  # Is this a draft? true/false
toc: true  # Show table of contents? true/false
type: docs  # Do not modify.

# Add menu entry to sidebar.
# - name: Declare this menu item as a parent with ID name.
# - weight: Position of link in menu.
menu:
  properties:
    parent: Properties
    name: "glide.discovery.use_probe_results_cache"
    weight: 1
---

Description: <b>Use probe results cache:</b> If set to yes, the cache will be checked to see if the results of the probe need to be processed by a sensor. It will only need to be processed if the results have changed from the last discovery run.

Value: `false`

repository: akhiltony/sn

gha_license_id: MIT

repo_name: akhiltony/sn


text:
modV exercises

- [1. Start modV](#1-start-modv)
  - [Note](#note)
- [2. Add the Waveform module to a layer](#2-add-the-waveform-module-to-a-layer)
  - [Question(s)](#questions)
- [3. Change layer options](#3-change-layer-options)
- [4. Save your preset](#4-save-your-preset)
  - [Note](#note-1)
- [5. Find the media folder](#5-find-the-media-folder)
  - [Mac](#mac)
  - [Linux](#linux)
  - [Windows](#windows)
- [6. Add the tapestryfract.fs module](#6-add-the-tapestryfractfs-module)
  - [Question(s)](#questions-1)
- [7. Make the Waveform visible again by using blending](#7-make-the-waveform-visible-again-by-using-blending)
- [8. Change module properties automatically by using an LFO (Low Frequency Oscillator)](#8-change-module-properties-automatically-by-using-an-lfo-low-frequency-oscillator)
- [9. Change module properties automatically with Audio analysis](#9-change-module-properties-automatically-with-audio-analysis)
  - [Note](#note-2)
- [10. Add custom visuals from Shadertoy](#10-add-custom-visuals-from-shadertoy)
  - [Note](#note-3)
- [11. Use a MIDI controller to enable modules](#11-use-a-midi-controller-to-enable-modules)
  - [Note](#note-4)
- [12. Audio Routing](#12-audio-routing)
- [13. Import Tims preset](#13-import-tims-preset)

---

## 1. Start modV

* Open your terminal
* Go into the `modV` folder
* Execute `npm start`
* After 30 to 60 seconds modV will automatically open in Chrome, if not then go to [localhost:8080](localhost:8080)
* Chrome will ask you to give access to your webcam and microphone and MIDI, please allow all of these!
* There will be two windows, one for modV and one for the `output window` (you can close the `output window` for performance improvements)
* Find the `preview window` in the bottom right (it's a black rectangle)
* Movee the `preview window` to the bottom left by dragging (click + hold and move your mouse / trackpad)

### Note

* You can close the output window that gets opened by modV as we will use the preview window instead
* If the output window doesn't open, your browser is blocking pop-ups!

---

## 2. Add the Waveform module to a layer

* Open the `Modules` tab
* Find the `Waveform` module in the `Module 2D` section
* Add it to the layer (either drag'n' drop or doubleclick)
* Enable it to see it in your output window
* Click on the module and find the module options in the bottom left of the screen
* Play around with the `stroke`, `height` & `color` attributes

### Question(s)

* Why is the waveform moving? Where does the sound come from?

---

## 3. Change layer options

* Click on the layer
* Find the `layer options` in the bottom right
* Activate `clearing` and deactivate `inherit`

---

## 4. Save your preset

* Open the `Presets` tab
* Enter a name for your preset
* Hit the `Save` button

### Note

* This will save your data into the media-folder that was created during startup of modV
* All your files will be there

## 5. Find the media folder

* Based on your operating system (Windows, Mac or Linux) you can find the folder in a different location:

### Mac
`~/Library/Application\ Support/modV/media/`

### Linux
`~/.config/modV/media/`

### Windows
`%appdata%\modV\media\`

* Open the preset you just saved with the editor of your choice
* You can find out more about the [folder structure in modV documentation](https://modv.js.org/guide/mediaManager.html#structure)

---

## 6. Add the tapestryfract.fs module

* Open the `Modules` tab
* Find the `tapestryfract.fs` module in the `Module ISF` section
* Add it to the layer
* The module was added on top of the layer, but we want it to be the last module in the layer (after `Waveform`), so drag'n'drop it to move it inside the layer
  * Your layer should look like this now
  ![modV ta](docs/media/modv_tapestryfract_last_module.png)
* Enable the module to see it in the output window

### Question(s)

* What happend with the Waveform? Why is it not visible anymore?

---

## 7. Make the Waveform visible again by using blending

* Disable the `tapestryfract.fs` module is the first option, but we want to see both at the same time
* This is where `blending` comes into play, but we can't see it  yet
* Open the `Plugins` tab
* Locate the `Slim UI` plugin and disable it by clicking on the button next to the name of the plugin

  ![Plugins button](docs/media/modv_plugin_button.png)
* You can now see that there are even more configuration options for each module in the layer
  ![SlimUI deactivated](docs/media/modv_modules_full.png)
* In the `Blending` dropdown select `source-in`
* The `Waveform` should be visible and instead of showing colors you see the `tapestryfract.fs`
* Play around with the other values for `blending` and also try out `opacity` of a module

## 8. Change module properties automatically by using an LFO (Low Frequency Oscillator)

* Select the `Waveform` module
* Right click on the `Stroke` attribute in the module options
* Select `Attach LFO` and then `sine`
* The `Stroke` is now updating according to a sine wave
* Right click again on the `Stroke`, select `LFO`  and then `Edit LFO`, which opens an editor to change the LFO
* Click on the checkbox `Use BPM` to not use the detected BPM
* Change the value to `5` and see that the `Stroke` is changing very fast
* Play around with `LFO` using the `LFO editor` and also use `Sawtooth`, `Square` and `Noise`
* To remove the `LFO` again you right click on the `Stroke`, select `LFO` and then `Remove LFO`

---

## 9. Change module properties automatically with Audio analysis

* Select the `Waveform` module
* Right click on the `Stroke` attribute in the module options
* Select `Attach Feature` and then `zcr`
* The value of `Stroke` is now updating live to audio input
* Right click on the `Stroke` attriubte, select `Attach Feature` and then `Remove Feature Assignment` to remove `zcr` again
* Right click on the `Stroke` attriubte, select `Attach Feature` and then select `energy`
* You will see that the `Stroke` is near to 0, as `energy` only provides a value between 0 and 1
* Right click on the `Stroke` attribute, select `Edit expression`
* The `Expression Editor` opens, which can be used to apply math to the value of the attribute
* Inside of the editor, change the text so that it looks like this: `value * 100`
* You can now see that the value for `Stroke` is back to something visible
* Play around with the other `Audio Features` and the `Expression Editor`

### Note

* The audio analysis is provided by [Meyda](https://meyda.js.org/)
* You can find out more about the different `audio features` [in this demo](https://jsbin.com/movezix/6/edit?html,js,output)

---

## 10. Add custom visuals from Shadertoy

* Open the `Shadertoy` tab
* You see a search box to find shaders
* Type in `garden` and hit the enter key on your keyboard
* Click on `Rock Garden`
* The module was added to your modules, so open the `Modules` tab
* In the top of the screen you can find a search box, type in `Rock Garden` to filter the modules that are visible
* Add the `Rock Garden` module to your layer
* Play around with Shadertoy and find new modules

### Note

* You can't save shadertoy modules into your preset, they are gone after modV was restarted
* To actually persist them, you have to follow the [instructions in the modV documentation](https://modv.js.org/guide/writingAShaderModule.html#_1-create-a-new-file)

---

## 11. Use a MIDI controller to enable modules

* Attach a MIDI controller via USB to your computer
* Select the `Waveform` module
* Right click on the `Enable` checkbox, then select `Learn MIDI assignment`
* The next time you use your MIDI controller and push a button, modV will assign the button to the checkbox
* If your MIDI controller also has knobs or faders, you can right click on the module attribute `Height` and select `Learn MIDI assignment`
* Now move the knob or fader on your MIDI controller and see that the value of the attribute is chaning accordingly

### Note

* You can see if your MIDI controller can be used by using [the MIDI console](https://factotumo.com/web-midi-console/)

--

## 12. Audio Routing

* Follow the [instructions in the modV documentation](https://modv.js.org/guide/audioRouting.html) for your operation system (Windows, Mac or Linux)
* Reload modV (make sure to save your preset)
* In the top right you find the menu of modV, click on the icon
* This will open a global configuration window
* The first block is called `Input`
* There you can find `Audio Input` with a dropdown
* Select the Audio Routing option of your OS and see that instead of the microphone it will use your configured audio
* Play some music and you see that your visuals react to it

## 13. Import Tims preset

* [Download the preset](https://github.com/TimPietrusky/visual-and-light-workshop/blob/master/timpietrusky.zip)
* Extract it
* Put it into your media folder (so its on the same level as the `default` folder)
* Reload modV
* Load the project `timpietrusky` using the `Projects` tab
* Load the preset `timpietrusky-live-2019`

repository: TimPietrusky/visual-and-light-workshop

gha_language: JavaScript

repo_name: TimPietrusky/visual-and-light-workshop


text:
---
# Documentation: https://sourcethemes.com/academic/docs/managing-content/

title: "When should ballooning incidents be reported?"
authors: [Ashleigh Filtness, Natassia Goode, Natassia, Rober Cook, and Gelareh Eighani]
date: 2015-09-26T20:36:02+01:00
doi: ""

# Schedule page publish date (NOT publication's date).
publishDate: 2020-07-26T20:36:02+01:00

# Publication type.
# Legend: 0 = Uncategorized; 1 = Conference paper; 2 = Journal article;
# 3 = Preprint / Working Paper; 4 = Report; 5 = Book; 6 = Book section;
# 7 = Thesis; 8 = Patent
publication_types: ["10"]

# Publication name and optional abbreviated publication name.
publication: "Aeronotes, the official journal of the Australian Ballooning Federation 37(3), 6-7. ISSN:1036-8264"
publication_short: ""

abstract: "This article follows on from our previous article in Aeronotes Volume 37 No.2 'Prepare and prevent, don't repair and repent, Causal factors of hot air ballooning incidents'. While nearly every balloon flight ends safely, with every flight comes the opportunity for an accident. The ABF maintains an incident reporting database containing information on all the accidents and near misses that are reported to them. The goal of the database is to provide a formal way for ABF members to share accident or near miss experiences and prevent future occurrences. We recently analysed the causal factors involved in the incident reports collected by the ABF. Twenty-two incident reports were analysed and 54 causal factors were identified that were reported to play a role in hot air ballooning accidents. While many factors were identified, the findings of this study were limited by the small number of incident reports available from the ABF reporting system..."

# Summary. An optional shortened abstract.
summary: ""

tags: []
categories: []
featured: false

# Custom links (optional).
#   Uncomment and edit lines below to show custom links.
# links:
# - name: Follow
#   url: https://twitter.com
#   icon_pack: fab
#   icon: twitter

url_pdf: "https://eprints.qut.edu.au/89661/7/89661.pdf"
url_code:
url_dataset:
url_poster:
url_project:
url_slides:
url_source:
url_video:

# Featured image
# To use, add an image named `featured.jpg/png` to your page's folder.
# Focal points: Smart, Center, TopLeft, Top, TopRight, Left, Right, BottomLeft, Bottom, BottomRight.
image:
  caption: ""
  focal_point: ""
  preview_only: false

# Associated Projects (optional).
#   Associate this publication with one or more of your projects.
#   Simply enter your project's folder or file name without extension.
#   E.g. `internal-project` references `content/project/internal-project/index.md`.
#   Otherwise, set `projects: []`.
projects: [balloonsafety]

# Slides (optional).
#   Associate this publication with Markdown slides.
#   Simply enter your slide deck's filename without extension.
#   E.g. `slides: "example"` references `content/slides/example/index.md`.
#   Otherwise, set `slides: ""`.
slides: ""
---

license: Unlicense,MIT

detected_licenses: Unlicense MIT

gha_license_id: NOASSERTION


text:
# Laravel Hey Man

## A package to help you write expressive code in a functional manner

![image](https://user-images.githubusercontent.com/6961695/43285148-4d86673e-9133-11e8-9415-2df017906762.png)

## And it works !!!

[![code coverage](https://codecov.io/gh/imanghafoori1/laravel-heyman/branch/master/graph/badge.svg)](https://codecov.io/gh/imanghafoori1/laravel-heyman)
[![Maintainability](https://api.codeclimate.com/v1/badges/9d6be7b057103cb14410/maintainability)](https://codeclimate.com/github/imanghafoori1/laravel-heyman/maintainability)
[![Build Status](https://travis-ci.org/imanghafoori1/laravel-heyman.svg?branch=master)](https://travis-ci.org/imanghafoori1/laravel-heyman)
[![Code Coverage](https://scrutinizer-ci.com/g/imanghafoori1/laravel-heyman/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/imanghafoori1/laravel-heyman/?branch=master)
[![StyleCI](https://github.styleci.io/repos/139709518/shield?branch=master)](https://github.styleci.io/repos/139709518)
[![Latest Stable Version](https://poser.pugx.org/imanghafoori/laravel-heyman/v/stable)](https://packagist.org/packages/imanghafoori/laravel-heyman)
[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=round-square)](LICENSE.md)

## :ribbon::ribbon::ribbon: HeyMan : "_cleaner code_" :heavy_plus_sign: "_easy authorization_" :ribbon::ribbon::ribbon:

### Built with :heart: for every smart laravel developer

and it is very well tested !

## Installation

```

composer require imanghafoori/laravel-heyman

```

### Requirements:

```
PHP > v7.0
Laravel > v5.4
```

## Sample Application :

https://github.com/imanghafoori1/council

https://github.com/imanghafoori1/council

This is fork from result of laracasts.com toturial series refactored to use the Heyman package.

### A story :

Imagine your boss comes to you and says :

> Hey man,
> When you go to login form, You should be guest,
> Otherwise you must get redirected to '/panel',
> Write the code for me, just now... But KEEP IN MIND you are not allowed to touch the current code. it is very sensitive and we do not want you to tamper with it. You may break it.

And you write code like this in a Service Provider `boot` method to implement what your boss wanted.

![image](https://user-images.githubusercontent.com/6961695/43285559-8c09a1e6-9134-11e8-841b-2dc933456082.png)

### That is what this package does for you + a lot more...

### Structural Benefits:

This way you can fully decouple authorization and a lot of guarding code from the rest of your application code and put it in an other place. So your Controllers and Routes become less crowded. and you will have a central place where you limit the access of users to your application or perform validation.

#### Should You Remember and Type in All The Methods?

You do not need any cheat sheet.

> IDE `Auto-completion` is fully supported.

![untitled](https://user-images.githubusercontent.com/6961695/43330799-7d02cc54-91d9-11e8-845b-946077033ec6.png)

#### Where do I put these codes ?
> You can put these codes in `AuthServiceProvider.php` (or any other service provider) `boot` method to take effect.

![image](https://user-images.githubusercontent.com/6961695/43330086-66d0b9a2-91d7-11e8-84fb-fa4ff90821a3.png)

## Watching Urls

```php
HeyMan::whenYouVisitUrl(['/welcome', '/home'])->...   // you can pass an Array
HeyMan::whenYouVisitUrl('/admin/articles/*')->...     // or match by wildcard
```
```php
HeyMan::whenYouSendPost($url)->   ...
HeyMan::whenYouSendPatch($url)->  ...
HeyMan::whenYouSendPut($url)->    ...
HeyMan::whenYouSendDelete($url)-> ...
```

## Watching Route Names

```php
HeyMan::whenYouReachRoute('welcome.name')->...              // For route names
HeyMan::whenYouReachRoute('welcome.*')->...                 // or match by wildcard
```

## Watching Controller Actions

```php
HeyMan::whenYouCallAction('HomeController@index')->...
HeyMan::whenYouCallAction('HomeController@*')->...          // or match by wildcard
```

## Watching Blade files
```php
 HeyMan::whenYouMakeView('article.editForm')->...     // also accepts an array
 HeyMan::whenYouMakeView('article.*')->...            // You can watch a group of views
 ```

 ## Watching Custom Events
```php
HeyMan::whenEventHappens('myEvent')->...
```

## Watching Eloquent Model Events
```php
HeyMan::whenYouSave(\App\User::class)->...
HeyMan::whenYouFetch(\App\User::class)->...
HeyMan::whenYouCreate(\App\User::class)->...
HeyMan::whenYouUpdate(\App\User::class)->...
HeyMan::whenYouDelete(\App\User::class)->...
```

 #### Note that the saving model is passed to the Gate of callback in the next chain call. so for example you can check the ID of the model which is saving.

*In case the gate returns `false` an `AuthorizationException` will be thrown.
*(If it is not the thing you want, do not worry you can customize the action very easily, we will discuss shortly.)

This way gate is checked after `event('myEvent')` is executed any where in our app

## What can be checked:

### 1 - Gates

```php
HeyMan::whenYouVisitUrl('/home')->thisGateShouldAllow('hasRole', 'param1')->otherwise()->...;
HeyMan::whenYouVisitUrl('/home')->thisGateShouldAllow('SomeClass@someMethod', 'param1')->otherwise()->...;
```

Passing a Closure as a Gate:

```php
$gate = function($user, $role){
    /// some logic
    return true;
}
HeyMan::whenYouVisitUrl('/home')->thisGateShouldAllow($gate, 'editor')->otherwise()->...;
```

### 2 - Authentication stuff:
```php
HeyMan::whenYouVisitUrl('/home')->  youShouldBeGuest()    ->otherwise()->...;
HeyMan::whenYouVisitUrl('/home')->  youShouldBeLoggedIn() ->otherwise()->...;
```

### 3 - Checking A `Closure` or `Method` or `Value`:
```php
HeyMan::whenYouVisitUrl('home')->thisMethodShouldAllow('someClass@someMethod', ['param1'])->otherwise()->...;
HeyMan::whenYouVisitUrl('home')->thisClosureShouldAllow(ّ function($a) { ... }, ['param1'])  ->otherwise()->...;
HeyMan::whenYouVisitUrl('home')->thisValueShouldAllow(ّ $someValue )->otherwise()->...;
```

### 4- Validate Requests:
```php
HeyMan::whenYouSendPost('articles.store')->yourRequestShouldBeValid([
    'title' => 'required', 'body' => 'required',
]);
```

That way you do not need to validate requests in your controllers or create dedicated FormRequest classes to validate input.

### Other things:

You can also use one of these:
```
HeyMan::whenYouVisitUrl('home')->youShouldAlways()-> ...
HeyMan::whenYouVisitUrl('home')->sessionShouldHave('key1')->...
```

--------------------

## Reactions:

### 1 - Deny Access
```php
HeyMan::whenSaving(\App\User::class)->thisGateShouldAllow('hasRole', 'editor')->otherwise()->weDenyAccess();
```
An `AuthorizationException` will be thrown if needed

### 2 - Redirect
```php
HeyMan::whenYouVisitUrl('/login')-> ... ->otherwise()->redirect()->to(...)     ->with([...]);
HeyMan::whenYouVisitUrl('/login')-> ... ->otherwise()->redirect()->route(...)  ->withErrors(...);
HeyMan::whenYouVisitUrl('/login')-> ... ->otherwise()->redirect()->action(...) ->withInput(...);
HeyMan::whenYouVisitUrl('/login')-> ... ->otherwise()->redirect()->intended(...);
HeyMan::whenYouVisitUrl('/login')-> ... ->otherwise()->redirect()->guest(...);
```
In fact the redirect method here is very much like the laravel's `redirect()` helper function.

### 3- Throw Exception:
```php
$msg = 'My Message';

HeyMan::whenYouVisitUrl('/login')
    ->youShouldBeGuest()
    ->otherwise()
    ->weThrowNew(AuthorizationException::class, $msg);
```

### 4- Abort:
```php
HeyMan::whenYouVisitUrl('/login')-> ... ->otherwise()->abort(...);
```

### 5- Send Response:
Calling these functions generate exact same response as calling them on the `response()` helper function:
`return response()->json(...);`

```php
HeyMan::whenYouVisitUrl('/login')-> ... ->otherwise()->response()->json(...);
HeyMan::whenYouVisitUrl('/login')-> ... ->otherwise()->response()->view(...);
HeyMan::whenYouVisitUrl('/login')-> ... ->otherwise()->response()->jsonp(...);
HeyMan::whenYouVisitUrl('/login')-> ... ->otherwise()->response()->make(...);
HeyMan::whenYouVisitUrl('/login')-> ... ->otherwise()->response()->download(...);
```

## Advanced Usage:

You may want to call some method or fire an event right before you send the response back.
You can do so by `afterCalling()` and `afterFiringEvent()` methods.

```php
HeyMan::whenYouVisitUrl('/login')-> ... ->otherwise()->afterFiringEvent('explode')->response()->json(...);
HeyMan::whenYouVisitUrl('/login')-> ... ->otherwise()->afterCalling('someclass@method1')->response()->json(...);
```

### Disabling Heyman:
You can disable HeyMan chacks like this (useful while testing):

![untitled](https://user-images.githubusercontent.com/6961695/43585840-53aae034-967b-11e8-8503-2c1de7a35e9f.png)

```php
HeyMan::turnOff()->allChecks();
...
/// some code here
...
HeyMan::turnOn()->allChecks();

```
--------------------

### :raising_hand: Contributing
If you find an issue, or have a better way to do something, feel free to open an issue or a pull request.
If you use laravel-widgetize in your open source project, create a pull request to provide it's url as a sample application in the README.md file.

### :exclamation: Security
If you discover any security related issues, please email<EMAIL_ADDRESS>instead of using the issue tracker.

### :star: Your Stars Make Us Do More :star:
As always if you found this package useful and you want to encourage us to maintain and work on it. Just press the star button to declare your willing.

### More from the authors:

### Laravel Widgetize

 :gem: A minimal yet powerful package to give a better structure and caching opportunity for your laravel apps.

- https://github.com/imanghafoori1/laravel-widgetize

------------

### Laravel Terminator

 :gem: A minimal yet powerful package to give you opportunity to refactor your controllers.

- https://github.com/imanghafoori1/laravel-terminator

------------

### Laravel AnyPass

:gem: It allows you login with any password in local environment only.

- https://github.com/imanghafoori1/laravel-anypass

repository: KhaledAbdulBasit/laravel-heyman

repo_name: KhaledAbdulBasit/laravel-heyman


text:
## Instructions

Install homebrew; follow instructions at http://brew.sh

Install pyenv using homebrew; follow instructions at https://github.com/pyenv/pyenv#homebrew-on-mac-os-x

Install pyenv-virtualenv using homebrew; follow instructions at https://github.com/pyenv/pyenv-virtualenv#installing-with-homebrew-for-os-x-users

Install python 3.8.5; you can get available versions by running `pyenv install -l`:

    pyenv install 3.8.5

cd into this repo and create a new virtualenv for it:

    cd ~/provision-mac
    pyenv virtualenv 3.8.5 provision-mac

Install ansible:

    pip install -r requirements.txt

Run:

    ./run

## Copyright

The following files in this directory are Copyright (c) to the Homebrew contributors under the BSD 2-Clause License:

- install-homebrew.sh

All other files in this directory are Copyright (c) 2019 to Yan Han Pang, under the 3-Clause BSD License.

repository: yanhan/provision-mac

gha_language: Vim Script

repo_name: yanhan/provision-mac


text:
# Releasing Google Cloud Ruby Client

These instructions apply to every gem within the [Google Cloud Ruby
Client](https://github.com/googleapis/google-cloud-ruby) project.

## Releasing individual gems and meta-packages

After all relevant [pull
requests](https://github.com/googleapis/google-cloud-ruby/pulls) for a
release have been merged and all [Kokoro builds](#checking-the-status-of-kokoro-builds) are
green, you may create a release as follows:

1.  Review the report of changes for all gems.

    ```sh
    $ bundle exec rake changes
    ```

1. Choose a gem to release based on the changes report from the previous step.
   If there are changes to
   [google-cloud-errors](https://github.com/googleapis/google-cloud-ruby/tree/master/google-cloud-errors),
   [google-cloud-core](https://github.com/googleapis/google-cloud-ruby/tree/master/google-cloud-core),
   and/or
   [stackdriver-core](https://github.com/googleapis/google-cloud-ruby/tree/master/stackdriver-core),
   be sure to release them first, in the order listed. Release
   [google-cloud](https://github.com/googleapis/google-cloud-ruby/blob/master/google-cloud)
   and
   [stackdriver](https://github.com/googleapis/google-cloud-ruby/blob/master/stackdriver)
   last, in case of dependency changes. (See steps 13 and 14, below.)

1. In the root directory of the project, from the master branch, review the changes for the gem since its
   last release.

    ```sh
    $ git pull
    $ bundle exec rake changes[<gem>]
    ```

1. Review the commits in the output from the previous step, making note of
   significant changes. (For examples of what a significant change is, browse
   the changes in the gem's `CHANGELOG.md`.)

1. If your gem is new, follow the steps in [Adding a new gem to the top-level
   package and the meta-packages](#adding-a-new-gem-to-the-top-level-package-and-the-meta-packages),
   below.

1. If the [semver](http://semver.org/) version change for your gem requires
   an increase in the requirement for your gem in
   `google-cloud/google-cloud.gemspec` and/or
   `stackdriver/stackdriver.gemspec`, replace the old version requirement with
   your new requirement. Note that because of the use of the [pessimistic
   operator (`~>`)](https://robots.thoughtbot.com/rubys-pessimistic-operator),
   only certain version changes will require updating the requirement. Note
   also that the dependency requirements in the `google-cloud` and
   `stackdriver` gems must remain compatible so the two can co-exist in the
   same bundle.

1. If your gem is new, ensure that a nav link and a main entry including
   code example have been added to the [top-level
   README](https://github.com/googleapis/google-cloud-ruby/blob/master/README.md).

1. Python 3.6 or 3.7 is required. If you do not have Python 3.6 or 3.7 installed we recommend [this guide](https://docs.python-guide.org/starting/installation/#installation-guides).

1. Update/Install releasetool with the following:

    ```sh
    $ python3 -m pip install --user --upgrade gcp-releasetool
    ```

1. While on the master branch, cd into the directory of the gem you would like to release, and run:

    ```sh
    $ python3 -m releasetool start
    ```

    1. If it's your first time running this, releasetool will likely ask you for a GitHub API token with write:repo_hook and public_repo permissions from https://github.com/settings/tokens.

    1. Next, releasetool will present you with an automatically generated changelog. Use the information from steps 4 and 5, as well as the provided PR numbers to edit and complete the changelog. Remove the "(#111)" style PR references before continuing.

    1. Releasetool will then ask you if your change is considered major, minor, or patch. This project uses [semantic versioning](http://semver.org).

    1. Releasetool will then create and switch to a branch called `release-#{gem-name}-v#{version}`, make all the necessary changes to the changelog and gem version, and open a [pull request](https://github.com/googleapis/google-cloud-ruby/pulls).

1. Review the PR created by releasetool in the previous step, apply the appropriate label (i.e. `api: #{gem_name}`), and request a review from googleapis/yoshi-ruby.

1. Repeat steps 3 through 12 if you are releasing multiple gems.

1. If you updated `google-cloud/google-cloud.gemspec` for a version change to
   any gem, repeat steps 4 through 12 for the `google-cloud` gem.

1. If you updated `stackdriver/stackdriver.gemspec` for a version change to any
   gem, repeat steps 4 through 12 for the `stackdriver` gem.

1. After your pull request has passed all checks and been approved by reviewers,
   **Squash and merge** it. Do **not** delete the branch. [Kokoro](#checking-the-status-of-kokoro-builds) will create the [GitHub release summary](https://github.com/googleapis/google-cloud-ruby/releases) and build and push the gem to [rubygems](https://rubygems.org/). If yoshi-automation reports a failure creating the [GitHub release summary](https://github.com/googleapis/google-cloud-ruby/releases), file a bug on [releasetool's issue tracker](https://github.com/googleapis/releasetool/issues), and [write the release manually](#writing-a-github-release-summary-manually). If yoshi-automation reports that the release build has failed, follow [these steps](#checking-the-status-of-kokoro-builds), selecting the Kokoro build titled "Kokoro - Release".

1. If everything has gone successfully, [yoshi-automation](https://github.com/yoshi-automation) will post twice on the merged PR. Once to provide the status and link for the [GitHub release summary](https://github.com/googleapis/google-cloud-ruby/releases), and again to provide the status of the task to publish to [rubygems](https://rubygems.org/). At this point, please delete the branch created by releasetool in step 11(iv).

1. Verify the [GitHub release summary](https://github.com/googleapis/google-cloud-ruby/releases), making sure that it fits the format of other releases, mirrors the changelog, is tagged to the appropriate commit hash, and is for the correct version.

1. Verify that the new version is displayed on the google-cloud-ruby doc site at `googleapis.dev/ruby/#{gem_name}/latest`. The docs are published from the staging bucket every 15 minutes, so it may a few minutes to update.

   If it's been 30 minutes and the docs have not updated, [inspect the Kokoro build logs](#checking-the-status-of-kokoro-builds) to confirm that the rake `release` task succeeded.

1. Verify that the correct version of the gem was published on [rubygems](https://rubygems.org/).

1. Verify that the [Kokoro Jobs](#checking-the-status-of-kokoro-builds) have succeeded. If so, you may now delete the branch belonging to the pull request.

High fives all around!

## Adding a new gem to the top-level package and the meta-packages

There are extra steps required to add a new gem to the top-level package and the
`google-cloud` and/or `stackdriver` meta-package gems. These instructions are
for the `google-cloud` gem.

1. Add the gem to
   [`Gemfile`](https://github.com/googleapis/google-cloud-ruby/blob/master/Gemfile).
1. Add the gem to
   [`google-cloud/Gemfile`](https://github.com/googleapis/google-cloud-ruby/blob/master/google-cloud/Gemfile).
1. Add the gem to
   [`google-cloud/google-cloud.gemspec`](https://github.com/googleapis/google-cloud-ruby/blob/master/google-cloud/google-cloud.gemspec).
1. Add the gem to
   [`gcloud/Gemfile`](https://github.com/googleapis/google-cloud-ruby/blob/master/gcloud/Gemfile).

## Checking the status of Kokoro builds

1. On the [commits](https://github.com/googleapis/google-cloud-ruby/commits/master) page, find the commit you expect to have launched a Kokoro build.

1. To the right of your commit, there should be either a red x, or a green checkmark. If it's the green checkmark, your build was a success, and no further inspection is necessary. If it's the red x, click it to find out why the build failed.

1. A modal will appear with the list of Kokoro builds. The build titled "Kokoro CI" can be ignored. To learn more about why a build failed or what it was testing for click "details" next to the build.

1. The "details" link will take you to a page on https://source.cloud.google.com/. On the "TARGETS" tab, there will be a link to the logs. It will look like `cloud-devrel/client-libraries/google-cloud-ruby/#{job_type}-#{operating_system}`. Click the link.

1. The next page will have a list of all the tasks carried out under the selected operating system. The top half will be a list of tasks and the links to their respective logs, the bottom half will be a list of tasks and their status (SUCCEEDED/FAILED). To learn more about why a task failed, clink the corresponding link on the top half of the screen.

1. You will be greeted with a screen similar to the one in step 4. The link to your task should look like `cloud-devrel/client-libraries/google-cloud-ruby/#{job_type}/#{operating_system}/#{task_name}`. Click it.

1. The "TARGET LOG" tab should be pre-selected, and will contain the complete logs. Examine the logs to determine what went wrong. Before taking the steps below, check to see if the issue appears on [the list of known issues](https://github.com/googleapis/google-cloud-ruby/wiki/Known-Issues#kokoro-build-failures). If you see the error there, and you are confident that your release is unrelated, no further steps are necessary.

1. If you feel the error was transient:
    1. If the error occurred on "Kokoro - Release", selected in step 2, go to [the PR containing your release](https://github.com/googleapis/google-cloud-ruby/pulls?utf8=%E2%9C%93&q=is%3Apr+is%3Aclosed+Release). Unselect the labels "autorelease: published" and "autorelease: failed". This will cause Kokoro to attempt to rebuild and publish the gem you are releasing.

    1. If the error occurred on "Kokoro - Linux", "Kokoro - OSx", or "Kokoro - Windows" and you have access to [fusion](https://fusion.corp.google.com/dashboard/findbuilds?search_pattern=google-cloud-ruby%2Fcontinuous&project_types=&include_inactive_projects=false), find the failing build, click on it, then click "rebuild". If you do not have access to [fusion](https://fusion.corp.google.com/dashboard/findbuilds?search_pattern=google-cloud-ruby%2Fcontinuous&project_types=&include_inactive_projects=false), file an [issue](https://github.com/googleapis/google-cloud-ruby/issues/new?template=bug_report.md) containing a link to the build logs, a brief summary, and "@googleapis/yoshi-ruby".

1. If you feel the error was deterministic:
    1. If you are confident that the error is unrelated to your release, please open an [issue](https://github.com/googleapis/google-cloud-ruby/issues/new?template=bug_report.md) with a description of the problem and a link to the build logs.

    1. If the error is related to your release and you have access to the googleapis [rubygems](https://rubygems.org/) account, follow [these instructions](http://help.rubygems.org/kb/gemcutter/removing-a-published-rubygem) to yank the gem. Open an [issue](https://github.com/googleapis/google-cloud-ruby/issues/new?template=bug_report.md) detailing what went wrong and begin working on a fix.

    1. If the error is related to your release and you do not have access to the googleapis [rubygems](https://rubygems.org/) account, please open an [issue](https://github.com/googleapis/google-cloud-ruby/issues/new?template=bug_report.md) containing a link to the build logs, a brief summary, and "@googleapis/yoshi-ruby".

## Writing a GitHub release summary manually
1. [Draft a new GitHub release summary](https://github.com/googleapis/google-cloud-ruby/releases/new).

1. Add a tag. The tag should be of the format `#{gem_name}/v#{version_number}`.

1. To the right of the tag and "@" symbol, there will be a dropdown with "Target: master. Click the dropdown, select the "Recent Commits" tab, and find and select the commit that was your merged PR.

1. Add a title in the format `Release #{gem_name} #{version_number}`.

1. Copy the content of the most recent update in the gem's `CHANGELOG.md` into the textarea with placeholder text "Describe this release".

1. Click "Publish release"

repository: googleapis/google-cloud-ruby

gha_language: Ruby

repo_name: googleapis/google-cloud-ruby


text:
---
layout: post
title: "Direct image uploads from the browser to the cloud with Ember.js and Cloudinary"
date: 2014-07-13 10:19
comments: true
categories: emberjs cloudinary javascript
---

**Update 07/20/2014:** I've written an additional post on [unsigned uploads]({% post_url 2014-07-20-direct-unsigned-cloudinary-uploads-with-emberjs %}) that builds upon this article.

Uploading images to a web application has historically sucked. If you're in the Ruby on Rails world, there are a few gems like [Paperclip](https://github.com/thoughtbot/paperclip) and [Carrierwave](https://github.com/carrierwaveuploader/carrierwave) which are great attempts at solving this problem, but are about as fun to work with as a pile of rocks. I'm picking on these two in particular because they are the [most popular Rails file upload gems](https://www.ruby-toolbox.com/categories/rails_file_uploads), and every time I have to use one of these libraries, I get pissed off.

Some of the issues I have with these gems include:

* They try to cover every possible use case, making it difficult to
  figure out what code you actually need.
* The DSLs are designed with nearly infinite flexibility, making them hard
  to learn and remember.
* They require storing image meta data in the database and it's hard to remember which columns are required.

* They're not opinionated enough and we end up with a slightly different implementation each time.

The last point is the main reason I'm writing this post. I like opinions and hate thinking about something boring after I've done it once. This is why I use Ember.js, Rails, OS X, a car with automatic transmission, and the popcorn setting on my microwave. I also don't set the clock on my microwave, but that has nothing to do with this blog post.

## Re-evaluating Our Needs

When [Agilion](http://agilion.com/) started working on a new customer project last month, I was less than thrilled to find out that we'd need to support image uploads. This was our first Ember.js project that required image uploads, so after a short discussion among our team, we wanted to try something different.

We decided to use [Cloudinary](http://cloudinary.com/) with direct image uploads to see if it made our lives any easier. The idea behind it is that the images go directly to the cloud storage host, and never pass through your server. If you've ever used Stripe for credit card processing, it's basically the same concept but for images. None of us had ever done this before, but the prospect of not dealing with storage, resizing images, and complicated documentation sounded too good to be true.

Our main goal for trying this approach was to reduce the development effort to support image uploading. Since all of our new projects are in Ember.js, we wanted to find a solution that would work well for this framework. As contract developers, we try to reduce our implementation time to keep costs down for our customers, and this seemed like a great opportunity to do that.

## Background Information and a Demo

After doing some research on direct image uploads, we learned that the basic flow works like this:

* User visits page and clicks file upload button
* User selects one or more images
* Images are sent directly to Cloudinary from the browser
* Cloudinary sends back meta data for each image one at a time, including the "public id" (later used to retrieve images)
* Browser makes API request to the server to create a new record for each image, and includes the Cloudinary "public id" in the request
* The image is fetched from Cloudinary on demand by constructing an image URL using the public ID.

 They are in separate repos because that is how we develop Ember apps at Agilion.

At the time of writing, the demo is using:

* [ember](http://emberjs.com/) - 1.6.0
* [ember-data](https://github.com/emberjs/data) - 1.0.0-beta.8
* [ember-cli](http://iamstef.net/ember-cli/) - 0.0.37
* [cloudinary_js](https://github.com/cloudinary/cloudinary_js) - 1.0.17
* [jquery-ui](http://jqueryui.com/) - 1.10.4
* [jquery-file-upload](http://blueimp.github.io/jQuery-File-Upload/) - 9.5.7
* [Rails](http://rubyonrails.org/) - 4.1.2
* [Rails::API](https://github.com/rails-api/rails-api) - 0.2.1

## Required Pieces of the Application

### Client-side (Ember)

* Initializer with Cloudinary configuration settings
* Cat Model
* Cats Controller
* Cloudinary File Input View
* Cats Template
* Cloudinary Image Tag Helper

### Server-side (Rails)

* API endpoint to generate authentication signature
* API endpoint to persist a record

I've only included the most important pieces of the Ember code to reduce the length of this post. Things like the router and Cats route are omitted but can be found in the example app. I've also left out the server-side code we use to generate the authentication signature because I want this to be a server-agnostic tutorial.

## Cloudinary Config Initializer

The initializer is simply telling the Cloudinary plugin what the **cloud name** and **public key** are for this application. In an Ember-CLI project, these values are stored in the [environment-specific configuration](https://github.com/beerlington/cats-ui/blob/master/config/environment.js#L30-L31). Note that there *is* a private key, but this is *not* set in the Ember app. The private key is used when creating an authentication signature (see "Authentication Signature" section) and is only included in the Rails app settings.

**app/initializers/cloudinary.js** - [GitHub](https://github.com/beerlington/cats-ui/blob/master/app/initializers/cloudinary.js)

```js
export default {
  name: 'cloudinary',

  initialize: function(/* container, app */) {
    $.cloudinary.config({
      cloud_name: CatsUiENV.CLOUDINARY_NAME,
      api_key:    CatsUiENV.CLOUDINARY_KEY
    });
  }
};
```

## Cat Model

The Cat model is pretty straightforward. We have a property for the name
of the cat, and a property for the Cloudinary Public ID. Both of these
attributes correspond to database columns on the [Cat model](https://github.com/beerlington/cats-api/blob/master/app/models/cat.rb) in the Rails application. Note that both are required in the demo.

**app/models/cat.js** - [GitHub](https://github.com/beerlington/cats-ui/blob/master/app/models/cat.js)

```js
export default DS.Model.extend({
  name:               DS.attr('string'),
  cloudinaryPublicId: DS.attr('string')
});
```

## The Cats Template

In the demo, the Cats template is used as both an index page to list all of the cats, as well as the location of the new cat form. I have only
included the form portion here.

**app/templates/cats.hbs** - [GitHub](https://github.com/beerlington/cats-ui/blob/master/app/templates/cats.hbs)

{% highlight handlebars %}
{% raw %}
<form role="form" {{action 'createCat' on='submit'}}>

    Cat Name
    {{input value=newCat.name class="form-control" id="cat-name" placeholder='Cat Name'}}

    File input
    {{view 'cloudinary'}}

  <button type="submit" class="btn btn-default">Submit</button>
</form>
{% endraw %}
{% endhighlight %}

In the code above, you can see that we are rendering the file input tag using an Ember view called 'cloudinary'.

## The Cloudinary View

The Cloudinary file input view has a few responsibilities related to setup and configuration of the Cloudinary widget. Here is the entire view in one piece, but it is broken down and explained in detail further down:

**app/views/cloudinary.js** - [GitHub](https://github.com/beerlington/cats-ui/blob/master/app/views/cloudinary.js)

```js
export default Ember.View.extend({
  tagName: 'input',
  name: 'file',
  attributeBindings: ['name', 'type', 'data-form-data'],
  type: 'file',

  didInsertElement: function() {
    var _this = this,
      controller = this.get('controller');

    $.get(CatsUiENV.API_NAMESPACE + '/cloudinary_params', {timestamp: Date.now() / 1000}).done(function(response) {
      // Need to ensure that the input attribute is updated before initializing Cloudinary
      Ember.run(function() {
        _this.set('data-form-data', JSON.stringify(response));
      });

      _this.$().cloudinary_fileupload({
        disableImageResize: false,
        imageMaxWidth: 1000,
        imageMaxHeight: 1000,
        acceptFileTypes: /(\.|\/)(gif|jpe?g|png|bmp|ico)$/i,
        maxFileSize: 5000000 // 5MB
      });

      _this.$().bind('fileuploaddone', function (e, data) {
        controller.set('newCat.cloudinaryPublicId', data.result.public_id);
      });
    });
  }
});
```

First, it is responsible for loading the authentication signature from the Rails API:

```js
$.get(CatsUiENV.API_NAMESPACE + '/cloudinary_params', {timestamp: Date.now() / 1000}).done(function(response) {
  Ember.run(function() {
    _this.set('data-form-data', JSON.stringify(response));
  });

  // ...
```

It appends the returned signature object to a data attribute on the file input HTML element called "data-form-data". Note that this is done within an `Ember.run` function to ensure that it is finished before initializing up the Cloudinary file upload. This was something that stumped us at first, and I'm sure there's a better approach.

After the signature data is set, the view initializes the Cloudinary file upload widget on the input.  Here is where we define the settings for our project such as the maximum file size allowed, accepted file types (images) and the maximum dimensions of the image (it automatically scales them down). Additional options can be found in the [jQuery File Upload documentation](https://github.com/blueimp/jQuery-File-Upload/wiki/Options#image-preview--resize-options).

```js
_this.$().cloudinary_fileupload({
  disableImageResize: false,
  imageMaxWidth: 1000,
  imageMaxHeight: 1000,
  acceptFileTypes: /(\.|\/)(gif|jpe?g|png|bmp|ico)$/i,
  maxFileSize: 5000000 // 5MB
});
```

The last functionality this view is responsible for is handling the Cloudinary response and setting a cat model's Cloudinary public ID. Cloudinary sends various events to the input including progress and completion, to which you can bind functionality. In the demo, we're just binding to the 'fileuploaddone' event and setting a controller property when it's complete. Additional callback options can be found in the [jQuery File Upload documentation](https://github.com/blueimp/jQuery-File-Upload/wiki/Options#callback-options).

```js
_this.$().bind('fileuploaddone', function (e, data) {
  controller.set('newCat.cloudinaryPublicId', data.result.public_id);
});
```

## The Cats Controller

In the demo, the cats controller is a simplified version of what you would use in a production application. By this point, the view has already set the public ID for the cat's image, and we are just persisting the cat with ember-data and then creating a new Cat record so the form has a different object.

```js
export default Ember.ArrayController.extend({
  // omitted ...

  actions: {
    createCat: function() {
      var _this = this;

      this.get('newCat').save().then(function() {
        _this.set('newCat', _this.store.createRecord('cat'));
      });
    }
  }
});
```

## Authentication Signature

Another thing that tripped us up was the process for authenticating the Cloudinary image upload request. Cloudinary requires that you generate an authentication signature on the server and pass it to the client *before* initializing the file upload widget. It wasn't clear from the documentation *why* this needed to be done or what was actually required to do it.

The authentication signature is a property that is sent to Cloudinary with the images, and is used to authenticate your request. It seemed counter-intuitive at first that we were depending on the Rails API for something that was supposedly 100% client-side. From a security standpoint, it makes perfect sense because the private key would not be private if it was included in the JavaScript source code.

When the page loads, our application makes a request to the server (via the Cats view) that generates an authentication signature. I've omitted the [controller code to generate the JSON](https://github.com/beerlington/cats-api/blob/master/app/controllers/v1/cloudinary_params_controller.rb), but the request will look something like this:

```
http://localhost:3000/v1/cloudinary_params?timestamp=1405265520.34
```

That request returns a response that looks like this:

```json
{
  "timestamp":1405265520,
  "signature":"4a49f7e9009924b0d811e9bdc8798ca19cdb2da4",
  "api_key":"123456789012345"
}
```

Note that the API key is the same *public* key that is also set in the
Cloudinary initializer above.

As described in the Cats view section, this entire signature object is appended to a data attribute on the file input field, and the Cloudinary upload widget automatically sends it with the image data when a user selects an image.

## Viewing the images

Another frustrating thing about the Cloudinary documentation is that everything we needed for this project was scattered among at least three different sources. After we had image uploads working, the docs we were referencing assumed we would be using our server-side framework (Rails) to render our HTML templates. Since Ember uses Handlebars and the templates are rendered 100% client-side, we needed a different solution.

In order to view images that are stored in Cloudinary, you need to construct a custom URL that includes the image's public ID, and any options such as image size and scale. We ended up creating a helper to handle this functionality, but in retrospect, a component may have been a more semantic option for us. Additional options for constructing the URL can be found in the [jQuery image manipulation documentation](http://cloudinary.com/documentation/jquery_image_manipulation).

**app/helpers/cloudinary-tag.js** - [GitHub](https://github.com/beerlington/cats-ui/blob/master/app/helpers/cloudinary-tag.js)

```js
export default Ember.Handlebars.makeBoundHelper(function(publicId, options) {
  if (Em.isBlank(publicId)) { return ''; }

  var height = options.hash.height || 535,
    width = options.hash.width || 535,
    crop = options.hash.crop || 'fill',
    cssClass = options.hash.class || 'cloudinary-image';

  return new Ember.Handlebars.SafeString($.cloudinary.image(publicId, {
    width: width,
    height: height,
    crop: crop,
    class: cssClass
  }).prop('outerHTML'));
});
```

Again, I've omitted the [less relevant template code](https://github.com/beerlington/cats-ui/blob/master/app/templates/cats.hbs#L5-L14) and only left in what is required to render the HTML image tag:

**app/templates/cats.hbs** - [GitHub](https://github.com/beerlington/cats-ui/blob/master/app/templates/cats.hbs)

{% highlight handlebars %}
{% raw %}
{{#each persistedCats}}

      {{cloudinary-tag cloudinaryPublicId}}

{{name}}

{{/each}}
{% endraw %}
{% endhighlight %}

## Conclusion

While not necessarily specific to this approach, the biggest downside I can see is that you're locking yourself into a single vendor. The pricing is reasonable for smallish applications that are just getting off the ground, but if you expect your users to upload thousands of large images, you'll quickly find yourself in Cloudinary's "Enterprise/Custom Plan" (which I suspect is significantly more expensive than straight up Amazon S3). During testing, we started on the free plan which includes 500MB of total storage and 1GB of monthly bandwidth. We ended up blowing through the 1GB of bandwidth in a couple days and had to upgrade to the $35/month "Basic" plan. In Cloudinary's defense, we were uploading large images during testing, which was not really necessary since we could have just been testing with much smaller file sizes.

Despite some initial frustration with the Cloudinary documentation, my overall impression is that this is the future of image and file uploading in JavaScript web applications. By not depending on the server to process image and file uploads, the API code is simpler and easier to maintain. Pushing this responsibility onto a cloud host like Cloudinary allows us to develop faster and focus on functionality that is relevant to our customers' applications.


text:
# Flutter Presentations

[![](https://github.com/tomaszpolanski/flutter-presentations/workflows/Analyze/badge.svg)](https://github.com/tomaszpolanski/fast_flutter_driver/actions?query=workflow%3A%22Analyze%22)

Presentations made with Flutter

This application should be run on a high-resolution device or a desktop - currently, it does not render properly on
small screens.

# Building

The last tested version of Flutter that works with this repo is `3.10.0`:

* **Important**: Here
  is [the guide](https://tomek-polanski.medium.com/running-flutter-desktop-on-stable-channel-c2ee38157e7b) on how to
  checkout a specific Flutter version

## Building for Web

Upgrade flutter to minimum `3.10.0`, enable web compilation, and run:

```
flutter config --enable-web
flutter run -d chrome -v
```

## Building for Desktop

* Check what desktop components are missing by running `flutter doctor`
* Install missing components that you can see under Flutter doctor's  `Linux`/`Window`/`MacOS` section

## Running on Desktop

Enter `flutter-presentations` folder in your terminal and run `flutter run`.
You might need to use `-d` to pick desktop if you have any other device connected.

### Melos

[Melos](https://melos.invertase.dev/) is a CLI tool used to help manage Dart projects with multiple packages.
It simplifies the selection of modules for testing and building.

To run use `melos` please activate it:

```bash
dart pub global activate melos 2.7.1
```

To get access to all available scripts for the project please run:

```bash
melos run
```

It will show the list of available scripts with the ability to select desired through the command line.

You can also run favorite scripts directly by their names:

```bash
melos run pr_check:all
```

### Mason

[Mason](https://pub.dev/packages/mason_cli) is a template generator that helps teams generate files quickly and
consistently.

We store our bricks in `.bricks` directory in the root of the project.
It needs to be a private (`.`) directory to not be considered when we perform `dart format`.

Please refer to the [documentation](https://pub.dev/packages/mason_cli) for the usage description.

Example usage:

```bash
dart pub global activate mason_cli

mason upgrade

mason make talk_module
```

repository: tomaszpolanski/flutter-presentations

gha_language: Dart

repo_name: tomaszpolanski/flutter-presentations


text:
# SiSC (Simple Storage Cluster) Design

Note that this software is currently in planning phase, not even alpha. You can't use the alpha and complain about bugs by now, so if you're not interested in aiding the development, come back at a later time.

## Basic Design

SiSC will be designed for very easy scaleability, yet it should allow an easy setup and easy network extension for home users (like me). To archieve this, SiSC will be a network of services for Storage (on per storage unit/file system), User Access (replicated Master) and a Control Unit (Master). To aid Systems behind a firewall, a relay node may also be implemented.

## Protocol

Yet none defined. It should however fullfill the following requirements:
- It should allow transportation of text (json?) message for inter-node requests and communication.
- It should be efficient for binary file transportation.
- Encryption has to be possible.

It should also be possible to access the master node (and UA nodes) by a different protocol (http probably) for user interaction (administration and file down-/uploading). HTTP is still an option since this would avoid rolling a own protocol, but on the other hand the overhead is sick. Maybe a protocol agnostic framework design would be the right way.

## Services

### Common Design

All nodes should generate an RSA Keypair on creation. This will be used for encryption and node identification. Nodes have specific rights assigend to them. Also, each server will have an instance, cluster and site value which will be used for replication rules (i.e. two clusters on two sites each on diffrent instances). Instance is a server or a VM host. Cluster describes the server cluster location in a site. The location should be the whole serer farm. Of course, these values may be ignored or used diffrently.

### Master Service

The master node is the only one allowed to issue right changes and to tell nodes to trust other nodes. If this node is compromised, the server is compromised. All right updates will be signed (here: encrypted) with the master's private key.

The master node should run a http backend or allow to be controlled by one in order to easily configure storage.

### User Access Service

Replicated master nodes, but they only supply read-only data. More of a cache. Since these are only useful in larger or HA clusters, their implementation is no priority.

### Storage Service

Storage Service instances will use exactly one specific path on the system they're running on as storage space. They will sync all their files there, as long as storage space is sufficient.

Configuration Nodes

### Proxy Service

No target for now. Should allow to traverse firewalls, i.e. by keeping a persistent connection between two nodes.

## Rights Managment

## Data Storage

There should be three categories of data stored:

### System Metadata

This includes user profiles, public keys (of users and servers) & configuration. This will be usually be stored on the service location.

### File Metadata

References on previous file version, public key used for encryption, hash and replication status. Stored at the files.

### Actual Data

Nothing unexpected. Data stored on the given file system. Maybe encrypted, may be encrypted twice (storage node encryption, user encryption).


text:
This Playbook handles false-positive incident closure for Cortex XDR - Malware investigation.

## Dependencies
This playbook uses the following sub-playbooks, integrations, and scripts.

### Sub-playbooks
Cortex XDR - Unisolate Endpoint

### Integrations
CortexXDRIR

### Scripts
This playbook does not use any scripts.

### Commands
* xdr-allowlist-files
* setIndicators
* closeInvestigation

## Playbook Inputs
---

| **Name** | **Description** | **Default Value** | **Required** |
| --- | --- | --- | --- |
| Comment | Add a comment to close this incident. | XSOAR Incident #${incident.id} | Optional |
| Reason | Possible values:
 * Unknown
* TruePositive
* FalsePositive | FalsePositive | Optional |
| AllowTag | The approving tag name for found indicators. | AllowTag | Optional |
| AutoUnisolation | Whether automatic un-isolation is allowed. | False | Optional |
| HostID | The ID of the host for running an un-isolation process. | ${incident.deviceid} | Optional |
| FileSha256 | The file SHA256 you want to block. | ${incident.filesha256} | Optional |

## Playbook Outputs
---
There are no outputs for this playbook.

## Playbook Image
---
![Cortex XDR - False Positive Incident Handling](../doc_files/Cortex_XDR_-_False_Positive_Incident_Handling.png)

repository: adambaumeister/content

gha_language: Python

repo_name: adambaumeister/content


text:
# radLens

##UPDATE: please refrain from using this repo.... some of the code has not been updated in months and may have numerous issues... please check out my upcoming updated repo for RadLens-AI 3.0 which let's you train your own CV AI models right on your phone using the power of tensorflow.js

##My first git project and
##it's for running a tensorflow model I trained in python that
##I'm trying to convert with tensorflowjs for deployment in the web.

I tried two differend bundlers: webpack and parcel.

the src and public folders are for my webpack build so if you prefer not to use webpack then you can ignore those.

the dist folder is the folder where the parcel bundler stores all my distributable files for the final product.
I currently prefer parcel over webpack though. All the parcel index files (index.html and index.js etc) are in the root of the project.

This is totally a work in progress. I put this here so that maybe others can learn from my mistakes and give me suggestions on how to improve the code.

My goal is to make a simple javascript web app that uses a phone's camera to classify and detect things.
I'm currently using python to train the model (Not included in this repo).
I'm using tensorflow.js and tensorflowjs_converter to use the trained model for web development and javascript (which is the purpose of this repo).

repository: RadEdje/RadLens

repo_name: RadEdje/RadLens


text:
Benchmarking Performance {#dev_guide_benchdnn}
==============================================

oneDNN has a built-in benchmarking program called benchdnn.

For a complete description of the available options and working examples, see
the [benchdnn readme](https://github.com/oneapi-src/oneDNN/blob/master/tests/benchdnn/README.md#benchdnn).

repository: oneapi-src/oneDNN

repo_name: oneapi-src/oneDNN


text:
---
path: '/slides/meetup-47'
date: '2019-02-20'
title: 'Meetup #47'
id: 47
---

### Ante Barić
#### Cross browser extensions

Browser extensions were a huge mess until not so long ago. Today with new WebExtensions API they are much more accessible and we can develop extensions that work inside all major browsers and share the same codebase. Other then intro into this new API, you will also hear about concepts, gotchas and ideas on how to use web extensions to enhance user experience on your website or app. Also, for old school guys, the secret guest will make a comeback.