How to make multiple objects work at same time? - python-3.x

I have been using Python to control some instruments, which I created a Class for. I have multiple instruments of the same kind, so my script has multiple instances of the same class.
Let's say the class is Arm, and it has methods move_left, move_right and reset. Right now I have script like this:
arm1 = Arm()
arm2 = Arm()
arm1.move_left()
arm2.move_left()
arm1.move_right()
arm2.move_right()
arm1.reset()
arm2.reset()
It's completely in serial. I have to wait for arm1 to finish move_left, then start arm2 to move_left. This is very inefficient. I would like arm1 and arm2 to move at the same time. They don't have to be exact same time, because arm1 and arm2 are quite independent and there's not much synchronization requirement. I just don't want to waste time in the serialization in the code.
I've done some searching and learned a little about threading, but what I found is all about putting a function in a Thread target, which doesn't really apply to my situation here.

One way to approach the problem would be to implement a state machine. That is, instead of defining the problem through commands like move_left() and move_right(), instead you can have some variables that represent the final position that you want each arm to end up at, and a second set of variables that represent the current position of the arm. Then at each time-step, you simply move the arms by a small amount towards their target-destination.
Here's a very simple toy program to demonstrate the idea. Note that it moves each "arm" by no more than 0.1 units every 100mS time-step (you can of course use any time-step and maximum-movement values you want instead):
import time
class Robot:
def __init__(self):
self._leftArmCurrentPos = 0.0
self._leftArmTargetPos = 0.0
self._rightArmCurrentPos = 0.0
self._rightArmTargetPos = 0.0
def setLeftArmTargetPos(self, newPos):
self._leftArmTargetPos = newPos
def setRightArmTargetPos(self, newPos):
self._rightArmTargetPos = newPos
# Returns the closest value to (deltaVal) in the range [-0.1, +0.1]
def clamp(self, deltaVal):
aLittleBit = 0.1 # or however much you want
if (deltaVal > aLittleBit):
return aLittleBit
elif (deltaVal < -aLittleBit):
return -aLittleBit
else:
return deltaVal
def moveArmsTowardsTargetPositions(self):
leftArmDelta = self.clamp(self._leftArmTargetPos - self._leftArmCurrentPos)
if (leftArmDelta != 0.0):
self._leftArmCurrentPos += leftArmDelta
print("Moved left arm by %f towards %f, new left arm pos is %f" % (leftArmDelta, self._leftArmTargetPos, self._leftArmCurrentPos))
rightArmDelta = self.clamp(self._rightArmTargetPos - self._rightArmCurrentPos)
if (rightArmDelta != 0.0):
self._rightArmCurrentPos += rightArmDelta
print("Moved right arm by %f towards %f, new right arm pos is %f" % (rightArmDelta, self._rightArmTargetPos, self._rightArmCurrentPos))
if __name__ == "__main__":
r = Robot()
r.setLeftArmTargetPos(10.0)
r.setRightArmTargetPos(-3.0)
while True:
r.moveArmsTowardsTargetPositions()
time.sleep(0.1)
A nice side-effect of this approach is that you if change your mind at any time about where you want the arms to be, you can simply call setLeftArmTargetPos() or setRightArmTargetPos() to give the arms new/different destination values, and they will immediately start moving from (wherever they currently are at) towards the new target positions -- there's no need to wait for them to arrive at the old destinations first.

Related

Pyqtgraph ROI Mirrors the Displayed Text

