Category: Blog

  • MLOpsTemplate

    MLOps Template

    MLOps Template is a repo created by Microsoft field personnel (CSA, GBB, MTC) that provides several tools and templates to facilitate modern MLOps practices.

    In addition to a template for an Active Learning implementation, there are also two sets of materials to facilitate an introductory workshop on modern MLOps practices, one, developed by the West Region CSU, using Azure Machine Learning and GitHub Actions, and another featuring Azure Databricks for ML asset development and Azure DevOps for CI/CD pipelines.

    Contributing

    This project welcomes contributions and suggestions. Most contributions require you to agree to a
    Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
    the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com.

    When you submit a pull request, a CLA bot will automatically determine whether you need to provide
    a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions
    provided by the bot. You will only need to do this once across all repos using our CLA.

    This project has adopted the Microsoft Open Source Code of Conduct.
    For more information see the Code of Conduct FAQ or
    contact opencode@microsoft.com with any additional questions or comments.

    Trademarks

    This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft
    trademarks or logos is subject to and must follow
    Microsoft’s Trademark & Brand Guidelines.
    Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship.
    Any use of third-party trademarks or logos are subject to those third-party’s policies.

    Visit original content creator repository
    https://github.com/microsoft/MLOpsTemplate

  • secret-keeper

    license codecov build

    clojars

    Secret Keeper

    A Clojure(Script) library for keeping your secrets under control.

    Motivation

    I want to be calm about sensitive data. This is security and responsibility to my clients. Specifying categories of sensitive data at the model level gives an understanding of what data we are working with.

    Easy to mark up categories of sensitive data at model level and use them when reading configuration files, environment variables and also in the middlewares of the public API.

    Installation

    Add the following dependency in your project:

    ;; project.clj or build.boot
    [team.sultanov/secret-keeper "1.0.86"]
    
    ;; deps.edn
    team.sultanov/secret-keeper {:mvn/version "1.0.86"}

    Usage

    (ns example
      (:refer-clojure :exclude [read-string])
      (:require
        #?(:clj  [clojure.edn :refer [read-string]]
           :cljs [cljs.reader :refer [read-string]])
        [malli.core :as m]
        [secret.keeper :as keeper]
        [secret.keeper.malli :as keeper.malli]))
    
    
    ;;
    ;; Build secrets
    ;;
    
    (def secret
      (keeper/make-secret {:passport "12345678"})) ; default category -> :secret
    
    
    (keeper/secret? secret) ; => true
    
    (prn secret) ; => #secret {:data "*** CENSORED ***", :category :secret}
    (pr-str secret) ; => "#secret {:data \"*** CENSORED ***\", :category :secret}"
    
    (keeper/data secret) ; => {:passport "12345678"}
    (keeper/category secret) ; => :secret
    
    
    ;; Change the secret category
    
    (-> secret
        (keeper/make-secret :personal)
        (keeper/category)) ; => :personal
    
    ;; nil and objects aren't a secret
    (keeper/secret? "NOT A SECRET") ; => false
    (keeper/data "NOT A SECRET") ; => "NOT A SECRET"
    (keeper/category "NOT A SECRET") ; => nil
    
    (keeper/secret? nil) ; => false
    (keeper/make-secret nil) ; => nil
    (keeper/data (keeper/make-secret nil)) ; => nil
    (keeper/category (keeper/make-secret nil)) ; => nil
    
    
    
    ;;
    ;; Parse secrets
    ;;
    
    (def read-secret
      (partial read-string {:readers {'secret keeper/make-secret}}))
    
    
    ;; Getting a secret from environment variables by symbols
    ;; For example, we have an environment variable: `$TEST_TOKEN=token_12345`
    
    (def secret-token
      (read-secret "#secret TEST_TOKEN"))
    
    
    (prn secret-token) ; => #secret {:data "*** CENSORED ***", :category :secret}
    (pr-str secret-token) ; => "#secret {:data \"*** CENSORED ***\", :category :secret}"
    
    (keeper/data secret-token) ; => "token_12345"
    (keeper/category secret-token) ; => :secret
    
    
    ;; Getting a secret from environment variables by symbols with the custom category
    
    (def secret-token+custom-category
      (read-secret "#secret {:data TEST_TOKEN, :category :confidential}"))
    
    
    (prn secret-token+custom-category) ; => #secret {:data "*** CENSORED ***", :category :confidential}
    (pr-str secret-token+custom-category) ; => "#secret {:data \"*** CENSORED ***\", :category :confidential}"
    
    (keeper/data secret-token+custom-category) ; => "token_12345"
    (keeper/category secret-token+custom-category) ; => :confidential
    
    
    
    ;;
    ;; Malli
    ;;
    
    ;; Transformer without any options
    
    (= {:password "p4$$w0rd"}
       (m/decode [:map [:password string?]]
                 {:password (keeper/make-secret "p4$$w0rd")}
                 (keeper.malli/transformer))) ; => true
    
    
    ;; Transformer with some options:
    ;; - :key     - schema property key (by default ::keeper/category)
    ;; - :secrets - schema type or map key name
    
    (def Transformer
      (keeper.malli/transformer
        {:key     :category
         :secrets {:passport :confidential
                   :password :internal-only}}))
    
    
    (def User
      [:map
       [:firstname string?]
       [:lastname string?]
       [:email string?]
       [:passport string?]
       [:address [:map {:category :personal} ; local category
                  [:street string?]
                  [:zip int?]
                  [:city string?]
                  [:country [:enum "USA"]]]]
       [:credentials [:map
                      [:login string?]
                      [:password string?]]]])
    
    
    (def FakeUser
      {:firstname   "john"
       :lastname    "doe"
       :email       "john@doe.me"
       :passport    "123456789"
       :address     {:street  "1488 Secret Street"
                     :zip     12345
                     :city    "Durham"
                     :country "USA"}
       :credentials {:login    "john"
                     :password "p4$$w0rd"}})
    
    
    (m/encode User FakeUser Transformer)
    ;; =>
    ;; {:firstname   "john"
    ;;  :lastname    "doe"
    ;;  :email       "john@doe.me"
    ;;  :passport    #secret{:data     "*** CENSORED ***"
    ;;                       :category :confidential}
    ;;  :address     #secret{:data     "*** CENSORED ***"
    ;;                       :category :personal}
    ;;  :credentials {:login    "john"
    ;;                :password #secret{:data     "*** CENSORED ***"
    ;;                                  :category :internal-only}}}
    
    (= FakeUser
       (as-> FakeUser $
             (m/encode User $ Transformer)
             (m/decode User $ Transformer))) ; => true

    Special thanks

    License

    Copyright © 2021 sultanov.team

    Visit original content creator repository https://github.com/sultanov-team/secret-keeper
  • vv

    Variable VVV – The Best VVV Site Wizard

     ██    ██ ██    ██
    ░██   ░██░██   ░██     Variable VVV 1.12
    ░░██ ░██ ░░██ ░██
     ░░████   ░░████       The easiest way to set up
      ░░██     ░░██        WordPress sites with VVV!
       ░░       ░░
    

    vv makes it extremely easy to create a new WordPress site using Varying Vagrant Vagrants. vv supports site creation with many different options; site blueprints to set up all your plugins, themes, and more; deployments; and lots more features.

    Travis

    Tired of the time it takes to do a vagrant provision or create new sites? Check out flip, a simple utility to solve that issue.

    Table of Contents

    Installation

    OS X Installation

    If you have Homebrew installed, you run the following in your terminal application:

    $ brew install bradp/vv/vv
    

    Otherwise, clone this repositoy and edit your $PATH to include the vv core file:

    1. Clone this repo: git clone https://github.com/bradp/vv.git
    2. Add the vv core script to your shell’s $PATH:
      • If you’re using bash: touch ~/.bash_profile && echo "export PATH=\$PATH:`pwd`/vv" >> ~/.bash_profile

    Windows Installation

    • Clone vv to a folder somewhere.

      $ git clone https://github.com/bradp/vv.git

    • Add that folder to your system path. See here if you need help.

    • Open an explorer window and go to My Computer (or This PC).

    • Right click and choose properties

    • Choose Advanced System Settings

    • Choose Environmental Variables form the Advanced Tab

    • Choose the “Path” variable and edit it.

    • Add a semicolon to end the previous path item and then add the vv folder path (Example: ;C:\Users\Name\Documents\vv)

    • Open Git Bash and run vv

    Alternately, you can use cmd.exe with bash vv.

    Props to Vinsanity for these instructions. If you’re having issues, please see this issue.

    Linux Installation

    • Clone vv into a folder.

      $ git clone https://github.com/bradp/vv.git

    • Access the directory that you cloned vv into.

    • Copy the vv executable to /usr/local/bin

      $ sudo cp vv /usr/local/bin

    • You should now be able to easily run vv from anywhere in your system.

    Adding tab-completion to vv

    Currently, vv supports tab-completion of arguments and options in both bash and ZSH. To enable this, you’ll first want to make sure you’re on the most current version of vv. Then simply add source $( echo $(which vv)-completions) to the end of your .bash_profile, .bashrc or .zshrc.

    Updating

    vv is currently under development, and you’ll probably want the latest and greatest version at all times.

    You can run vv --update to update to the latest version. This will update via Homebrew if you’ve installed it that way, otherwise vv will bootstrap an update on where ever you’ve installed it.

    vv will automatically check for updates and update itself once a week. You can disable this by adding "auto_update_disable": false to the JSON config in ~/.vv-config.

    If you have trouble updating, you may want to try some of the options below:

    Homebrew sometimes caches a version of Variable VV causing you to receive a message saying you are out of date with the Github version, however running vv --update simply downloads a version you already have installed. In cases like this, there are two safe options you can try.

    First, and simplest, run vv --force-update. Second, if that does not work you can safely uninstall Variable VV and re-install it via homebrew, you can do this with these commands: brew remove vv then brew untap bradp/vv and finally, run the install command brew install bradp/vv/vvas mentioned above. You will not lose any settings or sites.

    Usage

    Once installed, you can run vv anywhere you’d like. If vv can’t automatically find your VVV installation, you will be prompted for the path. It will also save this into a configuration file in ~/.vv-config, so you won’t be prompted again.

    At any time, you can run vv or vv --help to see a list of all possible options and flags.

    vv will prompt you for a value for any required flags that were not specified.

    The main commands are list, create, delete. These will list your sites, create a site, and delete a site. These each have a few aliases, so for example, if you run vv show, vv will know you meant vv list.

    To start creating a site, simply do vv create ( you can also do vv --create, or simply vv -c). You will then be prompted for all required options.

    All options and flags are listed below.

    Site Creation

    vv create

    Creating a site does the following:

    • Halts Vagrant (if running)
    • Creates a web root for the site in the www folder containing three files: vvv-init.sh, wp-cli.yml, and vvv-hosts
      • vvv-init.sh tells Vagrant to create a database if one does not exist and install the latest version of WordPress (via WP-CLI) the next time Vagrant is provisioned
      • wp-cli.yml tells WP-CLI that WordPress is in the htdocs folder
      • vvv-hosts contains the hosts entry to give your site a nice custom domain (the domain is set in the wizard)
    • Creates a file in the nginx-config folder to handle server settings for your site
    • Restarts Vagrant with vagrant up --provision

    Provisioning Vagrant takes a couple of minutes, but this is a crucial step as it downloads WordPress into your site’s htdocs directory and runs the installation. If you want to skip provisioning and install WordPress manually, you can run the new site’s vvv-init.sh file directly in the Vagrant shell.

    Subdomain Multisite Installation

    If you are using a subdomain multisite, you must edit vvv-hosts file inside of that site’s folder with each subdomain on a new line. For example:

    mysite.dev

    siteA.mysite.dev

    siteB.mysite.dev

    After this, run vagrant reload --provision and your subdomains should resolve. Please note, any sites set up prior to version 1.7.3 will need more configuration for this, either delete and re-set up the site or ping me on Twitter for help.

    Site Deletion

    vv delete site_name

    You can also leave off site_name to be prompted for it.

    Deleting a site does the following:

    • Halts Vagrant (if running)
    • Deletes the site’s web root (which deletes the vvv-init.sh, wp-cli.yml, and vvv-hosts files as well)
    • Deletes the file in the nginx-config folder pertaining to the site
    • Deletes the database associated with the site

    Deployments

    vv deployment-create, vv deployment-remove, vv deployment-config

    vv supports setting up deployments that work with Vagrant Push. You’ll need to be on version 1.7.0 or later of Vagrant. Simply run vv --deployment-create and walk through the wizard.

    To deploy a site, you can do vv vagrant push <sitename>-<deployment_name>.

    When removing a deployment, your current Vagrantfile will be backed up as Vagrantfile-backup.

    Advanced Usage

    Airplane Mode

    Using x as the first argument with vv will force airplane mode. This will cut off update checks on usage. This is useful if you’re using vv without an internet connection. The provision state of VVV will probably fail at some point, though.

    Flags

    Anything that vv prompts you for, you can pass in as an argument. Most of this is realized in the site creation. In fact, there are a few arguments you can pass in that aren’t prompted. This gives you total control over creating a new site.

    To create a new site named ‘mysite’ that has the domain ‘mysite.dev’ and is a multisite with subdomains, with WP_Debug turned on would be:

    vv create -d mysite.dev -n mysite -m subdomains -x

    Or, the more readable version with all expanded flags.

    vv create --domain mysite.dev --name mysite --multisite subdomains --debug

    To use a custom database prefix, simply use the vv create --prefix myprefix when creating a new site.

    Blueprints

    Blueprints allow you to set up different plugins, themes, mu-plugins, options, widgets, menus, or constants that will be installed to a new site you create. First, run vv --blueprint-init to have vv create a vv-blueprints.json file in your VVV directory. You can edit this file to create and set up different blueprints.

    A simple blueprint should look like this:

    {
      "sample": {
        "themes": [
          {
            "location": "automattic/_s",
            "activate": true
          }
        ],
        "mu_plugins": [
          {
            "location": "https://github.com/WebDevStudios/WDS-Required-Plugins.git"
          }
        ],
        "plugins": [
          {
            "location": "https://github.com/clef/wordpress/archive/master.zip",
            "version": null,
            "force": false,
            "activate": true,
            "activate_network": false
          },
          {
            "location": "cmb2",
            "version": "2.0.5",
            "force": false,
            "activate": true,
            "activate_network": false
          }
        ],
        "options": [
          "current_theme::_s"
        ],
        "widgets": [
          {
            "name": "meta",
            "location": "sidebar-1",
            "position": 1,
            "options": {
              "title": "Site login or logout"
            }
          },
          {
            "name": "text",
            "location": "sidebar-2",
            "position": 4,
            "options": {
              "title": "Hello world.",
              "text": "I'm a new widget."
            }
          }
        ],
        "menus": [
          {
            "name": "Example Menu",
            "locations": [
              "primary",
              "social"
            ],
            "items": [
              {
                "type": "post",
                "post_id": 2,
                "options": {
                  "title": "Read the 'Sample Post'"
                }
              },
              {
                "type": "custom",
                "title": "Our Partner Site",
                "link": "//example.com/",
                "options": {
                  "description": "Check out our partner's awesome website."
                }
              },
              {
                "type": "term",
                "taxonomy": "category",
                "term_id": 1,
                "options": {
                  "title": "Example category"
                }
              }
            ]
          }
        ],
        "demo_content": [
          "link::https://raw.githubusercontent.com/manovotny/wptest/master/wptest.xml"
        ],
        "defines": [
          "WP_CACHE::false"
        ]
      }
    }
    

    For themes, plugins, and mu-plugins, you can use:

    • Github username/repo
    • Full git url
    • Url to zip file
    • WordPress.org slug

    The options for plugins, themes, widgets, and menus correspond to the equivalent WP CLI option.

    For options, demo content, and constants, please note the :: as a separator between the key and value.

    Custom demo content can be imported through the blueprint. Be sure to use a link that points to just the xml code, like this. You can add as many demo content files as you’d like, just separate each line with a comma as usual.

    A multisite’s Network Settings can be configured using a network_options array in the blueprint.

    You can create as many named blueprints in this file as you would like, all with as many different settings as you’d like.

    When creating a site, the name you’ve specified (in this example, “sample”) is what you’ll need to specify to use this blueprint.

    You can use ‘SITENAME’ or ‘SITEDOMAIN’ anywhere in the blueprint, and that will be replaced with the actual site name or local domain when installing.

    Blueprints for Multisite configurations

    Blueprints also let you set up individual subsites in a Multisite network. For example, you can define a blueprint for a multisite network in which certain plugins or themes are activated across the whole network, or just for specific subsites.

    To add multisite support to your blueprint, add a sites key to a specific blueprint, like this:

    "sites": {
      "site2": {
        "plugins": [
          "...(same as above)..."
        ]
      }
    }

    The sites object holds a subsite definition, which has the same capabilities as a regular site’s blueprint (so plugins, themes, etc. are all the same), and also includes keys for WP-CLI’s wp site create command. For example, to create a subsite whose slug is subsite2, titled “Second Subsite” with an admin email address of subsite2admin@localhost.dev with robots.txt exclusions, use:

    "sites": {
      "subsite2": {
        "title": "Second Subsite",
        "email": "subsite2admin@localhost.dev"
      }
    }

    If your multisite network uses subdomains, you can include a blueprint-level key named like BLUEPRINT_NAME::subdomains to have vv configure your subdomains for you. BLUEPRINT_NAME should match the name of your blueprint, and the value should be a space-separated list of subdomains that match your subsite slugs. A complete example for the sample blueprint shown above using subdomain-based multisite configurations might look like this:

    {
      "sample": {
        "sample::subdomains": "site2 site3",
        "sites": {
          "site2": {
            "title": "Child Site (subsite2)",
            "plugins": [
              {
                "location": "buddypress",
                "activate": true
              }
            ]
          },
          "site3": {
            "title": "Private Child Site",
            "private": true,
            "email": "site2admin@local.dev",
            "themes": [
              {
                "location": "https://github.com/glocalcoop/anp-network-main-child/archive/master.zip",
                "activate": true
              }
            ]
          }
        },
        "themes": [
          {
            "location": "automattic/_s",
            "enable_network": true
          },
          {
            "location": "glocalcoop/anp-network-main-v2",
            "activate": true
          }
        ],
        "mu_plugins": [
          {
            "location": "https://github.com/WebDevStudios/WDS-Required-Plugins.git"
          }
        ],
        "plugins": [
          {
            "location": "https://github.com/clef/wordpress/archive/master.zip",
            "version": null,
            "force": false,
            "activate": true,
            "activate_network": false
          },
          {
            "location": "cmb2",
            "version": "2.0.5",
            "force": false,
            "activate": true,
            "activate_network": false
          },
        ],
        "demo_content": [
          "link::https://raw.githubusercontent.com/manovotny/wptest/master/wptest.xml"
        ],
        "defines": [
          "WP_CACHE::false"
        ]
      }
    }

    The above installs BuddyPress but activates it only for site2, enables the _s theme for the entire network but activates anp-network-main-v2 for the network’s main site and anp-network-main-child for site3, which is also given its own site admin user.

    Be sure to run vv with the --multisite subdomain option when you use a blueprint like this.

    Blueprints for Multi-Network configurations

    In addition to a multisite configuration, VV recognizes blueprints that will configure a WP Multi-Network (a network of WP Multisite networks). VV’s Multi-Network blueprints work just like Multisite blueprints, but have the following required additions:

    • A BLUEPRINT_NAME::subnetwork_domains key must be present listing the root domains for each network.
    • A networks object must be present, whose keys match the domains listed in the BLUEPRINT_NAME::subnetwork_domains member.

    For example, this Multi-Network configuration defines two WP Multisite subnetworks (for a total of three WP Multisites) in the blueprint called multinet.

    {
      "multinet": {
        "multinet::subdomains": "site2 site3",
        "multinet::subnetwork_domains": "wpsubnet1.dev wpsubnet2.dev",
        "networks": {
          "wpsubnet1.dev": {
            "path": "/",
            "site_name": "WP Subnetwork Example 1"
          },
          "wpsubnet2.dev": {
            "path": "/",
            "site_name": "WP Subnetwork Example 2"
          }
        }
      }
    }

    Note that empty network objects are allowed (i.e., path and site_name are optional), but not recommended.

    To associate a given subsite with a network, you can either use the network_id key or a network_domain key in the subsite object. A network_domain is recommended. For example, this object will associate the site2 subsite with the main network (because no network_domain or network_id key is defined), and the subsite with slug site3 with the network created at the given domain:

    {
      "site2": {
      },
      "site3": {
        "network_domain": "wpsubnet1.dev"
      }
    }

    The above will ultimately place site3 at the site3.wpsubnet1.dev URL while site2 will be created as a subdomain of whatever domain you chose when you invoked vv create.

    It is not an error for a WP network to be defined with no sites of its own.

    Vagrant Proxy

    Because vv knows where you VVV installation is, you can run it from anywhere. vv will proxy any commands passed into vv vagrant <command> to your VVV location. So vv vagrant halt will halt your VVV vagrant, no matter where you run it.

    vv Options

    Option Description
    --help, -h Show help and usage
    --version Show current vv version number.
    --about Show about screen.
    --update Updates vv to the latest stable version
    --debug-vv Outputs all debugging info needed for bug reporting.
    --path, -p Path to VVV installation
    --force-path, -fp Override vv auto-VVV locating
    --force-sites-folder,-fsf Override sites folder directory locating
    --defaults Accept all default options and skip the wizard. You can also run `yes

    Commands

    Command Description
    list, --list, -l List all VVV sites
    create, --create, -c Create a new site
    delete, --delete, -r Delete a site
    deployment-create, --deployment-create Set up deployment for a site
    deployment-remove, --deployment-remove Remove deployment for a site
    deployment-config, --deployment-config Manually edit deployment configuration
    blueprint-init, --blueprint-init Initalize blueprint file
    vagrant, v, --vagrant, -v Pass vagrant command through to VVV.

    Options for Site Creation

    Option Description
    --name, -n Desired name for the site directory (e.g. mysite)
    --domain, -d Domain of new site
    --webroot, -wr Subdirectory used for web server root
    --bedrock, -bed Creates Roots.io Bedrock install
    --blueprint, -b Name of blueprint to use
    --live-url, -u Live URL of site
    --files, -f Do not provision Vagrant, just create the site directory and files
    --images, -i Load images by proxy from the live site
    --wp-version, -wv Version of WordPress to install
    --debug, -x Turn on WP_DEBUG and WP_DEBUG_LOG
    --multisite, -m Install as a multisite. Can also pass in “subdomain” or “subdirectory”
    --sample-content,-sc Adds sample content to site.
    --username Admin username
    --password Admin password
    --email Admin email
    --prefix Database prefix to use
    --git-repo,-gr Git repo to clone as wp-content
    --path, -p Path to VVV installation
    --force-path, -fp Override vv auto-VVV locating
    --blank Creates blank VVV site, with no WordPress
    --blank-with-db Creates a blank VVV site, with a database
    --wpskeleton, -skel Creates a new site with the structure of WP Skeleton
    --database,-db Imports a local database export
    --remove-defaults,-rd Removes default themes and plugins
    --language,--locale Install WP in another locale. Need to pass the locale afterwards, like so: vv create --locale fr_FR

    Options for Site Removal

    Option Description
    --name, -n Desired name for the site directory (e.g. mysite)
    --path, -p Path to VVV installation
    --force_path, -fp Override vv auto-VVV locating

    Options for Deployment Setup

    Option Description
    --name, -n Desired name for the site directory (e.g. mysite)
    --deployment-name Name of deployment (production, staging, other, etc)
    --host Host (if SFTP, define port as host:port)
    --username FTP Username
    --password FTP Password
    --passive Use Passive transfer mode? (y/n)
    --secure Use SFTP? (y/n)
    --destination Destination path ( You probably want / or ~/public_html )
    --confirm-removal Used when removing a deployment to skip the confirmation prompt

    .vv-config

    The first time you run vv, it will attempt to locate your VVV installation location. If it can’t find it, you will be prompted for it. This will be written to a .vv-config file in your home directory. (~/.vv-config) You can also edit this file if you need to change your VVV path.

    Also, if vv detects a .vv-config file in your current directory, this local file will override the one in your home directory. A use case would be to have several different VVV installations, that each contain their own local .vv-config file. Provided that you enter the appropriate directory before sending commands to vv, this effectively allows you to manage several different installations through one user account.

    You can also add "auto_update_disable": false to this file to disable auto-update functionality.

    vv Hooks

    vv has support for extensibility within the ‘hooks’ system present. This allows for quite a lot of extensibility and injection into the vv process. This system allows you to add your own code to run within almost any point with vv.

    To get started with hooks, run any vv command with --show-hooks at the end. For example, vv list --show-hooks will run vv list as normal, but will also show all the hooks available.

    To create the folder that your hook code should live in, simply make a ‘vv’ folder inside of your VVV folder.

    To add code to run for a hook, make a file within your vv folder inside of VV named the hook that you want to add to. This file can be any command line runnable language, and will be executed inline.

    For example, saving this file as the name of any hook will output ‘Hello’ when that hook gets called.

        #! /usr/bin/php
        echo 'Hello'

    Another example would be running npm install inside of wp-content for all new sites.

    Make a file named post_site_creation_finished. This file gets 4 variables passed in: the hook name, the name of the site folder, the site domain, and the VVV path.

        #!/bin/bash
        cd www/"$2"/htdocs/wp-content || exit
        npm install

    Thanks

    Forked and based off of vvv-site-wizard from Alison Barrett. Also thanks to meitar, creativecoder, jtsternberg, caseypatrickdriscoll, gregrickaby, leogopal, ajdruff, schlessera, john-g-g, tnorthcutt, wpsmith, wesbos, protechig, Ipstenu, justintucker, michaelbeil, jb510, neilgee, nanomoffet, joehills, JeffMatson, greatislander, pelmered, gMagicScott, alexschlueter, eriktdesign, WPprodigy, michaelryanmcneill, boborchard, cryptelli, lswilson, Mte90 for their contributions.

    Visit original content creator repository https://github.com/bradp/vv
  • lab-exercises-in-intermmediate-programming

    C++ Intermediate Programming Laboratory Exercises

    This repository contains a collection of C++ lab exercises related to intermediate programming. Each lab exercise focuses on a specific programming problem and includes a PDF file with the problem description and one or more C++ source code files to implement the solution.

    Files

    1. Lab Exercise 3.pdf

      • Description: Instructions for solving the Fibonacci Reciprocals problem.
    2. fibonacci-reciprocals.cpp

      • Description: C++ source code for calculating the reciprocals of Fibonacci numbers.
    3. Lab Exercise 4 (1).pdf

      • Description: Instructions for solving Goldbach’s Conjecture in Array problem.
    4. Goldbach's-Conjecture-in-Array.cpp

      • Description: C++ source code for verifying Goldbach’s Conjecture in an array.
    5. Lab Exercise 5.pdf

      • Description: Instructions for calculating the standard deviation of records.
    6. standard-deviation-on-record-v1.cpp

      • Description: C++ source code (version 1) to calculate the standard deviation.
    7. standard-deviation-on-record-v2.cpp

      • Description: C++ source code (version 2) to calculate the standard deviation.
    8. standard-deviation-on-record-v3.cpp

      • Description: C++ source code (version 3) to calculate the standard deviation.
    9. Lab Exercise 6.pdf

      • Description: Instructions for solving the Cylinder Tank Problem.
    10. cylinder-tank-problem/CylinderTank.h

      • Description: C++ header file defining the CylinderTank class.
    11. cylinder-tank-problem/cylinderTankImp.cpp

      • Description: C++ source code implementing the CylinderTank class.
    12. cylinder-tank-problem/main.cpp

      • Description: Main C++ source code for the Cylinder Tank Problem solution.
    13. Lab Exercise 7.pdf

      • Description: Instructions for implementing a Bank Account system.
    14. bank-account/BankAccount.h

      • Description: C++ header file defining the BankAccount class.
    15. bank-account/BankAccountImp.cpp

      • Description: C++ source code implementing the BankAccount class.
    16. bank-account/CheckingAccount.h

      • Description: C++ header file defining the CheckingAccount class.
    17. bank-account/CheckingAccountImp.cpp

      • Description: C++ source code implementing the CheckingAccount class.
    18. bank-account/SavingsAccount.h

      • Description: C++ header file defining the SavingsAccount class.
    19. bank-account/SavingsAccountImp.cpp

      • Description: C++ source code implementing the SavingsAccount class.
    20. Lab Exercise 8.pdf

      • Description: Instructions for simulating rolling dice.
    21. rolling-dice-simulation/Dice.h

      • Description: C++ header file defining the Dice class.
    22. rolling-dice-simulation/RiggedDice.h

      • Description: C++ header file defining the RiggedDice class.
    23. rolling-dice-simulation/TwoDice.h

      • Description: C++ header file defining the TwoDice class.
    24. rolling-dice-simulation/diceImp.cpp

      • Description: C++ source code implementing the Dice class.
    25. rolling-dice-simulation/riggedDiceImp.cpp

      • Description: C++ source code implementing the RiggedDice class.
    26. rolling-dice-simulation/twoDiceImp.cpp

      • Description: C++ source code implementing the TwoDice class.
    27. main.cpp

      • Description: Main C++ source code for testing and running various lab exercises.

    How to Use

    To use any of the lab exercises, follow these steps:

    1. Clone the repository to your local machine.
    2. Choose the lab exercise you want to work on and open the corresponding directory.
    3. Review the Lab Exercise [Number].pdf file for instructions and problem details.
    4. Implement your solution in the provided C++ source code file (if applicable).
    5. Compile and run the code using your preferred C++ compiler.

    How to Contribute

    Contributions to this repository are welcome. If you wish to contribute to the lab exercises or make improvements, follow these steps:

    1. Fork this repository to your GitHub account.
    2. Create a new branch for your changes.
    3. Make your modifications and commit them with descriptive commit messages.
    4. Push the changes to your forked repository.
    5. Create a pull request to this repository’s main branch with a detailed explanation of your changes.

    Credits

    This repository’s lab exercises were created by Sir Michael Anthony Jay Regis as part of the C++ Intermediate Programming course. Credits to him for providing these problems and exercises.

    Happy coding!

    Visit original content creator repository
    https://github.com/VSUrhuel/lab-exercises-in-intermmediate-programming

  • SEN6X

    Sensirion SEN6x

    ===========================================================

    A program to set instructions and get information from an SEN6x. It has been
    tested to run I2C communication on UNOR4 Wifi

    A detailed description of the findings are in SEN6x.odt

    Getting Started

    As part of a larger project I am looking at analyzing and understanding the air quality.
    I have done a number of projects on air-sensors. This is a version of a working driver + examples.
    More work continues to happen to create examples and compare against other sensors.

    Prerequisites

    Examples 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 have a dependency on other libraries and hardware. Documented in sketch.

    Software installation

    Obtain the zip and install like any other.

    Program usage

    Install like any other external library

    Program options

    See the description in the top of the sketch and read the documentation (odt)

    Versioning

    Version DRAFT / December 2024

    • initial draft version
    • ver draft 1.1 : updates and added example
    • ver draft 1.2 : updates and added examples
    • ver draft 1.3 : add opcode structure, added examples
    • ver draft 1.5 : added examples and update source code routines
    • ver draft 1.6 : added and updated examples. Updates to SRC-code routines

    Version DRAFT / January 2025

    • ver draft 1.7 : added and updated CO2 examples. Updates to SRC-code routines
    • ver draft 1.8 : updated examples with CO2 ASc, added example7, Updates to SRC-code routines
    • ver draft 1.9 : updated example7 with information about RAW values

    Version 1.0 / February 2025

    • Version 1 : added /updated examples and documentation

    Version 1.0.1 / February 2025

    • added Example23 with SGP30
    • added Example31 with SCD41
    • updated documentation

    Author

    License

    This project is licensed under the GNU GENERAL PUBLIC LICENSE 3.0

    Acknowledgments

    Make sure to read the datasheet from Sensirion, November 2024 version.

    Also read the many documents in the extra-folder.

    Visit original content creator repository
    https://github.com/paulvha/SEN6X

  • leveldown-mobile

    leveldown-mobile

    This project has been abandoned. There will be no further releases. If you wish to revive leveldown-mobile, please open an issue in Level/community to discuss a way forward. Thank you! ❤️


    • Leveldown for Android, iOS. Also works on Destkop with SpiderMonkey / v8 engine
    • Requires JXcore to run.
    Installation

    • To use with a mobile node application (i.e. JXcore)
    npm install leveldown-mobile
    
    • To compile for SpiderMonkey desktop or OpenWrt embedded
    jx install leveldown-mobile  
    

    A Low-level Node.js LevelDB binding

    LevelDOWN was extracted from LevelUP and now serves as a stand-alone binding for LevelDB.

    Remarks

    • This version of Leveldown only works with JXcore and platform independent.

    • It is strongly recommended that you use LevelUP in preference to LevelDOWN unless you have measurable performance reasons to do so. LevelUP is optimised for usability and safety. Although we are working to improve the safety of the LevelDOWN interface it is still easy to crash your Node process if you don’t do things in just the right way.

    See the section on safety below for details of known unsafe operations with LevelDOWN.


    Tested & supported platforms

    • Android
    • iOS
    • Linux
    • Mac OS
    • Solaris
    • FreeBSD
    • Windows

    API


    leveldown(location)

    leveldown() returns a new LevelDOWN instance. location is a String pointing to the LevelDB location to be opened.


    leveldown#open([options, ]callback)

    open() is an instance method on an existing database object.

    The callback function will be called with no arguments when the database has been successfully opened, or with a single error argument if the open operation failed for any reason.

    options

    The optional options argument may contain:

    • 'createIfMissing' (boolean, default: true): If true, will initialise an empty database at the specified location if one doesn’t already exist. If false and a database doesn’t exist you will receive an error in your open() callback and your database won’t open.

    • 'errorIfExists' (boolean, default: false): If true, you will receive an error in your open() callback if the database exists at the specified location.

    • 'compression' (boolean, default: true): If true, all compressible data will be run through the Snappy compression algorithm before being stored. Snappy is very fast and shouldn’t gain much speed by disabling so leave this on unless you have good reason to turn it off.

    • 'cacheSize' (number, default: 8 * 1024 * 1024 = 8MB): The size (in bytes) of the in-memory LRU cache with frequently used uncompressed block contents.

    Advanced options

    The following options are for advanced performance tuning. Modify them only if you can prove actual benefit for your particular application.

    • 'writeBufferSize' (number, default: 4 * 1024 * 1024 = 4MB): The maximum size (in bytes) of the log (in memory and stored in the .log file on disk). Beyond this size, LevelDB will convert the log data to the first level of sorted table files. From the LevelDB documentation:

    Larger values increase performance, especially during bulk loads. Up to two write buffers may be held in memory at the same time, so you may wish to adjust this parameter to control memory usage. Also, a larger write buffer will result in a longer recovery time the next time the database is opened.

    • 'blockSize' (number, default 4096 = 4K): The approximate size of the blocks that make up the table files. The size related to uncompressed data (hence “approximate”). Blocks are indexed in the table file and entry-lookups involve reading an entire block and parsing to discover the required entry.

    • 'maxOpenFiles' (number, default: 1000): The maximum number of files that LevelDB is allowed to have open at a time. If your data store is likely to have a large working set, you may increase this value to prevent file descriptor churn. To calculate the number of files required for your working set, divide your total data by 2MB, as each table file is a maximum of 2MB.

    • 'blockRestartInterval' (number, default: 16): The number of entries before restarting the “delta encoding” of keys within blocks. Each “restart” point stores the full key for the entry, between restarts, the common prefix of the keys for those entries is omitted. Restarts are similar to the concept of keyframs in video encoding and are used to minimise the amount of space required to store keys. This is particularly helpful when using deep namespacing / prefixing in your keys.


    leveldown#close(callback)

    close() is an instance method on an existing database object. The underlying LevelDB database will be closed and the callback function will be called with no arguments if the operation is successful or with a single error argument if the operation failed for any reason.


    leveldown#put(key, value[, options], callback)

    put() is an instance method on an existing database object, used to store new entries, or overwrite existing entries in the LevelDB store.

    The key and value objects may either be Strings or Node.js Buffer objects. Other object types are converted to JavaScript Strings with the toString() method. Keys may not be null or undefined and objects converted with toString() should not result in an empty-string. Values of null, undefined, '', [] and new Buffer(0) (and any object resulting in a toString() of one of these) will be stored as a zero-length character array and will therefore be retrieved as either '' or new Buffer(0) depending on the type requested.

    A richer set of data-types are catered for in LevelUP.

    options

    The only property currently available on the options object is 'sync' (boolean, default: false). If you provide a 'sync' value of true in your options object, LevelDB will perform a synchronous write of the data; although the operation will be asynchronous as far as Node is concerned. Normally, LevelDB passes the data to the operating system for writing and returns immediately, however a synchronous write will use fsync() or equivalent so your callback won’t be triggered until the data is actually on disk. Synchronous filesystem writes are significantly slower than asynchronous writes but if you want to be absolutely sure that the data is flushed then you can use 'sync': true.

    The callback function will be called with no arguments if the operation is successful or with a single error argument if the operation failed for any reason.


    leveldown#get(key[, options], callback)

    get() is an instance method on an existing database object, used to fetch individual entries from the LevelDB store.

    The key object may either be a String or a Node.js Buffer object and cannot be undefined or null. Other object types are converted to JavaScript Strings with the toString() method and the resulting String may not be a zero-length. A richer set of data-types are catered for in LevelUP.

    Values fetched via get() that are stored as zero-length character arrays (null, undefined, '', [], new Buffer(0)) will return as empty-String ('') or new Buffer(0) when fetched with asBuffer: true (see below).

    options

    The optional options object may contain:

    • 'fillCache' (boolean, default: true): LevelDB will by default fill the in-memory LRU Cache with data from a call to get. Disabling this is done by setting fillCache to false.

    • 'asBuffer' (boolean, default: true): Used to determine whether to return the value of the entry as a String or a Node.js Buffer object. Note that converting from a Buffer to a String incurs a cost so if you need a String (and the value can legitimately become a UFT8 string) then you should fetch it as one with asBuffer: true and you’ll avoid this conversion cost.

    The callback function will be called with a single error if the operation failed for any reason. If successful the first argument will be null and the second argument will be the value as a String or Buffer depending on the asBuffer option.


    leveldown#del(key[, options], callback)

    del() is an instance method on an existing database object, used to delete entries from the LevelDB store.

    The key object may either be a String or a Node.js Buffer object and cannot be undefined or null. Other object types are converted to JavaScript Strings with the toString() method and the resulting String may not be a zero-length. A richer set of data-types are catered for in LevelUP.

    options

    The only property currently available on the options object is 'sync' (boolean, default: false). See leveldown#put() for details about this option.

    The callback function will be called with no arguments if the operation is successful or with a single error argument if the operation failed for any reason.


    leveldown#batch(operations[, options], callback)

    batch() is an instance method on an existing database object. Used for very fast bulk-write operations (both put and delete). The operations argument should be an Array containing a list of operations to be executed sequentially, although as a whole they are performed as an atomic operation inside LevelDB. Each operation is contained in an object having the following properties: type, key, value, where the type is either 'put' or 'del'. In the case of 'del' the 'value' property is ignored. Any entries with a 'key' of null or undefined will cause an error to be returned on the callback. Any entries where the type is 'put' that have a 'value' of undefined, null, [], '' or new Buffer(0) will be stored as a zero-length character array and therefore be fetched during reads as either '' or new Buffer(0) depending on how they are requested.

    See LevelUP for full documentation on how this works in practice.

    options

    The only property currently available on the options object is 'sync' (boolean, default: false). See leveldown#put() for details about this option.

    The callback function will be called with no arguments if the operation is successful or with a single error argument if the operation failed for any reason.


    leveldown#approximateSize(start, end, callback)

    approximateSize() is an instance method on an existing database object. Used to get the approximate number of bytes of file system space used by the range [start..end). The result may not include recently written data.

    The start and end parameters may be either String or Node.js Buffer objects representing keys in the LevelDB store.

    The callback function will be called with no arguments if the operation is successful or with a single error argument if the operation failed for any reason.


    leveldown#getProperty(property)

    getProperty can be used to get internal details from LevelDB. When issued with a valid property string, a readable string will be returned (this method is synchronous).

    Currently, the only valid properties are:

    • 'leveldb.num-files-at-levelN': return the number of files at level N, where N is an integer representing a valid level (e.g. “0”).

    • 'leveldb.stats': returns a multi-line string describing statistics about LevelDB’s internal operation.

    • 'leveldb.sstables': returns a multi-line string describing all of the sstables that make up contents of the current database.


    leveldown#iterator([options])

    iterator() is an instance method on an existing database object. It returns a new Iterator instance.

    options

    The optional options object may contain:

    • 'gt' (greater than), 'gte' (greater than or equal) define the lower bound of the values to be fetched and will determine the starting point where 'reverse' is not true. Only records where the key is greater than (or equal to) this option will be included in the range. When 'reverse' is ‘true` the order will be reversed, but the records returned will be the same.

    • 'lt' (less than), 'lte' (less than or equal) define the higher bound of the range to be fetched and will determine the starting poitn where 'reverse' is not true. Only key / value pairs where the key is less than (or equal to) this option will be included in the range. When 'reverse' is true the order will be reversed, but the records returned will be the same.

    • 'start', 'end' legacy ranges – instead use 'gte', 'lte'

    • 'reverse' (boolean, default: false): a boolean, set to true if you want the stream to go in reverse order. Beware that due to the way LevelDB works, a reverse seek will be slower than a forward seek.

    • 'keys' (boolean, default: true): whether the callback to the next() method should receive a non-null key. There is a small efficiency gain if you ultimately don’t care what the keys are as they don’t need to be converted and copied into JavaScript.

    • 'values' (boolean, default: true): whether the callback to the next() method should receive a non-null value. There is a small efficiency gain if you ultimately don’t care what the values are as they don’t need to be converted and copied into JavaScript.

    • 'limit' (number, default: -1): limit the number of results collected by this iterator. This number represents a maximum number of results and may not be reached if you get to the end of the store or your 'end' value first. A value of -1 means there is no limit.

    • 'fillCache' (boolean, default: false): wheather LevelDB’s LRU-cache should be filled with data read.

    • 'keyAsBuffer' (boolean, default: true): Used to determine whether to return the key of each entry as a String or a Node.js Buffer object. Note that converting from a Buffer to a String incurs a cost so if you need a String (and the value can legitimately become a UFT8 string) then you should fetch it as one.

    • 'valueAsBuffer' (boolean, default: true): Used to determine whether to return the value of each entry as a String or a Node.js Buffer object.


    iterator#next(callback)

    next() is an instance method on an existing iterator object, used to increment the underlying LevelDB iterator and return the entry at that location.

    the callback function will be called with no arguments in any of the following situations:

    • the iterator comes to the end of the store
    • the end key has been reached; or
    • the limit has been reached

    Otherwise, the callback function will be called with the following 3 arguments:

    • error – any error that occurs while incrementing the iterator.
    • key – either a String or a Node.js Buffer object depending on the keyAsBuffer argument when the iterator() was called.
    • value – either a String or a Node.js Buffer object depending on the valueAsBuffer argument when the iterator() was called.

    iterator#end(callback)

    end() is an instance method on an existing iterator object. The underlying LevelDB iterator will be deleted and the callback function will be called with no arguments if the operation is successful or with a single error argument if the operation failed for any reason.


    leveldown.destroy(location, callback)

    destroy() is used to completely remove an existing LevelDB database directory. You can use this function in place of a full directory rm if you want to be sure to only remove LevelDB-related files. If the directory only contains LevelDB files, the directory itself will be removed as well. If there are additional, non-LevelDB files in the directory, those files, and the directory, will be left alone.

    The callback will be called when the destroy operation is complete, with a possible error argument.

    leveldown.repair(location, callback)

    repair() can be used to attempt a restoration of a damaged LevelDB store. From the LevelDB documentation:

    If a DB cannot be opened, you may attempt to call this method to resurrect as much of the contents of the database as possible. Some data may be lost, so be careful when calling this function on a database that contains important information.

    You will find information on the repair operation in the LOG file inside the store directory.

    A repair() can also be used to perform a compaction of the LevelDB log into table files.

    The callback will be called when the repair operation is complete, with a possible error argument.


    Safety

    Database state

    Currently LevelDOWN does not track the state of the underlying LevelDB instance. This means that calling open() on an already open database may result in an error. Likewise, calling any other operation on a non-open database may result in an error.

    LevelUP currently tracks and manages state and will prevent out-of-state operations from being send to LevelDOWN. If you use LevelDOWN directly then you must track and manage state for yourself.


    Snapshots

    LevelDOWN exposes a feature of LevelDB called snapshots. This means that when you do e.g. createReadStream and createWriteStream at the same time, any data modified by the write stream will not affect data emitted from the read stream. In other words, a LevelDB Snapshot captures the latest state at the time the snapshot was created, enabling the snapshot to iterate or read the data without seeing any subsequent writes. Any read not performed on a snapshot will implicitly use the latest state.


    Getting support

    There are multiple ways you can find help in using LevelDB in Node.js:

    • IRC: you’ll find an active group of LevelUP users in the ##leveldb channel on Freenode, including most of the contributors to this project.
    • Mailing list: there is an active Node.js LevelDB Google Group.
    • GitHub: you’re welcome to open an issue here on this GitHub repository if you have a question.


    Contributing

    LevelDOWN is an OPEN Open Source Project. This means that:

    Individuals making significant and valuable contributions are given commit-access to the project to contribute as they see fit. This project is more like an open wiki than a standard guarded open source project.

    See the CONTRIBUTING.md file for more details.

    Contributors

    LevelDOWN is only possible due to the excellent work of the following contributors:

    Rod Vagg GitHub/rvagg Twitter/@rvagg
    John Chesley GitHub/chesles Twitter/@chesles
    Jake Verbaten GitHub/raynos Twitter/@raynos2
    Dominic Tarr GitHub/dominictarr Twitter/@dominictarr
    Max Ogden GitHub/maxogden Twitter/@maxogden
    Lars-Magnus Skog GitHub/ralphtheninja Twitter/@ralphtheninja
    David Björklund GitHub/kesla Twitter/@david_bjorklund
    Julian Gruber GitHub/juliangruber Twitter/@juliangruber
    Paolo Fragomeni GitHub/hij1nx Twitter/@hij1nx
    Anton Whalley GitHub/No9 Twitter/@antonwhalley
    Matteo Collina GitHub/mcollina Twitter/@matteocollina
    Pedro Teixeira GitHub/pgte Twitter/@pgte
    James Halliday GitHub/substack Twitter/@substack
    Oguz Bastemur GitHub/obastemur Twitter/@obastemur

    Windows

    A large portion of the Windows support comes from code by Krzysztof Kowalczyk @kjk, see his Windows LevelDB port here. If you’re using LevelUP on Windows, you should give him your thanks!


    License & copyright

    Copyright (c) 2012-2015 LevelDOWN contributors (listed above).

    LevelDOWN is licensed under the MIT license. All rights not explicitly granted in the MIT license are reserved. See the included LICENSE.md file for more details.

    LevelDOWN builds on the excellent work of the LevelDB and Snappy teams from Google and additional contributors. LevelDB and Snappy are both issued under the New BSD Licence.

    Visit original content creator repository
    https://github.com/Level/leveldown-mobile

  • vue-warehouse

    Codacy Badge Travis Build status codecov David David version License

    Vue.js Warehouse

    A Cross-browser storage for Vue.js and Nuxt.js, with plugins support and easy extensibility based on Store.js.

    This plugin will pick the best available browser storage, and automatically falls back to the first available storage that works.

    Read this in other languages: English, Español

    Features

    • Backed by the great library Store.js
    • Support for multiple Storages (localStorage, cookies, etc.)
    • Basic key/value storage functionality (get/set/remove/each)
    • Easy integration with Vue.js
    • Support for Nuxt.js
    • Get notified with Vuex when the stored values change

    Why use this plugin

    Some reasons why you could consider to use this plugin:

    • Use a fallback Browser storage method in case the user’s browser has limitations. Safari in Private mode can deny writing data in localStorage.
    • Easy extensibility with Plugins. Support for expiring stored values at a given time, declare default values, etc.
    • A consistent API across browsers for a key/value storage functionality.
    • Easy definition of alternative Storage methods. For example: you could reuse a Vue Component, that relies on a storage method, in the user’s browser (using localStorage) or a mobile app (using NativeScript application-settings module) just by changing the storage method without modifying the internal logic of the component.
    • Synchronization of stored values changes with Vuex.

    Installation

    This module is distributed via npm which is bundled with node and should be installed as one of your project’s dependencies:

    npm install --save store vue-warehouse

    or

    yarn add store vue-warehouse

    Example of use

    Suppose you want to use localStorage by default and cookies as an alternative in case your user’s browser doesn’t allow any interaction with localStorage (Safari Private mode). Besides, you want to define defaults values and an expiration date for all the data that is going to be saved.

    Configuration for Vue.js

    import Vue from 'vue'
    import VueWarehouse from 'vue-warehouse'
    import VueWarehouseSync from 'vue-warehouse/sync'
    
    import VuexStore from './vuex/store' // vuex store instance
    import VueWarehouseStore from 'store' // vue-warehouse store instance
    
    VueWarehouseSync(VuexStore, VueWarehouseStore)
    
    Vue.use(VueWarehouse, {
      store: VueWarehouseStore,
      plugins: [
        require('store/plugins/expire'),   // Expire stored values at a given time
        require('store/plugins/defaults')  // Declare default values
      ],
      storages: [
        require('store/storages/localStorage'),  // localStorage support
        require('store/storages/cookieStorage')  // cookies support
      ]
    })

    Configuration for Nuxt.js

    {
      modules: [
        ['vue-warehouse/nuxt',
          {
            vuex: true,
            plugins: [
              'store/plugins/expire',
              'store/plugins/defaults'
            ],
            storages: [
              'store/storages/localStorage',
              'store/storages/cookieStorage'
            ]
          }
        ],
      ]
    }

    API Usage

    // Define defaults values
    this.$warehouse.defaults({ user: { name: 'John Doe' } })
    
    // Change current user with an expiration date of 2 hours starting from now
    const expiration = new Date().getTime() + (3600 * 2000)
    this.$warehouse.set('user', { name:'Marie Doe' }, expiration)
    
    // Get current user value
    this.$warehouse.get('user')
    
    // Get current user expiration
    this.$warehouse.getExpiration('user')
    
    // Remove current user
    this.$warehouse.remove('user') // return the default value -> { name: 'John Doe' }
    
    // Clear all keys
    this.$warehouse.clearAll()
    
    // Loop over all stored values
    this.$warehouse.each(function(value, key) {
    	console.log(key, '==', value)
    })

    Vuex State

    The last change made to the browser store (localStorage, cookie, etc.) are synced with the Vuex state:

    // Store current user
    this.$warehouse.set('user', { name: 'John Doe' })
    
    // Update the user
    this.$warehouse.set('user', { name: 'Marie Doe' })
    
    // get state values
    store.state.warehouse.action    // action performed -> set
    store.state.warehouse.key       // key affected     -> user
    store.state.warehouse.value     // stored value     -> { name: 'Marie Doe' }
    store.state.warehouse.oldValue  // last value       -> { name: 'John Doe' }

    Documentation & Support

    Professional Support

    This project is sponsored by me, a Full Stack Developer. If you require Professional Assistance on your project(s), please contact me at https://marquez.co.

    Contributing

    Please make sure to read the Contributing Guide before making a pull request.

    Code of Conduct

    Everyone participating in this project is expected to agree to abide by the Code of Conduct.

    License

    Code released under the MIT License.

    Visit original content creator repository https://github.com/juliomrqz/vue-warehouse
  • antd-form-multi

    antd-form-multi

    背景

    在前端中后台的开发中,常见的业务场景是对表单的处理。对于简单、交互少、联动少的业务场景直接使用antd提供的Form组件就可以,对于追求性能,需要复杂表单生成的时候可以使用 formily 开源库,但其付出的学习成本会更高。所以本库是介于两者之间的一个便捷、高效、易于理解、且功能相对完整、适用于绝大多数业务场景开发的一个库。

    特性

    • 高效:自定义的配置项生成表单。
    • 强大:拥有表单内数据联动,多级列表控制等功能
    • 简单:其中基于 AntdV4 ,所有组件 API 保持一致,降低开发人员心智负担。

    安装

    npm install antd-form-multi

    或者

    yarn add antd-form-multi

    在组件内的<Form>(antd组件)内引用

    import FormItem from 'antd-form-multi'

    用法和实例说明

    import React from 'react';
    import { connect } from 'dva';
    import { Form } from 'antd';
    import FormItem from 'antd-form-multi';
    
    const Index = (props) => {
      const [form] = Form.useForm();
      return (
        <>
          <Form form={form} layout="vertical" initialValues={{}}>
            <FormItem
              ref={form}
              fields={[
                {
                  type: 'text',
                  required: true,
                  label: '标题',
                  code: 'title',
                  span: 24,
                },
                {
                  type: 'textarea',
                  label: '备注',
                  code: 'remark',
                  span: 10,
                },
              ]}
              labelCol={24}
              wrapperCol={24}
            ></FormItem>
          </Form>
        </>
      );
    }
    • ref 为表单实例项
    • fields 表单内每一控件的配置信息,详情配置信息参考下文(fields配置项)
    • labelCol、wrapperCol 每一项的标签和输入控件的布局样式

            const [groupValue, setGroupValue] = useState([]);
            ...
            <FormItem
              ref={form}
              fields={[
                {
                  type: 'select',
                  required: true,
                  label: '规则选择(一)',
                  code: 'rules1',
                  span: 24,
                  options: [
                    {
                      id: '1-1',
                      name: '规则1-1',
                    },
                    {
                      id: '1-2',
                      name: '规则1-2',
                    },
                  ],
                  onChange: (val) => {
                    const index = groupValue.findIndex((i) => i === '1-1' || i === '1-2');
                    if (index > -1) {
                      groupValue.splice(index, 1, val);
                    } else {
                      groupValue.push(val);
                    }
                    setGroupValue([...groupValue]);
                  },
                },
                {
                  type: 'select',
                  required: true,
                  label: '规则选择(二)',
                  code: 'rules2',
                  span: 24,
                  options: [
                    {
                      id: '2-1',
                      name: '规则2-1',
                    },
                    {
                      id: '2-2',
                      name: '规则2-2',
                    },
                  ],
                  onChange: (val) => {
                    const index = groupValue.findIndex((i) => i === '2-1' || i === '2-2');
                    if (index > -1) {
                      groupValue.splice(index, 1, val);
                    } else {
                      groupValue.push(val);
                    }
                    setGroupValue([...groupValue]);
                  },
                },
                {
                  type: 'text',
                  label: '我是规则1-1',
                  code: 'rule1-1',
                  span: 24,
                  group: ['1-1'],
                },
                {
                  type: 'text',
                  label: '我是规则1-2或2-1',
                  code: 'rule1-2,2-1',
                  span: 24,
                  group: ['1-2', '2-1'],
                },
                {
                  type: 'text',
                  required: true,
                  label: '规则2-2 必填',
                  code: 'rule2-2',
                  span: 24,
                  group: ['2-2'],
                },
                {
                  type: 'text',
                  label: '规则不是2-2 非必填',
                  code: 'rule2-2',
                  span: 24,
                  group: ['1-1', '1-2', '2-1'],
                },
              ]}
              groupValue={groupValue}
              labelCol={24}
              wrapperCol={24}
            ></FormItem>

    采用组的概念,将需要显示的内容全部传入fields内,当groupValue 内匹配有 group 时则该项显示,如果field没有group 则一值展示

    所以你只需要在触发改变group 时进行配置即可

        import FormItem, { FormWrapCard, addLevel1 } from '@/components/FormItem';
        ...
          const addHandle = () => {
            addLevel1(form, ['list'], {});
          };
          <Form form={form} layout="vertical" initialValues={{}}>
            <FormItem
              ref={form}
              fields={[
                {
                  type: 'text',
                  required: true,
                  label: '标题',
                  code: 'title',
                  span: 24,
                },
              ]}
              level1={{
                name: ['list'],
                fields: [
                  {
                    type: 'text',
                    label: '键',
                    code: 'key',
                    span: 12,
                  },
                  {
                    type: 'text',
                    label: '值',
                    code: 'value',
                    span: 12,
                  },
                ],
                WrapComponent: FormWrapCard,
                wrapCopy: true,
                wrapMove: true,
                openLabel: true,
              }}
              labelCol={24}
              wrapperCol={24}
            ></FormItem>
          </Form>
          <Button onClick={addHandle}> 添加一项</Button>

    level1

    level1 的配置项参考下方API

    这里提供了增加一级列表的函数

    addLevel1:(form:表单的ref,[]:一级列表的名称,{}:一级列表的默认值)=>void

    level2

    二级列表的API与一级列表保持一致

    基本与 数据联动一致,通过改变level1 内的groupValue的值显示/隐藏对应组的field,

    这里是隐藏,当切换,使得隐藏的显示时,隐藏的输入控件的内容会被保留,但表单提交时,也会保留
    如果不希望保留得话,需要手动清除值

    groupValue

    是一个数据集合,例如

    groupValue = [[0,['group1']],[1,['group2','group3']]]

    第一项 0name对应的 一级列表 的索引,第二项 ['group1']是一个数组,对应的是该索引列表的组的规则,满足规则的 field 项显示

    当 fields 其中一项改变时,接收的参数为2个,第一个是改变的值,第二个是改变的 name 的索引值

    例如

         {
            type: 'select',
            required: true,
            label: '规则选择(一)',
            code: 'rules1',
            span: 12,
            options: [
                {
                id: '1-1',
                name: '规则1-1',
                },
                {
                id: '1-2',
                name: '规则1-2',
                },
            ],
            onChange: (val, nameList) => {
                const index = groupListValue.findIndex((i) => i[0] === nameList[0]);
                const name = nameList[0];
                if (index > -1) {
                    groupListValue.splice(index, 1, [name, [val]]);
                } else {
                    groupListValue.push([name, [val]]);
                }
                setGroupListValue([...groupListValue]);
            },
        },

    我们可以通过onChange回调函数来接收到这两个参数,并且通过自己的方式去改变对应组的值

    基本上与一级列表一致
    在组的定义上,多了一层

    groupValue = [[0,0,['group1']],[0,1,['group2','group3']]]

    第一项 0 是一级列表对应的索引,第二项是二级列表 name对应的索引, 第三项 ['group1']是一个数组,对应的是该索引列表的组的规则,满足规则的 field 项显示

    当 fields 其中一项改变时,接收的参数为3个,第一个是改变的值,第二个是改变的 name 的索引值,第三个是上级/第一级的索引值

    API

    fields配置项

    type

    参数 说明
    datePicker 日期选择器
    rangePicker 日期范围选择器
    timePicker 时间选择器
    timeRangePicker 时间范围选择器
    switch 开关
    radio 圆形单选框
    radio_button 方形单选框
    checkbox 复选框
    text 输入框
    password 密码输入框
    text_group 输入组
    textarea 输入框-文本域
    number_text 数字输入框
    select 选择框
    select_multi 多选框
    autoComplete 自动完成
    upload 文件上传
    transfer 穿梭框
    table 表格
    template 自定义

    code

    对应 antd 文档的 name

    span

    表示控件的占位大小(24份大小)

    其余

    antd 文档API 一致

    配置项

    参数 说明 类型 默认值
    fields 列表的表单配置 Array
    labelCol 表单的label占位宽度 Number 6
    wrapperCol 表单的wrapper占位宽度 Number 18
    offset 表单的offset占位宽度 Number null
    plugin 自行添加的组件插件 [] []

    plugin

    • 类型 Array
      包含多个对象,对象内字段为

      • type(String):对应fields 内的 type,如果与 fields配置项冲突,则使用该type
      • component(Function):接收 item 字段,该字段包含传入的配置参数,field包含改项的位置参数。返回值:一个组件
    • 示例

      plygin=[
        {
            type:'input',
            component:(item,field)=><input></input>
        }
      ]

    level1 配置项

    参数 说明 类型 默认值
    name 列表的名称 Array
    fields 列表的表单配置 Array
    rules 列表的规则(参照 antd 的配置) Array
    openLabel 列表的标题显示 Boolean false
    labelCol 表单的label占位宽度 Number 6
    wrapperCol 表单的wrapper占位宽度 Number 18
    offset 表单的offset占位宽度 Number null
    WrapComponent 包裹组件 React.Element <></>
    wrapName 包裹组件的名称 String ‘新的标签页’
    wrapCopy 包裹组件复制操作 Boolean false
    wrapMove 包裹组件移动操作 Boolean false
    sortable 包裹组件可拖拽 Boolean false

    level2 配置项与 level1 一致

    level2配置暂不支持

    sortable 包裹组件可拖拽 Boolean false


    Visit original content creator repository
    https://github.com/CMG-CEO/antd-form-multi

  • DocumentApplication

    DocumentApplication

    This application was generated using JHipster 5.8.1, you can find documentation and help at https://www.jhipster.tech/documentation-archive/v5.8.1.

    Development

    Before you can build this project, you must install and configure the following dependencies on your machine:

    1. Node.js: We use Node to run a development web server and build the project. Depending on your system, you can install Node either from source or as a pre-packaged bundle.

    After installing Node, you should be able to run the following command to install development tools. You will only need to run this command when dependencies change in package.json.

    npm install
    

    We use npm scripts and Webpack as our build system.

    Run the following commands in two separate terminals to create a blissful development experience where your browser auto-refreshes when files change on your hard drive.

    ./mvnw
    npm start
    

    Npm is also used to manage CSS and JavaScript dependencies used in this application. You can upgrade dependencies by specifying a newer version in package.json. You can also run npm update and npm install to manage dependencies. Add the help flag on any command to see how you can use it. For example, npm help update.

    The npm run command will list all of the scripts available to run for this project.

    Service workers

    Service workers are commented by default, to enable them please uncomment the following code.

    • The service worker registering script in index.html
    <script>
        if ('serviceWorker' in navigator) {
            navigator.serviceWorker.register('./service-worker.js').then(function() {
                console.log('Service Worker Registered');
            });
        }
    </script>

    Note: workbox creates the respective service worker and dynamically generate the service-worker.js

    Managing dependencies

    For example, to add Leaflet library as a runtime dependency of your application, you would run following command:

    npm install --save --save-exact leaflet
    

    To benefit from TypeScript type definitions from DefinitelyTyped repository in development, you would run following command:

    npm install --save-dev --save-exact @types/leaflet
    

    Then you would import the JS and CSS files specified in library’s installation instructions so that Webpack knows about them: Edit src/main/webapp/app/vendor.ts file:

    import 'leaflet/dist/leaflet.js';
    

    Edit src/main/webapp/content/css/vendor.css file:

    @import '~leaflet/dist/leaflet.css';
    

    Note: there are still few other things remaining to do for Leaflet that we won’t detail here.

    For further instructions on how to develop with JHipster, have a look at Using JHipster in development.

    Using angular-cli

    You can also use Angular CLI to generate some custom client code.

    For example, the following command:

    ng generate component my-component
    

    will generate few files:

    create src/main/webapp/app/my-component/my-component.component.html
    create src/main/webapp/app/my-component/my-component.component.ts
    update src/main/webapp/app/app.module.ts
    

    Building for production

    To optimize the DocumentApplication application for production, run:

    ./mvnw -Pprod clean package
    

    This will concatenate and minify the client CSS and JavaScript files. It will also modify index.html so it references these new files. To ensure everything worked, run:

    java -jar target/*.war
    

    Then navigate to http://localhost:8080 in your browser.

    Refer to Using JHipster in production for more details.

    Testing

    To launch your application’s tests, run:

    ./mvnw clean test
    

    Client tests

    Unit tests are run by Jest and written with Jasmine. They’re located in src/test/javascript/ and can be run with:

    npm test
    

    For more information, refer to the Running tests page.

    Code quality

    Sonar is used to analyse code quality. You can start a local Sonar server (accessible on http://localhost:9001) with:

    docker-compose -f src/main/docker/sonar.yml up -d
    

    Then, run a Sonar analysis:

    ./mvnw -Pprod clean test sonar:sonar
    

    For more information, refer to the Code quality page.

    Using Docker to simplify development (optional)

    You can use Docker to improve your JHipster development experience. A number of docker-compose configuration are available in the src/main/docker folder to launch required third party services.

    For example, to start a mysql database in a docker container, run:

    docker-compose -f src/main/docker/mysql.yml up -d
    

    To stop it and remove the container, run:

    docker-compose -f src/main/docker/mysql.yml down
    

    You can also fully dockerize your application and all the services that it depends on. To achieve this, first build a docker image of your app by running:

    ./mvnw package -Pprod verify jib:dockerBuild
    

    Then run:

    docker-compose -f src/main/docker/app.yml up -d
    

    For more information refer to Using Docker and Docker-Compose, this page also contains information on the docker-compose sub-generator (jhipster docker-compose), which is able to generate docker configurations for one or several JHipster applications.

    Continuous Integration (optional)

    To configure CI for your project, run the ci-cd sub-generator (jhipster ci-cd), this will let you generate configuration files for a number of Continuous Integration systems. Consult the Setting up Continuous Integration page for more information.

    Upload Products CSV Sequence

    picture alt

    Visit original content creator repository https://github.com/puttareddy/DocumentApplication
  • waodate_deeplink_docs

    Document Deeplink WAODATE

    Description:

    • Document about library, installation, coding and testing and some problems about i need everyone helps… 🐼

    Library:

    uni_links: ^0.5.1

    Installation:

    For Android

    • **You need to declare at least one of the two intent filters in android/app/src/main/AndroidManifest.xml:

    • replace “[YOUR_SCHEME]” by http or https

    • replace “[YOUR_HOST]” by waodate.com

    import 'package:uni_links/uni_links.dart';

    Write function handler

    Future<void> initUniLinks() async {
        _sub = uriLinkStream.listen((Uri uri) {
          List<String> paths = uri.path.split("https://github.com/");
          if (paths.contains('home')) {
            navGlogbalKey.currentState.pushNamedAndRemoveUntil(
              AppRoutes.HOME,
              (route) => false,
              arguments: {
                'index': 0,
              },
            );
          } else if (paths.contains('profile')) {
            navGlogbalKey.currentState.pushNamed(
              AppRoutes.PROFILE,
              arguments: {'userId': paths.last},
            );
          } else if (paths.contains('vvip')) {
            navGlogbalKey.currentState.pushNamedAndRemoveUntil(
              AppRoutes.HOME,
              (route) => false,
              arguments: {
                'index': 0,
              },
            );
            navGlogbalKey.currentState.pushNamed(
              AppRoutes.VVIP,
            );
          } else if (paths.contains('concept')) {
            navGlogbalKey.currentState.pushNamedAndRemoveUntil(
              AppRoutes.HOME,
              (route) => false,
              arguments: {
                'index': 1,
              },
            );
            navGlogbalKey.currentState.pushNamed(
              AppRoutes.DETAILS_CONCEPT,
              arguments: {
                'conceptId': paths.last,
                'appointmentModel': AppointmentModel(
                  appointmentId: paths.last,
                ),
              },
            );
          }
          // Use the uri and warn the user, if it is not correct
        }, onError: (err) {
          // Handle exception by warning the user their action did not succeed
        });
    }

    Call function run when open app and keep alive until user killed application:

      @override
      void initState() {
        initUniLinks();
      }

    Test cases:

    Case Android iOS
    https://waodate.com/home DONE DONE
    https://waodate.com/vvip DONE DONE
    https://waodate.com/profile/:id DONE DONE
    https://waodate.com/concept/:id DONE DONE

    If you want test, lets run below bash code in terminal

    Android

    adb shell 'am start -W -a android.intent.action.VIEW -c android.intent.category.BROWSABLE -d "https://waodate.com/home"'
    

    iOS

    /usr/bin/xcrun simctl openurl booted "https:waodate.com/home"
    

    Problems:

    • I were config for iOS like documents: uni_link
    • But can’t test on iOS simulator. I think have a problem here: Apple_Document
    • OKAY, if you have a idea for resolve this problem, lets contact me by email or skype

    Author: lambiengcode from waodate.com

    Visit original content creator repository
    https://github.com/lambiengcode/waodate_deeplink_docs