text:
# ICTSBA-Krita-eLearn
Originally 2021 HKDSE ICT SBA, themed as e-learn platform on software Krita

This project was originally a part of the 2021 HKDSE examination SBA (School-based Assessment),\
while unluckily, CVOID-19 has damaged Hong Kong SAR in different areas include our education time\
And so, Hong Kong Education Bureau has decided to cancel most of the elective's SBA project\
I feel extremely sad and completely can't accept the decide from them,\
As ICT is always a subject to proof ur skill with computers, and not with stupid paper tests.\
Sadly im not powerful enough to change the result from government,\
Therefore I decided to open source my project.\

##### Hope that one day i will be powerful enough to change all of this shits.

---

### Special Thanks
Here I want to shout out my thanks to the developers and contributors who given lots of time on\
Developing, maintaining such amazing open-source software [Krita](https://Krita.org) ([repo](https://github.com/KDE/krita))\
You provided lots of help to the people that wasn't able to buy Photoshop yet
Thank you, i appreciate the hard work of you guys give to this project!

### Highlights
![](/file/preview-images/mc.mccwtech.net_projects_e-learn_login_(1080p%20onitor).png?raw=true)
![](/file/preview-images/mc.mccwtech.net_projects_e-learn_(1080p%20Monitor).png?raw=true)
![](/file/preview-images/mc.mccwtech.net_projects_e-learn_profile(1080p%20Monitor).png?raw=true)
![](/file/preview-images/mc.mccwtech.net_projects_e-learn_tutorial_intro_(1080p%20Monitor).png?raw=true)
![](/file/preview-images/mc.mccwtech.net_projects_e-learn_tutorial_video-sample_(1080p%20Monitor).png?raw=true)
![](/file/preview-images/mc.mccwtech.net_projects_e-learn_tutorial_final-quiz_(1080p%20Monitor).png?raw=true)
![](/file/preview-images/mc.mccwtech.net_projects_e-learn_download(1080p%20Monitor).png?raw=true)
![](/file/preview-images/mc.mccwtech.net_projects_e-learn_forum(1080p%20Monitor).png?raw=true)

### Live Demo
https://mc.mccwtech.net/projects/e-learn

### Includes/Basic features
  - Basic account creation and deletion (username, email, password)
  - Basic session system (PHP session)
  - Basic storage (local json storage system)
  - Baisc security (MD5 hashed passwords)
  - Basic profile viewing
  - An article introducing Krita
  - Basic tutorial for making icons with Krita
  - A video showcasing how to use Krita to draw anime
  - Simple quiz system on basic knownledge of Krita
  - Basic download page (Krita installtion file is removed as it is too big & copyright issue)
  - Basic forums (Storing message, time, user, email, avatar in local)
  - Basic games (include a unity block obstacle game, probably gona open-source too later)

### Installation
  - Install a web server
  - ```cd /var/www/html/``` //Go to ur www folder
  - ```mkdir /projects/``` //Setup website folder (you can changed to whatever u like)
  - ```cd /projects/```
  - ```git clone https://github.com/mkcoldwolf/ICTSBA-Krita-eLearn```

### License
  - [Apache License 2.0](LICENSE)

repository: mkcoldwolf/ICTSBA-Krita-eLearn

repo_name: mkcoldwolf/ICTSBA-Krita-eLearn


text:
# And more!

## Might Require Some 3rd Party Integrations

These features work for the most part, but might require JsInterop classes for some external JavaScript libraries (or the usage of Java ones).

* [Transition Effects](https://vuejs.org/v2/guide/transitions.html)
    * Will work for the most part, except when using Velocity (which would require JsInterop for [Velocity](http://velocityjs.org/)).
* [Transitioning State](https://vuejs.org/v2/guide/transitioning-state.html)
    * You would need to code the transitions code yourself, or code JsInterop for [tween.js](https://github.com/tweenjs/tween.js/).

## Unsupported Features

Vue GWT doesn't support all of Vue.js features yet.
If you would like to help we are [open to contributions](https://github.com/Axellience/vue-gwt)!

Here is the list of unsupported features:

* [Mixins](https://vuejs.org/v2/guide/mixins.html)
    * Would be pretty hard to achieve because of Java single inheritance and type checking in templates.
* [State Management](https://vuejs.org/v2/guide/state-management.html)
    * Would require JsInterop for Vuex.
* [Server Side Rendering](https://vuejs.org/v2/guide/ssr.html)
    * Vue GWT components compiled and loaded in a Vue.js app should work server side (but not tested).
    * Full Vue GWT app would probably not work server side or would require lots of work.

license: MIT

repository: SwordCode/vue-gwt

branch_name: refs/heads/master

extension: md

license_type: permissive

repo_name: SwordCode/vue-gwt


text:
---
layout: posts
title:  "Old-Clients"
date:   2021-09-23
categories:
  - chaos_experiment
  - clients
tags:
  - availability
authors: zell
---

# Chaos Day Summary

It has been awhile since the last post, I'm happy to be back.

In today's chaos day we want to verify the hypothesis from [zeebe-chaos#34](https://github.com/zeebe-io/zeebe-chaos/issues/34) that old
clients can't disrupt a running cluster.

It might happen that after upgrading your Zeebe to the newest shiny version, you might forget to
update some of your workers or starters etc. This should normally not an issue since Zeebe is
backwards compatible, client wise since 1.x. But what happens when older clients are used. Old
clients should not have a negative effect on a running cluster.

**TLDR** Older clients (0.26) have no negative impact on a running cluster (1.2), and clients after
1.x are still working with the latest version.

<!--truncate-->

## Chaos Experiment

We will run a simple setup with, three nodes and three partitions (replication factor 3). The
version we use is the latest release candidate (1.2.0). Normally we run a load of 200 process
instances per second (pi/s) on our benchmarks. This time we will put a load of 100 pi/s to get
something running and start an old starter (v0.26.x) with the same frequency. Later we will scale
the old starter to see whether it makes any effect.

### Expected

We expect that we can start and complete the 100 pi/s, since we can normally run 200 pi/s.

### Actual

The cluster was first started with starters of the same version, and we saw a stable load of ~100
process instances completed per second. After starting the old starters (with version 0.26.3), we
can't observe any difference.

Interesting is even when scaling the starters up to 10 replicas, which means 1000 PI creations per
second, it doesn't seem to make any effect. *Side note:* The
[starters](https://github.com/camunda-cloud/zeebe/tree/develop/benchmarks/project) have been
modified, such they only start instances without deploying the model.

![old26-general](old26-general.png)

The drops we see in the processing are related to restart's.

The gateway and grpc metrics doesn't indicate that more requests are sent.

![old26-grpc](old26-grpc.png)
![old26-gateway](old26-gateway.png)

If we take a look in the clients log, we can see that the request are failing because the RPC Method names have been changed between 0.26 and 1.0.

```shell
java.util.concurrent.ExecutionException: io.grpc.StatusRuntimeException: UNIMPLEMENTED: Method not found: gateway_protocol.Gateway/CreateWorkflowInstance
	...
Caused by: io.grpc.StatusRuntimeException: UNIMPLEMENTED: Method not found: gateway_protocol.Gateway/CreateWorkflowInstance
	...
```

It seems this kind of "old" requests can be blocked quite early in the request chain to make no effect.

In order to experiment a bit further I created a starter image with version 1.0 to see whether this still works with our newest release candidate 1.2.

We can see in the metrics right after starting the starter that the throughput goes up and we can reach our 200 pi/s.

![old10-general](old10-general.png)

We run the benchmark overnight, and we haven't seen any issues. Be aware that the throughput is calculated over the 24h which makes is lower than 200.

![general](general.png)

Furthermore, taking a look at the resource consumption, especially at the gateway, gives no evidence that something wrong is going on.

![res](res.png)

### Result

We were able to confirm the hypothesis written in [zeebe-chaos#34](https://github.com/zeebe-io/zeebe-chaos/issues/34), that an old client can't disrupt a running cluster.

## Found Bugs

None this time :)

repository: zeebe-io/zeebe-chaos

branch_name: refs/heads/main

gha_language: Go

repo_name: zeebe-io/zeebe-chaos


text:
---
title: Moby Summits
layout: default
---

## Moby Summits

Moby Summits allow community members to meet in person and share what they're doing with the various Moby projects. This page contains links to previous summits summaries, with slides and videos when available, as well as information and planning documents for the next one.

### Moby Summit LA, September 2017

Register for [Moby Summit at OSS LA](https://www.eventbrite.com/e/moby-summit-los-angeles-tickets-35930560273) September 14, 2017 in Los Angeles.

If there are topics you want to see covered in this summit, please send a pull request to modify [the agenda](/events/summit-agenda-sept-2017/).

### Previous Moby Summits recaps

* [Moby Summit, June 2017](http://mobyproject.org/blog/2017/06/26/moby-summit-recap/)
* [Moby Summit, May 2017](http://mobyproject.org/blog/2017/05/11/moby-summit-report/)

repository: justincormack/mobywebsite

repo_name: justincormack/mobywebsite


text:
# Changelog

All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.

## 1.0.0 (2020-10-20)

### Bug Fixes

* href and favicon ([4b2d09b](https://github.com/tensegrity666/x-check-app/commit/4b2d09b7351b3dcaf997be9fd73de12d171f9773))

### [0.1.3](https://github.com/tensegrity666/x-check-app/compare/v0.1.2...v0.1.3) (2020-09-19)

### Features

* add constants file ([21c766e](https://github.com/tensegrity666/x-check-app/commit/21c766e88cc8aa9f350a09470540cf17f2ab13ac))
* add method for cross-check-session ([ee0f64a](https://github.com/tensegrity666/x-check-app/commit/ee0f64a6ceb854fef02d0d365d5a6ff7ebbe6993))
* add method getItemsTask(taskId) ([e35ffb2](https://github.com/tensegrity666/x-check-app/commit/e35ffb2157de65cbb9a67b9a016a97a5403c3e8f))
* add methods for the review request entity ([8710532](https://github.com/tensegrity666/x-check-app/commit/8710532b210f28f0755e483ac2bd70c47f0c4390))
* add obj constants  actionRevReqList ([654a0ee](https://github.com/tensegrity666/x-check-app/commit/654a0eeeec2cba665f4b5ec6488f00a906e0ce46))
* add review-requests table ([ff1b63d](https://github.com/tensegrity666/x-check-app/commit/ff1b63da9218c38beb66a3d20a78751bfffae9ba))
* add styles to review-requests page ([9134997](https://github.com/tensegrity666/x-check-app/commit/913499738985a18ca331271bf6277efb7c3e2727))
* checking user rights, dividing REST API into classes by entities ([4798821](https://github.com/tensegrity666/x-check-app/commit/4798821b60d32834c2f63c8c8c5ff12a6904ea4a))
* implement logout ([aaaeb85](https://github.com/tensegrity666/x-check-app/commit/aaaeb85618f7ed498285579deb0e1bbe2705c4d2))
* implement saving to local storage ([6200ff1](https://github.com/tensegrity666/x-check-app/commit/6200ff1c983dc42b91d4415223e7ac8431b5a3a3))
* install storybook ([78de379](https://github.com/tensegrity666/x-check-app/commit/78de379060f928e08a73e6692303f7dcecf14df9))
* render user info ([4596c0a](https://github.com/tensegrity666/x-check-app/commit/4596c0a3b59821f8e0990f16d3413819e9b500bd))
* save user info to store after login ([196fd93](https://github.com/tensegrity666/x-check-app/commit/196fd93d8bff5f464b4b3fe2ea6b412a1a8da16d))

### Bug Fixes

* add env-file ([544bd8c](https://github.com/tensegrity666/x-check-app/commit/544bd8c684badc4d20e739347afc515121393534))
* change some styles ([a47f410](https://github.com/tensegrity666/x-check-app/commit/a47f410ec7b8e4be7761ea9ad91b76300fa9b542))
* convert id from float to integer ([200e72e](https://github.com/tensegrity666/x-check-app/commit/200e72e65688810595e350087d68be21e4183c26))
* corrected text readmi ([4a3f255](https://github.com/tensegrity666/x-check-app/commit/4a3f255af7893c6002e9b7d16bf355cd1a1ebaaf))
* delete env-file ([a20cfbe](https://github.com/tensegrity666/x-check-app/commit/a20cfbe18027e5c726307cb42dff068cf38b100d))
* error correction user-api ([dd29db4](https://github.com/tensegrity666/x-check-app/commit/dd29db44ca6e9e3ac753db2e9864f16c36603062))
* fix merging conflicts ([ff6b1af](https://github.com/tensegrity666/x-check-app/commit/ff6b1af7325588328a577b32276891f50e50c9fe))
* gh-action ([8d98ba7](https://github.com/tensegrity666/x-check-app/commit/8d98ba7b781f569ea98edeee8b3759a9ac68b615))
* git-hooks and husky ([82015a5](https://github.com/tensegrity666/x-check-app/commit/82015a59fdb0a40b316fc047e8d6d3c4e1cb214b))
* pathes ([9aa421a](https://github.com/tensegrity666/x-check-app/commit/9aa421ab2405f0032c6c03186cb2941db710448c))
* redirect to login page after signout ([55725db](https://github.com/tensegrity666/x-check-app/commit/55725dbe666a7ebfebb5b95f6dd20132589708eb))
* return searchedText highlighter ([5fdb56f](https://github.com/tensegrity666/x-check-app/commit/5fdb56fa57bd5f91fe12c6b8757262871cb817a1))
* syntax error in yaml ([33d8f14](https://github.com/tensegrity666/x-check-app/commit/33d8f143336a00c1692bc506d2d9b99cde0dcee5))
* syntax error in yaml ([f40ea43](https://github.com/tensegrity666/x-check-app/commit/f40ea43b52d04e66643f159b9a0df9c14316d2e9))
* update from remote dev ([2a3512d](https://github.com/tensegrity666/x-check-app/commit/2a3512d23bc19b983503843242e4456e77f49b28))

### [0.1.2](https://github.com/tensegrity666/x-check-app/compare/v0.1.1...v0.1.2) (2020-09-10)

### Features

* implement GH-login ([f5f89e2](https://github.com/tensegrity666/x-check-app/commit/f5f89e21d9d8cbd67002276b36ab1a22ac02f91b))

### Bug Fixes

* problem in task name updating ([43a5565](https://github.com/tensegrity666/x-check-app/commit/43a5565237e437b818014a9cfe9724693861d11c))
* typo in gh-action file ([c3315f3](https://github.com/tensegrity666/x-check-app/commit/c3315f336f8f26cf58a93f61d752358d7b1e0756))

### [0.1.1](https://github.com/tensegrity666/x-check-app/compare/v0.1.0...v0.1.1) (2020-09-08)

### Features

* add gh-action for deploying on netlify ([838fe2a](https://github.com/tensegrity666/x-check-app/commit/838fe2a2c10a989fc42db03cbb03e9b43e9511f3))
* add icons for login component ([9fd825c](https://github.com/tensegrity666/x-check-app/commit/9fd825c5ad12a62e3b93d8334cd9d583530ce6cc))
* add login component ([062321f](https://github.com/tensegrity666/x-check-app/commit/062321f8186661f30af245fa1f8f0d83349f8bb5))
* add sessions path ([2736e17](https://github.com/tensegrity666/x-check-app/commit/2736e178eb16154dc2eb6f7d9c8db28428c1cdef))
* add side menu with navigation ([be4934a](https://github.com/tensegrity666/x-check-app/commit/be4934a7954c610e2e19d8608d339ac4c7a3f366))
* create routs ([41bc15f](https://github.com/tensegrity666/x-check-app/commit/41bc15fc0984a0e64667c4f383e9b04d57a7781a))
* setup environment ([eb81ea8](https://github.com/tensegrity666/x-check-app/commit/eb81ea8f27dfe4e4a33dfcf23036469799320df3))

### Bug Fixes

* relocate login component into components directory ([2d9d785](https://github.com/tensegrity666/x-check-app/commit/2d9d785fc27a620dff780331a2364c50812c0cf9))

## 0.1.0 (2020-08-29)

### Features

* add example ([1d70d01](https://github.com/tensegrity666/x-check-app/commit/1d70d01e735d6312e4827c5980cfecd6c357cabd))
* setup env ([251af16](https://github.com/tensegrity666/x-check-app/commit/251af160b286732b09201c8b4497818b62825734))

gha_license_id: MIT


text:
# how to continously deploy your web app to kubernetes like a boss

goals
- provision a brand-new kubernetes cluster, on digitalocean
- setup github actions to continuously deploy images and push helm upgrades

assumptions
- your app source is on github
- your've dockerized your microservices, including an nginx web server
- you've written a helm chart
- you're cool with publishing/pulling public images on dockerhub
- you're cool with publishing/pulling private images on github packages

prerequisite steps
1. set your domains' nameservers to cloudflare for dns hosting and cdn proxy
1. create a directory on a secure machine, to save super sneaky-beaky secrets, passwords, tokens, etc
1. cd into this tutorial directory to run scripts

## provision a kubernetes cluster

### (a) create fresh cluster
1. sign up on digitalocean
1. create kubernetes cluster. name it something cool

### (b) install local tools
1. follow the digitalocean instructions to install `doctl` and `kubectl` and `helm`
    - authenticate with `doctl`
    - set your kubectl context by running `doctl kubernetes cluster kubeconfig save CLUSTERNAME`
      - replace `CLUSTERNAME` with your cool cluster name
    - verify connection via `kubectl get namespace` to see standard kubernetes namespaces
    - *high five*

### (c) use digitalocean's prefabricated 1-click installs!
1. kubernetes monitoring stack - click to install
    - log into grafana and set it up
    - run `kubectl -n prometheus-operator get pods | grep prometheus-operator-grafana`
    - copy the pod name
    - run `kubectl port-forward POD_NAME_HERE -n prometheus-operator 9080:3000`
      - replace POD_NAME_HERE with the pod name
    - visit http://localhost:9080/ and login as `admin` / `prom-operator`
    - update password, write down in your sneaky-beaky dir
    - dashboards, manage, select compute resources cluster, star it
    - profile settings, set ui dark mode, and default dashboard to the one you starred
    - *neato!*
1. ingress-nginx controller - click to install
    - *boom done, fantastic!*

### (c) install standard web app infrastructure onto cluster

1. install cert-manager: run `./install-cert-manager`
1. install external-dns, and configure it with cloudflare
    - sign up for cloudflare and set your domain's nameservers to cloudflare
    - generate a cloudflare api token, zone=read, dns=edit, save to your sneaky dir
    - run `./install-external-dns-cloudflare XXXXXX proxy`
      - replace `XXXXXX` with the cloudflare token
      - remove `proxy` at the end to disable cloudflare proxy

## setup your continuous deployment pipeline

1. create a namespace for your app: `kubectl create namespace APPNAME`
    - replace `APPNAME` with the lowercase name of your app, eg `metalshop`

1. if you need source ips for whitelisting to work
    - go into digitalocean web ui and find your load balancer
    - set loadbalancer "proxy protocol" to "true"

1. give build agent permission to perform the helm upgrade
    - download your cluster's kubeconfig file from digitalocean, and paste the contents as github secret `STAGE_KUBECONFIG`

1. wire up each docker image registry
    1. ***if*** you're using dockerhub *(probably for public images)*
        - sign up for dockerhub
        - *allow the github build agent to publish images:* set github secrets on your app's repo, `DOCKER_USERNAME` and `DOCKER_PASSWORD` as secrets on your git repo
    1. ***if*** you're using github packages *(for private images)*
        - github packages requires your cluster to authorize all image pulls
        - generate a github token to read packages
          - profile settings, developer settings, personal access tokens
          - create a new token with one permission: read packages
          - hold onto this token for next step
        - run script `./install-github-secret APPNAMESPACE GITHUBUSER XXXXXX`
          - replace `APPNAMESPACE` with your app namespace, eg `metalshop`
          - replace `GITHUBUSER` with your github username, eg `chase-moskal`
          - replace `XXXXXX` with the github access token you generated
        - configure your app's deployments to include an entry in `imagePullSecrets`, like so
          ```yaml
          spec:

            # configure this field on all deployments pulling images from github
            imagePullSecrets:
            - name: dockerconfigjson-github-com

            # just example for context
            containers:
            - name: your-container-name
              image: docker.pkg.github.com/<ORG>/<REPO>/<PKG>:<TAG>
          ```

license: ISC

repository: chase-moskal/metalshop

gha_language: TypeScript

gha_license_id: ISC

repo_name: chase-moskal/metalshop


text:
Make sure the daemon script isn't running before doing
any of this stuff.

If you just pull'ed, it's probably a good idea to rebuild
the apps.  Use the export script for that:

  python export_script.py

Then start up the daemon:

  python daemon.py


text:
---
home: true
heroImage: https://www.pascalcoin.org/images/logo.png
heroText: PascalCoin Documentation
tagline: PascalCoin is an instant, zero-fee, infinitely scalable, and decentralized cryptocurrency with advanced privacy and smart contract capabilities.
actionText: Get Started →
actionLink: /guide/
features:
- title: Infinite Scaling
  details: All-in-one cryptocurrency (payment, privacy, and smart contract) with a theoretical limit of 72,000 TPS.
  link: http://www.google.de
- title: Next Generation CC
  details: Introducing a groundbreaking new technology called SafeBox, the basis of a finite and minimal blockchain memory size.
- title: Accounts
  details: An account number is only few digits (e.g. 1000-84) and could also be associated with any account name
footer: MIT Licensed | Copyright © 2019-present pascalcoin.org
---

repository: Techworker/pascalcoin-docs

repo_name: Techworker/pascalcoin-docs


text:
---
layout: post
title: A new PhD student, and serendipity
---

An update: I have been accepted into a PhD program in theology (not
history, as I initially planned) at the [University of Divinity](https://www.divinity.edu.au/),
on the topic of 'Identity and belonging in queer Christian
autobiographies'. In the same month that the Australian government has
initiated a public opinion poll on marriage equality, I have committed
to three to six years of reading and writing about the lived experiences
of LGBTIQ Christians, whose voices are frequently suppressed by both
homophobic faith communities and by secular LGBTIQ communities. This
thesis isn't primarily about LGBTIQ themes in scripture, or arguments
about marriage, ordination or any other kind of inclusion -- it's about
real people's real lives.

From the conclusion to my [research proposal]({% link /assets/files/Research-Proposal.pdf %}):

> Discussions of LGBTIQ Christians in the context of church unity and
> division frequently conclude that theologians and church leaders need
> to listen to the people they are discussing. This thesis aims to
> facilitate such listening. As a systematic study of the lived
> experiences of LGBTIQ Christians as reported in their own words, it
> will demonstrate the breadth of voices that have already asserted
> themselves in these debates. More hopefully, it may show future
> generations of LGBTIQ Christians that they are not alone, and
> encourage them to make their voices heard in their own contexts.

I'm not an expert (yet?) on queer theology or on the scriptural
arguments for or against inclusion, but I've spent twenty years learning
about these issues and developing my own identity as a gay Christian. As
my proposal hopefully suggests, this project is not meant to just end up
on a bookshelf or a digital repository and make no impact on church and
society. The Australian marriage equality debate, and the theological
muddiness associated with it, is perhaps an opportunity for me to put my
research to practical use in real time. So I'm open to working with
researchers and activists on the campaign for marriage equality, in
particular by adding depth to theological discourse. More broadly, I
would welcome any recommendations for expanding my
[bibliography]({% link /assets/files/Research-Proposal.pdf %}).

gha_language: CSS

gha_license_id: NOASSERTION


text:
# php-comic-generator

## Usage

For usage reference see the `examples` directory.

*Note: in order to fit and center the text in the comic we use a brute force approach. Which may be slow for certain texts.*

## Credits

Original illustrations by [Netmosfera](https://github.com/Netmosfera).

repository: PeeHaa/php-comic-generator

repo_name: PeeHaa/php-comic-generator


text:
---
downloaded:       2022-01-12
page-url:         https://web.archive.org/web/20080925185646/http://www.abstractmath.org/MM/MMImagesMetaphorsFunctions.htm#funcmathobj
article-title:    Abstract Math: Functions: Images and Metaphors
---
# Abstract Math: Functions: Images and Metaphors

The Wayback Machine - https://web.archive.org/web/20080925185646/http://www.abstractmath.org:80/MM/MMImagesMetaphorsFunctions.htm
The Wayback Machine - https://web.archive.org/web/20080925185646/http://www.abstractmath.org:80/MM/MMImagesMetaphorsFunctions.htm

Posted 16 September 2008

FUNCTIONS: IMAGES AND METAPHORS

#### Contents

- [Math object][1]
- [Expression to evaluate][2]
- [Process][3]
- [Graph][4]
- [Table of values][5]
- [Dependency relation][6]
- [Transformer][7]
- [Algorithm][8]
- [Relocator][9]
- [Map][10]
- [Point in a function space][11]

Most basic mental representation: A function is a [mathematical object][12].

You must think of functions as [math objects][13] when you are taking the [rigorous view][14], which happens specificially when you are trying to prove something about the function.

#### Remarks

These remarks are intended to raise your consciousness about the possibilities for functions as objects.  (Read [this][15], too.) The [function][16]  defined by  is an example . ([See its graph.][17])  Its value can be computed at many different numbers but it is a single, static math object.

¨ As with any math object, you can apply operators to the function. You can find its derivative.  You can integrate it. But there are plenty of functions you can't differentiate or integrate.

¨ Like all math objects, functions have properties. The function defined by  is periodic with period , meaning that for any *x*, .  Another property is that it is bounded by the horizontal lines *y* \= 1 and *y =* 3.

¨ As a math object, a function can be the element of a set, for example of a [function space][18].  As such it is convenient to think of it as a point in the space.  There are many different kinds of function spaces.

Mental representation: A function is an expression (or formula) to evaluate.

The formula  of the function f [above][19] allows you to compute its value at any x easily.  But its formula is not the function. And not every function has a formula., for example the word length function or the nth prime function.  (There are programs that can calculate those functions, but programs are not usually called expressions or formulas.)

Function-as-expression is the image that motivates using the [defining expression as the name of a function][20], as in  "the derivative of  is  " .   This works well for many functions studied in calculus.

Good:  The expression can tell you properties of the function in a succinct way.  For example, you can tell by looking at the expression that  is going to be a parabola with a minimum and arms pointing upwards.  You can tell that  is defined for all real *x* and that  is not.  The expression , studied in the [zoom and chunk chapter][21], requires a bit of work to understand it, but, as I showed in that chapter, with work you can figure out quite a lot about it.

Bad:  Some expressions are so complicated it is hard to analyze them.   The expression

is difficult because you can't glance at it and see where its roots are.  (The chapter on [derivatives][22] shows a graph of this function.)  Nevertheless, it is a fifth degree polynomial, so you know that it is unbounded in both directions.

Bad: Many functions cannot be given by expressions, for example the [word length function][23] and the *[nth prime function][24]*.   The [finite function][25] can be given by the expression  for  but the function is defined for only four inputs (although of course the expression is defined for all real numbers) so it is much easier to see what it is like from the [table.][26]

It is useful to think of calculus-type functions as defined by expressions

but don't automatically look for expressions for a function in general.

Mental representation: A function is the process used to evaluate it at an input

### Example

When you think of the function *f* defined by , your concern may be to know how to find its value at a given *x.* There are various processes for doing this, listed below.  Method a) is what most people would use for this function.

a) You can do it in your head:  Multiply *x* by 2, then add 2 to the result.  Or, since , you could add 1 to *x*, then multiply the result by 2.

b) You can punch buttons on your calculator:  Put in the value for *x*, multiply it by 2, then add 2 to the result.  Or you could put in the value for *x*, add 1, then multiply the result by 2.

c) You could look at a graph for the function that you created using some program, and measure the *y* value for the given *x* value.

d) You could write a program in some computer language that would compute the function.

### Example

If you were faced with the function  you would probably punch buttons on your calculator, since it is difficult to calculate sin *x* in your head for most values of *x.* But for example if , you know that , so in that case you could do it in your head.

The computational process is not the same thing as the function.
There may be many ways to compute the value of a function.

### Example

Even functions that don't have formulas may still be computable using some process.  The *[nth prime function][27]* can be computed at *n* by finding the first prime, finding the second prime, and so on until you get to *n.* Of course this is ridiculously tedious.  You can also evaluate it on a computer, for example in Mathematica or Maple.

### Example

A function defined by a [table][28] has a process for computing a value, too:  Look it up in the table!

### Example

Edited to here

For a real function of one variable picturing its graph is an extraordinarily useful help in understanding it.   The graph of  (part of which is shown at the right) suggests properties that it might have, such as where its zeroes are. But its graph is not the function. And there are many functions whose graph you cannot draw in any reasonable way.

Function as a dependency relation. This is the metaphor behind such descriptions as "let *x* depend smoothly on *t*". It is related to the graph point of view, but may not carry an explicit picture; indeed, an explicit picture may be impossible.

Function as transformer, that takes an [object][29] and turns it into another object. In this picture, the function transforms 2 into 8. This is often explicitly expressed as a "black box" interpretation, meaning that all that matters is input and output and not how the output is found.. This point of view is revealed by such language as " 2 becomes 8 under *F*".

Function as [algorithm][30] or set of rules that tell you how to take an input and convert it into an output. This is a [metaphor][31] related to those of function as expression and as transformer, but the actual process is implicit in the expression view and hidden in the transformer (black box) view. Spell this out

Function as relocator. In this version, the function  moves the point at 2 over to the location labeled 8. This is the "alibi" interpretation. It is revealed by such language as " *F* takes 2 to 8".

Function as map is one of the most powerful [metaphors][32] in mathematics.

It takes the point of view that the function  renames the point labeled 2 as 8. A clearer picture of a function as a map is given by some function that maps the unit circle onto, say, an ellipse in the plane. The ellipse is a map of the unit circle in the same way that a map of Ohio has a point corresponding to each point in the actual state of Ohio (and preserving shapes in some approximate way). The point on the map labeled "Oberlin", for example, has been renamed "Oberlin".

[1]: https://web.archive.org/web/20080925185646/http://www.abstractmath.org/MM/MMImagesMetaphorsFunctions.htm#_Toc193703318
[2]: https://web.archive.org/web/20080925185646/http://www.abstractmath.org/MM/MMImagesMetaphorsFunctions.htm#_Toc193703319
[3]: https://web.archive.org/web/20080925185646/http://www.abstractmath.org/MM/MMImagesMetaphorsFunctions.htm#_Toc193703320
[4]: https://web.archive.org/web/20080925185646/http://www.abstractmath.org/MM/MMImagesMetaphorsFunctions.htm#_Toc193703321
[5]: https://web.archive.org/web/20080925185646/http://www.abstractmath.org/MM/MMImagesMetaphorsFunctions.htm#_Toc193703322
[6]: https://web.archive.org/web/20080925185646/http://www.abstractmath.org/MM/MMImagesMetaphorsFunctions.htm#_Toc193703323
[7]: https://web.archive.org/web/20080925185646/http://www.abstractmath.org/MM/MMImagesMetaphorsFunctions.htm#_Toc193703324
[8]: https://web.archive.org/web/20080925185646/http://www.abstractmath.org/MM/MMImagesMetaphorsFunctions.htm#_Toc193703325
[9]: https://web.archive.org/web/20080925185646/http://www.abstractmath.org/MM/MMImagesMetaphorsFunctions.htm#_Toc193703326
[10]: https://web.archive.org/web/20080925185646/http://www.abstractmath.org/MM/MMImagesMetaphorsFunctions.htm#_Toc193703327
[11]: https://web.archive.org/web/20080925185646/http://www.abstractmath.org/MM/MMImagesMetaphorsFunctions.htm#_Toc193703328
[12]: https://web.archive.org/web/20080925185646/http://www.abstractmath.org/MM/MMMathObj.htm
[13]: https://web.archive.org/web/20080925185646/http://www.abstractmath.org/MM/MMMathObj.htm
[14]: https://web.archive.org/web/20080925185646/http://www.abstractmath.org/MM/MMImagesMetaphors.htm#rigorousview
[15]: https://web.archive.org/web/20080925185646/http://www.abstractmath.org/MM/MMFuncExamples.htm#consciousnessraising
[16]: https://web.archive.org/web/20080925185646/http://www.abstractmath.org/MM/MMFunctions.htm
[17]: https://web.archive.org/web/20080925185646/http://www.abstractmath.org/MM/MMImagesMetaphorsFunctions.htm#graph
[18]: https://web.archive.org/web/20080925185646/http://en.wikipedia.org/wiki/Function_space
[19]: https://web.archive.org/web/20080925185646/http://www.abstractmath.org/MM/MMImagesMetaphorsFunctions.htm#functionf
[20]: https://web.archive.org/web/20080925185646/http://www.abstractmath.org/MM/MMFuncName.htm#definingexpression
[21]: https://web.archive.org/web/20080925185646/http://www.abstractmath.org/MM/MMZoomChunk.htm#complicated
[22]: https://web.archive.org/web/20080925185646/http://www.abstractmath.org/MM/MMDerivatives.htmfifthdegreepolynomial
[23]: https://web.archive.org/web/20080925185646/http://www.abstractmath.org/MM/MMFunctions.htm#wordlength
[24]: https://web.archive.org/web/20080925185646/http://www.abstractmath.org/MM/MMFunctions.htm#nthprime
[25]: https://web.archive.org/web/20080925185646/http://www.abstractmath.org/MM/MMFunctions.htm#finite
[26]: https://web.archive.org/web/20080925185646/http://www.abstractmath.org/MM/MMFunctions.htm#table
[27]: https://web.archive.org/web/20080925185646/http://www.abstractmath.org/MM/MMFuncExamples.htm#nthprime
[28]: https://web.archive.org/web/20080925185646/http://www.abstractmath.org/MM/MMImagesMetaphorsFunctions.htm#tableofvalues
[29]: https://web.archive.org/web/20080925185646/http://www.abstractmath.org/MM/MMMathObj.htm
[30]: https://web.archive.org/web/20080925185646/http://www.abstractmath.org/MM/MMGlossaryA.htm#algorithm
[31]: https://web.archive.org/web/20080925185646/http://www.abstractmath.org/MM/MMImagesMetaphors.htm#metaphor
[32]: https://web.archive.org/web/20080925185646/http://www.abstractmath.org/MM/HB/hb.html#metaphor

license: Unlicense


text:
---
layout: post
title: "Home Energy Monitor: V2"
quote: Building an energy monitor with ESP32, SCT-013 sensor and Emonlib. Measures total electricity consumption in the entire house.
thumbnail: /uploads/2020-02-11-home-energy-monitor-v2/poster-750.jpg
upload_directory: /uploads/2020-02-11-home-energy-monitor-v2
tags: [ESP32, DIY, Energy, FreeRTOS, AWS, Home Assistant, GraphQL]
toc_enabled: true
---

My DIY home energy monitor has been running for almost a year now. It's been recording my electricity consumption every second and everything is neatly archived in my AWS account.

Still, though, there is room for improvement. It's time to look back, evaluate & improve the design. I've identified a few pain points that have to be fixed, so let's go!

<!--more-->

[Read more about Energy Monitor v1 here.]({% link collections.posts, '2019-07-07-Home-Energy-Monitor-ESP32-CT-Sensor-Emonlib.md' %})

## What could be improved
Out of all the things I could improve about V1, there is only one really critical thing:

* **WiFi stability**: One of the main problems with the V1 was that it couldn't recover from a lost WiFi connection. I would walk past it and see an invalid IP address on its display: `<IP_ADDRESS>`, meaning it had lost its WiFi connection, and a power cycle was needed to solve it. Aargh!

![Orginal version of my home energy monitor](/uploads/2020-02-11-home-energy-monitor-v2/v1.jpg)
*Orginal version of my home energy monitor*

Then there were also some nice-to-haves:

* **Better display**: The LCD is okay to show basic information, but it isn't very fancy. It can only show two lines of 16 characters, and you can't draw custom shapes on it. It's also quite bulky and makes the whole unnecessarily large.
* **DIN-rail mountable**: Right now, my energy monitor sits on top of my internet router, which is conveniently mounted next to my electrical panel. I would prefer it if the energy monitor could be smaller so I could fit it on the DIN rail next to one of the circuit breakers.
* **Better wiring**: When I was building V1, I soldered the ESP32 directly onto a protoboard. I won't be making that mistake twice. It's nearly impossible (for me) to get the board off again.
* **12-bit ADC support**: The ESP32 has a 12-bit ADC, but Emonlib (the library used to measure electricity consumption) only supports 10-bit. Bumping this up to 12-bit should increase the accuracy of the monitor.

## Better display: ESP32 + OLED
I started my journey by looking for a new display. I found [several small TFT panels on Adafruit](https://www.adafruit.com/category/63) that would work perfectly with the ESP32. But then I came across this beauty:

![NodeMCU ESP32 OLED Module](/uploads/2020-02-11-home-energy-monitor-v2/esp32-oled.jpg)
*ESP32 + OLED in a single module*

This is the `NodeMCU ESP32 OLED Module`, on some sites referred to as `Wemos LOLIN32`. It's an ESP32 development board with a built-in OLED display.

Microcontroller and display on the same board? That meant I didn't have to figure out how to mount a separate display in my enclosure and how to connect it to the ESP32. Yay!

Aside from these practicalities, it's also quite cheap. You can find different models on AliExpress that go for around €10.

The integrated OLED panel is 0.96" in size and has a resolution of 128x64. Not huge but perfect for this use case. While waiting for it to arrive, I broke out Sketch and started designing a simple user interface for it:

![Designing the OLED interface](/uploads/2020-02-11-home-energy-monitor-v2/esp32-oled-ui-design.png)
*Designing the OLED interface*

I decided to show the current time, the WiFi signal strength, the current electricity consumption, and a progress meter at the bottom. Progress of what? Well, the ESP32 takes one measurement each second and sends it to AWS after 30 seconds. The progress bar shows how close it is to sending a new batch to AWS ;)

## Better wiring
After selecting the new hardware, it was time to adjust the wiring. While building the previous version, I soldered my ESP32 directly onto a protoboard. Bad idea! It's nearly impossible to remove the ESP32 from the protoboard. As a result: the ESP32 used in V1 will be lost forever. Thank god these microcontrollers are cheap.

So for V2, I purchased some female pin headers to solder onto the protoboard instead. This means I can now easily swap the ESP32 should it be necessary. Or I could decommission the energy monitor and re-use it for another project.

![Female pin headers soldered onto the protoboard](/uploads/2020-02-11-home-energy-monitor-v2/protoboard-1.jpg)
*Female pin headers soldered onto the protoboard.*

And here's how it looks with the ESP32 fitted onto the pin headers:

![ESP32 fitted on the pin headers](/uploads/2020-02-11-home-energy-monitor-v2/protoboard-2.jpg)
*ESP32 fitted on the pin headers*

## Improved stability: Arduino + FreeRTOS!
After improving the wiring, I started improving the software. The main issue with V1 was that it couldn't reconnect to the WiFi if it lost the connection. And because I'm using an unstable ISP-provided router, that happened quite often.

To fix this, I decided to use FreeRTOS, a system that allows you to create many tasks and let the scheduler worry about running them. I blogged about this before: [Multitasking on ESP32 with Arduino and FreeRTOS]({% link collections.posts, '2020-01-06-multitasking-esp32-arduino-freertos' %})

To solve my WiFi problem, I created a task that checks the connection every 10 seconds. WiFi still connected? Great, the task suspends itself for 10 seconds and then runs again. If it's disconnected, it will try to reconnect. Simple:

```cpp
#include <Arduino.h>
#include "WiFi.h"

#define WIFI_NETWORK "YOUR-NETWORK-NAME"
#define WIFI_PASSWORD "YOUR-WIFI-PASSWORD"
#define WIFI_TIMEOUT 20000 // 20 seconds

/**
 * Task: monitor the WiFi connection and keep it alive!
 *
 * When a WiFi connection is established, this task will check it every 10 seconds
 * to make sure it's still alive.
 *
 * If not, a reconnect is attempted. If this fails to finish within the timeout,
 * the ESP32 is sent to deep sleep in an attempt to recover from this.
 */
void keepWiFiAlive(void * parameter){
    for(;;){
        if(WiFi.status() == WL_CONNECTED){
            vTaskDelay(10000 / portTICK_PERIOD_MS);
            continue;
        }

        Serial.println("[WIFI] Connecting");

        WiFi.mode(WIFI_STA);
        WiFi.setHostname(DEVICE_NAME);
        WiFi.begin(WIFI_NETWORK, WIFI_PASSWORD);

        unsigned long startAttemptTime = millis();

        // Keep looping while we're not connected and haven't reached the timeout
        while (WiFi.status() != WL_CONNECTED &&
                millis() - startAttemptTime < WIFI_TIMEOUT){}

        // If we couldn't connect within the timeout period, retry in 30 seconds.
        if(WiFi.status() != WL_CONNECTED){
            Serial.println("[WIFI] FAILED");
            vTaskDelay(30000 / portTICK_PERIOD_MS);
			  continue;
        }

        Serial.println("[WIFI] Connected: " + WiFi.localIP());
    }
}
```

To start this task, I use:

```cpp
// ----------------------------------------------------------------
// TASK: Connect to WiFi & keep the connection alive.
// ----------------------------------------------------------------
xTaskCreatePinnedToCore(
    keepWiFiAlive,
    "keepWiFiAlive",  // Task name
    10000,            // Stack size (bytes)
    NULL,             // Parameter
    1,                // Task priority
    NULL,             // Task handle
    ARDUINO_RUNNING_CORE
);
```

This task has solved my WiFi connectivity issue! And thanks to FreeRTOS, I don't have to worry about when to run this code. I just rely on the scheduler to run it every 10 seconds.

## 12-Bit ADC compatibility
While I was improving the software, I also remembered that Emonlib - the library which converts raw readings into amps - only supports a 10-bit ADC, while the ESP32 has a 12-bit one.

It doesn't seem like a big deal until you realize that 10-bit ADC's have a range of 0-1024, while 12-bit ones go up to 4096. That's four times the range, and so it's four times more accurate.

To fix this, I forked Emonlib and create a version specifically for the ESP32: [https://github.com/Savjee/EmonLib-esp32](https://github.com/Savjee/EmonLib-esp32)

I then added it as a dependency to my PlatformIO project (in `platformio.ini`):

```ini
lib_deps =
  https://github.com/Savjee/EmonLib-esp32.git
```

I only changed [the implementation](https://github.com/Savjee/EmonLib-esp32/commit/d00e0bc75eb5275bd0b994b1af23bf10af3ed37f) of the `calcVI` and `calcIrms` functions. Their signatures remain the same, so the rest of my code could stay the same.

## Smaller case & DIN rail
Next step: adapting the case. It could be made a lot smaller because the display is now integrated into the microcontroller. Additionally, I wanted the option to put it on a DIN rail (a standardized way of mounting electrical hardware such as circuit breakers).

A DIN-rail mount would allow me to put the energy monitor inside my breaker box. In Belgium, our breaker boxes usually have transparent covers so you can see each breaker, which is ideal for making the OLED visible.

Just like last time, I designed the case in Fusion360. I opted to go for a design where the back could be swapped out for different models:

![3D model of the enclosure's base](/uploads/2020-02-11-home-energy-monitor-v2/3d-case-base.png)
*3D model of the enclosure's base*

There are cutouts for the OLED display, the micro-USB port, and the headphone jack that connects the CT sensor. I also added standoffs for the ESP32 so I can securely screw it into place. For the top lid, I designed four standoffs located in the corners of the case. They have a 45° tapered angle so that they can be 3D printed.

After designing the enclosure, I designed two versions of the top lid. One flat one (which I'm currently using) and one with a DIN rail mount:

![3D model of the DIN-rail mount](/uploads/2020-02-11-home-energy-monitor-v2/3d-case-din-rail.png)
*3D model of the DIN-rail mount*

After tweaking some of the margins, it was time to assemble everthing. Starting by screwing the ESP32 into the base of the case:

![3D model of the DIN-rail mount](/uploads/2020-02-11-home-energy-monitor-v2/3d-case-esp-installed.jpg)
*Fitting the ESP32 and the protoboard into the case.*

Putting on the top lid (without DIN-rail for now):

![3D model of the DIN-rail mount](/uploads/2020-02-11-home-energy-monitor-v2/3d-case-esp-installed-closed.jpg)
*Screwing on the top lid*

In comparison to the V1:

![3D model of the DIN-rail mount](/uploads/2020-02-11-home-energy-monitor-v2/v1-vs-v2.jpg)
*Old case vs. new case*

## Cloud architecture
While it hasn't been changed, I want to mention the cloud infrastructure as well. Here is an overview of what I have running currently:

![AWS architecture powering the energy monitor](/uploads/2020-02-11-home-energy-monitor-v2/aws-cloud-architecture.png)
*AWS architecture poweirng the energy monitor.*

In a nutshell:

* I'm using [AWS IoT Core](https://aws.amazon.com/iot-core/) to connect my ESP32 to the cloud (it's basically an MQTT broker with fancy features).
* An [IoT Rule](https://docs.aws.amazon.com/iot/latest/developerguide/iot-rules.html) is trigged every time my energy monitor sends a message to AWS. The rule writes each message to a DynamoDB table. I'm using the device's ID as the primary key and the timestamp as the sort key.
* Every night, CloudWatch triggers a Lambda function that gets yesterday's readings from DynamoDB, puts them in a CSV file, and archives them to S3. I've added Gzip compression to this step to keep storage costs low.
* A second Lambda function exposes a GraphQL API that is consumed by the web dashboard and the Ionic app.

## Integrating with Home Assistant
I've been a huge fan of [Home Assistant](https://www.home-assistant.io/), ever since a colleague of mine introduced me to it. I have it running [on a Raspberry Pi that is booting from an external SSD]({% link collections.posts, '2019-12-03-home-assistant-boot-pi-from-usb-ssd' %}).

Naturally, I wanted my energy consumption to show up there as well. So that means the ESP32 has to connect to two services: AWS (to archive all my readings) and Home Assistant.

You can interface with Home Assistant in a number of ways. I decided to use MQTT because I already know how to use it on the ESP32. The only requirement is that you install a broker (or use an online service) on your Home Assistant machine. I chose to use the [Mosquito integration of HASS.IO](https://github.com/home-assistant/hassio-addons/tree/master/mosquitto).

Home Assistant gives device makers two options to integrate with MQTT: either the user has to configure the device manually in the `configuration.yaml` file, or the device can configure itself by using [MQTT Discovery](https://www.home-assistant.io/docs/mqtt/discovery/).

Of course, I choose the latter -- no manual configuration for me.

To make it all work, you have to tell Home Assistant everything there is to know about your device. The name, type, measurement units, the icon, and so on... This can be done by posting a message to this MQTT topic: `homeassistant/sensor/home-energy-monitor-1/config` with the following contents:

```json
{
    "name": "home-energy-monitor-1",
    "device_class": "power",
    "unit_of_measurement": "W",
    "icon": "mdi:transmission-tower",
    "state_topic": "homeassistant/sensor/home-energy-monitor-1/state",
    "value_template": "{% raw %}{{ value_json.power }}{% endraw %}",
    "device": {
        "name": "home-energy-monitor-1",
        "sw_version": "2.0",
        "model": "HW V2",
        "manufacturer": "Xavier Decuyper",
        "identifiers": ["home-energy-monitor-1"]
    }
}
```

This will automatically configure my energy monitor in Home Assistant and even adds it to the device registry. No additional work required!

All that's left now is to periodically send the energy consumption to the topic `homeassistant/sensor/home-energy-monitor-1/state`:

```json
{ "power": 163 }
```

This is the end result:

![Energy Monitor integrated with Home Assistant](/uploads/2020-02-11-home-energy-monitor-v2/home-assistant-integration.png)
*Home Assistant integration up and running.*

Note: Home Assistant integration is optional and disabled by default in the firmware. If you want to enable it, open the `config.h` file, set `HA_ENABLED` to `true` and enter the IP address of your Home Assistant instance as well as the login credentials for your MQTT broker.

## Status & next steps
I've been running V2 of my energy monitor since January 3th, 2020, and so far, it's been rock solid. The WiFi and MQTT connections are automatically reconnected if necessary. That's already a huge improvement.

In terms of next steps, I only have three:
1. Print & test the DIN rail mount
2. Design & order a custom PCB to replace the protoboard and my bad soldering skills ;)
3. <strike>Integrate it with my Home Assistant installation</strike>

So stay tuned for an update ;)

## A note on calibration
The SCT013 sensors aren't very accurate with low current. You might see "idle" readings of a couple of watts even though no current is flowing through the wire.

According to Jm Casler, this is caused by

* The SCT013 is built for price, not for quality
* The cable's shielding can induce noise if it's shorted with the signal cable
* A filter capacitor is needed (preferably a ceramic one)

You can read his full (detailed) analysis here: [https://www.casler.org/wordpress/low-current-measurement-performance-of-the-sct013/](https://www.casler.org/wordpress/low-current-measurement-performance-of-the-sct013/).

Additionally, he shared the formula that he uses to calculate the calibration value for emonlib:

```
Calibration number = Number of turns of CT Clamp / Burden Resistor
```

So for a CT clamp with 2000 turns and a 68-ohm burden, that gives a calibration of 29.4.

Thanks, man!

## Source code
All of the source code for this project is available [on GitHub](https://github.com/Savjee/home-energy-monitor). That includes the ESP32 firmware, the AWS Lambda functions (and Serverless configuration file) as well as the Fusion360 design files.

gha_language: HTML


text:
# examples-playbooks

This project is a repository of examples / exercises to **practices** with some **playbooks** of **Ansible**

## Prerequisites

Define which elements are necessary to use the examples

* Ansible installed
* Define your own inventory file with the name : "inventory.txt"
* The inventory file should have a grouping of hosts named "all_targets"

**Example "inventory.txt"**

```bash
ansible-target-1 ansible_host=IP_1
ansible-target-2 ansible_host=IP_2

[all_targets]
ansible-target-1
ansible-target-2
```

## Examples

**Simple**

* Basic Playbook
* Ping Playbook
* Reoot Playbook
* File Playbook
* User Playbook
* Replace Playbook (Mix: )
* Archive Playbook
* Manager Software Package Module (yum for CentOs) / Service Module

**Complex**

* Install JDK

## Simple

### Basic Playbook

**Example 1 : Print Hello World**

Step to follow:

* Create "basic-hello-world.yml" file in playbooks

```bash
---
- name: Print Hellow World
  hosts: all_targets
  tasks:
  - debug:
      msg: "Hello World!"
```

* Execute the following command (examples-playbooks/simple/basic/)

```bash
# Syntax-check
ansible-playbook -i inventory.txt  playbooks/simple/basic/basic-hello-world.yml --syntax-check

# Check
ansible-playbook -i inventory.txt  playbooks/simple/basic/basic-hello-world.yml --check

# Execute
ansible-playbook -i inventory.txt playbooks/simple/basic/basic-hello-world.yml
```

**Example 2 : Print Facts**

Step to follow:

* Create "basic-print-facts.yml" file in playbooks

```bash
---
- name: Print Hellow World
  hosts: all_targets
  tasks:
  - debug:
      msg: "Hello World!"
```

* Execute the following command (examples-playbooks/simple/basic/)

```bash
ansible-playbook -i inventory.txt playbooks/simple/basic/basic-print-facts.yml
```

### Ping Playbook

**Example 1 : Pinging Group**

Step to follow:

* Create "ping.yml" file in playbooks

```bash
---
- name: Ping Group
  hosts: all_targets
  tasks:
  - name: Ping Group
    ping:
```

* Execute the following command (examples-playbooks/simple/ping/)

```bash
ansible-playbook -i inventory.txt playbooks/simple/ping/ping.yml
```

### Reboot Playbook

**Example 1 : Reboot and wait hosts**

Step to follow:

* Create "rebot-wait.yml" file in playbooks

```bash
---
- name: Reboot and wait
  hosts: all_targets
  tasks:

  - name: Rebooting
    shell: sleep 2 && reboot
    async: 1
    poll: 0

  - name: Waiting for rebooting
    wait_for_connection:
      delay: 15
      sleep: 10
      timeout: 300

  - debug:
        msg: "{{ inventory_hostname }} is up and running"
```

* Execute the following command (examples-playbooks/simple/reboot/)

```bash
ansible-playbook -i inventory.txt playbooks/simple/reboot/rebot-wait.yml
```

### File Playbook

**Example 1 : Create File**

Step to follow:

* Create "file-create-empty-file.yml" file in playbooks

```bash
---
- name: Create Empty File 'example-txt'
  hosts: all_targets
  become: true
  tasks:
  - name: Create Empty File
    file:
        path: "/home/ansible/example.txt"
        state: touch
```

* Execute the following command (examples-playbooks/simple/file/)

```bash
ansible-playbook -i inventory.txt playbooks/simple/file/file-create-empty-file.yml
```

* Verify

```bash
ssh ansible-target-1

ls

exit
```

**Example 2 : Create Directory**

Step to follow:

* Create "file-create-directory.yml" file in playbooks

```bash
---
- name: Create Directory 'example'
  hosts: all_targets
  become: true
  tasks:
  - name: Create Directory
    file:
        path: "/home/ansible/example"
        state: directory
        mode: 755
        owner: ansible
        group: ansible
```

* Execute the following command (examples-playbooks/simple/file)

```bash
ansible-playbook -i inventory.txt playbooks/simple/file/file-create-directory.yml
```

* Verify

```bash
ssh ansible-target-1

ls

exit
```

### User Playbook

**Example 1 : Create "test" user**

Step to follow:

* Create "user-create-test-user.yml" file in playbooks

```bash
---
- name: Create 'test' user
  hosts: all_targets
  become: true
  tasks:
  - name: Create User
      user:
        name: test
        password: changeit2020
        groups: ansible
        shell: /bin/bash
```

* Execute the following command (examples-playbooks/simple/user/)

```bash
ansible-playbook -i inventory.txt playbooks/simple/user/user-create-test-user.yml
```

Verify

```bash
ssh ansible-target-1

cat /etc/passwd

su test

exit
```

**Example 2 : Delete "test" user**

Step to follow:

* Create "user-delete-test-user.yml" file in playbooks

```bash
---
- name: Delete 'test' user
  hosts: all_targets
  become: true
  tasks:
  - name: Delete user
      user:
        name: test
        state: absent
        remove: yes
        force: yes
```

remove : delete home directory
force : delete all files

* Execute the following command (examples-playbooks/simple/user)

```bash
ansible-playbook -i inventory.txt playbooks/simple/user/user-delete-test-user.yml
```

### Replace Playbook

**Example 1 : Replace Strings user**

Step to follow:

* Create "replace-all-instances-string.yml" file in playbooks

```bash
---
- name: Replace all instances of String
  hosts: all_targets
  become: true
  tasks:
  - name: Copy content to a file
    copy:
      content: "Hello World!\n"
      dest: /home/ansible/result.txt
      remote_src: yes
  - name: Replace all instances of a string
    replace:
      path: /home/ansible/result.txt
      regexp: 'World'
      replace: 'Test'
  - name: Ensure SELinux is set to enforcing mode
    lineinfile:
      path: /home/ansible/result.txt
      regexp: 'Test'
      line: 'Test Updated'
```

remove : delete home directory
force : delete all files

* Execute the following command (examples-playbooks/simple/)

```bash
ansible-playbook -i inventory.txt playbooks/simple/replace-all-instances-string.yml
```

* Verify

```bash
ssh ansible-target-1

cat result.txt

exit
```

### Archive Playbook

**Example 1 : Zip file**

Step to follow:

* Create "archive-create-zip.yml" file in playbooks

```bash
---
- name: Create Zip
  hosts: all_targets
  tasks:
  - name: Ansible zip directory home 'ansible'
    archive:
      path:
      - /home/ansible
      dest: /home/ansible/example.zip
      format: zip
```

* Execute the following command (examples-playbooks/simple/)

```bash
ansible-playbook -i inventory.txt playbooks/simple/archive-create-zip.yml
```

* Verify

```bash
ssh ansible-target-1

ls

exit
```

### Manager Software Package Module (yum for CentOs) / Service Module

**Example 1 : Install vim and git (case 1)**

Step to follow:

* Create "yum-install-1.yml" file in playbooks

```bash
---
- name: Install Package 1
  hosts: all_targets
  become: true
  tasks:
  - name: Install Package 1
    yum:
      name: vim,git
      state: latest
```

* Execute the following command (examples-playbooks/simple/yum/)

```bash
ansible-playbook -i inventory.txt playbooks/simple/yum/yum-install-1.yml
```

* Verify

```bash
ssh ansible-target-1

git

exit
```

**Example 2 : Install vim and git (case 2)**

Step to follow:

* Create "yum-install-2.yml" file in playbooks

```bash
---
- name: Install Package 2
  hosts: all_targets
  become: true
  tasks:
  - name: Install Package 2
    yum:
      name:
        - vim
        - git
      state: latest
```

* Execute the following command (examples-playbooks/simple/yum/)

```bash
ansible-playbook -i inventory.txt playbooks/simple/yum/yum-install-2.yml
```

* Verify

```bash
ssh ansible-target-1

git

exit
```

**Example 3 : Install Common Dependencies**

Step to follow:

* Create "yum-install-common-dependencies.yml" file in playbooks

```bash
---
- name: Install Common Dependencies
  hosts: all_targets
  become: true
  tasks:
  - name: Install Common Dependdencies
    yum:
      name:
        - libselinux-python
        - libsemanage-python
        - firewalld
      state: latest
```

* Execute the following command (examples-playbooks/simple/yum/)

```bash
ansible-playbook -i inventory.txt playbooks/simple/yum/yum-install-common-dependencies.yml
```

* Verify

```bash
ssh ansible-target-1

python3

exit
```

**Example 4 : Install & Start httpd**

Step to follow:

* Create "yum-install-start-httpd.yml" file in playbooks

```bash
---
- name: Install Package httpd
  hosts: all_targets
  become: true
  tasks:
  - name: Install Package httpd
    yum: name=httpd state=present
  - name: Start httpd service
    service: name=httpd state=started
```

* Execute the following command (examples-playbooks/simple/)

```bash
ansible-playbook -i inventory.txt playbooks/simple/yum-install.yml
```

## Complex

### Install JRE

Step to follow:

* Create "install-jre.yml" file in playbooks

```bash
---
- name: Install JRE
  hosts: all_targets
  become: true
  vars:
    JRE_VERSION: java-1.8.0-openjdk
  tasks:
  - name: Install OpenJDK Java JRE
    yum:
      name: "{{ JRE_VERSION }}"
      state: present
```

* Execute the following command (examples-playbooks/complex/)

```bash
ansible-playbook -i inventory.txt  playbooks/complex/install-jre.yml
```

### Install Maven

Step to follow:

* Create "install-maven.yml" file in playbooks

```bash
---
- name: Install Maven
  hosts: all_targets
  become: true
  vars:
    MAVEN_MAJOR: "3"
    MAVEN_VERSION: "3.6.3"
    MAVEN_DOWNLOAD_URL: "http://www.apache.org/dist/maven/maven-{{ MAVEN_MAJOR }}/{{ MAVEN_VERSION }}/binaries/apache-maven-{{ MAVEN_VERSION }}-bin.tar.gz"
    MAVEN_HOME: "/opt"
    MAVEN_ENV_FILE: "/etc/profile.d/maven.sh"
  tasks:

    - name: Check If Maven is already installed
      shell: "mvn -version | grep -w 'Apache Maven' | awk '{print $3}'"
      register: maven_version_installed

    - name: Print Maven Version Installed
      debug: "msg={{ maven_version_installed.stdout }}"

    # No install
    - block:

      - name: Download and Unarchive maven
        unarchive:
          src: "{{ MAVEN_DOWNLOAD_URL }}"
          dest: "{{MAVEN_HOME}}"
          copy: no

      - name: Create maven symlink to /usr/bin
        file:
          src: "{{ MAVEN_HOME }}/apache-maven-{{ MAVEN_VERSION }}/bin/mvn"
          dest: /usr/bin/mvn
          state: link

      - name: Configure maven and its environment variables
        lineinfile:
          dest: "{{MAVEN_ENV_FILE}}"
          line: "{{ item.line }}"
          create: yes
          state: present
        with_items:
        - { line: 'M2_HOME={{MAVEN_HOME}}/apache-maven-{{MAVEN_VERSION}}' }
        - { line: 'PATH=$PATH:$M2_HOME/bin' }

      - name: Exports/Run maven env file for make M2_HOME available globally
        shell: "source {{MAVEN_ENV_FILE}}"

      when: maven_version_installed.stdout == ""
```

* Execute the following command (examples-playbooks/complex/)

```bash
ansible-playbook -i inventory.txt  playbooks/complex/install-maven.yml
```

Verify

```bash
ssh ansible-target-1

mvn

echo $M2_HOME

exit
```

## Authors

* **Víctor Madrid**

repository: vjmadrid/workspace-ansible-lab

repo_name: vjmadrid/workspace-ansible-lab


text:
<!-- ![](https://s3-eu-west-1.amazonaws.com/userlike-cdn-blog/20171113-development/header-development-news.png) -->

# Email Templates for Developers <html>

**Important! Table-based Design**

<!-- You can review the detail of the available templates by visiting the [**Email Templates for Developers page**](https://google.com). -->

Email Templates for Developers is a collection of **html templates** for sending notifications through an email template. The available templates are: Activation Code, Payments, Password reset, Verify Account, Welcome Users and it will continue to grow.

This repository attempts to cover best practices for design and layout in creating templates for sending emails as described in the detailed specifications of [**Email Design Reference**](https://templates.mailchimp.com/getting-started/html-email-basics/) by **MailChimp** and [**Create HTML Email Newsletters in Outlook**](https://www.contactmonkey.com/blog/outlook-rendering-issues) by **Contact Monkey**.

## Templates Test

All the templates available in this repositories passed the test successfully in **Gmail** and **Outlook** services in the desktop and mobile version. If you want to verify use the [**Litmus online tool**](https://putsmail.com/tests/new) to send a template to any email address for design testing and debugging.

## Templates Available
#### Activation Code
* [**Ar18**](https://moiseshp.github.io/email-templates-for-developers/templates/verification-code/Ar18.html)
* [**As33**](https://moiseshp.github.io/email-templates-for-developers/templates/verification-code/As33.html)

#### Payments
* [-]() - Comming soon

#### Password Reset
* [**Ac98**](https://moiseshp.github.io/email-templates-for-developers/templates/password-reset/Ac89.html)
* [**Sb51**](https://moiseshp.github.io/email-templates-for-developers/templates/password-reset/Sb51.html)
* [**Ar18**](https://moiseshp.github.io/email-templates-for-developers/templates/password-reset/Ar18.html)

#### Verify Account
* [-]() - Comming soon

#### Welcome users
* [-]() - Comming soon

## About templates
Initially created as a personal repository but now open to the community. Feel free to use all the html templates for your personal projects or with your company.

##  Authors
Moisés Huaringa

## Dummy Logo Maker
DUMMY LOGO MAKER is an easy, fast and even fun way to create your own dummy logo for your projects. [**Visit the page here**](https://moiseshp.github.io/dummy-logo-maker).

## License
This project is released under the MIT license.


text:
# iCast

## A Simple Podcast Player for MacOS _(Supports Apple Silicon)_

This first alpha release of iCast supports adding new podcasts via RSS url. You can add multiple podcasts and view and play their episodes. Whatever podcast you add will be saved for you, although you can delete them as well.

Download the latest alpha release from https://github.com/axayjha/iCast/releases

repository: axayjha/iCast

repo_name: axayjha/iCast


text:
# TRU-Datasets

### Parking Data

Each file is limited by 2000 rows and there is 60 different files.

Source:

https://streetsoncloud.com/parking/rest/occupancy/id/95

| time | free_spaces | total_spaces | occupied_spaces |
| ---- | ----------- | ------------ | --------------- |
|      |             |              |                 |

### Note:

occupied_spaces was removed halfway through recording as it is redundant.

repository: Evantm/TRU-Datasets

path: /Parking data/N_lot/README.md

repo_name: Evantm/TRU-Datasets


text:
---
layout: default
---

# 1994-04-14 - Re: Tech: Encryption and Satellites (re: GI)

## Header Data

From<EMAIL_ADDRESS>(Paul Robichaux)

To<EMAIL_ADDRESS>(Harry Shapiro Hawk)

Message Hash: 52e737db6ec4e6b44c18002266b16b9175c047ea441160ba7db6c301dabed059

Message ID<EMAIL_ADDRESS>Reply To<EMAIL_ADDRESS>UTC Datetime: 1994-04-14 13:06:45 UTC

Raw Date: Thu, 14 Apr 94 06:06:45 PDT

## Raw message

```
{% raw  %}From<EMAIL_ADDRESS>(Paul Robichaux)
Date: Thu, 14 Apr 94 06:06:45 PDT
To<EMAIL_ADDRESS>(Harry Shapiro Hawk)
Subject: Re: Tech: Encryption and Satellites (re: GI)
In-Reply-To<EMAIL_ADDRESS>Message-ID<EMAIL_ADDRESS>MIME-Version: 1.0
Content-Type: text/plain

-----BEGIN PGP SIGNED MESSAGE-----

> Key pay cable providers are now going though the second stage
> of moving from General Instrument's Video Cipher II (VC II)
> encryption system to its more secure VideoCipher Renewable
> Security (VCRS) system.

VCII and VCII+ both use DES. VC/RS uses a plug-in card; right now the
RS cards are all still DES. An interesting note is that the VC family
uses digital sound and encrypts it. You can allegedly reconstruct the
vertical sync signal and get watchable pictures, but for sound you
either need to break DES or exploit a system vulnerability.

> Adopting VCRS are HBO, Cinemax, Showtime, TMC, Viewer's choice,
> REquest TV, Playboy channel, Spice, and Netlink. Netlink offers
> three superstations.

All of the above are presently VCII+ customers.

There were several such design and implementation vulnerabilities in
the VCII system, and they were quickly exploited by pirates. As a
counter, GI introduced the VCII+, which has fewer vulnerabilities and
has not yet (AFAIK) been "broken". (n.b. I know that the use of
"wizard codes", or master keys, still continues, but I don't really
count that as a break.)

> "There have been 30,000 to 40,000 conversion customers
> a month for the past for months."

Part of the reason behind the conversion is necessity. Programmers
were downlinking both VCII and VCII+ authorization datastreams for a
while. When VC/RS became available, some programmers switched over to
downlinking VCII+ and VC/RS. When the VCII+ datastreams go dark, VCII+
descramblers won't work.

> Meanwhile, with the digital era in mind, Primestar Partners
> is preparing to move its DBS (direct broadcast satellite)
> from Scientific-Atlanta's analog B-Mac encryption to
> General Instrument's DigiCipher digital compression
> technology, which also provides teh most recent security
> meansures.

GI has been very, very tightlipped about any of the compression or
encryption technology behind DigiCipher.

- -Paul

- --
Paul Robichaux, KD4JZG      | Out the 10Base-T port, through the router,
<EMAIL_ADDRESS>         | over the leased line, off the bridge, past
Intergraph Federal Systems  | the firewall... nothing but net.
	       Of course I don't speak for Intergraph.

-----BEGIN PGP SIGNATURE-----
Version: 2.3a

iQCVAgUBLa0+OiA78To+806NAQEJAQQAiS7q/xO+EI44NlVh2KBeP3e8/wBzD9HO
L59ez9oSWV8etUfyokbbNcjHT5xbKImuN3oUxYGA7A0s0eGc/IGQfgTJ2Dn7qITN
UyKNXuBm3l2wkKj0szp723lQSRjWJp7cIVFy0lbDZEA0yIzAyMC5WPWFunYE9ND3
hTzLxbY5Jdk=
=WtA3
-----END PGP SIGNATURE-----

{% endraw %}
```

## Thread

+ Return to [April 1994](/archive/1994/04)

+ Return to "["Harry Shapiro Hawk" <habs@warwick.com>](/authors/harry_shapiro_hawk_habs_at_warwick_com_)"
+ Return to<EMAIL_ADDRESS>(Paul Robichaux)](/authors/paul_at_poboy_b17c_ingr_com_paul_robichaux_)"

+ 1994-04-13 (Wed, 13 Apr 94 09:31:29 PDT) - [Tech: Encryption and Satellites (re: GI)](/archive/1994/04/bd20c8a875b92d095171188551ac09360624dbc4f01fb221a217c9abf2a3afa0) - _"Harry Shapiro Hawk"<EMAIL_ADDRESS>  + 1994-04-14 (Thu, 14 Apr 94 06:06:45 PDT) - Re: Tech: Encryption and Satellites (re: GI) -<EMAIL_ADDRESS>(Paul Robichaux)_


text:
hache [![Build Status](https://travis-ci.org/frodsan/hache.svg)](https://travis-ci.org/frodsan/hache)
=====

Escapes HTML tag characters: `&`, `<`, `>`, `"` and `'`.

Installation
------------

Add this line to your application's Gemfile:

```ruby
gem "hache"
```

And then execute:

```
$ bundle
```

Or install it yourself as:

```
$ gem install hache
```

Usage
-----

```ruby
require "hache"

Hache.h(%q(<>&"')) == "<>&"'"
# => true
```

Contributing
------------

Fork the project with:

```
$ git clone git@github.com:frodsan/hache.git
```

To install dependencies, use:

```
$ bundle install
```

To run the test suite, do:

```
$ rake test
```

For bug reports and pull requests use [GitHub][issues].

License
-------

Hache is released under the [MIT License][mit].

[mit]: http://www.opensource.org/licenses/MIT
[issues]: https://github.com/frodsan/hache/issues

repository: frodsan/hache

gha_language: Ruby

repo_name: frodsan/hache


text:
# Radio Group
and
# Radio Button Group

Both RadioGroup and RadioButtonGroup are used when there are a variety of options to choose from, but only one can be selected at once.
RadioButtonGroup behaves nearly identically to RadioGroup but has the styling of buttons.

### Examples
#### General use
```
  import { RadioGroup, RadioButtonGroup } from 'bloom-inputs'

  ...

  const options = [
    {
      id: 'x-small',
      label: 'XS'
    },
    {
      id: 'small',
      label: 'S'
    },
    {
      id: 'medium',
      label: 'M'
    },
    {
      id: 'large',
      label: 'L'
    }
  ]

  ...

  <RadioGroup // (or RadioButtonGroup)
    name='size'
    onChange={(e) => this.props.updateSize(e.target.id)}
    options={options}
    value={this.props.size.value}
  />
```

#### Bloom-Forms use
```
  import { RadioGroup, RadioButtonGroup } from 'bloom-inputs'

  ...

  const { checkField, formData, updateField } = this.props
  const options = [
    {
      id: 'x-small',
      label: 'XS'
    },
    {
      id: 'small',
      label: 'S'
    },
    {
      id: 'medium',
      label: 'M'
    },
    {
      id: 'large',
      label: 'L'
    }
  ]

  ...

  <RadioGroup // (or RadioButtonGroup)
    formData={formData}
    name='size'
    onBlur={checkField}
    onChange={updateField}
    options={options}
    validateAs='not-empty'
  />
```

### Required Props
- `name`:
  A string tying the `RadioGroup`'s value to the `formData`. Also sets the `name` prop of each element in the group.
- `onChange`:
  A function used to update the `RadioGroup`'s value. If using bloom-forms, this should be `updateForm`.
- `options`:
  An array of radio options, with each one looking like:
```
  {
    id: string,
    label: either a string or a react element
  }
```
- Either `value` or `formData`:
  value: A string mapped to the `RadioGroup`'s value in `formData`.
  formData: The object holding all keys mapped to fields in your form. See [bloom-forms' formData prop](https://github.com/vineyard-bloom/bloom-forms/blob/master/docs/children-props.md). If you use formData via bloom-forms, the value will be derived from it, and any errors on that field will be passed in for you too.

### Optional Props
- `className`:
  A string to style each radio input.
- `containerClass`:
  A string to style the entire component wrapper.
- `error`:
  A string usually passed in directly from `formData` that notes an error with that field validation. Generally passed in like `formData.field.error`.
- `labelClass`:
  A string that styles only the label text of each radio input.
- `onBlur`:
  A function that fires when focus leaves the element. Usually used to `checkField`.
- `required`:
  A boolean indicating if the input value can't be empty.
- `validateAs`:
  A string tying into the validation help passed in to the wrapper `<Form>`. Examples include 'not-empty', 'zip', and 'number'.

[Back to Contents](https://github.com/vineyard-bloom/bloom-inputs#contents)


text:
## j-ASelected

- singleton
- readonly

The component adds `selected` class to `<a` element if the `href` attribute of the element will contain URL address from the web browser. It's targeted for public websites.

__Configuration__:

- `class` {String} is a class name for selected element (default: `selected`)
- `selector` {String} is a jQuery selector (default: `a`)
- `attr` {String} attribute for comparing (default: `href`)
- `strict` {Boolean} enables strict comparing of URL address (default: `false`)
- `delay` {Number} a delay for rebinding of selection when the model is changed (default: `300`)

### Author

- Peter Širka<EMAIL_ADDRESS>- [License](https://www.totaljs.com/license/)

repository: totaljs/components

repo_name: totaljs/components