kandi background
Explore Kits

dive | A tool for exploring each layer in a docker image | Continuous Deployment library

 by   wagoodman Go Version: v0.10.0 License: MIT

 by   wagoodman Go Version: v0.10.0 License: MIT

Download this library from

kandi X-RAY | dive Summary

dive is a Go library typically used in Devops, Continuous Deployment, Docker applications. dive has no bugs, it has no vulnerabilities, it has a Permissive License and it has medium support. You can download it from GitHub, GitLab.
To analyze a Docker image simply run dive with an image tag/id/digest:.
Support
Support
Quality
Quality
Security
Security
License
License
Reuse
Reuse

kandi-support Support

  • dive has a medium active ecosystem.
  • It has 27275 star(s) with 1037 fork(s). There are 340 watchers for this library.
  • It had no major release in the last 12 months.
  • There are 88 open issues and 140 have been closed. On average issues are closed in 53 days. There are 9 open pull requests and 0 closed requests.
  • It has a neutral sentiment in the developer community.
  • The latest version of dive is v0.10.0
dive Support
Best in #Continuous Deployment
Average in #Continuous Deployment
dive Support
Best in #Continuous Deployment
Average in #Continuous Deployment

quality kandi Quality

  • dive has 0 bugs and 0 code smells.
dive Quality
Best in #Continuous Deployment
Average in #Continuous Deployment
dive Quality
Best in #Continuous Deployment
Average in #Continuous Deployment

securitySecurity

  • dive has no vulnerabilities reported, and its dependent libraries have no vulnerabilities reported.
  • dive code analysis shows 0 unresolved vulnerabilities.
  • There are 0 security hotspots that need review.
dive Security
Best in #Continuous Deployment
Average in #Continuous Deployment
dive Security
Best in #Continuous Deployment
Average in #Continuous Deployment

license License

  • dive is licensed under the MIT License. This license is Permissive.
  • Permissive licenses have the least restrictions, and you can use them in most projects.
dive License
Best in #Continuous Deployment
Average in #Continuous Deployment
dive License
Best in #Continuous Deployment
Average in #Continuous Deployment

buildReuse

  • dive releases are available to install and integrate.
  • Installation instructions, examples and code snippets are available.
  • It has 6956 lines of code, 370 functions and 78 files.
  • It has medium code complexity. Code complexity directly impacts maintainability of the code.
dive Reuse
Best in #Continuous Deployment
Average in #Continuous Deployment
dive Reuse
Best in #Continuous Deployment
Average in #Continuous Deployment
Top functions reviewed by kandi - BETA

kandi's functional review helps you automatically verify the functionalities of the libraries and avoid rework.
Currently covering the most popular Java, JavaScript and Python libraries. See a Sample Here

Get all kandi verified functions for this library.

Get all kandi verified functions for this library.

dive Key Features

docker: Docker engine (the default option)

docker-archive: A Docker Tar Archive from disk

podman: Podman engine (linux only)

dive

copy iconCopydownload iconDownload
dive <your-image-tag>

Basic Features

copy iconCopydownload iconDownload
dive <your-image> --source <source>

Installation

copy iconCopydownload iconDownload
wget https://github.com/wagoodman/dive/releases/download/v0.9.2/dive_0.9.2_linux_amd64.deb
sudo apt install ./dive_0.9.2_linux_amd64.deb

CI Integration

copy iconCopydownload iconDownload
rules:
  # If the efficiency is measured below X%, mark as failed.
  # Expressed as a ratio between 0-1.
  lowestEfficiency: 0.95

  # If the amount of wasted space is at least X or larger than X, mark as failed.
  # Expressed in B, KB, MB, and GB.
  highestWastedBytes: 20MB

  # If the amount of wasted space makes up for X% or more of the image, mark as failed.
  # Note: the base image layer is NOT included in the total image size.
  # Expressed as a ratio between 0-1; fails if the threshold is met or crossed.
  highestUserWastedPercent: 0.20

UI Configuration

copy iconCopydownload iconDownload
# supported options are "docker" and "podman"
container-engine: docker
# continue with analysis even if there are errors parsing the image archive
ignore-errors: false
log:
  enabled: true
  path: ./dive.log
  level: info

# Note: you can specify multiple bindings by separating values with a comma.
# Note: UI hinting is derived from the first binding
keybinding:
  # Global bindings
  quit: ctrl+c
  toggle-view: tab
  filter-files: ctrl+f, ctrl+slash

  # Layer view specific bindings
  compare-all: ctrl+a
  compare-layer: ctrl+l

  # File view specific bindings
  toggle-collapse-dir: space
  toggle-collapse-all-dir: ctrl+space
  toggle-added-files: ctrl+a
  toggle-removed-files: ctrl+r
  toggle-modified-files: ctrl+m
  toggle-unmodified-files: ctrl+u
  toggle-filetree-attributes: ctrl+b
  page-up: pgup
  page-down: pgdn

diff:
  # You can change the default files shown in the filetree (right pane). All diff types are shown by default.
  hide:
    - added
    - removed
    - modified
    - unmodified

filetree:
  # The default directory-collapse state
  collapse-dir: false

  # The percentage of screen width the filetree should take on the screen (must be >0 and <1)
  pane-width: 0.5

  # Show the file attributes next to the filetree
  show-attributes: true

layer:
  # Enable showing all changes from this layer and every previous layer
  show-aggregated-changes: false

ShouldProcess failing in PowerShell7

copy iconCopydownload iconDownload
function Test-ShouldProcess {
    [CmdletBinding(SupportsShouldProcess, ConfirmImpact = "High")]
    param()

    $obj = [System.Management.Automation.PSSerializer]::Deserialize(
        [System.Management.Automation.PSSerializer]::Serialize((Get-Process)[0])
    )

    # will throw
    if ($PSCmdlet.ShouldProcess($obj)) { 'hello' }
}

Test-ShouldProcess

Flag provided but not defined: -rpc

copy iconCopydownload iconDownload
geth --datadir ~/etherprivate/ --networkid 786 --http --http.api 'web3,eth,net,debug,personal' --http.corsdomain '*'
  --http                              Enable the HTTP-RPC server
  --http.addr value                   HTTP-RPC server listening interface (default: "localhost")
  --http.port value                   HTTP-RPC server listening port (default: 8545)
  --http.api value                    API's offered over the HTTP-RPC interface
  --http.rpcprefix value              HTTP path path prefix on which JSON-RPC is served. Use '/' to serve on all paths.
  --http.corsdomain value             Comma separated list of domains from which to accept cross origin requests (browser enforced)
  --http.vhosts value                 Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard. (default: "localhost")