I want to display some text close to the handles of crosshair ROI. The text is mirrored and I don't know why or how to fix it.
The following code runs, where the class CrossHair is a slight modification of the CrosshairROI given at https://pyqtgraph.readthedocs.io/en/latest/_modules/pyqtgraph/graphicsItems/ROI.html#ROI. More precisely, all I did was setting lock aspect to be False and making another handle to deal with another direction.
import pyqtgraph as pg
from PyQt5.QtWidgets import*
from PyQt5.QtCore import*
from PyQt5.QtGui import*
class MainWindow(pg.GraphicsLayoutWidget):
def __init__(self):
super().__init__()
layout = self.addLayout()
self.viewbox = layout.addViewBox(lockAspect=True)
self.viewbox.setLimits(minXRange = 200, minYRange = 200,maxXRange = 200,maxYRange = 200)
self.crosshair = CrossHair()
self.crosshair.setPen(pg.mkPen("w", width=5))
self.viewbox.addItem(self.crosshair)
class CrossHair(pg.graphicsItems.ROI.ROI):
def __init__(self, pos=None, size=None, **kargs):
if size is None:
size=[50,50]
if pos is None:
pos = [0,0]
self._shape = None
pg.graphicsItems.ROI.ROI.__init__(self, pos, size, **kargs)
self.sigRegionChanged.connect(self.invalidate)
self.addScaleRotateHandle(pos = pg.Point(1,0), center = pg.Point(0, 0))
self.addScaleRotateHandle(pos = pg.Point(0,1), center = pg.Point(0,0))
def invalidate(self):
self._shape = None
self.prepareGeometryChange()
def boundingRect(self):
return self.shape().boundingRect()
def shape(self):
if self._shape is None:
x_radius, y_radius = self.getState()['size'][0],self.getState()['size'][1]
p = QPainterPath()
p.moveTo(pg.Point(-x_radius, 0))
p.lineTo(pg.Point(x_radius, 0))
p.moveTo(pg.Point(0, -y_radius))
p.lineTo(pg.Point(0, y_radius))
p = self.mapToDevice(p)
stroker = QPainterPathStroker()
stroker.setWidth(10)
outline = stroker.createStroke(p)
self._shape = self.mapFromDevice(outline)
return self._shape
def paint(self, p, *args):
x_radius, y_radius = self.getState()['size'][0],self.getState()['size'][1]
p.setRenderHint(QPainter.RenderHint.Antialiasing)
p.setPen(self.currentPen)
p.drawLine(pg.Point(0, -y_radius), pg.Point(0, y_radius))
p.drawLine(pg.Point(-x_radius, 0), pg.Point(x_radius, 0))
x_pos, y_pos = self.handles[0]['item'].pos(), self.handles[1]['item'].pos()
x_length, y_length = 2*x_radius, 2*y_radius
x_text, y_text = str(round(x_length,2)) + "TEXT",str(round(y_length,2)) + "TEXT"
p.drawText(QRectF(x_pos.x()-50, x_pos.y()-50, 100, 100), Qt.AlignmentFlag.AlignLeft, x_text)
p.drawText(QRectF(y_pos.x()-50, y_pos.y()-50, 100, 100), Qt.AlignmentFlag.AlignBottom, y_text)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
main = MainWindow()
main.show()
app.exec()
We see that:
The objective is to fix the above code such that:
It displays texts dependent on the length of the line (2*radius) close to each handle without reflecting.
The text is aligned close to the handle such that no matter how the user rotates the handle the text is readable (i.e. not upside down).
I am having great deal of trouble with the first part. The second part can probably be fixed by changing aligning policies but I don't know which one to choose .
The reason of the inversion is because the coordinate system of pyqtgraph is always vertically inverted: similarly to the standard convention of computer coordinates, the reference point in Qt is always considered at the top left of positive coordinates, with y > 0 going down instead of up.
While, for general computer based imaging this is fine, it clearly doesn't work well for data imaging that is commonly based on standard Cartesian references (positive values of y are always "above"). And that's what pyqtgraph does by default.
The result is that, for obvious reasons, basic drawing that is directly done on an active QPainter will always be vertically inverted ("mirrored"). What you show in the image is the result of a composition of vertical mirroring and rotation, which is exactly the same as horizontal mirroring.
To simplify: when p is vertically mirrored, it becomes b, which, when rotated by 180°, results in q.
There's also another issue: all pyqtgraph items are actually QGraphicsItem subclasses, and one of the most important aspects of QGraphicsItems is that their painting is and shall always be restricted by its boundingRect():
[...] all painting must be restricted to inside an item's bounding rect. QGraphicsView uses this to determine whether the item requires redrawing.
If you try to move the handles very fast, you'll probably see some drawing artifacts ("ghosts") in the text caused by the painting buffer that is used to improve drawing performance, and that's because you didn't consider those elements in the boundingRect() override: the painting engine didn't know that the bounding rect was actually bigger, and didn't consider that the previously drawn regions required repainting in order to "clear up" the previous content.
Now, since those are text displaying objects, I doubt that you're actually interested in having them always aligned to their respective axis (which is not impossible, but much more difficult). You will probably want to always display the values of those handles to the user in an easy, readable way: horizontally.
Considering the above, the preferred solution is to use child items for the text instead of manually drawing it. While, at first sight, it might seem a risk for performance and further complication, it actually ensures 2 aspects:
the text items will always be properly repainted, and without any "ghost residue" caused by the wrong bounding rect;
the performance loss is practically little to none, since item management (including painting) is completely done on the C++ side;
For that, I'd suggest the pg.TextItem class, which will also completely ignore any kind of transformation, ensuring that the text will always be visible no matter of the scale factor.
Note that "mirroring" is actually the result of a transformation matrix that uses negative scaling: a scaling of (0, -1) means that the coordinates are vertically mirrored. If you think about it, it's quite obvious: if you have a positive y value in a cartesian system (shown "above" the horizontal axis) and multiply it by -1, that result is then shown "below".
Given the above, what you need to do is to add the two "labels" as children of the handle items, and just worry about painting the two crosshair lines.
Finally, due to the general performance requirements of pyqtgraph (and QGraphicsView in general), in the following example I took the liberty to make some modifications to the original code in order to improve responsiveness:
class CrossHair(pg.graphicsItems.ROI.ROI):
_shape = None
def __init__(self, pos=None, size=None, **kargs):
if size is None:
size = [50, 50]
if pos is None:
pos = [0, 0]
super().__init__(pos, size, **kargs)
self.sigRegionChanged.connect(self.invalidate)
font = QFont()
font.setPointSize(font.pointSize() * 2)
self.handleLabels = []
for refPoint in (QPoint(1, 0), QPoint(0, 1)):
handle = self.addScaleRotateHandle(pos=refPoint, center=pg.Point())
handle.xChanged.connect(self.updateHandleLabels)
handle.yChanged.connect(self.updateHandleLabels)
handleLabel = pg.TextItem(color=self.currentPen.color())
handleLabel.setParentItem(handle)
handleLabel.setFont(font)
self.handleLabels.append(handleLabel)
self.updateHandleLabels()
def updateHandleLabels(self):
for label, value in zip(self.handleLabels, self.state['size']):
label.setText(format(value * 2, '.2f'))
def invalidate(self):
self._shape = None
self.prepareGeometryChange()
def boundingRect(self):
return self.shape().boundingRect()
def shape(self):
if self._shape is None:
x_radius, y_radius = self.state['size']
p = QPainterPath(QPointF(-x_radius, 0))
p.lineTo(QPointF(x_radius, 0))
p.moveTo(QPointF(0, -y_radius))
p.lineTo(QPointF(0, y_radius))
p = self.mapToDevice(p)
stroker = QPainterPathStroker()
stroker.setWidth(10)
outline = stroker.createStroke(p)
self._shape = self.mapFromDevice(outline)
return self._shape
def paint(self, p, *args):
p.setRenderHint(QPainter.Antialiasing)
p.setPen(self.currentPen)
x_radius, y_radius = self.state['size']
p.drawLine(QPointF(0, -y_radius), QPointF(0, y_radius))
p.drawLine(QPointF(-x_radius, 0), QPointF(x_radius, 0))
Notes:
pg.Point is actually a subclass of QPointF; unlike helper functions like mkColor() that can be actually necessary for pg objects and are effective in their simplicity/readability, there is really no point (pun intended) to use those subclasses for basic Qt functions, like you're doing for paintEvent(); just use the basic class;
considering the point above, always try to leave object conversion on the C++ side; QPainterPath's moveTo and lineTo always accept floating point values (they are overloaded functions that internally transform the values to QPointF objects); on the other hand, QPainter functions like drawLine only accept individual numeric values as integers (that's why I used QPointF in paintEvent()), so in that case you cannot directly use the coordinate values; always look for the C++ implementation and the accepted value types;
self.getState()['size'] is already a two-item tuple (width and height), retrieving it twice is unnecessary; also, since getState() actually recalls the internal self.state dict, you can avoid the function call (as I did above) as long as getState() is not overridden by a custom subclass;

