text:
---
layout: post
title: Using SQLite in React Native & Expo
image: "assets/img/thumbnails/sqlite.png" #seo tag
tags: [React Native, Expo, Databases]

header-color: rgb(33, 33, 33);

excerpt_separator: <!--more-->
published: true
---

In this guide, we are going to take a look at using SQLite to **store** and **persist** data locally in our React Native & Expo applications. SQLite is available on nearly all mobile devices. We have to write SQL queries to access it, however, the data returned is in javascript arrays & objects form. We are going to perform CRUD operations to demonstrate how to perform queries and update React states.
 <!--more-->

Following topics will be covered in this post and for simplicity and demonstration purpose, all the code will be written in app.js file:
* TOC
{:toc}

### Packages
We are going to use the [expo-sqlite](https://docs.expo.io/versions/latest/sdk/sqlite/) package.
```bash
expo install expo-sqlite
```

### Imports and Connection
New we can import the package and create our database connection. We **openDatabase** method to create a connection with the database. If the database doesn't exists then a new one is created.

```javascript
import React from 'react';
import { View, Text, TouchableOpacity, ScrollView } from 'react-native';

import * as SQLite from 'expo-sqlite'
const db = SQLite.openDatabase('db.testDb') // returns Database object
```

### Initialization and UI
In this stage we will wire up the App class with essential UI, state and basic database check.

```jsx
class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      data: null
    }
    // Check if the items table exists if not create it
    db.transaction(tx => {
      tx.executeSql(
        'CREATE TABLE IF NOT EXISTS items (id INTEGER PRIMARY KEY AUTOINCREMENT, text TEXT, count INT)'
      )
    })
    this.fetchData() // ignore it for now
  }
  render() {
    return (
        <View style={Style.main}>
        <Text>Add Random Name with Counts</Text>
        <TouchableOpacity onPress={this.newItem} style={Style.green}>
          <Text style={Style.white}>Add New Item</Text>
        </TouchableOpacity>

        <ScrollView style={Style.widthfull}>
        {
            this.state.data && this.state.data.map(data =>
            (
                <View key={data.id} style={Style.list}>
                <Text >{data.text} - {data.count}</Text>
                <TouchableOpacity onPress={() => this.increment(data.id)}>
                    <Text style={Style.boldGreen}> + </Text>
                </TouchableOpacity>
                <TouchableOpacity onPress={() => this.delete(data.id)}>
                    <Text style={Style.boldRed}> DEL </Text>
                </TouchableOpacity>
                </View>
            )
        )}
        </ScrollView>
      </View >
    )
  }
}
export default App
// Styles are removed purpose-fully
}
```
Ok so, we are creating a table named 'items' if it doesn't exists using the db connection we created above. We created a button that is supposed to add some gibberish text and a count of how many times it was pressed to the database. You can see the event handlers like addItem, increment and delete but they haven't been implemented yet, we'll implement the CRUD operations in the next section.

### Operations
In this section, we are going to take a look at how we can perform CRUD operations on SQLite and update React's state. We'll be using Transactions for interacting with the db using the method **Database.transaction**.
> Database.transaction(callback, errorCallback, successCallback)

In every transaction main callback, a Transaction object is passed that can be used to execute queries using the method **Transaction.executeSql()**.
> Transaction.executeSql(sqlStatementString, argumentsArray, successCallback, errorCallback)

SuccessCallback returns ResultSets, which contains rowsAffected count, insertIds in case of insert and rows of data in case of read.

#### Read
The first step is to read the data in the table every time the app is leaded. In the transaction method, we only use the main callback where a transaction object *tx* is passed. We use it to run a standard SQL read query. Since we don't need to pass any parameters to the query, we send null in second parameter and then we setState the ResultSet.rows._array as data. We have used the ES6 Object matching feature to extract the _array value from the ResultSet object parameter directly into _array variable.
```jsx
 fetchData = () => {
    db.transaction(tx => {
      // sending 4 arguments in executeSql
      tx.executeSql('SELECT * FROM items', null, // passing sql query and parameters:null
        // success callback which sends two things Transaction object and ResultSet Object
        (txObj, { rows: { _array } }) => this.setState({ data: _array })
        // failure callback which sends two things Transaction object and Error
        (txObj, error) => console.log('Error ', error)
        ) // end executeSQL
    }) // end transaction
  }
```
#### Create
We use the same pattern of transaction and executeSql as before to insert new row in the items table. To keeps thing simple, we have hardcoded the insert data for insert and state update.

On successful insert, we use the array concat method to update the state. Concat method creates and returns a new array with the added item. It is very useful for state updates, since we don't want to alter the state object directly.

 In the setState, we also needed the Id of the new item,  we accessed it from ResultSet object.
```javascript
// event handler for new item creation
 newItem = () => {
    db.transaction(tx => {
      tx.executeSql('INSERT INTO items (text, count) values (?, ?)', ['gibberish', 0],
        (txObj, resultSet) => this.setState({ data: this.state.data.concat(
            { id: resultSet.insertId, text: 'gibberish', count: 0 }) }),
        (txObj, error) => console.log('Error', error))
    })
  }
```
#### Update
We have a count property on each item and we want to increment it every time the plus button of the object is pressed. The methods we'll be using will be same as above. However, we have to be careful in updating our React states. We can't update the state directly so we'll use the map method here.

The map method creates a new array by perform operation on each element of the original array. Thus in the map, we check to see if the Id of an item is same as the updated item. If so, create a new object and alter its count using ES 6 destructuring syntax, else return the object as it is. Thus a new list is created and we can use it to update the state safely.
```jsx
  increment = (id) => {
    db.transaction(tx => {
      tx.executeSql('UPDATE items SET count = count + 1 WHERE id = ?', [id],
        (txObj, resultSet) => {
          if (resultSet.rowsAffected > 0) {
            let newList = this.state.data.map(data => {
              if (data.id === id)
                return { ...data, count: data.count + 1 }
              else
                return data
            })
            this.setState({ data: newList })
          }
        })
    })
  }
```
#### Delete
We also have a delete button on each item to delete it. Once the delete button is pressed, the query will be executed using the methods same as above but how do we update the React state?

We can use the Arrays filter method to create a new array with filtered items. In the filter method, we can specify which elements to include or exclude by returning true or false. Once this new array is created, we can update the state safely.
```jsx
 delete = (id) => {
    db.transaction(tx => {
      tx.executeSql('DELETE FROM items WHERE id = ? ', [id],
        (txObj, resultSet) => {
          if (resultSet.rowsAffected > 0) {
            let newList = this.state.data.filter(data => {
              if (data.id === id)
                return false
              else
                return true
            })
            this.setState({ data: newList })
          }
        })
    })
  }
```


text:
### [CVE-2023-28443](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-28443)
![](https://img.shields.io/static/v1?label=Product&message=directus&color=blue)
![](https://img.shields.io/static/v1?label=Version&message=%3D%20%3C%209.23.3%20&color=brighgreen)
![](https://img.shields.io/static/v1?label=Vulnerability&message=CWE-284%3A%20Improper%20Access%20Control&color=brighgreen)
![](https://img.shields.io/static/v1?label=Vulnerability&message=CWE-532%3A%20Insertion%20of%20Sensitive%20Information%20into%20Log%20File&color=brighgreen)

### Description

Directus is a real-time API and App dashboard for managing SQL database content. Prior to version 9.23.3, the `directus_refresh_token` is not redacted properly from the log outputs and can be used to impersonate users without their permission. This issue is patched in version 9.23.3.

### POC

#### Reference
- https://github.com/directus/directus/commit/349536303983ccba68ecb3e4fb35315424011afc
- https://github.com/directus/directus/security/advisories/GHSA-8vg2-wf3q-mwv7

#### Github
No PoCs found on GitHub currently.

license: MIT

repository: trickest/cve

branch_name: refs/heads/main

extension: md

gha_language: HTML

gha_license_id: MIT

license_type: permissive

repo_name: trickest/cve


text:
# Binomial Expansion

## Instructions

The purpose of this kata is to write a program that can do some algebra. Write
a function `expand` that takes in an expresion with a single, one character
variable, and expands it. The expresion is in the form `(ax+b)^n` where `a` and
`b` are integers which may be positive or negative, `x` is any one character
long variable, and `n` is a natural number. If a = 1, no coefficient will be
placed in front of the variable. If a = -1, a "-" will be placed in front of
the variable.

The expanded form should be returned as a string in the form `ax^b+cx^d+ex^f...`
where `a`, `c`, and `e` are the coefficients of the term, `x` is the original
one character variable that was passed in the original expression and `b`, `d`,
and `f`, are the powers that `x` is being raised to in each term and are in
decreasing order. If the coefficient of a term is zero, the term should not be
included. If the coefficient of a term is one, the coefficient should not be
included. If the coefficient of a term is -1, only the "-" should be included.
If the power of the term is 0, only the coefficient should be included. If the
power of the term is 1, the carrot and power should be excluded.

### Examples

```
expand("(x+1)^2")      # returns "x^2+2x+1"
expand("(p-1)^3")      # returns "p^3-3p^2+3p-1"
expand("(2f+4)^6")     # returns "64f^6+768f^5+3840f^4+10240f^3+15360f^2+12288f+4096"
expand("(-2a-4)^0")    # returns "1"
expand("(-12t+43)^2")  # returns "144t^2-1032t+1849"
expand("(r+0)^203")    # returns "r^203"
expand("(-x-1)^2")     # returns "x^2+2x+1"
```

branch_name: refs/heads/master


text:
---
layout: post
title:  "Enterprise smart contracts: Security aspects"
author: stelios
tags: [blockchain, smart contracts, security]
categories: [Blockchain, Security, Smart contracts]
featured: true
description: "Smart contracts promise to complete Africa's leapfrog into Internet 3.0. An analysis to navigate the security aspects of deploying smart contracts for mission-critical processes."
image: assets/images/smart-contracts/chris-ried-ieic5Tq8YMk-unsplash.jpg
---

Smart contracts are revolutionizing whole industries and promise to optimize and automate decades-old inefficient
processes. Africa has already [leapfrogged][1] ahead of the rest of the world into the mobile-first technological
era. Smart contracts can enable another leapfrog into the [Internet of Agreements][2] era.

Like with any brave new world, there are some serious caveats and security implications.
Decision makers must take them into account before making an informed decision.

This post attempts to go beyond the marketing hype to highlight some key concepts that everyone considering this technology
should be familiar with.

# Let's look around us

![A small world](../assets/images/smart-contracts/blur-cartography-close-up-concept-408503.jpg)
> Photo by slon_dot_pics from Pexels

The world around us works because of contracts, because of agreements.

You are reading this blog post on your phone or computer because you purchased the device.
In other words, there was an agreement between you and the device seller, which was fulfilled once money and device
changed hands.

The device making its way from the factory to the shop meant that tens if not hundreds of contracts and agreements had
to be drafted, agreed, verified and honoured:
* the factory to the wholesaler,
* the wholesaler to the shipping agent,
* the shipping agent to the shipping company, etc

The device is powered by electricity, because you have a contract with the power company: pay on time, in exchange for
electricity.
You get where this is going! Almost every interaction around us happens, has happened and will continue to happen, because
there is an agreement, a contract, between two or more parties. Written or unwritten, it is recognized and is honoured,
because it is ultimately enforceable by a "power that be" (state, courts,...)

The majority of these transactions, especially the ones with a small monetary value, happen seamlessly, without us
even noticing. On the contrary, the higher the value of a transaction the more friction is involved in completing it.

For example, in a real estate purchase a contract is drafted describing the building/land in detail. In most
jurisdictions this is drafted by a notary or lawyer (a trusted third party). Both parties sign, the signed contract is
submitted to the relevant authority (e.g. land registry), the monetary value is transferred in the opposite direction, etc.
All these checks and balances are introduced to secure the interests of the parties involved, as well as comply with
legal requirements.

# How about some automation?

![Computer](../assets/images/smart-contracts/johannes-plenio-FZpCcPss9to-unsplash.jpg)
> Photo by Johannes Plenio on Unsplash

Something seemingly so simple as a title of ownership transfer, involves different trusted third parties, authorities
and "process gates" to minimise the possibility of mistakes or fraud. In the enterprise domain, e.g. shipping and
logistics, the contracts and process gates that need to be fulfilled are [even more complex][4] involving multiple
parties and authorities.

One answer to this complexity is the introduction of automation. Paper- and rule-based processes have been digitized
for many years now. Steps are automated and friction is constantly reduced for even the most complex transactional processes.

One great example of simplification made possible by digitization is [parametric insurance][9]. In it all
manual processing (claims form, assessment, payout) has been replaced with 1-2 simple and automatic
rules (e.g. "pay the farmer her insurance if monthly rain is more than 100mm").

However, digitization of contracts in IT systems introduces a critical weak point: centralization in a few data centers.
This makes critical transactional processes vulnerable to physical (power cuts) and cyber attacks. This was
demonstrated in a spectacular way in 2017 with the [NotPetya malware][3]. This single virus crippled the multi-national
shipping company [Maersk][5] along with almost the [entire public infrastructure of Ukraine][6].

# A new paradigm

![Blockchain](../assets/images/smart-contracts/launchpresso-h5iazR-wljU-unsplash.jpg)
> Photo by Launchpresso on Unsplash

Smart contracts are a new way to address the problem of digitization.
Built on top of blockchain, they offer automation, without any central points of failure.

Let's unpack this "heavy" definition into more understandable concepts.

## Blockchain

At its core a blockchain is a *distributed data storage*.
'Distributed' means from a few computers in a data center to many thousands across the globe. Public blockchains allow
any computer to connect and become part of them. Private blockchains allow only a preselected set of servers.

<div
    style="width: 640px; height: 480px; margin: 10px; position: relative;">
    <iframe allowfullscreen frameborder="0" style="width:640px; height:480px"
        src="https://www.lucidchart.com/documents/embeddedchart/b29b2c36-bc5a-4af7-89f5-651da8d74ca1"
        id="lRl62L5eteGn">
    </iframe>
</div>

This diagram shows how a collection of servers/computers can
* form a robust network through [peer-to-peer networking][12], and
* confirm and validate transactions originating from users.
These transactions belong to (and originate from) users, because they are signed with the users' cryptographic keys.

The nodes participating in the blockchain network, reach a consensus on what the true state of the world is at any given
moment. This happens without necessarily trusting each other.
This is a remarkable feature and is achieved through cryptography and game theory incentives.

For a deeper technical analysis this [article][10] and this [article][11] are good starting points.

The important takeaway for our discussion is that **a blockchain is a distributed trust machine**. A way for any 2
people or systems on the planet to agree on the truth without an intermediary. Social norms, law and institutions
underpin trust in the real world. Blockchain is now offering this underlying fabric for the digital world.

## The next step

The obvious question then is: how do we fully utilize this trust machine to replicate real world processes? The answer
is **smart contracts**.

A smart contract is a piece of code which
* belongs to (and is deployed by) a user on the blockchain network,
* can be called by (and itself can call) other smart contracts, and
* is executed by **all** of the nodes of the network

<div
    style="width: 640px; height: 480px; margin: 10px; position: relative;">
    <iframe allowfullscreen frameborder="0" style="width:640px; height:480px"
        src="https://www.lucidchart.com/documents/embeddedchart/d65697d0-4df3-4fb5-8de0-5f71f6c8e3ba" id="L9l6W1HWTkXY">
    </iframe>
</div>

Smart contracts are a powerful concept.
Blockchain provides the foundation for random participants to agree on the state of the world (e.g. `A belongs to X`).
Smart contracts provide the mechanism for anyone to verify **how and when** the state of the world changes (`if W happens, then
A belongs to Y`).
These changes and state transitions happen
* **Immutably**: Once recorded they cannot change.
* **At scale**: Thousands of smart contracts for all kinds of processes can be processing millions of requests.

For a deeper dive in smart contracts this [article][13] and this [article][14] will provide a good context.

# Security and scalability

Smart contracts solve a number of problems in an elegant way.
However they do not solve *all* problems. As with any technology, there are some important considerations and trade-offs
to take into account.

## Which platform and where

![Private area](../assets/images/smart-contracts/business-dirty-door-security-241028.jpg)
> Photo by Nguyen Nguyen from Pexels

Most smart contract networks ([Ethereum][15], [Tezos][16], [EOS][17],...) have been designed to scale on a global level.
Any computer is incentivised to join their public network and, effectively, increase the network's strength against malicious attacks.

From a smart contract creator's point of view, this sounds intriguing: deploying on a global platform which never shuts
down and is resistant to attacks. On the other hand, the default decision of an enterprise or government body is
probably to deploy everything on its own data centers for security reasons. After all, you can't trust the Internet, can you?

There are some important implications, which make this decision a little bit more involved.

* **Volumes**
How many transactions should the smart contract process? How quickly?
A few a day, completed within a couple of hours? Or millions a day, completed within seconds?
Deploying on a public network means your contract is competing for network resources with others.
One should seriously consider the current [performance guarantees][18] of a public blockchain platform versus
deploying smart contracts in private, dedicated data centers. In the latter case, there are no third-party contracts
allowed, which means no competition for resources, which means higher performance.

* **Privacy of data**
A smart contract needs to store data, expose callable methods and (in the case of Ethereum) emit events, if it is going
to be of any use. In a public platform other participants can eavesdrop; not necessarily access the data, but have a
good feel of traffic/load based on transactions/events on the blockchain.
Is this something acceptable?
If yes, then a public blockchain is fine.  If not, the whole system should be ring-fenced in a private network.
Are the data and actions available to everyone on the network or is access permissioned?
If permissions are needed, then an enterprise-oriented blockchain like [Corda][21] would be more suitable.

* **System criticality**
How critical is the smart contract system?
For example, a smart contract and blockchain holding all the land titles of the country is a completely different beast
to, say, an automatic parking ticketing system.
Losing the former and you have riots in the streets (almost [mission-critical][19] for a country). Lose the latter and
people are happy :-)
Critical systems **must** be deployed with [black swan events][20] in mind. Wars, earthquakes, tsunamis, country-wide
power cuts,...; catastrophic events **will** happen.
Is the blockchain supported by enough servers around the country (private) or the world (private/public) to survive
and continue functioning?

* **Cost of public tokens**
Each action which modifies a public blockchain comes with a cost attached; these are the fees for the computers securing
the network. Deploying a smart contract on a public network, means being ready to fund the cost of it, by buying tokens
(ETH, XTZ,...) in the public market. Given the historical volatility of cryptocurrency prices, this might not be
acceptable for an enterprise or government body.
In this case, a private blockchain system might be the only option.

## Private keys

![Keys, keys, keys!](../assets/images/smart-contracts/antique-close-up-equipment-hanging-615350.jpg)
> Photo by Skitterphoto from Pexels

We already mentioned that blockchains are based on cryptography. In layman's terms, users and systems identify
themselves to (and interact with) the blockchain using their private encryption keys.
These software keys **cannot** be just stored in a server or a hard drive. If they are copied or stolen, the attacker
will be able to impersonate the user with impunity. In a similar vein, if keys are lost or destroyed, it is an
irreparable loss. The user can no longer interact with the blockchain; the private encryption keys are truly "the keys
to the kingdom".

In an enterprise or government setting, it is imperative that there is a proper [Key Management System][22] in place.
The most appropriate solution is a [Hardware Security Module][23].
This offers full protection against key theft, loss or tampering. At the same time, it allows secure interaction with the
blockchain and the smart contracts at a high volume.

## Contract logic

![Re-arranging](../assets/images/smart-contracts/toys-letters-pay-play-48898.jpg)
> Photo by Pixabay from Pexels

In the real world the law is the law, setting the rules and boundaries.
If something is unclear, then the judiciary is in charge of interpreting and amending. Even in the extreme case that
society "changes its mind" on something, in many jurisdictions past actions and agreements can be reversed with
[ex post facto laws][25].

In the world of smart contracts "[the code is the law is the law][26]".
This means that, since a blockchain captures the agreed-upon true state of things, by consequence a smart contract's
actions are final and irrevocable. Reversing a smart contract is impossible without invalidating the integrity of the
entire blockchain.

The most well-known example of this was one of the most publicized smart contract systems created, the [DAO][24].
In June 2016, some Ethereum blockchain users took advantage of a weak point in the DAO's code and siphoned off the
equivalent of millions in US dollars from the DAO contract's account.
Notice that we did **not** use the word "steal"!
Since in the new world code is law, could it be that the weakness was intentional? I.e. the real-world equivalent of a
"legal loophole". If the intention was for weaknesses to not be allowed, why was it not cemented in the DAO's code?

This discussion can only highlight that a smart contract's code might be as important (if not more) than the code
running in a nuclear reactor. It has to be checked and tested and verified 1000 times over for any possible and
impossible situation.
Once deployed, it is "law".

## Future-proofing

![Law](../assets/images/smart-contracts/j-zamora-GWOTvo3qq7U-unsplash.jpg)
> Photo by j zamora on Unsplash

Having said that "code is law" does not mean that either code or law remains static.
The world around us moves. The agreements of today do not use the same terms as they did 10 years go, nor will they be
the same 10 years from now.
The last thing an organisation wants is to deploy a smart contract, only to discover a few months later that it cannot
upgrade it without major disruption.

Not architecting the smart contracts the right way to make them easy to upgrade will inevitably result in expensive and
unplanned retrofitting.
For example, it is realistic to assume that a land registry smart contract will soon end up being used by a large number of
different systems and applications across the country. In most platforms, simply deploying a new smart contract to add
some new features will result in the contract's address changing. This means that all the downstream systems which depend
on it will need to be updated to use the new contract.
Depending on the nature and number of these systems, this may be prohibitively complex and expensive.

This problem calls for a deeply technical solution and is different depending on the chosen smart contract platform.
It requires deep knowledge of the features and restrictions of it.
For reference, some options (each one with its own pros and cons) are
* the [proxy contract][30] pattern ([widely][27] [supported][32])
* lazily [migrating data][28]
* separating [data from logic][31]
* using [libraries][29] (if supported)

## Oracles

![Ancient Greece](../assets/images/smart-contracts/low-angle-photograph-of-the-parthenon-during-daytime-164336.jpg)
> Photo by Pixabay from Pexels

In the world of smart contracts the term **oracle** identifies any trusted source of information and events from the
external world. The term has its root in ancient Greece. Oracles were believed to be the [undisputable voice of the gods][7].
A [golden source][8] of information from the "world beyond".

Remember from the introduction that smart contracts execute in a secure, isolated environment.
They can be called by users (using their private keys) as well as other smart contracts.
For their logic to be useful to the real world, smart contracts need to react to real-world events and consume real-world
information.
For example:
> "Is the ship docked in port?"
> "Has $100 landed in bank account Y?"
> "What product model does serial number XYZ correspond to?"

These external stimuli result in the smart contract taking some action and recording a side-effect in the blockchain
for ever. However, the finality of all smart contract actions raises an important question:
How trust-worthy is the oracle?
What if it gives the wrong information the moment the contract requests it?

For example, a property purchase smart contract may depend on a banking oracle to confirm that the [fiat money][33] funds
have landed in the bank account. What if (by accident or malicious action) the banking oracle incorrectly reports that
the money is there, when it is not? The contract will be triggered and the property title will be irrevocably transferred,
when in fact it should not.

Depending on the situation and the domain, there are various strategies to address oracle security issues.

* **Own oracle**
The simplest way to address the issue of oracle security is by implementing the oracle ourselves.
This way the enterprise does not have to trust any third party for the smart contract information. However, in many cases,
this may be easier said than done. It is one thing to write the code for a weather oracle. It is quite another to
actually install and weather stations around the world to feed it with data.

* **Consensus-based decision**
Another way of mitigating the risk of a compromised oracle is to reach out to more than one.
For example, reach out to 3 weather providers to get the current temperature. We can then either consider the average or
only the value provided by the majority or oracles.
In this case a hacker would have to concurrently attack the majority of our oracles to affect the outcome of the smart
contract.

* **"Cooling off" period**
Another way to address a compromised oracle would be to check again after a few minutes/hours/days. If the value is
the same in both calls, then the transaction can be completed.
If the business domain logic allows it, this approach adds an additional hurdle for an attacker: not only to take control
of an oracle but also keep it for a prolonged period of time without being discovered.

* **Indemnity covenant**
In the case of a paid-for oracle (i.e. the smart contract owners pay the oracle to supply information), adding an
indemnity covenant is a must.
With it the oracle provider is solely responsible for the correct function of the oracle. If a material loss arises because of
incorrect data, then it would be up to the oracle provider to indemnify.
The question then is: *how do we prove in the future that the oracle returned a given value?*
For web-based oracles (i.e. web sites, APIs,...) the answer already exists in the form of TLS notaries.
Using the [properties of the TLS security protocol][34], the smart contract can generate a non-repudiating signature
of the value returned by the oracle.
In simple words, this is the equivalent of asking someone to take their own photo with their own camera and we keep it
as future proof.

# Parting thought

![Lift off](../assets/images/smart-contracts/flight-sky-earth-space-2166.jpg)
> Photo by Pixabay from Pexels

Blockchain and smart contracts have the potential to revolutionize everyday life and interactions in a similar way that
internet and the smartphone did.
There are however some important considerations and security concerns to address.
Designing, coding, deploying and maintaining a smart contract system requires skill, extreme preparation and diligence.

repository: angelina-kenza/blog-brevasolutions

gha_language: JavaScript

repo_name: angelina-kenza/blog-brevasolutions


text:
# Liquid Swipe

[![GitHub license](https://img.shields.io/badge/license-MIT-lightgrey.svg)](https://raw.githubusercontent.com/Cuberto/flashy-tabbar-android/master/LICENSE)

![Animation](https://raw.githubusercontent.com/Cuberto/liquid-swipe/master/Screenshots/animation.gif)

## Requirements

- Android 5.0+

## Example

To run the example project, clone the repo, and run `app`

### As library

#### GitHub Packages

Step 1 : Generate a Personal Access Token for GitHub
- Inside you GitHub account:
- Settings -> Developer Settings -> Personal Access Tokens -> Generate new token
- Make sure you select the following scopes (“ read:packages”) and Generate a token
- After Generating make sure to copy your new personal access token. You cannot see it again! The only option is to generate a new key.

Step 2: Store your GitHub — Personal Access Token details
- Create a github.properties file within your root Android project
- In case of a public repository make sure you add this file to .gitignore for keep the token private
- Add properties gpr.usr=GITHUB_USERID and gpr.key=PERSONAL_ACCESS_TOKEN
- Replace GITHUB_USERID with personal / organisation Github User ID and PERSONAL_ACCESS_TOKEN with the token generated in #Step 1

Step 3 : Update build.gradle inside the application module
- Add the following code to build.gradle inside the app module that will be using the library
```
    def githubProperties = new Properties()
    githubProperties.load(new FileInputStream(rootProject.file("github.properties")))
    repositories {
        maven {
            name = "GitHubPackages"

            url = uri("https://maven.pkg.github.com/Cuberto/liquid-swipe-android")
            credentials {
                /** Create github.properties in root project folder file with
                ** gpr.usr=GITHUB_USER_ID & gpr.key=PERSONAL_ACCESS_TOKEN
                ** Or set env variable GPR_USER & GPR_API_KEY if not adding a properties file**/
                username = githubProperties['gpr.usr'] ?: System.getenv("GPR_USER")
                password = githubProperties['gpr.key'] ?: System.getenv("GPR_API_KEY")
            }
        }
    }
```
- inside dependencies of the build.gradle of app module, use the following code
```
    dependencies {
        //consume library
        implementation 'com.cuberto:liquid-swipe:1.0.0'
        ....
    }
```
Sync project and now you can use flashytabbar library

## Usage

Add LiquidPager to your xml and use it like you would ViewPager

```

    <com.cuberto.liquid_swipe.LiquidPager
        android:id="@+id/pager"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

```

## iOS

Similar library [LiquidSwipe](https://github.com/Cuberto/liquid-swipe) by [Cuberto](https://github.com/Cuberto)

## Author

Cuberto Design<EMAIL_ADDRESS>
## License

Liquid Swipe is available under the MIT license. See the LICENSE file for more info.

repository: rtchagas/liquid-swipe-android

repo_name: rtchagas/liquid-swipe-android


text:
# dir2feed

A script that publishes directory/folder listing in a file system as RSS feed.

Jaanus Kase, <http://jaanuskase.com>

## How to get started

1. Rename dir2feedSettings_example.py to dir2feedSettings.py.
1. Edit it.
1. Run dir2feed.py.

## Change log

### October 2010

Initial publishing.

## Motivation

This is an old script that I’m republishing to github to tidy my house. The value of this is that you simply put some files in a filesystem, and you can receive an RSS feed of a folder and any subfolders. Not sure how much value there is to this at this era of Dropbox and other such solutions, but I wrote this before these things came around, so maybe it’s useful to someone.

## License (MIT)

Copyright (c) 2006—2010 Jaanus Kase

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.


text:
# TreesGrowDownward
build a simple sorted binary tree contains Integer objects.

A binary tree is a _recursive data structure_ where each node can have 2 children at most.

A common type of binary tree is a binary search tree, in which every node has a value that is greater
than or equal to the node values in the left sub-tree, and less than or equal to the node values in the right sub-tree.

Here's a quick visual representation of this type of binary tree:

![binary tree](./simplebinarytree.png)

Take a look at Node.java, it's a very simple container to hold our Integer object.

Now, what operations do yo need to implement in TreeOneZero.java?

## Some Common Operations

Now, let's see the most common operations we can perform on a binary tree. You should step through each operation,
adding the methods described. You'll be making all these changes to class __TreeOneZero__, a special
binary tree class.

### Inserting Elements

The first operation we're going to cover is the insertion of new nodes.

First, we have to find the place where we want to add a new node in order to keep the tree sorted. We'll follow these rules starting from the root node:

`private Node addRecursive(Node current, Integer value)`

- if current node is null, we've reached a leaf node and we can insert the new node in that position
- if the new node's value is lower than the current node's, we call addRecurive on the left child
- if the new node's value is greater than the current node's, we call addRecurive on the right child

Next, we'll create the public method that starts the recursion from the root node:

`public void add(Integer value)`

- we set this.root to `addRecursive` for the value object.

The idea is to create two methods that allow you to do this:
Now let's see how we can use this method to create the tree from our example:

```
private TreeOneZero createBinaryTree() {
    TreeOneZero bt = new TreeOneZero();

    bt.add(Integer(6));
    bt.add(Integer(4));
    bt.add(Integer(8));
    bt.add(Integer(3));
    bt.add(Integer(5));
    bt.add(Integer(7));
    bt.add(Integer(9));

    return bt;
}
```

### Finding an Element

Let's now add a method to check if the tree contains a specific value.

We will use Recursion to make pretty simple method which can return true or false.
RECURSION is a technique where a method can call **itself**, usually with different parameters,
based on the current status of the method.

As before, we'll first create a recursive method that traverses the tree:

`private boolean containsNodeRecursive(Node current, Integer value)`

And it will have two __base cases__, one which returns false, and another which return true.
If neither case is true, we change the state and call the method itself with changed parameters:

- if current is null, return false
- if current's value equals what we're looking for, return true
- otherwise if the value is less than current's value,
    - call containsNodeRecursive on current's left node
    - otherwise call is on the right node.

Build a simple start method to the recursion much like we did with the `add` and `addRecursive` methods:
`public boolean containsNode(Integer value) `

These two methods need to be able to pass a test like this one:

```aidl
@Test
public void givenABinaryTree_WhenAddingElements_ThenTreeContainsThoseElements() {
    BinaryTree bt = createBinaryTree();

    assertTrue(bt.containsNode(6));
    assertTrue(bt.containsNode(4));

    assertFalse(bt.containsNode(1));
}
```

### Deleting an Element

Another common operation is the deletion of a node from the tree.

By this point, you're starting to see that we have acode pattern here. Define a recursive method, and
then define a starter method that kicks off the recursion.

First, we have to find the node to delete in a similar way as we did before:

`private Node deleteRecursive(Node current, Integer value)`

Notice here, we want to return the Node we are removing.

Now, Once we find the node to delete, there are 3 main different cases:

- a node has no children – this is the simplest case; we just need to replace this node with null in its parent node
- a node has exactly one child – in the parent node, we replace this node with its only child.
- a node has two children – this is the most complex case because it requires a tree reorganization

We can implement the first case when the node is a leaf node:

- if both left and right of this node are null, return null

Now let's continue with the case when the node has one child:

- if the right node is null, return left node
- if the left node is null, return right node

Here, we're returning the non-null child so it can be assigned to the parent node.

Finally, we have to handle the case where the node has two children.

First, we need to find the node that will replace the deleted node.
We'll use the smallest node of the node to be deleted's right sub-tree:

`private int findSmallestValue(Node n)`

- if the left node is null, return n's object,
- otherwise call findSmallestValue on n's left node

Then, we assign the smallest value to the node to delete and after that, we'll delete it from the right subtree:

int smallestValue = findSmallestValue(current.right);
current.value = smallestValue;
current.right = deleteRecursive(current.right, smallestValue);
return current;

Finally, let's create the public method that starts the deletion from the root:

`public void delete(Integer value)`

Now, let's check that the deletion works as expected:

```
@Test
public void givenABinaryTree_WhenDeletingElements_ThenTreeDoesNotContainThoseElements() {
    BinaryTree bt = createBinaryTree();

    assertTrue(bt.containsNode(9));
    bt.delete(9);
    assertFalse(bt.containsNode(9));
}
```

### Traversing the Tree

In this section, we'll see different ways of traversing a tree, covering in detail the depth-first and breadth-first searches.

We'll use the same tree that we used before and we'll show the traversal order for each case.

#### Depth-First Search

Depth-first search is a type of traversal that goes deep as much as possible in every child before exploring the next sibling.

The in-order traversal consists of first visiting the left sub-tree, then the root node, and finally the right sub-tree:

`public void traverseInOrder(Node node)`

It would do something like:
- if node is not null
  - traverseInOrder(node.left)
  - print(" " + node.value)
  - traverseInOrder(node.right)

If we call this method, the console output will show the in-order traversal:

3 4 5 6 7 8 9

Pre-order traversal visits first the root node, then the left subtree, and finally the right subtree:

`public void traversePreOrder(Node node)`

Look carefully how this is different from **in order**.

- if (node != null)
  - print(" " + node.value)
  - traversePreOrder(node.left)
  - traversePreOrder(node.right)

And let's check the pre-order traversal in the console output:

6 4 3 5 8 7 9

Post-order traversal visits the left subtree, the right subtree, and the root node at the end:

`public void traversePostOrder(Node node)`

- if (node != null)
  - traversePostOrder(node.left)
  - traversePostOrder(node.right)
  - print(" " + node.value)

Here are the nodes in post-order:

3 5 4 7 9 8 6

#### Breadth-First Search

This is another common type of traversal that visits all the nodes of a level before going to the next level.

This kind of traversal is also called level-order and visits all the levels of the tree starting from the root, and from left to right.

For the implementation, we'll use a Queue to hold the nodes from each level in order. We'll extract each node from the list, print its values, then add its children to the queue:

This is the most complex of the routines, and it's a gift :-)

```java
public void traverseLevelOrder() {
    if (root == null) {
        return;
    }

    Queue<Node> nodes = new LinkedList<>();
    nodes.add(root);

    while (!nodes.isEmpty()) {

        Node node = nodes.remove();

        System.out.print(" " + node.value);

        if (node.left != null) {
            nodes.add(node.left);
        }

        if (node.right != null) {
            nodes.add(node.right);
        }
    }
}
```

In this case, the order of the nodes will be:

6 4 8 3 5 7 9

repository: ZipCodeCore/TreesGrowDownward

repo_name: ZipCodeCore/TreesGrowDownward


text:
# Ivy

A Language and its compiler on Ethereum Virtual Machine

## Syntax

[Here](https://github.com/yigitozkavci/ivy/blob/master/standard/ivy.abnf), you can find the language syntax in ABNF form.

## Language Features
Here is the [Midterm Progress Report](https://github.com/yigitozkavci/ivy/blob/master/standard/report_491_midterm/report.pdf)

## License
[License](https://github.com/yigitozkavci/ivy/blob/master/LICENSE)

repository: jaklinenataly/ivy

repo_name: jaklinenataly/ivy


text:
---
layout: post
title: Working to make our lives better
subtitle: Developers Italia will participate to the ISA² closing event
date:   2021-04-19 10:00:00 +0100
tags: developers opensource
categories: news
author: Michela Gabrieli
image: /assets/icons/logo-it.png
locale: en
ref:
  it: /it/news/2021/04/19/working-to-make-our-lives-better
redirect_from:
   -
---

Also Developers Italia will participate in the international event "[Working to make our lives better](https://digitallpublic.eu/)" which will be held online on the 20th, 21th and 22nd of April.

This is the final event of the [ISA²](https://ec.europa.eu/isa2/isa2_en) European programme. The initiative, managed by the European Commission's DG DIGIT, supports the development of digital solutions that enable public administrations, businesses and citizens in Europe to benefit from **interoperable cross-border and cross-sector public services**. Thanks to the collaboration of Member States, the programme has helped to create shared public services for citizens, provided free interoperable solutions to businesses and connected various organisations in different sectors.

The conference will be an opportunity to review successes in the digital transformation of public services across the EU and celebrate the next step in this journey by looking ahead to Europe's digital future and launching the new 'Digital Europe' programme.

With over 1500 participants already registered, the event is organised in more than 30 sessions, and will provide an opportunity to take part in discussions on innovation and GovTech, interoperability, open source, smart cities, trust and security. It will host numerous European and international guests from institutions, Member States and industry, including Developers Italia, which will be present on Wednesday the 21st of April at 10.45 am in the session "[The role of open source in the public sector](https://digitallpublic.eu/agenda/)".

If you are interested you can attend the event by registering at the following [link](https://digitallpublic.app.swapcard.com/event/digitall-public/planning/UGxhbm5pbmdfMzUzNTA3).


text:
---
title: "Weak and Strong ties"
authors:
- admin
date: "2018-12-10T00:00:00Z"
doi: ""

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

abstract: In this paper, we present an asynchronous optimization algorithm for distributed learning, that efficiently reduces the communications between a master and working machines by randomly sparsifying the local updates. This sparsification allows to lift the communication bottleneck often present in distributed learning setups where computations are performed by workers on local data while a master machine coordinates their updates to optimize a global loss. We prove that despite its sparse asynchronous communications, our algorithm allows for a fixed stepsize and benefits from a linear convergence rate in the strongly convex case. Moreover, for $\ell_1$-regularized problems, this algorithm identifies near-optimal sparsity patterns, so that all communications eventually become sparse. We furthermore leverage on this identification to improve our sparsification technique. We illustrate on real and synthetic data that this algorithm converges faster in terms of data exchanges.

links:
#- name: Custom Link
#  url: http://example.org
url_pdf: https://arxiv.org/pdf/1812.03871.pdf
url_code: ''
url_dataset: ''
url_poster: ''
url_project: ''
url_slides: ''
url_source: ''
url_video: ''

---

repository: MartynovVadim/academic-kickstart

path: /content/Weak and Strong Ties/index.md

repo_name: MartynovVadim/academic-kickstart


text:
---
title: "Setting up SSO with SAML 2.0"
id: "setting-up-sso-with-saml-2.0"
---

:::info Enterprise Feature

This guide describes a feature of the dbt Cloud Enterprise plan. If you’re interested in learning
more about an Enterprise plan, contact us at<EMAIL_ADDRESS>
:::

dbt Cloud Enterprise supports single-sign on (SSO) for any SAML 2.0-compliant identity provider (IdP).
Currently supported features include:
* IdP-initiated SSO
* SP-initiated SSO
* Just-in-time provisioning

This document details the steps to integrate dbt Cloud with an identity
provider in order to configure Single Sign On and [role-based access control](access-control-overview#role-based-access-control).

## Generic SAML 2.0 integrations

_Use this section if you are configuring an identity provider besides Okta._

### Configuration in your identity provider

_Note: You'll need administrator access to your SAML 2.0 compliant identity provider to follow this guide.
This approach will work with any SAML 2.0 compliant identity provider._

### Creating the application

First, log into your SAML 2.0 identity provider and create a new application.
When promoted, configure the application with the following details:
 - **Platform:** Web
 - **Sign on method:** SAML 2.0
 - **App name:** dbt Cloud
 - **App logo (optional):** You can optionally [download the dbt logo](https://drive.google.com/file/d/1w_Yj7QK-ULP4ebtKbrbvGo04pWlg0Y7S/view), and use as the logo for this app.

#### Configuring the application

:::info

This guide assumes that your dbt Cloud instance is running at
https://cloud.getdbt.com. If your deployment is running at a different url, then
substitute cloud.getdbt.com for the url of your instance.

:::

To complete this section, you will need to create a login slug. This slug controls the URL where users on your account
can log into your application. Login slugs are typically the lowercased name of your organization
separated with dashes. For example, the login slug for _Fishtown Analytics_ would be _fishtown-analytics_.
Login slugs must be unique across all dbt Cloud accounts, so pick a slug that uniquely identifies your company.

When prompted for the SAML 2.0 application configurations, supply the following
values:

- Single sign on URL: `https://cloud.getdbt.com/complete/saml`
- Audience URI (SP Entity ID): `https://cloud.getdbt.com/`
- Relay State: `<login slug>`

Additionally, you may configure the IdP attributes passed from your identity
provider into dbt Cloud. We recommend using the following values:

| name | name format | value | description |
| ---- | ----------- | ----- | ----------- |
| email | Unspecified | ${user.email} | The user's email address |
| first_name | Unspecified | ${user.first_name} | The user's first name |
| last_name | Unspecified | ${user.last_name} | The user's last name |

dbt Cloud's [role-based access control](access-control-overview#role-based-access-control) relies
on group mappings from the IdP to assign dbt Cloud users to dbt Cloud groups. To
use role-based access control in dbt Cloud, also configure your identity
provider to provide group membership information in user attribute called
`groups`:

| name | name format | value | description |
| ---- | ----------- | ----- | ----------- |
| groups | Unspecified | `<IdP-specific>` | The groups a user belongs to in the IdP |

Note: You may use a restricted group attribute statement to limit the groups set
to dbt Cloud for each authenticated user. For example, if all of your dbt Cloud groups start
with `DBT_CLOUD_...`, you may optionally apply a filter like `Starts With: DBT_CLOUD_`.
Please contact support if you have any questions.

### Collect integration secrets

After confirming your details, the IdP should show you the following values for
the new SAML 2.0 integration. Keep these values somewhere safe, as you will need
them to complete setup in dbt Cloud.

- Identity Provider Issuer
- Identity Provider SSO Url
- X.509 Certificate

### Finish setup

After creating the Okta application, follow the instructions in the [dbt Cloud Setup](#dbt-cloud-setup)
section to complete the integration.

## Okta integration

_Use this section if you are configuring Okta as your identity provider_.

First, log into your Okta account. Using the Admin dashboard, create a new app.

<Lightbox
    collapsed={false}
    src="/img/docs/dbt-cloud/dbt-cloud-enterprise/okta/okta-1-new-app.png"
    title="Create a new app"
/>

On the following screen, select the following configurations:
- **Platform**: Web
- **Sign on method**: SAML 2.0

Click **Create** to continue the setup process.

<Lightbox
    collapsed={false}
    src="/img/docs/dbt-cloud/dbt-cloud-enterprise/okta/okta-1-new-app-create.png"
    title="Configure a new app"
/>

### Configure the Okta application

On the **General Settings** page, enter the following details::

* **App name**: dbt Cloud
* **App logo** (optional): You can optionally [download the dbt logo](https://drive.google.com/file/d/1w_Yj7QK-ULP4ebtKbrbvGo04pWlg0Y7S/view),
  and upload it to Okta to use as the logo for this app.

Click **Next** to continue.

<Lightbox
    collapsed={false}
    src="/img/docs/dbt-cloud/dbt-cloud-enterprise/okta/okta-2-general-settings.png"
    title="Configure the app's General Settings"
/>

### Configure SAML Settings

On the **SAML Settings** page, enter the following values:

* **Single sign on URL**: `https://cloud.getdbt.com/complete/okta`
* **Audience URI (SP Entity ID)**: `https://cloud.getdbt.com/`
* **Relay State**: `<login slug>`

<Lightbox
    collapsed={false}
    src="/img/docs/dbt-cloud/dbt-cloud-enterprise/okta/okta-3-saml-settings-top.png"
    title="Configure the app's SAML Settings"
/>

Use the **Attribute Statements** and **Group Attribute Statements** forms to
map your organization's Okta User and Group Attributes to the format that
dbt Cloud expects.

Expected **User Attribute Statements**:

| Name           | Name format | Value                | Description                |
| -------------- | ----------- | -------------------- | -------------------------- |
| `email`        | Unspecified | `${user.email}`      | _The user's email address_ |
| `first_name`   | Unspecified | `${user.firstName}`  | _The user's first name_    |
| `last_name`    | Unspecified | `${user.lastName}`   | _The user's last name_     |

Expected **Group Attribute Statements**:

| Name     | Name format | Filter        | Value | Description                           |
| -------- | ----------- | ------------- | ----- | ------------------------------------- |
| `groups` | Unspecified | Matches regex | `.*`  | _The groups that the user belongs to_ |

**Note:** You may use a more restrictive Group Attribute Statement than the
example shown above. For example, if all of your dbt Cloud groups start with
`DBT_CLOUD_`, you may use a filter like `Starts With: DBT_CLOUD_`. **Okta
only returns 100 groups for each user, so if your users belong to more than 100
IdP groups, you will need to use a more restrictive filter**. Please contact
support if you have any questions.

<Lightbox
    collapsed={false}
    src="/img/docs/dbt-cloud/dbt-cloud-enterprise/okta/okta-3-saml-settings-bottom.png"
    title="Configure the app's User and Group Attribute Statements"
/>

Click **Next** to continue.

### Finish Okta setup

Select *I'm an Okta customer adding an internal app*, and select *This is an
internal app that we have created*. Click **Finish** to finish setting up the
app.

<Lightbox
    collapsed={false}
    src="/img/docs/dbt-cloud/dbt-cloud-enterprise/okta/okta-4-feedback.png"
    title="Finishing setup in Okta"
/>

### View setup instructions

On the next page, click **View Setup Instructions**. In the steps below,
you'll supply these values in your dbt Cloud Account Settings to complete
the integration between Okta and dbt Cloud.

<Lightbox
    collapsed={true}
    src="/img/docs/dbt-cloud/dbt-cloud-enterprise/okta/okta-5-view-instructions.png"
    title="Viewing the configured application"
/>

<Lightbox
    collapsed={true}
    src="/img/docs/dbt-cloud/dbt-cloud-enterprise/okta/okta-5-instructions.png"
    title="Application setup instructions"
/>

### Finish setup

After creating the Okta application, follow the instructions in the [dbt Cloud Setup](#dbt-cloud-setup)
section to complete the integration.

## dbt Cloud Setup

### Providing IdP values

To complete setup, follow the steps below in dbt Cloud. First, navigate to the
**Enterprise > Single Sign On** page under Account Settings. Next, click
the **Edit** button and supply the following SSO details:

| Field | Value |
| ----- | ----- |
| Log in with | SAML 2.0 |
| Identity Provider SSO Url | Paste the **Identity Provider Single Sign-On URL** shown in the IdP setup instructions |
| Identity Provider Issuer | Paste the **Identity Provider Issuer** shown in the IdP setup instructions |
| X.509 Certificate | Paste the **X.509 Certificate** shown in the IdP setup instructions |
| Slug | Enter your desired login slug. |

<Lightbox
    collapsed={false}
    src="/img/docs/dbt-cloud/dbt-cloud-enterprise/okta/okta-6-setup-integration.png"
    title="Configuring the application in dbt Cloud"
/>

Click **Save** to complete setup for the SAML 2.0 integration.

### Test the integration
After setup is complete, you can navigate to the URL generated for your account's _slug_ to
test logging in with your identity provider. Additionally, users added the the SAML 2.0 app
will be able to log in to dbt Cloud from the IdP directly.

Users in your IdP will now be able to log into the application by navigating to the URL:

`https://cloud.getdbt.com/enterprise-login/<login-slug>`

### Setting up RBAC
After configuring an identity provider, you will be able to set up [role-based
access control](/access-control/enterprise-permissions) for your account.

branch_name: refs/heads/current


text:
# Shell Colorized Aliases for Docker (SCAD)

Docker commands ~~are~~ were tedious to type.

![ddils image listing](ddils.png)

This project defines [Docker][1] aliases (and a few functions) for
shells (zsh, bash, fish), with colorized output for many commands, and
[fuzzy completions](https://github.com/jhawthorn/fzy).

These aliases adhere to the
[newer style](https://blog.couchbase.com/docker-1-13-management-commands/) of
organizing and invoking docker with *management commands* rather than
the notoriously confusing “random solo commands”.

This work was inspired by
[akarzim/zsh-docker-aliases](https://github.com/akarzim/zsh-docker-aliases).
It uses [GRC](https://github.com/garabik/grc) and jq for colorized
Docker command output.

## How to Install

### With [zplug][2]

```sh
zplug "MicahElliott/scad"
zplug "greymd/docker-zsh-completion" # and completions!
```

## Usage Tips

This was put together with Zsh in mind; YMMV for other shells.

These shell aliases are all short mnemonics for docker **management
commands** (eg, `container`, `image`, `volume`), and **subsystems**
(eg, `compose`), and just a few**basic commands** (whose use are
discouraged; eg, `ps`, `build`).  The commands all start with a `dd`
(by default, configurable) and take form like `ddcls` (*container ls*)
and `ddcb` (*container build*).

Any aliases that end with a capital letter require an extra argument.
E.g., `ddcrD` means “run a docker container, in detached mode, with a
name that must be specified.

With such a voluminous set of commands, it’s helpful to use zsh’s tab
completion constantly to explore what you’re actually trying to
invoke.  Say you’re just looking for a basic command…

«demonstration here»

Think in terms of *management commands*: Containers, Images, Volumes,
Networks, System, Daemon.

Compose and Machine are their own separate systems, and maybe Compose
is the only one you’ll care about, so get used to typing `ddk<tab>` for
all of its commands.

If you’re using (any parts of) oh-my-zsh, use `CASE_SENSITIVE="true"`
to make alias completion differentiation sane.  This way typing
`dc<tab>` will be distinguished from `dC<tab>`.

SCAD works well with [podman](https://podman.io/) too! Just:
`alias docker=podman`, and the completions should all work fine.

## Help System

### run-help (bound to `M-h`)

See [this solution](https://stackoverflow.com/a/46415388/326516) for
conveniently seeing alias definitions on-the-fly.

### Extra provided help

All the management commands include a `?` suffixed command.  So you
can see all the _container_ commands with:

```shell
❯ ddc?
Docker CONTAINER commands:
ddca   — Attach local standard input, output, and error streams to a running container
ddcci  — Commit a new image from a container’s changes
ddccp  — Copy files/folders between a container and the local filesystem
…
```

There is a top-level help also:

```shell
❯ dd?
Docker Alias Help

MOST COMMON
  ddb Builder
  ddc Container
  ddi Image
  ddn Network
  ddv Volume

LESS COMMON
  ddf conFig
  ddx conteXt
…
```

The help is all built in, so these won’t be documented in this README!

You can get subcommand help by invoking it with `--help`:

```shell
❯ ddcr --help

Usage: docker container run [OPTIONS] IMAGE [COMMAND] [ARG...]

Run a command in a new container

Options:
      --add-host list                  Add a custom host-to-IP mapping (host:ip)
  -a, --attach list                    Attach to STDIN, STDOUT or STDERR
…
```

### Apropos

You can search all commands help.  E.g., you know there’s some command
to show you some top-like status of your containers, but you can’t
think of it.  Use `dda` for apropos-searching.

```shell
❯ dda cpu
  ddcst  — Display a live stream of container(s) resource usage statistics (cpu, mem)

❯ dda stop
  ddcpr  — Prune/remove all stopped containers
  ddcs   — Start one or more stopped containers
  ddcx   — Stop one or more running containers
  ddcw   — Wait/block until one or more containers stop, then print their exit codes
```

### Alias Expansion

You can see expand an alias in Zsh with `C-x a`. This is another
useful way to inspect or edit a full command when needed.

## Author

*The author of this module should be contacted via the [issue tracker][3].*

- [Micah Elliott](https://github.com/MicahElliott)

[1]: https://www.docker.com/
[2]: https://github.com/zplug/zplug
[3]: https://github.com/MicahElliott/scad/issues

repository: MicahElliott/scad

repo_name: MicahElliott/scad


text:
# Prosthetics Vacuum Pump Controller

## Bill of Materials

- [Adafruit PowerBoost 1000 Charger](https://www.adafruit.com/product/2465)
- [Adafruit MPRLS Ported Pressure Sensor Breakout](https://www.adafruit.com/product/3965)
- [Air Pump and Vacuum DC Motor](https://www.adafruit.com/product/4699)
- [Silicone Tubing for Air Pumps and Valves - 3mm ID](https://www.adafruit.com/product/4661)
- [T-Connector For Silicone Tubing](https://www.adafruit.com/product/4662)
- [Lithium Ion Polymer Battery - 3.7v 2500mAh](https://www.adafruit.com/product/328)
- [N-channel power MOSFET - 30V / 60A](https://www.adafruit.com/product/355)
- [Pro Micro 5V 16MHz Development Board](https://amazon.com/gp/product/B07FXCTVQP)
- [SPST Toggle Switch](https://amazon.com/gp/product/B08F816MB4)
- [4mm Check Valve](https://www.amazon.com/gp/product/B08HYVKTLX)

path: /Bill of Materials.md

filename: Bill of Materials.md


text:
# Using Tensor Comprehensions for writing a layer in PyTorch

We provide integration of Tensor Comprehensions (TC) with PyTorch for both training
and inference purpose. Using TC, you can express any operator using [Einstein
notation](https://obilaniu6266h16.wordpress.com/2016/02/04/einstein-summation-in-numpy/)
and generate the fast cuda implementation code for that layer with just 3-4 lines
of code. A few examples are shown below and a detailed tutorial will be provided for this.

## Installation and prerequisites

For native and python TC development, follow the following installation instructions **step-wise**. If you have already done some steps (in-order), you can skip them.

### **Step 1:** Install Clang+LLVM

For building TC, you also need to install a custom clang+llvm. For that, follow the instructions below:

```Shell
# now check your gcc/g++ and make sure they are in system path, somewhere like /usr/bin
which gcc
which g++

export CC=$(which gcc)
export CXX=$(which g++)
export LLVM_SOURCES=/tmp/llvm_sources-tapir5.0
export CLANG_PREFIX=$HOME/clang+llvm-tapir5.0  # change this to whatever path you want
export CMAKE_VERSION=cmake

mkdir -p $LLVM_SOURCES
cd $LLVM_SOURCES

# clone the repo now
git clone --recursive https://github.com/wsmoses/Tapir-LLVM llvm
mkdir -p ${LLVM_SOURCES}/llvm_build && cd ${LLVM_SOURCES}/llvm_build

# cmake and install
${CMAKE_VERSION} -DCMAKE_INSTALL_PREFIX=${CLANG_PREFIX} -DLLVM_TARGETS_TO_BUILD=X86 -DCOMPILER_RT_BUILD_CILKTOOLS=OFF -DLLVM_ENABLE_CXX1Y=ON -DLLVM_ENABLE_TERMINFO=OFF -DLLVM_BUILD_TESTS=OFF -DLLVM_ENABLE_ASSERTIONS=ON -DCMAKE_BUILD_TYPE=Release -DLLVM_BUILD_LLVM_DYLIB=ON  -DLLVM_ENABLE_RTTI=ON ../llvm/

make -j"$(nproc)" -s && make install -j"$(nproc)" -s

cd $HOME && rm -rf $LLVM_SOURCES
```

### **Step 2:** Install Anaconda3
In order to contribute to TC python/C++ API, you need to install TC from source. For this,
anaconda3 is required. Install anaconda3 by following the instructions below:

```Shell
cd $HOME
wget https://repo.continuum.io/archive/Anaconda3-5.0.1-Linux-x86_64.sh -O anaconda3.sh
chmod +x anaconda3.sh
./anaconda3.sh -b -p $HOME/anaconda3
rm anaconda3.sh
```

Now add anaconda3 to your PATH so that you can use it. For that run the following command:

```Shell
export PATH=$HOME/anaconda3/bin:$PATH
```

Now, verify your conda installation and check the version:

```Shell
which conda
```

This command should print the path of your conda bin. If it doesn't, make sure conda is
in your $PATH.

Now, let's create a conda environment which we will work in.

```Shell
conda create -y --name tc-build python=3.6
source activate tc-build
```

### **Step 3:** Install PyTorch

Now for PyTorch, we will install it from conda. Run the following command:

```Shell
conda install -y -c soumith pytorch
```

Wait for this to finish and verify your PyTorch installed correctly. For that run following on your command line:

```python
python -c "import torch"
```

### **Step 4:** Get CUDA and CUDNN
In order to build TC, you also need to have CUDA and cudnn. If you already have it
you can just export the PATH, LD_LIBRARY_PATH simply (see the end of this step). If you don't have CUDA/CUDNN, then follow the instructions below:

```Shell
# install CUDA Toolkit v8.0
# instructions from https://developer.nvidia.com/cuda-downloads (linux -> x86_64 -> Ubuntu -> 16.04 -> deb (network))
CUDA_REPO_PKG="cuda-repo-ubuntu1604_8.0.61-1_amd64.deb"
wget http://developer.download.nvidia.com/compute/cuda/repos/ubuntu1604/x86_64/${CUDA_REPO_PKG}
sudo dpkg -i ${CUDA_REPO_PKG}
sudo apt-get update
sudo apt-get -y install cuda

# install cuDNN v6.0
CUDNN_TAR_FILE="cudnn-8.0-linux-x64-v6.0.tgz"
wget http://developer.download.nvidia.com/compute/redist/cudnn/v6.0/${CUDNN_TAR_FILE}
tar -xzvf ${CUDNN_TAR_FILE}
sudo cp -P cuda/include/cudnn.h /usr/local/cuda/include
sudo cp -P cuda/lib64/libcudnn* /usr/local/cuda/lib64/
sudo chmod a+r /usr/local/cuda/lib64/libcudnn*

# set environment variables
export LD_LIBRARY_PATH=/usr/local/cuda/lib64:$LD_LIBRARY_PATH
export PATH=/usr/local/bin:/usr/local/cuda/bin:$PATH
```

### **Step 5:** Installing TC

Now, you need to install TC from source (conda packages coming soon). For installing
TC from source, checkout the c2isl repo and run the following commands:

```Shell
cd $HOME && git clone git@github.com:nicolasvasilache/c2isl.git --recursive
cd c2isl
git submodule update --init --recursive
export CC=$(which gcc)
export CXX=$(which g++)
export TC_DIR=$(pwd)

# install pyyaml now, this is needed for some dependencies
conda install -y pyyaml
```

**NOTE 1:**: Please make sure that you are using system gcc/g++ and not the ones that
are provided by conda. TC supports gcc 4.8.* and gcc 5 builds at the moment.

**NOTE 2:**: Please also make sure that you don't have gflags or glog in your system path. Those might conflict with the TC gflags/glog.

Now, let's run the TC installation.

1. If you want to install Caffe2 as well, run the following:

```Shell
# you set the CLANG_PREFIX variable in your CLANG+LLVM install above, use that
WITH_PYTHON_C2=OFF CLANG_PREFIX=$HOME/clang+llvm-tapir5.0 ./build.sh --all
```

**NOTE**: This turns off the Caffe2 python build. If you want to turn on the Caffe2
python build, see next step:

2. For installing python binaries as well of Caffe2 with TC:

```Shell
WITH_PYTHON_C2=ON CLANG_PREFIX=$HOME/clang+llvm-tapir5.0 ./build.sh --all
```

**NOTE**: Caffe2 doesn't provide support for pip/conda at the moment and this means
in order to use the caffe2 python, you might need to set $PYTHONPATH. Normally,
it could be

```Shell
${TC_DIR}/third-party-install/
```

However, please check caffe2 official instructions [here](https://caffe2.ai/docs/getting-started.html?platform=mac&configuration=compile#test-the-caffe2-installation). TC doesn't yet provide support for caffe2 python usage.

3. For installing TC without Caffe2:

```Shell
WITH_CAFFE2=OFF CLANG_PREFIX=$HOME/clang+llvm-tapir5.0 ./build.sh --all
```

### **Step 6:** Verify TC installation:

```Shell
cd $HOME/c2isl
./test.sh                 # if you have GPU
./test_cpu.sh             # if you have only CPU
./test_python/run_test.sh   # if you have GPU
```

Make sure all the tests pass here. Now you are ready to start contributing to the C++/Python API of TC.

### Examples
A very simple example of how writing new layers with TC in PyTorch looks like:

Now, let's see how to write a matmul example with TC and use it as a PyTorch Layer:

```python
# first import tc and torch
import tensor_comprehensions as tc
import torch

# use Einstein notation to write the TC expression for layer
lang = """
def matmul(float(M,N) A, float(N,K) B) -> (output) {
  output(i, j) += A(i, kk) * B(kk, j)
}
"""

# now we register the op with TC using tc.define()
matmul = tc.define(lang, name="matmul")

# create input tensors and run layer on it
mat1, mat2 = torch.randn(3, 4).cuda(), torch.randn(4, 5).cuda()
out = matmul(mat1, mat2)
```

For using TC for training purposes, you need write the expression for backward
layer following Einstein notation. Let's take a look at one example:

```python
import tc
import torch

# define the forward and backward operations
lang = """
def MY_LAYER(float(D2, N2) W2, float(M, N0, N1, N2) X) -> (XW2) {
   XW2(m, n0, n1, d2)   += X(m, n0, n1, n2_red) * W2(d2, n2_red)
}
def MY_LAYER_GRAD(float(D2, N2) W2, float(M, N0, N1, N2) X, float(M, N0, N1, D2) XW2_grad) -> (W2_grad, X_grad) {
   W2_grad(d2, n2)   += XW2_grad(m_red, n0_red, n1_red, d2) * X(m_red, n0_red, n1_red, n2)
   X_grad(m, n0, n1, n2) += XW2_grad(m, n0, n1, d2_red) * W2(d2_red, n2)
}
"""

MY_LAYER = tc.define(lang, training=True, name="MY_LAYER", backward="MY_LAYER_GRAD")
X = Variable(torch.randn(256, 16, 16, 16), requires_grad=True).cuda()
W2 = Parameter(torch.randn(32, 16)).cuda()
out = MY_LAYER(W2, X)

# get the gradients by simply calling backward
out[0].sum().backward()
```

These were simple examples of how to use TC with PyTorch. Please refer to the documentation
for various rules around how to pass the inputs, creating tensors etc.

More details will be available in TC documentation.


text:
# pcre

The PCRE library is a set of functions that implement regular expression pattern matching using the same syntax and semantics as Perl 5, with just a few differences (see below). The current implementation corresponds to Perl 5.005.

| Platform | Url                                                              |
|----------|------------------------------------------------------------------|
| PHP.net  | https://www.php.net/manual/en/book.pcre.php                      |

repository: devilbox/docker-php-fpm

gha_language: Dockerfile

repo_name: devilbox/docker-php-fpm


text:
---
title: "\n\t\t\t\tBest Prices on 8GB DDR3 Memory Upgrades for the Dell Inspiron 15R
  Laptop/Notebook\t\t"
date: 2011-09-09 00:00:00 Z
categories:
- jim
author<EMAIL_ADDRESS>comments: true
excerpt: "\n\t\t\t\t\t\t"
layout: post
link: https://jim.am/best-prices-on-8gb-ddr3-memory-upgrades-for-the-dell-inspiron-15r-laptop-notebook/
wordpress_id: 5622
---

[

![](http://www.jim.am/wp-content/uploads/2011/09/Screen-Shot-2011-09-09-at-9.06.17-AM.png)](http://www.amazon.com/gp/product/B004XZMA9C/ref=as_li_ss_tl?ie=UTF8&tag=ramseeker-20&linkCode=as2&camp=217145&creative=399373&creativeASIN=B004XZMA9C)

**[Save on the Dell Inspiron 15R Notebook](http://www.amazon.com/gp/product/B004XZMA9C/ref=as_li_ss_tl?ie=UTF8&tag=ramseeker-20&linkCode=as2&camp=217145&creative=399373&creativeASIN=B004XZMA9C)

**

This particular notebook computer from Dell is the **[best selling notebook computer](http://www.amazon.com/gp/bestsellers/electronics/565108?ie=UTF8&ref_=zg_bs_nav_e_2_541966#?ie=UTF8&tag=ramseeker-20&linkCode=ur2&camp=1789&creative=390957)** from Dell and available in quite a few different configurations if you buy from Dell directly, but my advice is to buy the **[cheapest Dell 15R](http://www.amazon.com/gp/product/B004XZMA9C/ref=as_li_ss_tl?ie=UTF8&tag=ramseeker-20&linkCode=as2&camp=217145&creative=399373&creativeASIN=B004XZMA9C)** you can find and upgrade the RAM and even the hard drive yourself rather than buying memory direct from the manufacturer, which is going to be more expensive than buying high quality memory and installing it yourself.

The Dell 15R from dell is available in two memory configurations:

Dell Inspiron 15R with 4GB Single Channel DDR3 SDRAM at 1333MHz

Dell Inspiron 15R with 6GB Single Channel DDR3 SDRAM at 1333MHz

The best deal on a 15R from Dell is to buy the 4GB version and apply the money saved by not **[adding an 8GB Memory Upgrade Kit](http://www.tkqlhce.com/click-1548159-10273954?url=http%3A%2F%2Fwww.crucial.com%2Fstore%2Faffiliateredirect.asp%3Fimodule%3DCT2KIT51264BC1339%26aid%3D10273954%26cid%3D777292%26subid%3D890%26PRS%3Duscj&cjsku=CT2KIT51264BC1339)**, which is the maximum memory for the Dell Inspiron 15R.

Be sure you buy right memory for the Dell Inspiron 15R, as this notebook requires the use of DDR3 1333Mhz sodimms. To replace the ram on your Dell, there are two memory upgrade slots available in this popular dell notebook and assuming you want to max out the Dell notebook to a full 8GB you would remove the factory installed RAM (either 1x2Gb and 1x4GB or 2X2GB, depending on original configuration and replace it with an [8GB Dell Inspiron 15R Memory Upgrade Kit](http://www.tkqlhce.com/click-1548159-10273954?url=http%3A%2F%2Fwww.crucial.com%2Fstore%2Faffiliateredirect.asp%3Fimodule%3DCT2KIT51264BC1339%26aid%3D10273954%26cid%3D777292%26subid%3D890%26PRS%3Duscj&cjsku=CT2KIT51264BC1339) consisting of 2x4GB ddr3 1333Mhz memory modules.

**Where To Buy Dell Inspiron 15R Memory Upgrades.

**

At the time of writing this the cheapest Dell Inspiron 15R memory upgrades are available ****[on sale at Amazon](http://www.amazon.com/dp/B002YUF8ZG/ref=as_li_ss_til?tag=ramseeker-20&camp=213381&creative=390973&linkCode=as4&creativeASIN=B002YUF8ZG&adid=1M72YM31597Z6H77GVMK&)**** and better any of the prices you see below. This may change over time so it’s best to check for yourself to see if any Dell ram prices have changed. More Memory Upgrade Options for the Dell Inspiron 15R are below:

[table id=7 /]

**How to Install Dell Inspiron 15R Memory Upgrades

**

Dell offers an [excellent manual](http://support.dell.com/support/edocs/systems/insN5010/en/sm/memory.htm#wp1180987) for the Dell Inspiron 15R that describes how to easily replace the memory upgrades in the Dell notebook to maximize the performance from the Dell Laptop.

The Dell Inspiron 15R is a fast, cheap 15 inch notebook available with both Intel i3 and i5 processors, and adding more memory to the Dell Inspiron 15R will offer faster performance and a smoother windows operating system experience by adding more memory to your Dell notebook computer

repository: ramseeker/sidey

extension: markdown

repo_name: ramseeker/sidey


text:
Code to work with Google Project Tango tablet

There are two parts to this project.

The first part is the JavaPointCloud application. This is the demo program
that is included with the Project Tango tablet, but modified to write the
data sets to a directory.

Run the program and press the save button the right side of the screen to
save the point cloud. Each data set includes the pose information, the
point cloud data, and a color image from the camera.

When you have finished scanning, connect the Project Tango tablet to a PC,
and nagivate to the Internal storage/Documents/myScans directory. You should
find one numbered Scan<N>.data and tango<N>.png for each time you hit save. Drag those over to your PC.

The second application is a reader for these data sets. This will read in the
scan file and write out an XYZ file in the same directory. All the points in
the scan file will by transformed by the data from the pose so the data should
all line up.

Run the reader as:
    python reader.py DIR
Where dir is a directory containing the scans.

It will output a few lines of diagnostic information as it processes each of the scans. The output will be a ply file in the same directory.

I've been loading the scan in to meshlab. You should see your scans basically line up.

The reader is really simple, and the matmath.py file includes the details of
the transformations being used to align the data. Hopefully this is a simple
example for others using the tablet.

I don't have a precise roadmap, but my next couple goals are:

1) Modify the reader program to combine all the scans for you. This should be
trivial to do in python.

2) DONE ~~Snap a color photo along with each scan, and use the reader program
to create color point clouds.~~

3) Extend the reader to write a threejs program to display these point clouds
on the web.

4) Use meshlab to learn the best ways to process these point clouds and then
write code to use Point Cloud Library (PCL) to process them wihtout meshlab.

If you're interested, please follow the project, fork the code, provide merge
requests, etc. and we'll see what we can do.

You can reach me as daryll.strauss on gmail.

repository: Timmsh/tango

gha_language: Java

repo_name: Timmsh/tango


text:
# Milestone Delivery :mailbox:

**
The [invoice form :pencil:](https://docs.google.com/forms/d/e/1FAIpQLSfmNYaoCgrxyhzgoKQ0ynQvnNRoTmgApz9NrMp-hd8mhIiO0A/viewform)
has been filled out correctly for this milestone.**

* **Application Document:** https://github.com/w3f/Grants-Program/blob/master/applications/xcm-tools.md
* **Milestone Number:** 2

| Number | Deliverable               | Link                                                             | Notes      |
|--------|---------------------------|------------------------------------------------------------------|------------|
| 0a.    | License                   | https://github.com/gmajor-encrypt/xcm-tools/blob/main/LICENSE    | Apache 2.0 |
| 0b.    | Documentation             | https://github.com/gmajor-encrypt/xcm-tools/blob/main/README.md  |            |
| 0c.    | Testing and Testing Guide | https://github.com/gmajor-encrypt/xcm-tools#test                 |            |
| 0d.    | Docker                    | https://github.com/gmajor-encrypt/xcm-tools/blob/main/Dockerfile |            |
| 1.     | Send UMP message          | https://github.com/gmajor-encrypt/xcm-tools/blob/main/tx/ump.go  |            |
| 2.     | Send DMP message          | https://github.com/gmajor-encrypt/xcm-tools/blob/main/tx/dmp.go  |            |
| 3.     | Send HRMP message         | https://github.com/gmajor-encrypt/xcm-tools/blob/main/tx/hrmp.go |            |


text:
# Project Demo

To see the demonstration of the model as a web application, please:

1. Install streamlit using requirements.txt or pipenv.
2. Run models/train_model.py to create a pkl file in tree_model.
3. On `src/demo` folder, type:
```
$ streamlit run app.py
```

By default, the application already loads a valid input choosing (randomly) a line of tree_model/test_input.csv.


text:
meArm_Adafruit
==============

Inverse Kinematics motion control library for Phenoptix meArm on an Arduino with an Adafruit 16-channel PWM Servo driver board.

The meArm has four mini servos - one for the gripper, and one each to rotate the base, shoulder joint and elbow joint.  But it's not terribly convenient to be specifying things in terms of servo angles when you're much more interested in where you would like to place the gripper, in normal Cartesian (x, y, z) coordinates.

This library solves the angles required to send to the servos in order to meet a given position, allowing for much simpler coding.

Coordinates are measured in mm from the base rotation centre.  Initial 'home' position is at (0, 100, 50), i.e. 100mm forward of the base and 50mm off the ground.

For a version of this library which drives the servos directly without the Adafruit board, try: https://github.com/yorkhackspace/meArm

Usage
-----

```
#include "meArm_Adafruit.h"
#include <Adafruit_PWMServoDriver.h>
#include <Wire.h>

meArm arm;

void setup() {
  arm.begin();
  arm.openGripper();
}

void loop() {
  //Go up and left to grab something
  arm.gotoPoint(-80,100,140);
  arm.closeGripper();
  //Go down, forward and right to drop it
  arm.gotoPoint(70,200,10);
  arm.openGripper();
  //Back to start position
  arm.gotoPoint(0,100,50);
}
```

Three usage examples are included:
* IKTest follows a pre-programmed path defined in Cartesian coordinates
* JoystickIK uses two analogue thumb sticks to guide the gripper in Cartesian space
* meArm_Wii_Classic uses a Wii Classic gamepad connected over I2C to guide the gripper

Installation
------------
* Clone this repository to your Arduino libraries folder
* You will also need Adafruit's PWM Servo driver library from here: https://github.com/adafruit/Adafruit-PWM-Servo-Driver-Library

Class methods of meArm object
-----------------------------
* void begin(int pinBlock = 0, int address = 0x40) - Optionally specify which block of four pins on the Adafruit board to use (base, shoulder, elbow and gripper), and which I2C address to use.  Block -1 mirrors to all four blocks.  Begin must be called in setup() before any other calls to the meArm instance are made.
* void openGripper() - opens the gripper, letting go of anything it was holding
* void closeGripper() - closes the gripper, perhaps grabbing and holding something as it does so
* void gotoPoint(float x, float y, float z) - move in a straight line from the current point to the requested position
* void goDirectlyTo(float x, float y, float z) - set the servo angles to immediately go to the requested point without caring what path the arm swings through to get there - faster but less predictable than gotoPoint
* bool isReachable() - returns true if the point can theoretically be reached by the arm
* float getX() - current x coordinate
* float getY() - current y coordinate
* float getZ() - current z coordinate