Split text into smaller paragraphs of a minimal length without breaking the sentences given a threshold

copy iconCopydownload iconDownload
out = []
threshold = 200
for chunk in text.split('. '):
    if out and len(chunk)+len(out[-1]) < threshold:
        out[-1] += ' '+chunk+'.'
    else:
        out.append(chunk+'.')
['Marketing products and services is a demanding and tedious task in today’s overly saturated market. Especially if you’re in a B2B lead generation business.',
 'As a business owner or part of the sales team, you really need to dive deep into understanding what strategies work best and how to appeal to your customers most efficiently.',
 'Lead generation is something you need to master. Understanding different types of leads will help you sell your product or services and scale your business faster.',
 'That’s why we’re explaining what warm leads are and how you can easily turn them into paying customers..']
out = []
threshold = 200
for chunk in text.split('. '):
    if out and len(chunk)+len(out[-1]) < threshold:
        out[-1] += ' '+chunk+'.'
    else:
        out.append(chunk+'.')
['Marketing products and services is a demanding and tedious task in today’s overly saturated market. Especially if you’re in a B2B lead generation business.',
 'As a business owner or part of the sales team, you really need to dive deep into understanding what strategies work best and how to appeal to your customers most efficiently.',
 'Lead generation is something you need to master. Understanding different types of leads will help you sell your product or services and scale your business faster.',
 'That’s why we’re explaining what warm leads are and how you can easily turn them into paying customers..']

How does React update a component and its children after a state change?

copy iconCopydownload iconDownload
function App() {
  return <div>
    <Parent>
      <Child01/>
      <Child01/>
    </Parent>
    <Child03/>
  </div>
}

function Parent({children}) {
  const [state, setState] = useState(0);

  return <div>
    <button onClick={x => x+1)>click</button>
    <Child02 />
    {children}
  </div>
}
- button click
- setState(...), add Parent to dirty list
- start re-rendering all dirty nodes
- Parent rerenders
- Child02 rerenders
- DONE
function App() {
  return <div>
    <Parent>
      <Child01/>
      <Child01/>
    </Parent>
    <Child03/>
  </div>
}