Python - Iterate over while loop to compile an average runtime of program

So I want to preface this by saying one of the biggest problems with this I'm assuming is the return section of this code. With that being said, exactly what I'm trying to do is based off of my previous question for this code which was answered in two different ways, one said to be faster than the other. I wanted to see just how much faster myself by comparing the numbers. The problem I am now having though is that I would like to iterate over this function X amount of times, take the runtimes for each of those executions of the code, compile them, and create an average so I can then do the same with the other proposed solution, and compare the two. The main answer or help I'm currently looking for is getting this to iterate so I can have X different runtimes available to be seen. After that I will try to figure out how to compile them on my own, unless someone would be kind enough to help me through this entire process in one go.
import time
start_time = time.time()
def fibonacci():
previous_num, result = 0, 1
user = 1000
iterations = 10
while len(str(result)) < user:
while iterations != 0:
iterations -= 1
previous_num, result = result, previous_num + result
print(iterations)
return result
print(fibonacci())
print("--- %s seconds ---" % (time.time() - start_time))

Python 3: 'multiprocessing' and 'time' module incompatibility?

I use a multiprocessing.Pool().imap_unordered(...) to perform some tasks in parallel and measure the time it takes by calculating the difference of time.time() before and after starting the pool tasks.
However, it returns wrong results! When I watch my wall clock while the program runs, it tells me a run time of around 5 seconds. But the program itself outputs a run time of only 0.1 seconds.
I also have a variant of this code without any multiprocessing which takes double the time, but outputs the correct run times.
Here is my code:
if __name__ == "__main__":
n = int(input("How many grids to create? "))
use_multiprocessing = None
while use_multiprocessing is None:
answer = input("Use multiprocessing to speed things up? (Y/n) ").strip().lower()
if len(answer) == 1 and answer in "yn":
use_multiprocessing = True if answer == "y" else False
t0 = time.time()
if use_multiprocessing:
processes = cpu_count()
worker_pool = Pool(processes)
print("Creating {} sudokus using {} processes. Please wait...".format(n, processes))
sudokus = worker_pool.imap_unordered(create_sudoku, range(n), n // processes + 1)
else:
progress_bar, progress_bar_length = 0, 10
sudokus = []
print("Creating {} sudokus".format(n), end="", flush=True)
for i in range(n):
p = int((i / n) * progress_bar_length)
if p > progress_bar:
print("." * (p-progress_bar), end="", flush=True)
progress_bar = p
new_sudoku = create_sudoku()
sudokus.append(new_sudoku)
t = time.time() - t0
l = len(list(sudokus))
print("\nSuccessfully created {} grids in {:.6f}s (average {:.3f}ms per grid)!".format(
l, t, 1000*t/l
))
And here an example run, which took around 5-6 seconds in reality (after entering the number of grids to create and whether to use multiprocessing, of course):
How many grids to create? 100000
Use multiprocessing to speed things up? (Y/n) y
Creating 100000 sudokus using 4 processes. Please wait...
Successfully created 100000 grids in 0.122141s (average 0.001ms per grid)!
Process finished with exit code 0
Are multiprocessing and time.time() incompatible? I've heard that time.clock() can make problems under these circumstances, but I thought time.time() should be safe. Or is there any other problem?
I figured it out.
Pool.imap_unordered(...) returns a generator and no list. That means, its elements are not already created when the method finishes, but only as soon as I access them.
I did this in the line l = len(list(sudokus)), where I converted the generator into a list to get the length. And the finish time got measured one line before that, so it correctly reported the time it took to initialize the generator. This was not what I want, so swapping those two lines results in correct times.
I know I may not convert a generator into a list just to find out the length and then discard the list again. I must either rely on the saved requested length if I want a generator, or I must use Pool.map(...) instead which produces a list and blocks until it's ready.

Heron method in Python

Heron's method generates a sequence of numbers that represent better and better approximations for √n. The first number in the sequence is an arbitrary guess; every other number in the sequence is obtained from the previous number prev using the formula:
(1/2)*(prev+n/prev)
I am supposed to write a function heron() that takes as input two numbers: n and error. The function should start with an initial guess of 1.0 for √n and then repeatedly generate better approximations until the difference (more precisely, the absolute value of the difference) between successive approximations is at most error.
usage:
>>> heron(4.0, 0.5)
2.05
>>> heron(4.0, 0.1)
2.000609756097561
this is a bit tricky, but I will need to keep track of four variables:
# n, error, prev and current
I will also need a while loop with the condition:
((current - prev) > error):
A general rule for the while loop is that:
# old current goes into new prev
So this is what I got so far, it's not much because to start with I don't know how to incorporate the 'if' statement under the while loop.
def heron(n, error):
guess = 1
current = 1
prev = 0
while (current - prev) > error:
previous==1/2*(guess+n/guess):
print (previous) # just a simple print statement
# in order to see what i have so far
Can someone give me a few pointers in the right direction please?
thank you
If you don't want to use generators then the simplest would be:
def heron(n, error):
prev, new = 1.0, 0.5 * (1 + n)
while abs(new - prev) > error:
prev, new = new, 0.5 * (new + n/new)
return new
You can also generate an "infinite" sequence of heron numbers:
def heron(n):
prev = 1.0
yield prev, float('inf')
while True:
new = 0.5 * (prev + n/prev)
error = new - prev
yield new, error
prev = new
Now you can print so many numbers as you like, for example:
list(islice(heron(2), 3)) # First 3 numbers and associated errors
Generate as long as the error is greater than 0.01:
list(takewhile(lambda x:x[1] > 0.01, heron(2)))
Just to build on #elyase's answer, here's how you would get the arbitrary precision square root from the heron number generator they have provided. (the generator just gives the next number in the heron sequence)
def heron(n): ### posted by elyase
a = 1.0
yield a
while True:
a = 0.5 * (a + n/a)
yield a
def sqrt_heron(n, err):
g = heron(n)
prev = g.next()
current = g.next()
while( (prev - current) > err):
prev = current
current = g.next()
print current, prev
return current
print sqrt_heron(169.0,0.1)
Aside from python syntax, the thing that may be messing you up is that you need two guesses calculated from your initial guess to get started, and you compare how far apart these two guesses are. The while condition should be (prev - current) > err not (current - prev) > err since we expect the previous guess to be closer to the square (and therefore larger) than the current guess which should be closer to the square root. Since the initial guess could be any positive number, we need to calculate two iterations from it, to ensure that current will be less than prev.
The other answers up as I write this are using a Python generator function. I love generators but those are overkill for this simple problem. Below, solutions with simple while loops.
Comments below the code. heron0() is what you asked for; heron() is my suggested version.
def heron0(n, error):
guess = 1.0
prev = 0.0
while (guess - prev) > error:
prev = guess
guess = 0.5*(guess+n/guess)
print("DEBUG: New guess: %f" % guess)
return guess
def _close_enough(guess, n, allowed_error):
low = n - allowed_error
high = n + allowed_error
return low <= guess**2 <= high
def heron(n, allowed_error):
guess = 1.0
while not _close_enough(guess, n, allowed_error):
guess = 0.5*(guess+n/guess)
print("DEBUG: New guess: %f" % guess)
return guess
print("Result: %f" % heron0(4, 1e-6))
print("Result: %f" % heron(4, 1e-6))
Comments:
You don't really need both guess and current. You can use guess to hold the current guess.
I don't know why you were asking about putting an if statement in the while loop. In the first place, it is easy: you just put it in, and indent the statement(s) that are under the if. In the second place, this problem doesn't need it.
It's easy and fast to detect whether guess is close to prev. But I think for numerical accuracy, it would be better to directly test how good a square root guess actually is. So, square the value of guess and see if that is close to n. See how in Python it is legal to test whether a value is, at the same time, greater than or equal to a lower value and also less than or equal to a high value. (The alternate way to check: abs(n - guess**2) <= allowed_error)
In Python 2.x, if you divide an integer by an integer you will probably get an integer result. Thus 1/2 can very possibly have a result of 0. There are a couple of ways to fix that, or you can run your program in Python 3.x which guarantees that 1/2 returns 0.5, but it's simple to make your starting value for guess be a floating-point number.
I think this meets your requirements (note: I wrote it with python 2.7.10): it doesn't assume a guess of 1 and it takes takes 'num' and 'tolerance' as arguments for 'n' and 'error'. Also, it doesn't use variables "prev" and "current" or a while loop - are those part of your requirements, or your thoughts regarding a solution?
def heron(num, guess, tolerance):
if guess**2 != num:
##print "guess =", guess
if abs(float(num) - float(guess)**2) > float(tolerance):
avg_guess = 0.5 * (float(guess) + (float(num) / float(guess)))
return heron(num, avg_guess, tolerance)
print "Given your tolerance, this is Heron's best guess:", guess
else:
print guess, "is correct!"
Uncomment the print cmd if you want to see the progression of guesses.
I was dealing with the same problem and not many tools to solve it since my knowledge in Python is very limited.
I came up with this solution that is not very elegant nor advanced, but it solves the problem using Heron's algorithm. Just want it to share it here:
print("Please enter a positive integer 'x' to find its square root.")
x = int(input("x ="))
g = int(input("What's your best guess: "))
results = [g]
if g * g == x:
print("Good guess! The square root of", x, "is", g)
else:
g = (g + (x / g)) / 2
results.append(g)
while results[-1] != results[-2]:
g = (g + (x / g)) / 2
results.append(g)
else:
print(results)
print("Not quite. The square root of", x, "is", results[-1])

Performance difference RBFS - A*

I've implemented the RBFS as defined in AIMA and wanted to compare it to an implementation of A*. When I try it out on an instance from the TSPlib (ulyssis16 - 16 cities), both come up with a correct solution, the memory usage is also correct (exponential for A*, linear for RBFS). The only weird thing is that the RBFS algorithm is much faster than A* when it shouldn't be the case. A* finished in about 3.5 minutes, RBFS takes only a few seconds. When I count the number of visits for each node, A* visits a lot more nodes than RBFS. That also seems counter-intuitive.
Is this because of the trivial instance? I can't really try it out on a bigger instance as my computer doesn't have enough memory for that.
Has anyone got any suggestions? Both algorithms seem to be correct according to their specifications, their results and memory usage. Only the execution time seems off...
I already looked everywhere but couldn't find anything about a difference in their search strategy. Except for the fact that RBFS can revisit nodes.
Thanks
Jasper
Edit 1: AIMA corresponds to the book Artificial Intelligence a Modern Approach by Russel and Norvig.
Edit 2: TSPlib is a set of instances of the TSP problem (http://comopt.ifi.uni-heidelberg.de/software/TSPLIB95/)
Edit 4: The code for the A* algorithm is given as follows. This should be correct.
def graph_search(problem, fringe):
"""Search through the successors of a problem to find a goal.
The argument fringe should be an empty queue.
If two paths reach a state, only use the best one. [Fig. 3.18]"""
closed = {}
fringe.append(Node(problem.initial))
while fringe:
node = fringe.pop()
if problem.goal_test(node.state):
return node
if node.state not in closed:
closed[node.state] = True
fringe.extend(node.expand(problem))
return None
def best_first_graph_search(problem, f):
return graph_search(problem, PriorityQueue(f,min))
def astar_graph_search(problem, h):
def f(n):
return n.path_cost + h(n)
return best_first_graph_search(problem, f)
Where problem is a variable containing details about the problem to be solved (when the goal is reached, how to generate successors, the initial state,...). A node contains the path on how to reach that state by storing the parent node and some other utility functions. Here is an older version of this code http://aima-python.googlecode.com/svn/trunk/search.py) For the TSP problem, the tours are created incrementally. The used heuristic is the minimal spanning tree on the nodes that are not yet visited.
The code for RBFS is as follows:
def rbfs(problem, h):
def f(n):
return n.path_cost + h(n)
def rbfs_helper(node, bound):
#print("Current bound: ", bound)
problem.visit(node)
if (problem.goal_test(node.state)):
return [node, f(node)]
backup = {}
backup[node.state.id] = f(node)
succ = list(node.expand(problem))
if (not succ):
return [None, float("inf")]
for v in succ:
backup[v.state.id] = max(f(v), backup[node.state.id])
while(True):
sortedSucc = sorted(succ, key=lambda node: backup[node.state.id])
best = sortedSucc[0]
if (backup[best.state.id] > bound):
return [None, backup[best.state.id]]
if (len(sortedSucc) == 1):
[resultNode, backup[best.state.id]] = rbfs_helper(best, bound)
else:
alternative = sortedSucc[1]
[resultNode, backup[best.state.id]] = rbfs_helper(best, min(bound, backup[alternative.state.id]))
if (resultNode != None):
return [resultNode, backup[best.state.id]]
[node, v] = rbfs_helper(Node(problem.initial), float("inf"))
return node
It also uses the problem and node as defined above. Those were specifically designed to be used as generic elements.

Resources