function Parent({children}) {
  const [state, setState] = useState(0);

  return <div>
    <button onClick={x => x+1)>click</button>
    <Child02 />
    {children}
  </div>
}
- button click
- setState(...), add Parent to dirty list
- start re-rendering all dirty nodes
- Parent rerenders
- Child02 rerenders
- DONE
  updateComponent(prevElement, nextElement) {
  //...
    if (shouldUpdateComponent(prevRenderedElement, nextRenderedElement)) {
      Reconciler.receiveComponent(this._renderedComponent, nextRenderedElement);
  //...
  receiveComponent(nextElement) {
    this.updateComponent(this._currentElement, nextElement);
  }

  updateComponent(prevElement, nextElement) {
    // debugger;
    this._currentElement = nextElement;
    this._updateDOMProperties(prevElement.props, nextElement.props);
    this._updateDOMChildren(prevElement.props, nextElement.props);
  }
let renderedComponent = instantiateComponent(renderedElement);
this._renderedComponent = renderedComponent;
  let type = element.type;

  let wrapperInstance;
  if (typeof type === 'string') {
    wrapperInstance = HostComponent.construct(element);
  } else if (typeof type === 'function') {
    wrapperInstance = new element.type(element.props);
    wrapperInstance._construct(element);
  } else if (typeof element === 'string' || typeof element === 'number') {
    wrapperInstance = HostComponent.constructTextComponent(element);
  }

  return wrapperInstance;
HostComponent.inject(DOMComponentWrapper);
function inject(impl) {
  implementation = impl;
}
function construct(element) {
  assert(implementation);

  return new implementation(element);
}
const Child = <div>Hello</div>

const Parent = () => <Child />
  updateComponent(prevElement, nextElement) {
  //...
    if (shouldUpdateComponent(prevRenderedElement, nextRenderedElement)) {
      Reconciler.receiveComponent(this._renderedComponent, nextRenderedElement);
  //...
  receiveComponent(nextElement) {
    this.updateComponent(this._currentElement, nextElement);
  }

  updateComponent(prevElement, nextElement) {
    // debugger;
    this._currentElement = nextElement;
    this._updateDOMProperties(prevElement.props, nextElement.props);
    this._updateDOMChildren(prevElement.props, nextElement.props);
  }
let renderedComponent = instantiateComponent(renderedElement);
this._renderedComponent = renderedComponent;
  let type = element.type;

  let wrapperInstance;
  if (typeof type === 'string') {
    wrapperInstance = HostComponent.construct(element);
  } else if (typeof type === 'function') {
    wrapperInstance = new element.type(element.props);
    wrapperInstance._construct(element);
  } else if (typeof element === 'string' || typeof element === 'number') {
    wrapperInstance = HostComponent.constructTextComponent(element);
  }

  return wrapperInstance;
HostComponent.inject(DOMComponentWrapper);
function inject(impl) {
  implementation = impl;
}
function construct(element) {
  assert(implementation);

  return new implementation(element);
}
const Child = <div>Hello</div>

const Parent = () => <Child />
  updateComponent(prevElement, nextElement) {
  //...
    if (shouldUpdateComponent(prevRenderedElement, nextRenderedElement)) {
      Reconciler.receiveComponent(this._renderedComponent, nextRenderedElement);
  //...
  receiveComponent(nextElement) {
    this.updateComponent(this._currentElement, nextElement);
  }

  updateComponent(prevElement, nextElement) {
    // debugger;
    this._currentElement = nextElement;
    this._updateDOMProperties(prevElement.props, nextElement.props);
    this._updateDOMChildren(prevElement.props, nextElement.props);
  }
let renderedComponent = instantiateComponent(renderedElement);
this._renderedComponent = renderedComponent;
  let type = element.type;

  let wrapperInstance;
  if (typeof type === 'string') {
    wrapperInstance = HostComponent.construct(element);
  } else if (typeof type === 'function') {
    wrapperInstance = new element.type(element.props);
    wrapperInstance._construct(element);
  } else if (typeof element === 'string' || typeof element === 'number') {
    wrapperInstance = HostComponent.constructTextComponent(element);
  }

  return wrapperInstance;
HostComponent.inject(DOMComponentWrapper);
function inject(impl) {
  implementation = impl;
}
function construct(element) {
  assert(implementation);

  return new implementation(element);
}
const Child = <div>Hello</div>

const Parent = () => <Child />
  updateComponent(prevElement, nextElement) {
  //...
    if (shouldUpdateComponent(prevRenderedElement, nextRenderedElement)) {
      Reconciler.receiveComponent(this._renderedComponent, nextRenderedElement);
  //...
  receiveComponent(nextElement) {
    this.updateComponent(this._currentElement, nextElement);
  }

  updateComponent(prevElement, nextElement) {
    // debugger;
    this._currentElement = nextElement;
    this._updateDOMProperties(prevElement.props, nextElement.props);
    this._updateDOMChildren(prevElement.props, nextElement.props);
  }
let renderedComponent = instantiateComponent(renderedElement);
this._renderedComponent = renderedComponent;
  let type = element.type;

  let wrapperInstance;
  if (typeof type === 'string') {
    wrapperInstance = HostComponent.construct(element);
  } else if (typeof type === 'function') {
    wrapperInstance = new element.type(element.props);
    wrapperInstance._construct(element);
  } else if (typeof element === 'string' || typeof element === 'number') {
    wrapperInstance = HostComponent.constructTextComponent(element);
  }

  return wrapperInstance;
HostComponent.inject(DOMComponentWrapper);
function inject(impl) {
  implementation = impl;
}
function construct(element) {
  assert(implementation);

  return new implementation(element);
}
const Child = <div>Hello</div>

const Parent = () => <Child />
  updateComponent(prevElement, nextElement) {
  //...
    if (shouldUpdateComponent(prevRenderedElement, nextRenderedElement)) {
      Reconciler.receiveComponent(this._renderedComponent, nextRenderedElement);
  //...
  receiveComponent(nextElement) {
    this.updateComponent(this._currentElement, nextElement);
  }

  updateComponent(prevElement, nextElement) {
    // debugger;
    this._currentElement = nextElement;
    this._updateDOMProperties(prevElement.props, nextElement.props);
    this._updateDOMChildren(prevElement.props, nextElement.props);
  }
let renderedComponent = instantiateComponent(renderedElement);
this._renderedComponent = renderedComponent;
  let type = element.type;

  let wrapperInstance;
  if (typeof type === 'string') {
    wrapperInstance = HostComponent.construct(element);
  } else if (typeof type === 'function') {
    wrapperInstance = new element.type(element.props);
    wrapperInstance._construct(element);
  } else if (typeof element === 'string' || typeof element === 'number') {
    wrapperInstance = HostComponent.constructTextComponent(element);
  }

  return wrapperInstance;
HostComponent.inject(DOMComponentWrapper);
function inject(impl) {
  implementation = impl;
}
function construct(element) {
  assert(implementation);

  return new implementation(element);
}
const Child = <div>Hello</div>

const Parent = () => <Child />
  updateComponent(prevElement, nextElement) {
  //...
    if (shouldUpdateComponent(prevRenderedElement, nextRenderedElement)) {
      Reconciler.receiveComponent(this._renderedComponent, nextRenderedElement);
  //...
  receiveComponent(nextElement) {
    this.updateComponent(this._currentElement, nextElement);
  }

  updateComponent(prevElement, nextElement) {
    // debugger;
    this._currentElement = nextElement;
    this._updateDOMProperties(prevElement.props, nextElement.props);
    this._updateDOMChildren(prevElement.props, nextElement.props);
  }
let renderedComponent = instantiateComponent(renderedElement);
this._renderedComponent = renderedComponent;
  let type = element.type;

  let wrapperInstance;
  if (typeof type === 'string') {
    wrapperInstance = HostComponent.construct(element);
  } else if (typeof type === 'function') {
    wrapperInstance = new element.type(element.props);
    wrapperInstance._construct(element);
  } else if (typeof element === 'string' || typeof element === 'number') {
    wrapperInstance = HostComponent.constructTextComponent(element);
  }

  return wrapperInstance;
HostComponent.inject(DOMComponentWrapper);
function inject(impl) {
  implementation = impl;
}
function construct(element) {
  assert(implementation);

  return new implementation(element);
}
const Child = <div>Hello</div>

const Parent = () => <Child />
  updateComponent(prevElement, nextElement) {
  //...
    if (shouldUpdateComponent(prevRenderedElement, nextRenderedElement)) {
      Reconciler.receiveComponent(this._renderedComponent, nextRenderedElement);
  //...
  receiveComponent(nextElement) {
    this.updateComponent(this._currentElement, nextElement);
  }

  updateComponent(prevElement, nextElement) {
    // debugger;
    this._currentElement = nextElement;
    this._updateDOMProperties(prevElement.props, nextElement.props);
    this._updateDOMChildren(prevElement.props, nextElement.props);
  }
let renderedComponent = instantiateComponent(renderedElement);
this._renderedComponent = renderedComponent;
  let type = element.type;

  let wrapperInstance;
  if (typeof type === 'string') {
    wrapperInstance = HostComponent.construct(element);
  } else if (typeof type === 'function') {
    wrapperInstance = new element.type(element.props);
    wrapperInstance._construct(element);
  } else if (typeof element === 'string' || typeof element === 'number') {
    wrapperInstance = HostComponent.constructTextComponent(element);
  }

  return wrapperInstance;
HostComponent.inject(DOMComponentWrapper);
function inject(impl) {
  implementation = impl;
}
function construct(element) {
  assert(implementation);

  return new implementation(element);
}
const Child = <div>Hello</div>

const Parent = () => <Child />
  updateComponent(prevElement, nextElement) {
  //...
    if (shouldUpdateComponent(prevRenderedElement, nextRenderedElement)) {
      Reconciler.receiveComponent(this._renderedComponent, nextRenderedElement);
  //...
  receiveComponent(nextElement) {
    this.updateComponent(this._currentElement, nextElement);
  }

  updateComponent(prevElement, nextElement) {
    // debugger;
    this._currentElement = nextElement;
    this._updateDOMProperties(prevElement.props, nextElement.props);
    this._updateDOMChildren(prevElement.props, nextElement.props);
  }
let renderedComponent = instantiateComponent(renderedElement);
this._renderedComponent = renderedComponent;
  let type = element.type;

  let wrapperInstance;
  if (typeof type === 'string') {
    wrapperInstance = HostComponent.construct(element);
  } else if (typeof type === 'function') {
    wrapperInstance = new element.type(element.props);
    wrapperInstance._construct(element);
  } else if (typeof element === 'string' || typeof element === 'number') {
    wrapperInstance = HostComponent.constructTextComponent(element);
  }

  return wrapperInstance;
HostComponent.inject(DOMComponentWrapper);
function inject(impl) {
  implementation = impl;
}
function construct(element) {
  assert(implementation);

  return new implementation(element);
}
const Child = <div>Hello</div>

const Parent = () => <Child />
function App() {
  return <div>
    <Parent>
      <Child01/>
      <Child01/>
    </Parent>
    <Child03/>
  </div>
}

function Parent({children}) {
  const [state, setState] = useState(0);

  return <div>
    <button onClick={x => x+1)>click</button>
    <Child02 />
    {children}
  </div>
}
node01 = { type: App, return: null, child: node02, sibling: null }
node02 = { type: 'div', return: node01, child: node03, sibling: null }
node03 = { type: Parent, return: node02, child: node05(?), sibling: node04 }
node04 = { type: Child03, return: node02, child: null, sibling: null }
node05 = { type: Child01, return: node03, child: null, sibling: node06 }
node06 = { type: Child01, return: node03, child: null, sibling: null }

// Parent will spawn its own FiberTree,
node10 = { type: 'div', return: node02, child: node11, sibling: null }
node11 = { type: 'button', return: node10, child: null, sibling: node12 }
node12 = { type: Child02, return: node10, child: null, sibling: node05 }
function App() {
  return <div>
    <Parent>
      <Child01/>
      <Child01/>
    </Parent>
    <Child03/>
  </div>
}

function Parent({children}) {
  const [state, setState] = useState(0);

  return <div>
    <button onClick={x => x+1)>click</button>
    <Child02 />
    {children}
  </div>
}
node01 = { type: App, return: null, child: node02, sibling: null }
node02 = { type: 'div', return: node01, child: node03, sibling: null }
node03 = { type: Parent, return: node02, child: node05(?), sibling: node04 }
node04 = { type: Child03, return: node02, child: null, sibling: null }
node05 = { type: Child01, return: node03, child: null, sibling: node06 }
node06 = { type: Child01, return: node03, child: null, sibling: null }

// Parent will spawn its own FiberTree,
node10 = { type: 'div', return: node02, child: node11, sibling: null }
node11 = { type: 'button', return: node10, child: null, sibling: node12 }
node12 = { type: Child02, return: node10, child: null, sibling: node05 }

JavaScript if/else statements are altering variables used as conditions in the same statements

copy iconCopydownload iconDownload
if (day = 0) // incorrect
if (day == 0) // correct

Is TMP really faster if the recusion depth is very deep?

copy iconCopydownload iconDownload
template <int N, int i>
struct sqrt {
    static const int val = (i*i <= N && (i + 1)*(i + 1) > N) ? i : sqrt<N, i - 1 >::val;
};
template <int N> struct val_identity { static const int val = N; };

template <int N, int i>
struct sqrt {
    static const int val =
        std::conditional_t<i * i <= N && N < (i + 1) * (i + 1),
                           val_identity<i>,
                           sqrt<N, i - 1 >
                          >::val;
};
template <int N, int i>
struct sqrt {
    static const int val = (i*i <= N && (i + 1)*(i + 1) > N) ? i : sqrt<N, i - 1 >::val;
};
template <int N> struct val_identity { static const int val = N; };

template <int N, int i>
struct sqrt {
    static const int val =
        std::conditional_t<i * i <= N && N < (i + 1) * (i + 1),
                           val_identity<i>,
                           sqrt<N, i - 1 >
                          >::val;
};

Measuring the distance between two lines using DipLib (PyDIP)

copy iconCopydownload iconDownload
import cv2
import numpy as np

img = cv2.imread("img.jpg")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
_, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)

x1, x2 = 0, img.shape[1] - 1
diff1, diff2 = np.diff(thresh[:, [x1, x2]].T, 1)
y1_1, y2_1 = np.where(diff1)[0][:2]
y1_2, y2_2 = np.where(diff2)[0][:2]

cv2.line(img, (x1, y1_1), (x2, y1_2), 0, 10)
cv2.line(img, (x1, y2_1), (x2, y2_2), 0, 10)

cv2.imshow("Image", img)
cv2.waitKey(0)
print(y1_2 - y1_1)
print(y2_2 - y2_1)
100
105
import cv2
import numpy as np

img = cv2.imread("img.jpg")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
_, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)

x1, x2 = 0, img.shape[1] - 1
diff1, diff2 = np.diff(thresh[:, [x1, x2]].T, 1)
y1_1, y2_1 = np.where(diff1)[0][:2]
y1_2, y2_2 = np.where(diff2)[0][:2]

cv2.line(img, (x1, y1_1), (x2, y1_2), 0, 10)
cv2.line(img, (x1, y2_1), (x2, y2_2), 0, 10)

cv2.imshow("Image", img)
cv2.waitKey(0)
print(y1_2 - y1_1)
print(y2_2 - y2_1)
100
105
import cv2
import numpy as np

img = cv2.imread("img.jpg")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
_, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)

x1, x2 = 0, img.shape[1] - 1
diff1, diff2 = np.diff(thresh[:, [x1, x2]].T, 1)
y1_1, y2_1 = np.where(diff1)[0][:2]
y1_2, y2_2 = np.where(diff2)[0][:2]

cv2.line(img, (x1, y1_1), (x2, y1_2), 0, 10)
cv2.line(img, (x1, y2_1), (x2, y2_2), 0, 10)

cv2.imshow("Image", img)
cv2.waitKey(0)
print(y1_2 - y1_1)
print(y2_2 - y2_1)
100
105
import diplib as dip
import numpy as np
import matplotlib.pyplot as pp

# load
img = dip.ImageRead('wDnU6.jpg') 
img = img(1)  # use green channel
img.SetPixelSize(0.042, "mm")

# find edges
edges = dip.GradientMagnitude(img)

# binarize
mask = dip.Threshold(edges)[0]
mask = dip.Dilation(mask, 9)  # we want the mask to include the "tails" of the Gaussian
mask = dip.AreaOpening(mask, filterSize=1000)  # remove small regions

# measure the two edges
mask = dip.Label(mask)
msr = dip.MeasurementTool.Measure(mask, edges, ['Gravity','GreyMajorAxes'])
# msr[n] is the measurements for object with ID n, if we have two objects, n can be 1 or 2.

# get distance between edges
center1 = np.array(msr[1]['Gravity'])
center2 = np.array(msr[2]['Gravity'])

normal1 = np.array(msr[1]['GreyMajorAxes'])[0:2]  # first axis is perpendicular to edge
normal2 = np.array(msr[2]['GreyMajorAxes'])[0:2]
normal = (normal1 + normal2) / 2  # we average the two normals, assuming the edges are parallel

distance = abs((center1 - center2) @ normal)
units = msr['Gravity'].Values()[0].units
print("Distance between lines:", distance, units)
Distance between lines: 21.491425398007312 mm
mmpp = img.PixelSize()[0].magnitude
center1 = center1 / mmpp  # position in pixels
center2 = center2 / mmpp
L = 1000
v = L * np.array([normal[1], -normal[0]])
img.Show()
pt1 = center1 - v
pt2 = center1 + v
pp.plot([pt1[0], pt2[0]], [pt1[1], pt2[1]])
pt1 = center2 - v
pt2 = center2 + v
pp.plot([pt1[0], pt2[0]], [pt1[1], pt2[1]])
mask = dip.Threshold(img)[0]
dt = dip.EuclideanDistanceTransform(mask, border='object')
width = 2 * np.amax(dt, axis=0)
width = width[100:-100]  # close to the image edges the distance could be off
print("Distance between lines:", np.mean(width), img.PixelSize()[0].units)
Distance between lines: 21.393684 mm
width_smooth = dip.Gauss(width, 100)
pp.plot(width)
pp.plot(width_smooth)
pp.show()
import diplib as dip
import numpy as np
import matplotlib.pyplot as pp

# load
img = dip.ImageRead('wDnU6.jpg') 
img = img(1)  # use green channel
img.SetPixelSize(0.042, "mm")

# find edges
edges = dip.GradientMagnitude(img)

# binarize
mask = dip.Threshold(edges)[0]
mask = dip.Dilation(mask, 9)  # we want the mask to include the "tails" of the Gaussian
mask = dip.AreaOpening(mask, filterSize=1000)  # remove small regions

# measure the two edges
mask = dip.Label(mask)
msr = dip.MeasurementTool.Measure(mask, edges, ['Gravity','GreyMajorAxes'])
# msr[n] is the measurements for object with ID n, if we have two objects, n can be 1 or 2.

# get distance between edges
center1 = np.array(msr[1]['Gravity'])
center2 = np.array(msr[2]['Gravity'])

normal1 = np.array(msr[1]['GreyMajorAxes'])[0:2]  # first axis is perpendicular to edge
normal2 = np.array(msr[2]['GreyMajorAxes'])[0:2]
normal = (normal1 + normal2) / 2  # we average the two normals, assuming the edges are parallel

distance = abs((center1 - center2) @ normal)
units = msr['Gravity'].Values()[0].units
print("Distance between lines:", distance, units)
Distance between lines: 21.491425398007312 mm
mmpp = img.PixelSize()[0].magnitude
center1 = center1 / mmpp  # position in pixels
center2 = center2 / mmpp
L = 1000
v = L * np.array([normal[1], -normal[0]])
img.Show()
pt1 = center1 - v
pt2 = center1 + v
pp.plot([pt1[0], pt2[0]], [pt1[1], pt2[1]])
pt1 = center2 - v
pt2 = center2 + v
pp.plot([pt1[0], pt2[0]], [pt1[1], pt2[1]])
mask = dip.Threshold(img)[0]
dt = dip.EuclideanDistanceTransform(mask, border='object')
width = 2 * np.amax(dt, axis=0)
width = width[100:-100]  # close to the image edges the distance could be off
print("Distance between lines:", np.mean(width), img.PixelSize()[0].units)
Distance between lines: 21.393684 mm
width_smooth = dip.Gauss(width, 100)
pp.plot(width)
pp.plot(width_smooth)
pp.show()
import diplib as dip
import numpy as np
import matplotlib.pyplot as pp

# load
img = dip.ImageRead('wDnU6.jpg') 
img = img(1)  # use green channel
img.SetPixelSize(0.042, "mm")

# find edges
edges = dip.GradientMagnitude(img)

# binarize
mask = dip.Threshold(edges)[0]
mask = dip.Dilation(mask, 9)  # we want the mask to include the "tails" of the Gaussian
mask = dip.AreaOpening(mask, filterSize=1000)  # remove small regions

# measure the two edges
mask = dip.Label(mask)
msr = dip.MeasurementTool.Measure(mask, edges, ['Gravity','GreyMajorAxes'])
# msr[n] is the measurements for object with ID n, if we have two objects, n can be 1 or 2.

# get distance between edges
center1 = np.array(msr[1]['Gravity'])
center2 = np.array(msr[2]['Gravity'])

normal1 = np.array(msr[1]['GreyMajorAxes'])[0:2]  # first axis is perpendicular to edge
normal2 = np.array(msr[2]['GreyMajorAxes'])[0:2]
normal = (normal1 + normal2) / 2  # we average the two normals, assuming the edges are parallel

distance = abs((center1 - center2) @ normal)
units = msr['Gravity'].Values()[0].units
print("Distance between lines:", distance, units)
Distance between lines: 21.491425398007312 mm
mmpp = img.PixelSize()[0].magnitude
center1 = center1 / mmpp  # position in pixels
center2 = center2 / mmpp
L = 1000
v = L * np.array([normal[1], -normal[0]])
img.Show()
pt1 = center1 - v
pt2 = center1 + v
pp.plot([pt1[0], pt2[0]], [pt1[1], pt2[1]])
pt1 = center2 - v
pt2 = center2 + v
pp.plot([pt1[0], pt2[0]], [pt1[1], pt2[1]])
mask = dip.Threshold(img)[0]
dt = dip.EuclideanDistanceTransform(mask, border='object')
width = 2 * np.amax(dt, axis=0)
width = width[100:-100]  # close to the image edges the distance could be off
print("Distance between lines:", np.mean(width), img.PixelSize()[0].units)
Distance between lines: 21.393684 mm
width_smooth = dip.Gauss(width, 100)
pp.plot(width)
pp.plot(width_smooth)
pp.show()
import diplib as dip
import numpy as np
import matplotlib.pyplot as pp

# load
img = dip.ImageRead('wDnU6.jpg') 
img = img(1)  # use green channel
img.SetPixelSize(0.042, "mm")

# find edges
edges = dip.GradientMagnitude(img)

# binarize
mask = dip.Threshold(edges)[0]
mask = dip.Dilation(mask, 9)  # we want the mask to include the "tails" of the Gaussian
mask = dip.AreaOpening(mask, filterSize=1000)  # remove small regions

# measure the two edges
mask = dip.Label(mask)
msr = dip.MeasurementTool.Measure(mask, edges, ['Gravity','GreyMajorAxes'])
# msr[n] is the measurements for object with ID n, if we have two objects, n can be 1 or 2.

# get distance between edges
center1 = np.array(msr[1]['Gravity'])
center2 = np.array(msr[2]['Gravity'])

normal1 = np.array(msr[1]['GreyMajorAxes'])[0:2]  # first axis is perpendicular to edge
normal2 = np.array(msr[2]['GreyMajorAxes'])[0:2]
normal = (normal1 + normal2) / 2  # we average the two normals, assuming the edges are parallel

distance = abs((center1 - center2) @ normal)
units = msr['Gravity'].Values()[0].units
print("Distance between lines:", distance, units)
Distance between lines: 21.491425398007312 mm
mmpp = img.PixelSize()[0].magnitude
center1 = center1 / mmpp  # position in pixels
center2 = center2 / mmpp
L = 1000
v = L * np.array([normal[1], -normal[0]])
img.Show()
pt1 = center1 - v
pt2 = center1 + v
pp.plot([pt1[0], pt2[0]], [pt1[1], pt2[1]])
pt1 = center2 - v
pt2 = center2 + v
pp.plot([pt1[0], pt2[0]], [pt1[1], pt2[1]])
mask = dip.Threshold(img)[0]
dt = dip.EuclideanDistanceTransform(mask, border='object')
width = 2 * np.amax(dt, axis=0)
width = width[100:-100]  # close to the image edges the distance could be off
print("Distance between lines:", np.mean(width), img.PixelSize()[0].units)
Distance between lines: 21.393684 mm
width_smooth = dip.Gauss(width, 100)
pp.plot(width)
pp.plot(width_smooth)
pp.show()
import diplib as dip
import numpy as np
import matplotlib.pyplot as pp

# load
img = dip.ImageRead('wDnU6.jpg') 
img = img(1)  # use green channel
img.SetPixelSize(0.042, "mm")

# find edges
edges = dip.GradientMagnitude(img)

# binarize
mask = dip.Threshold(edges)[0]
mask = dip.Dilation(mask, 9)  # we want the mask to include the "tails" of the Gaussian
mask = dip.AreaOpening(mask, filterSize=1000)  # remove small regions

# measure the two edges
mask = dip.Label(mask)
msr = dip.MeasurementTool.Measure(mask, edges, ['Gravity','GreyMajorAxes'])
# msr[n] is the measurements for object with ID n, if we have two objects, n can be 1 or 2.

# get distance between edges
center1 = np.array(msr[1]['Gravity'])
center2 = np.array(msr[2]['Gravity'])

normal1 = np.array(msr[1]['GreyMajorAxes'])[0:2]  # first axis is perpendicular to edge
normal2 = np.array(msr[2]['GreyMajorAxes'])[0:2]
normal = (normal1 + normal2) / 2  # we average the two normals, assuming the edges are parallel

distance = abs((center1 - center2) @ normal)
units = msr['Gravity'].Values()[0].units
print("Distance between lines:", distance, units)
Distance between lines: 21.491425398007312 mm
mmpp = img.PixelSize()[0].magnitude
center1 = center1 / mmpp  # position in pixels
center2 = center2 / mmpp
L = 1000
v = L * np.array([normal[1], -normal[0]])
img.Show()
pt1 = center1 - v
pt2 = center1 + v
pp.plot([pt1[0], pt2[0]], [pt1[1], pt2[1]])
pt1 = center2 - v
pt2 = center2 + v
pp.plot([pt1[0], pt2[0]], [pt1[1], pt2[1]])
mask = dip.Threshold(img)[0]
dt = dip.EuclideanDistanceTransform(mask, border='object')
width = 2 * np.amax(dt, axis=0)
width = width[100:-100]  # close to the image edges the distance could be off
print("Distance between lines:", np.mean(width), img.PixelSize()[0].units)
Distance between lines: 21.393684 mm
width_smooth = dip.Gauss(width, 100)
pp.plot(width)
pp.plot(width_smooth)
pp.show()
import diplib as dip
import numpy as np
import matplotlib.pyplot as pp

# load
img = dip.ImageRead('wDnU6.jpg') 
img = img(1)  # use green channel
img.SetPixelSize(0.042, "mm")

# find edges
edges = dip.GradientMagnitude(img)

# binarize
mask = dip.Threshold(edges)[0]
mask = dip.Dilation(mask, 9)  # we want the mask to include the "tails" of the Gaussian
mask = dip.AreaOpening(mask, filterSize=1000)  # remove small regions

# measure the two edges
mask = dip.Label(mask)
msr = dip.MeasurementTool.Measure(mask, edges, ['Gravity','GreyMajorAxes'])
# msr[n] is the measurements for object with ID n, if we have two objects, n can be 1 or 2.

# get distance between edges
center1 = np.array(msr[1]['Gravity'])
center2 = np.array(msr[2]['Gravity'])

normal1 = np.array(msr[1]['GreyMajorAxes'])[0:2]  # first axis is perpendicular to edge
normal2 = np.array(msr[2]['GreyMajorAxes'])[0:2]
normal = (normal1 + normal2) / 2  # we average the two normals, assuming the edges are parallel

distance = abs((center1 - center2) @ normal)
units = msr['Gravity'].Values()[0].units
print("Distance between lines:", distance, units)
Distance between lines: 21.491425398007312 mm
mmpp = img.PixelSize()[0].magnitude
center1 = center1 / mmpp  # position in pixels
center2 = center2 / mmpp
L = 1000
v = L * np.array([normal[1], -normal[0]])
img.Show()
pt1 = center1 - v
pt2 = center1 + v
pp.plot([pt1[0], pt2[0]], [pt1[1], pt2[1]])
pt1 = center2 - v
pt2 = center2 + v
pp.plot([pt1[0], pt2[0]], [pt1[1], pt2[1]])
mask = dip.Threshold(img)[0]
dt = dip.EuclideanDistanceTransform(mask, border='object')
width = 2 * np.amax(dt, axis=0)
width = width[100:-100]  # close to the image edges the distance could be off
print("Distance between lines:", np.mean(width), img.PixelSize()[0].units)
Distance between lines: 21.393684 mm
width_smooth = dip.Gauss(width, 100)
pp.plot(width)
pp.plot(width_smooth)
pp.show()
import diplib as dip
import numpy as np
import matplotlib.pyplot as pp

# load
img = dip.ImageRead('wDnU6.jpg') 
img = img(1)  # use green channel
img.SetPixelSize(0.042, "mm")

# find edges
edges = dip.GradientMagnitude(img)

# binarize
mask = dip.Threshold(edges)[0]
mask = dip.Dilation(mask, 9)  # we want the mask to include the "tails" of the Gaussian
mask = dip.AreaOpening(mask, filterSize=1000)  # remove small regions

# measure the two edges
mask = dip.Label(mask)
msr = dip.MeasurementTool.Measure(mask, edges, ['Gravity','GreyMajorAxes'])
# msr[n] is the measurements for object with ID n, if we have two objects, n can be 1 or 2.

# get distance between edges
center1 = np.array(msr[1]['Gravity'])
center2 = np.array(msr[2]['Gravity'])

normal1 = np.array(msr[1]['GreyMajorAxes'])[0:2]  # first axis is perpendicular to edge
normal2 = np.array(msr[2]['GreyMajorAxes'])[0:2]
normal = (normal1 + normal2) / 2  # we average the two normals, assuming the edges are parallel

distance = abs((center1 - center2) @ normal)
units = msr['Gravity'].Values()[0].units
print("Distance between lines:", distance, units)
Distance between lines: 21.491425398007312 mm
mmpp = img.PixelSize()[0].magnitude
center1 = center1 / mmpp  # position in pixels
center2 = center2 / mmpp
L = 1000
v = L * np.array([normal[1], -normal[0]])
img.Show()
pt1 = center1 - v
pt2 = center1 + v
pp.plot([pt1[0], pt2[0]], [pt1[1], pt2[1]])
pt1 = center2 - v
pt2 = center2 + v
pp.plot([pt1[0], pt2[0]], [pt1[1], pt2[1]])
mask = dip.Threshold(img)[0]
dt = dip.EuclideanDistanceTransform(mask, border='object')
width = 2 * np.amax(dt, axis=0)
width = width[100:-100]  # close to the image edges the distance could be off
print("Distance between lines:", np.mean(width), img.PixelSize()[0].units)
Distance between lines: 21.393684 mm
width_smooth = dip.Gauss(width, 100)
pp.plot(width)
pp.plot(width_smooth)
pp.show()

Language browser detection and action rewrite

copy iconCopydownload iconDownload
RewriteEngine On

# external redirect from actual URL to pretty one
RewriteCond %{THE_REQUEST} /(?:index\.php)?\?lang=([^\s&]+)&action=([^\s&]+)\s [NC]
RewriteRule ^ /%1/%2? [R=301,L,NE]

# add default language prefix
RewriteCond %{HTTP:Accept-Language} ^([a-z]{2})- [NC]
RewriteRule ^(?![a-z]{2}/)[^/]*/?$ /%1%{REQUEST_URI} [L,R=301,NE]

# internal forward from pretty URL to actual one
RewriteRule ^([a-z]+)/([\w-]+)/?$ index.php?lang=$1&action=$2 [L,QSA,NC]

Rust traits with constant field defined by implementation

copy iconCopydownload iconDownload
trait MyTrait {
    const MY_CONST: u8;
    fn foo();
    fn bar();
}

struct MyFirstStruct;

impl MyTrait for MyFirstStruct {
    const MY_CONST: u8 = 42;
    fn foo() {}
    fn bar() {}
}

How does clang check redefinitions?

copy iconCopydownload iconDownload
/* file_1.c */
int a = 123;

/* file_2.c */
int a = 456;
% clang file_*
...
ld: 1 duplicate symbol
clang: error: linker command failed with exit code 1
/* file.c */
int main(){
  int b;
  int b=1;
}
# ---
# GCC (gcc version 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04))
# ---
$ gcc file.c 
file.c: In function ‘main’:
file.c:4:6: error: redeclaration of ‘b’ with no linkage
  int b=1;
      ^
file.c:3:6: note: previous declaration of ‘b’ was here
  int b;
      ^


# ---
# CLANG  (Apple clang version 13.0.0 (clang-1300.0.29.3))
# ---
% clang file.c 
file.c:4:6: error: redefinition of 'b'
 int b;
     ^
file.c:3:6: note: previous definition is here
 int b=1;
     ^
1 error generated.

/* file_1.c */
int a = 123;

/* file_2.c */
int a = 456;
% clang file_*
...
ld: 1 duplicate symbol
clang: error: linker command failed with exit code 1
/* file.c */
int main(){
  int b;
  int b=1;
}
# ---
# GCC (gcc version 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04))
# ---
$ gcc file.c 
file.c: In function ‘main’:
file.c:4:6: error: redeclaration of ‘b’ with no linkage
  int b=1;
      ^
file.c:3:6: note: previous declaration of ‘b’ was here
  int b;
      ^


# ---
# CLANG  (Apple clang version 13.0.0 (clang-1300.0.29.3))
# ---
% clang file.c 
file.c:4:6: error: redefinition of 'b'
 int b;
     ^
file.c:3:6: note: previous definition is here
 int b=1;
     ^
1 error generated.

/* file_1.c */
int a = 123;

/* file_2.c */
int a = 456;
% clang file_*
...
ld: 1 duplicate symbol
clang: error: linker command failed with exit code 1
/* file.c */
int main(){
  int b;
  int b=1;
}
# ---
# GCC (gcc version 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04))
# ---
$ gcc file.c 
file.c: In function ‘main’:
file.c:4:6: error: redeclaration of ‘b’ with no linkage
  int b=1;
      ^
file.c:3:6: note: previous declaration of ‘b’ was here
  int b;
      ^


# ---
# CLANG  (Apple clang version 13.0.0 (clang-1300.0.29.3))
# ---
% clang file.c 
file.c:4:6: error: redefinition of 'b'
 int b;
     ^
file.c:3:6: note: previous definition is here
 int b=1;
     ^
1 error generated.

/* file_1.c */
int a = 123;

/* file_2.c */
int a = 456;
% clang file_*
...
ld: 1 duplicate symbol
clang: error: linker command failed with exit code 1
/* file.c */
int main(){
  int b;
  int b=1;
}
# ---
# GCC (gcc version 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04))
# ---
$ gcc file.c 
file.c: In function ‘main’:
file.c:4:6: error: redeclaration of ‘b’ with no linkage
  int b=1;
      ^
file.c:3:6: note: previous declaration of ‘b’ was here
  int b;
      ^


# ---
# CLANG  (Apple clang version 13.0.0 (clang-1300.0.29.3))
# ---
% clang file.c 
file.c:4:6: error: redefinition of 'b'
 int b;
     ^
file.c:3:6: note: previous definition is here
 int b=1;
     ^
1 error generated.

Community Discussions

Trending Discussions on dive
  • type deduction for std::function argument types with auto adds const
  • ShouldProcess failing in PowerShell7
  • how to skip json validation for an empty array via Golang
  • Flag provided but not defined: -rpc
  • Split text into smaller paragraphs of a minimal length without breaking the sentences given a threshold
  • How does React update a component and its children after a state change?
  • JavaScript if/else statements are altering variables used as conditions in the same statements
  • Is TMP really faster if the recusion depth is very deep?
  • Measuring the distance between two lines using DipLib (PyDIP)
  • Language browser detection and action rewrite
Trending Discussions on dive

QUESTION

type deduction for std::function argument types with auto adds const

Asked 2022-Apr-08 at 14:31

I have a struct with a method called call which has a const overload. The one and only argument is a std::function which either takes a int reference or a const int reference, depending on the overload.

The genericCall method does exactly the same thing but uses a template parameter instead of a std::function as type.

struct SomeStruct {
    int someMember = 666;

    void call(std::function<void(int&)> f) & {
        f(someMember);
        std::cout << "call: non const\n";
    }

    void call(std::function<void(const int&)> f) const& {
        f(someMember);
        std::cout << "call: const\n";
    }


    template <typename Functor>
    void genericCall(Functor f) & {
        f(someMember);
        std::cout << "genericCall: non const\n";
    }

    template <typename Functor>
    void genericCall(Functor f) const& {
        f(someMember);
        std::cout << "genericCall: const\n";
    }
};

When I now create this struct and call call with a lambda and auto & as argument the std::function always deduces a const int & despite the object not being const.

The genericCall on the other hand deduces the argument correctly as int & inside the lamdba.

SomeStruct some;
some.call([](auto& i) {
    i++;  // ?? why does auto deduce it as const int & ??
});
some.genericCall([](auto& i) {
    i++;  // auto deduces it correctly as int &
});

I have no the slightest clue why auto behaves in those two cases differently or why std::function seems to prefer to make the argument const here. This causes a compile error despite the correct method is called. When I change the argument from auto & to int & everything works fine again.

some.call([](int& i) {
    i++; 
});

When I do the same call with a const version of the struct everything is deduced as expected. Both call and genericCall deduce a const int & here.

const SomeStruct constSome;
constSome.call([](auto& i) {
    // auto deduces correctly const int & and therefore it should
    // not compile
    i++;
});
constSome.genericCall([](auto& i) {
    // auto deduces correctly const int & and therefore it should
    // not compile
    i++;
});

If someone could shine some light on this I would be very grateful!

For the more curious ones who want to dive even deeper, this problem arose in the pull request: https://github.com/eclipse-iceoryx/iceoryx/pull/1324 while implementing a functional interface for an expected implementation.

ANSWER

Answered 2022-Apr-08 at 13:25

The problem is that generic lambdas (auto param) are equivalent to a callable object whose operator() is templated. This means that the actual type of the lambda argument is not contained in the lambda, and only deduced when the lambda is invoked.

However in your case, by having specific std::function arguments, you force a conversion to a concrete type before the lambda is invoked, so there is no way to deduce the auto type from anything. There is no SFINAE in a non-template context.

With no specific argument type, both your call are valid overloads. Actually any std::function that can match an [](auto&) is valid. Now the only rule is probably that the most cv-qualified overload wins. You can try with a volatile float& and you will see it will still choose that. Once it choose this overload, the compilation will fail when trying to invoke.

Source https://stackoverflow.com/questions/71797023

Community Discussions, Code Snippets contain sources that include Stack Exchange Network

Vulnerabilities

No vulnerabilities reported

Install dive

Available as dive in the Arch User Repository (AUR). The above example assumes yay as the tool for installing AUR packages.

Support

For any new features, suggestions and bugs create an issue on GitHub. If you have any questions check and ask questions on community page Stack Overflow .

DOWNLOAD this Library from

Find, review, and download reusable Libraries, Code Snippets, Cloud APIs from
over 430 million Knowledge Items
Find more libraries
Reuse Solution Kits and Libraries Curated by Popular Use Cases
Explore Kits

Save this library and start creating your kit

Share this Page

share link
Consider Popular Continuous Deployment Libraries
Try Top Libraries by wagoodman
Compare Continuous Deployment Libraries with Highest Support
Compare Continuous Deployment Libraries with Highest Quality
Compare Continuous Deployment Libraries with Highest Security
Compare Continuous Deployment Libraries with Permissive License
Compare Continuous Deployment Libraries with Highest Reuse
Find, review, and download reusable Libraries, Code Snippets, Cloud APIs from
over 430 million Knowledge Items
Find more libraries
Reuse Solution Kits and Libraries Curated by Popular Use Cases
Explore Kits

Save this library and start creating your kit

  • © 2022 Open Weaver Inc.