import itertools
from collections import deque
from scipy.spatial.distance import euclidean
import numpy as np
import rdkit.Chem.AllChem as rdkit
from ..base import Topology
from ....utilities import (centroid,
vector_theta,
add_fragment_props,
normalize_vector)
[docs]class Vertex:
"""
Used to represent the vertices of cage polyhedra.
This class stores information about the vertices which make up a
cage's structure.
Attributes
----------
coord : :class:`numpy.array`
An array which holds the x, y and z coordinates of the
vertex, in that order.
connected : :class:`list` of :class:`Edge` or :class:`Vertex`
This :class:`list` holds the :class:`Edge` or :class:`Vertex`
instances which represent the edges or vertices connected to
this one.
fg_ids : :class:`list` of :class:`int`
This :class:`list` holds the ids of fgs which belong to the
building block placed on the vertex and will form bonds. The
ids reflect those in the macromolecule not in the building
block itself.
fg_position_pairs : :class:`list`
A :class:`list` of the form
.. code-block:: python
fg_position_pairs = [(4, v1), (8, v2)]
Where ``v1`` and ``v2`` are :class:`Vertex` instances.
Each fg which is paired to a neighboring vertex or
edge first. Only after this is the fg-fg pairing
performed. The fg-edge/vertex pairing is stored here. The
:class:`int` represents the id of the fg.
distances : :class:`list`
A :class:`list` of the form
.. code-block:: python
distances = [(15.2, 5, 10), (18.4, 3, 8), ...]
After fgs have been associated with vertices to which
they join, the idividual fgs are paired up. To do this the
distance between every fg on the paired vertex and the
fg which is paired to the vertex is found. This
information is stored here the first element of each
:class:`tuple` the distance, and the second and third elements
represent the fgs.
id_ : :class:`object`, optional
An id to identify the vertex. Used by
:meth:`CageTopology.place_mols`.
custom_position : :class:`bool`
A flag to inidcate if the position of :attr:`coord` was derived
from connected vertices or set manually. If the position is
derived from the vertices then the position of the building
block being placed is derived from the bonder atoms in the
conncected vertices.
"""
def __init__(self, x, y, z, id_=None, custom_position=True):
"""
Initializes a :class:`Vertex`.
Parameters
----------
x : :class:`int` or :class:`float`
The x coordinate.
y : :class:`int` or :class:`float`
The y coordiante
z : :class:`int` or :class:`float`
The z coordiante
id : :class:`object`, optional
An id to identify the vertex.
custom_position : :class:`bool`, optional
See :attr:`custom_position`.
"""
self.coord = np.array([x, y, z])
self.custom_position = custom_position
self.connected = []
self.fg_ids = []
self.fg_position_pairs = []
self.distances = []
self.id = id_
[docs] @classmethod
def vertex_init(cls, *vertices):
"""
Intializes the :class:`Vertex` from other vertices.
This initalizer automatically calculates the position of the
vertex from the positions of the vertices provided to the
initializer. Its position is set to the centroid of the
provided vertices.
The :attr:`connected` attributes of all the involved vertices
are also updated.
Parameters
----------
vertices : :class:`tuple` of :class:`Vertex`
Holds :class:`Vertex` objects used for initialization.
Returns
-------
:class:`Vertex`
The initialized vertex.
"""
# Get the position of this Vertex, as the centroid of the
# supplied vertices.
obj = cls(*centroid(*(v.coord for v in vertices)),
custom_position=False)
# Update the `connected` attributes.
obj.connected.extend(vertices)
for v in vertices:
v.connected.append(obj)
return obj
[docs] def place_mol(self,
scale,
building_block,
aligner=0,
aligner_edge=0,
macro_mol=None):
"""
Place a :class:`.StructUnit3` building block on the vertex.
The orientation of the building block is aligned with 2
parameters. Firstly, the normal of the plane of fgs of
the building block is aligned with the normal of the plane
formed by the edges connected to the vertex. Because the normal
of the plane of fgs always points in the direction of
the building block's centroid, this alignment causes the bulk
of the building block molecule to point away from the center
of the cage.
Secondly, the building block is rotated so that a fg
is aligned perfectly with an edge. This reduces the rms
distance between the edges and fgs to some extent,
probably.
Parameters
----------
scale : :class:`float`
The amount by which the size of the topology is scaled.
building_block : :class:`.StructUnit3`
The building block molecule to be placed on a vertex.
aligner : :class:`int`, optional
The ``fg_id`` of the aligned fg.
aligner_edge : :class:`int`, optional
The index of an edge in :attr:`connected`. It is the edge
with which `aligner` is aligned.
macro_mol : :class:`.MacroMolecule`, optional
The macromolecule being built. Used for vertex only cage
topologies where the position of some of the vertices
is derived from the positions of the fgs on
connected vertices.
Returns
-------
:class:`rdkit.Chem.rdchem.Mol`
The ``rdkit`` instance holding the building block molecule
with the coordinates placed on the vertex and orientation
set as described in the docstring.
"""
icoord = building_block.position_matrix()
# Flush the list of data from previous molecules.
self.distances = []
# The method first aligns the normal of the fg plane
# to the normal of the edge plane. This means the bulk of the
# building block is always pointed away from the center of the
# molecule.
building_block.set_orientation2(self.edge_plane_normal(scale))
# Next, define the direction vector going from the edge
# centroid to the edge with which the fg is aligned.
building_block.set_bonder_centroid(
self.bonder_centroid(macro_mol, scale))
vector = (self.connected[aligner_edge].coord*scale -
self.edge_centroid(scale))
# Minimize the angle between these things by rotating about the
# normal of the edge plane.
building_block.minimize_theta2(aligner,
vector,
self.edge_plane_normal(scale))
mol = rdkit.Mol(building_block.mol)
building_block.set_position_from_matrix(icoord)
return mol
[docs] def edge_plane_normal(self, scale):
"""
Return the normal of the plane formed by the connected edges.
The normal is set such that it always points away from the
origin.
Parameters
----------
scale : :class:`float`
The amount by which the size of the topology is scaled.
Returns
-------
:class:`numpy.array`
A normalized vector which defines the normal pointed away
from the origin.
"""
# Get two of the direction vectors running between the edges.
v1, v2 = itertools.islice(self.edge_direction_vectors(scale), 2)
# To get the normal to the plane get the cross product of these
# vectors. Normalize it.
normal = normalize_vector(np.cross(v1, v2))
# To check that the normal is pointing away from the center of
# cage, find the angle, `theta`, between it and one of the
# position vectors of the edges on the plane. Assuming that the
# center of the cage is at the origin, which it should be as
# this is specified in the documentation, if the angle between
# the normal the position vector is less than 90 degrees they
# point in the same general direction. If the angle is greater
# than 90 degrees it means that they are pointing in opposite
# directions. If this is the case make sure to multiply the
# nomral by -1 in all axes so that it points in the correct
# direction while still acting as the normal to the plane.
theta = vector_theta(normal, self.connected[0].coord*scale)
if theta > np.pi/2:
normal *= -1
return normal
[docs] def edge_plane(self, scale):
"""
Return coefficients of plane of edges connected to the vertex.
A plane is defined by the scalar plane equation::
ax + by + cz = d.
This method returns the ``a``, ``b``, ``c`` and ``d``
coefficients of this equation for the plane formed by the
connected edges. The coefficents ``a``, ``b`` and ``c`` decribe
the normal vector to the plane. The coefficent ``d`` is found
by substituting these coefficients along with the ``x``, ``y``
and ``z`` variables in the scalar equation and solving for
``d``. The variables ``x``, ``y`` and ``z`` are substituted by
the coordinate of some point on the plane. For example, the
position of one of the connected edges.
Parameters
----------
scale : :class:`float`
The amount by which the size of the topology is scaled.
Returns
-------
:class:`numpy.array`
This array has the form ``[a, b, c, d]`` and represents the
scalar equation of the plane formed by the connected edges.
References
----------
https://tinyurl.com/okpqv6
"""
edge_coord = self.edges[0].coord*scale
d = -np.sum(self.edge_plane_normal(scale) * edge_coord)
return np.append(self.edge_plane_normal(scale), d)
[docs] def edge_direction_vectors(self, scale):
"""
Yields direction vectors between edges connected to the vertex.
Parameters
---------
scale : :class:`float`
The amount by which the size of the topology is scaled.
Yields
------
:class:`numpy.array`
A normalized direction vector running from one edge
connected to the vertex to another.
"""
for edge1, edge2 in itertools.combinations(self.connected, 2):
yield normalize_vector(scale*(edge1.coord-edge2.coord))
[docs] def edge_coord_matrix(self, scale):
"""
Return matrix holding coords of edges joined to the vertex.
Parameters
----------
scale : :class:`float`
The amount by which the size of the topology is scaled.
Returns
-------
:class:`numpy.matrix`
The matrix of shape ``[n, 3]``, where ``n`` is the number
of edges connected to the vertex. The row holds the x, y
and z coordinates, respectively.
"""
coords = []
for edge in self.connected:
coords.append(edge.coord*scale)
return np.matrix(coords)
[docs] def edge_centroid(self, scale):
"""
Returns the centroid of the edges connected to the vertex.
Parameters
----------
scale : :class:`float`
The amount by which the size of the topology is scaled.
Returns
-------
:class:`numpy.array`
An array which holds the x, y and z positions of the
centroid of the edges connected to the vertex.
"""
# The connected edges are held in the `edges`. To get the
# centroid, add up all the x, y and z coordinates (separately)
# and divide each sum by the number of edges.
return (sum(edge.coord*scale for edge in self.connected) /
len(self.connected))
[docs] def bonder_centroid(self, macro_mol, scale):
"""
Calculates the centroid of the fgs on the vertex.
However if :attr:`custom_position` is ``True`` or
`macro_mol` is ``None``, then :attr:`coord` is returned.
Parameters
----------
macro_mol : :class:`.MacroMolecule`
The macromolecule being built.
scale : :class:`float`
The amount by which the size of the topology is scaled.
Returns
-------
:class:`numpy.array`
The centroid of the bonder atoms.
"""
if self.custom_position or macro_mol is None:
return self.coord*scale
centroid = np.zeros((3, ))
count = 0
for v in self.connected:
for fg, edge in v.fg_position_pairs:
if edge is self:
centroid += macro_mol.fg_centroid(fg)
count += 1
return centroid / count
def __repr__(self):
return "Vertex({:.3}, {:.3}, {:.3})".format(*self.coord)
def __str__(self):
return repr(self)
[docs]class Edge(Vertex):
"""
Used to represent the edges of Cage polyhedra.
This class stores information about the edges which make up a
cage's structure.
Attributes
----------
direction : :class:`numpy.array`
This vector represents the orientation of the edge. It is a
normalized direction vector which runs from `v2` to `v1`,
provided in the initalizer.
"""
def __init__(self, v1, v2, id_=None, custom_position=False):
"""
Initializes an :class:`Edge` instance.
Parameters
----------
v1 : :class:`Vertex`
A vertex joined to the edge.
v2 : :class:`Vertex`
Another vertex joined to the edge.
id_ : :class`str`, optional
An id for the edge.
custom_position : :class:`bool`
See :attr:`Vertex.custom_position`
"""
Vertex.__init__(self,
*centroid(v1.coord, v2.coord),
id_,
custom_position)
self.connected.extend([v1, v2])
v1.connected.append(self)
v2.connected.append(self)
[docs] def direction(self, macro_mol, scale):
if self.custom_position or macro_mol is None:
v1, v2 = self.connected
return normalize_vector(v1.coord - v2.coord)
fgs = []
for v in self.connected:
for fg, edge in v.fg_position_pairs:
if edge is self:
fgs.append(macro_mol.fg_centroid(fg))
return normalize_vector(fgs[0] - fgs[1])
[docs] def place_mol(self, scale, linker, alignment, macro_mol):
"""
Places a linker molecule on the coordinates of an edge.
It also orientates the linker so that a the fgs sit
exactly on the edge and the bulk of the linker points away from
the center of the cage.
Parameters
----------
scale : :class:`float`
The amount by which the size of the topology is scaled.
linker : :class:`.StructUnit2`
The linker which is to be placed and orientated as
described in the docstring.
alignment : :class:`int`
``1`` for parallel alignment with :attr:`direction` and
``-1`` for anti-parallel alignment with :attr:`direction`.
macro_mol : :class:`.MacroMolecule`
The macromolecule being constructed.
Returns
-------
:class:`rdkit.Chem.rdchem.Mol`
The ``rdkit`` instance holding the linker molecule with the
coordinates placed on the edge and orientation set as
described in the docstring.
"""
icoord = linker.position_matrix()
# Flush the lists from data of previous molecules.
self.distances = []
# Align then place the linker.
linker.set_orientation2(self.direction(macro_mol, scale)*alignment)
linker.minimize_theta2(self.coord*scale,
self.direction(macro_mol, scale))
linker.set_bonder_centroid(self.bonder_centroid(macro_mol, scale))
mol = rdkit.Mol(linker.mol)
linker.set_position_from_matrix(icoord)
return mol
def __repr__(self):
v1, v2 = self.connected
return f"Edge({v1}, {v2})"
def __str__(self):
return repr(self)
[docs]class CageTopology(Topology):
"""
An abstract base class for cage topologies.
Attributes
----------
A_alignments : :class:`list` of :class:`int`
The length of this :class:`list` must be equal to the number of
building blocks in the cage. When cages are built one of the
fgs of each building block is aligned with an edge
during placement. The :class:`int` is the ``fg_id`` of the
aligned functional group.
If ``None`` then the functional group with ``fg_id`` of ``0``
is always aligned.
For example,
.. code-block:: python
A_alignments = [0, 2, 1, 2]
In this case there must be 4 building blocks in the cage. The
the first building block has its first (``fg_id = 0``) fg
aligned. The 2nd building block has the 3rd fg (``fg_id = 2``)
aligned. The 3rd building block has the 2nd fg (``fg_id = 1``)
aligned. The 4th building block has the 3rd fg (``fg_id = 2``)
aligned.
B_alignments : :class:`list` of :class:`int`
The length of this :class:`list` should be euqal to the number
of linkers in the cage. The linkers of a cage can have either 2
functional groups or 3 or more, depending on the topology.
When the linkers have 2 functional groups, the :class:`list`
should hold either ``1`` or ``-1``. The value indicates that
the linker is aligned parallel or antiparallel with the edge
its placed on. For example, in a tetrahedral topology,
.. code-block:: python
B_alignments = [-1, 1, 1, -1, 1, -1]
It indicates that the first linker is aligned anti parallel and
the second is aligned in parallel, and so on.
If the linkers have 3 or more functional groups, the values
in :attr:`B_alignments` have the same role as
:attr:`A_alignments`. The only difference is that by default
the second fg is aligned, rather than the first.
edge_alignments : :class:`list` of :class:`int`
The length of the :class:`list` is equal to the number of
building blocks in the cage. Each element is an :class:`int`
which holds the id of an edge. For example,
.. code-block:: python
edge_alignments = [1, 2, 3, 4]
then the first building block is aligned with the edge with
:attr:`Vertex.id_` of ``1``, the second building block is
aligned with the edge with :attr:`Vertex.id_` ``2`` and so on.
For this to work, the edges must have their :attr:`Vertex.id_`
attributes defined.
bb_assignments : :class:`dict`
A :class:`dict` of the form
.. code-block:: python
bb_assignments = {
0: [0, 1, 3],
1: [2]
2: [0, 4, 5],
3: [1, 2, 3]
}
This means the building block at index ``0`` of
:attr:`.MacroMolecule.building_blocks` sits on the vertices
of indices ``0``, ``1``, and ``3``. The building block at
index ``1`` of :attr:`.MacroMolecule.building_blocks` sits on
verticex of index ``2``.
The building block at index ``2`` in
:attr:`.MacroMolecule.building_blocks` also sits on the vertex
of index ``0``. However each cage is composed of two sets of
building blocks, called building blocks and linkers. This means
that the building block at index ``0`` is builing block while
the one at index ``2`` is a linker, or vice versa. Which one
is which is automatically deduced by looking at the number of
functional groups.
If ``None`` then building blocks are assigned at random.
"""
def __init__(self,
A_alignments=None,
B_alignments=None,
edge_alignments=None,
bb_assignments=None):
if A_alignments is None:
A_alignments = np.zeros(len(self.positions_A))
if B_alignments is None:
B_alignments = np.ones(len(self.positions_B))
if edge_alignments is None:
edge_alignments = [None for x in
range(len(self.positions_A))]
super().__init__()
self.A_alignments = A_alignments
self.B_alignments = B_alignments
self.edge_alignments = edge_alignments
self.bb_assignments = bb_assignments
[docs] def _bb_maps(self, macro_mol):
"""
"""
bb_fgs = max(len(bb.functional_group_atoms()) for
bb in macro_mol.building_blocks)
bb_map, lk_map = {}, {}
if self.bb_assignments is None:
bbs = [bb for bb in macro_mol.building_blocks if
len(bb.functional_group_atoms()) == bb_fgs]
lks = [bb for bb in macro_mol.building_blocks if
len(bb.functional_group_atoms()) != bb_fgs]
for i in range(len(self.positions_A)):
bb_map[i] = np.random.choice(bbs)
for i in range(len(self.positions_B)):
lk_map[i] = np.random.choice(lks)
else:
for bb_index, positions in self.bb_assignments.items():
bb = macro_mol.building_blocks[bb_index]
n_fgs = len(bb.functional_group_atoms())
map_ = bb_map if n_fgs == bb_fgs else lk_map
for position in positions:
map_[position] = bb
return bb_map, lk_map
[docs] def bonded_fgs(self, macro_mol):
"""
Joins up the separate building blocks which form the molecule.
Parameters
----------
macro_mol : :class:`.MacroMolecule`
The macromolecule being assembled.
Yields
------
:class:`tuple` of :class:`int`
The ``fg_ids`` of functional groups to be bonded.
"""
# This loop finds all the distances between a fg paired with
# a postion and all other fgs at the paired position.
for position in self.positions_A:
for fg1, vertex in position.fg_position_pairs:
# Get all the distances between the fg and the other
# fgs on the vertex. Store this information
# on the vertex.
for fg2 in vertex.fg_ids:
distance = macro_mol.fg_distance(fg1, fg2)
position.distances.append((distance, fg1, fg2))
# This loop creates bonds between fgs at two different
# positions so that each fg only bonds once and so that the
# total length of all bonds made is minimzed.
paired = set()
for position in self.positions_A:
for _, fg1, fg2 in sorted(position.distances):
if fg1 in paired or fg2 in paired:
continue
yield fg1, fg2
paired.add(fg1)
paired.add(fg2)
[docs] def pair_fgs_with_positions(self, scale, macro_mol, vertex):
"""
Matches fgs with the closest building block position.
After a building block is placed on a position, each fg
which forms a bond must be paired with the location of the
building block to which it bonds. This function matches fgs
and positions so that each is only present in one pairing and
so that the total distance of the pairings is minimized.
This updates of :attr:`Vertex.fg_position_pairs` attribute of
`vertex`.
Parameters
----------
scale : :class:`float`
The amount by which the size of the topology is scaled.
macro_mol : :class:`.MacroMolecule`
The macromolecule being buit.
vertex : :class:`Vertex`
The position at which all the atoms being paired are
located.
Returns
-------
None : :class:`NoneType`
"""
# This loop looks at each fg which forms a new bond and all
# the positions (not fgs) to which it may end up bonding. It
# finds the distances of all the options.
distances = []
for fg in vertex.fg_ids:
fg_coord = macro_mol.fg_centroid(fg)
for position in vertex.connected:
distance = euclidean(fg_coord, position.coord*scale)
distances.append((distance, fg, position))
# Sort the pairings of fgs with potential bonding position,
# smallest first.
distances.sort(key=lambda x: x[0])
# This loop looks at all the potential pairings of fgs to
# positions. It pairs the shortest combinations of fgs and
# positions, making sure that each fg and position is only
# paired once. The pairings are saved to the `
# fg_positions_pairs` attribute of the position on which all
# the fgs are placed.
paired_pos = set()
paired_ids = set()
vertex.fg_position_pairs = []
for _, fg, pos in distances:
if fg in paired_ids or pos in paired_pos:
continue
vertex.fg_position_pairs.append((fg, pos))
paired_ids.add(fg)
paired_pos.add(pos)
[docs] def place_mols(self, macro_mol):
"""
Places all building block molecules on correct coordinates.
The building block molecules are placed in their appropriate
positions based on the topology. It does not join them.
Also updates :attr:`.MacroMolecule.bb_counter`.
Parameters
----------
macro_mol : :class:`.MacroMolecule`
The macromolecule being built.
Returns
-------
None : :class:`NoneType`
"""
macro_mol.mol = rdkit.Mol()
bb_map, lk_map = self._bb_maps(macro_mol)
scale = max(bb.max_diameter()[0] for bb in macro_mol.building_blocks)
# This loop places all building-blocks* on the points at
# `positions_A`. It then pairs all fgs which form a new bond
# with the positions to which they will be bonding. It also
# counts the nubmer of building-blocks* which make up the
# structure.
for i, position in enumerate(self.positions_A):
bb = bb_map[i]
n_bb = len(bb.functional_group_atoms())
# Position the molecule on the vertex.
aligner_edge_id = self.edge_alignments[i]
aligner_edge = next((position.connected.index(x) for x in
position.connected if
x.id == aligner_edge_id), 0)
bb_mol = position.place_mol(scale,
bb,
int(self.A_alignments[i]),
aligner_edge)
add_fragment_props(bb_mol,
macro_mol.building_blocks.index(bb),
i)
bb_mol = self.update_fg_id(macro_mol, bb_mol)
macro_mol.mol = rdkit.CombineMols(macro_mol.mol, bb_mol)
# Update the counter each time a building-block* is added.
macro_mol.bb_counter.update([bb])
# Get ids of fgs which form new bonds.
fg_ids = deque(maxlen=n_bb)
for atom in macro_mol.mol.GetAtoms():
if (atom.HasProp('fg_id') and
atom.GetIntProp('fg_id') not in fg_ids):
fg_ids.append(atom.GetIntProp('fg_id'))
# Save the ids of fgs which form new bonds and pair them
# up with positions.
position.fg_ids = sorted(fg_ids)
self.pair_fgs_with_positions(scale, macro_mol, position)
# This loop places all linkers on the points at `positions_B`.
# It then saves all fgs which form a new bond to the position
# they are found at. It also counts the number of linkers which
# make up the structure.
for i, position in enumerate(self.positions_B):
lk = lk_map[i]
n_lk = len(lk.functional_group_atoms())
lk_mol = position.place_mol(scale,
lk,
int(self.B_alignments[i]),
macro_mol=macro_mol)
add_fragment_props(lk_mol,
macro_mol.building_blocks.index(lk),
i)
lk_mol = self.update_fg_id(macro_mol, lk_mol)
macro_mol.mol = rdkit.CombineMols(macro_mol.mol, lk_mol)
# Update the counter each time a linker is added.
macro_mol.bb_counter.update([lk])
# Get ids of fgs which form new bonds.
fg_ids = deque(maxlen=n_lk)
for atom in macro_mol.mol.GetAtoms():
if (atom.HasProp('fg_id') and
atom.GetIntProp('fg_id') not in fg_ids):
fg_ids.append(atom.GetIntProp('fg_id'))
# Save the ids of fgs which form new bonds.
position.fg_ids = list(fg_ids)
[docs]class VertexOnlyCageTopology(CageTopology):
"""
Abstract base class for cage topologies using ditopics.
"""
...
[docs]class NoLinkerCageTopology(CageTopology):
"""
Abstract base class for cage topologies without linkers.
This means that all building blocks have the same number of
functional groups.
Attributes
----------
alignments : :class:`list` of :class:`int`
See :attr:`CageTopology.A_alignments`
bb_assignments : :class:`list` of :class:`int`
For each vertex, the :class:`int` is the index of a
building block in :attr:`.MacroMolecule.building_blocks`.
It is the building block to be placed on that vertex. Can be
``None`` if a random building block should be placed.
"""
def __init__(self, alignments=None, bb_assignments=None):
if alignments is None:
alignments = np.zeros(len(self.positions_A))
if bb_assignments is None:
bb_assignments = [None for i in range(len(self.positions_A))]
self.alignments = alignments
self.bb_assignments = bb_assignments
self.connect()
self.react_del = True
[docs] def place_mols(self, macro_mol):
macro_mol.mol = rdkit.Mol()
scale = max(bb.max_diameter()[0] for bb in macro_mol.building_blocks)
for position, orientation, bb_index in zip(self.positions_A,
self.alignments,
self.bb_assignments):
if bb_index is None:
bb = np.random.choice(macro_mol.building_blocks)
else:
bb = macro_mol.building_blocks[bb_index]
ipos = bb.position_matrix()
n_bb = len(bb.functional_group_atoms())
mol = position.place_mol(scale, bb, int(orientation))
mol = self.update_fg_id(macro_mol, mol)
macro_mol.mol = rdkit.CombineMols(macro_mol.mol, mol)
macro_mol.bb_counter.update([bb])
fg_ids = deque(maxlen=n_bb)
for atom in macro_mol.mol.GetAtoms():
if (atom.HasProp('fg_id') and
atom.GetIntProp('fg_id') not in fg_ids):
fg_ids.append(atom.GetIntProp('fg_id'))
position.fg_ids = sorted(fg_ids)
self.pair_fgs_with_positions(scale, macro_mol, position)
bb.set_position_from_matrix(ipos)
[docs] @classmethod
def connect(cls):
"""
Updates each :attr:`Vertex.connected`.
Returns
-------
None : :class:`NoneType`
"""
if getattr(cls, 'connected', False):
return
for v1, v2 in cls.connections:
v1.connected.append(v2)
v2.connected.append(v1)
cls.connected = True


Introduction
The open science movement presents many opportunities to reimagine the way we do research. Evidence continues to mount that the open publication of data and papers benefits the researchers who publish them, and the creation, modification and reuse of software is becoming commonplace in many fields of research. And yet, few places exist to support and encourage the exploration of these skills and ideas; where does a researcher go to learn these techniques and start these conversations?
It's possible to explore these opportunities effectively today by creating a Mozilla Study Group. Mozilla Study Groups are regular meetups for researchers and scientists to improve their code and data skills, learn new tools, and work openly together to share solutions. We'd like to achieve three main goals in a Study Group:
- Skill Sharing. A good Mozilla Study Group shares lessons on open science skills, from data management to coding to communicating in a forum where we can learn from each other.
- Idea Discovery. There is a rich world of open-source code & open science strategies to support research, but these can be hard to discover on our own. A Mozilla Study Group brings the experiences of many researchers together to help you discover tools, code and projects to supercharge your research.
- Community Support. Learning how to work with data and code can be isolating, stressful and time consuming for many early career researchers. A Mozilla Study Group gives people a place to ask questions, get help and receive encouragement on their path to learning open research practices and technologies.
Hack This Book
This handbook serves two purposes. In Setting Up a Mozilla Study Group, we'll discuss how to easily set up things like website and communication channels for your Study Group, and strategies for organizing great events without it becoming a full time job. After that, in Running a Mozilla Study Group and Lesson Ideas, we'll describe some example events that have been successful in the past, and point you to curriculum and other resources you can reuse for your own purposes.
These ideas are based on stories from other Study Groups around the world - but feel free to change anything you like! Different strategies will work for different groups, so change things up and let us know what happens; the only hard rule is to create a place that respects & welcomes everybody.
Study Groups Worldwide
Study Groups are starting around the world! Click on a pin to find a link describing how to get involved in each group. When you start a Mozilla Study Group, let us know, and we'll add you to the map!
Next Chapter
In Organizing a Mozilla Study Group, we'll learn how to set up a simple website and communication channels for our Study Group, so we can start listing events and reaching out to our community, and discuss some day-to-day event planning and management.


Showing results for --{{filterByText}} --{{filterByGrade}}
| ID | Name | Grade | Tution Fee | Transportation Fee | Computer Fee | Due | |
|---|---|---|---|---|---|---|---|
| {{student.id}} | {{student.firstName}} {{student.lastName}} | {{student.grade}} | {{student.tutionFee}} | {{student.transportationFee}} | {{student.computerFee}} | {{student.lastdue}} |


--- layout: page title: About header-img: "img/about-bg.png" ---
I'm a foster child from the city with aspergers, a past of former folly and ad/hd. I'm here to prove if i can make it, so can you. Oh and I'm an engineering technician and a black belt and neither of those two titles were handed to me.


The way we communicate when we play games is often different than how we do in other situations. The often competitive nature of games can make us act in ways that we normally would not. This includes changesin our speech. You see a similar thing in sports however games can depict situations that would not happen in sports. There is an interesting playfulness to how people interact about things that would usually not be playful. For instance when outside of Monopoly are you going to hear anyone say "oh screw you I was going to buy that property." Or with more violent games such as shooters people can say "C'mon stop killing me" or similar things. On the other side of things, people who are really competitive can get angry at other players especially when they feel they are unable to compete with them either because of a lack of skill or more commonly some unfair advantage that they have.
People who get really good at certain games develop a language of their own to quickly communicate things. This can be seen in the shooter Counter Strike: Global Offensive. Players use complicated slang to quickly communicate their position, the amount of health they have left, and other critical information.
Mid - The middle of the map.
Push - Head toward a specific area
Lit - Less than 40 HP
Rotate - Move to the opposite control point to defend it.
Execute - throw everything you have at certain points to cripple the enemy team.
Hold - Stay at a certain place and defend it.
Jiggle - sidestep out and back into a corner or hallway to gather information and bait a shot.


Support¶
Usage Questions¶
If you have questions about how to use Read the Docs, or have an issue that
isn’t related to a bug, Stack Overflow is the best place to ask. Tag
questions with read-the-docs
so other folks can find them easily.
Good questions for Stack Overflow would be:
- “What is the best way to structure the table of contents across a project?”
- “How do I structure translations inside of my project for easiest contribution from users?”
- “How do I use Sphinx to use SVG images in HTML output but PNG in PDF output?”
Community Support¶
Read the Docs is a community supported site, nobody is paid to handle readthedocs.org support. We are hoping to bring in enough money with our Gold program to change that, so please sign up if you are able.
All people answering your questions are doing it with their own time, so please be kind and provide as much information as possible.
Bugs & Support Issues¶
You can file bug reports on our GitHub issue tracker, and they will be addressed as soon as possible. Support is a volunteer effort, and there is no guaranteed response time. If you need answers quickly, you can buy commercial support below.
Reporting Issues¶
When reporting a bug, please include as much information as possible that will help us solve this issue. This includes:
- Project name
- URL
- Action taken
- Expected result
- Actual result
Commercial Support¶
We offer commercial support for Read the Docs, commercial hosting, as well as consulting around all documentation systems. You can contact us at<EMAIL_ADDRESS>to learn more, or read more at https://readthedocs.com/services/#open-source-support.


Price $125,000
Acres 0.5
Neighborhood Academy Bevo Mill Clayton-Tamm Carondelet Downtown Ellendale Fairground Midtown O'Fallon Penrose Shaw Soulard The Hill The Ville Tower Grove East Walnut Park West Wells Goodfellow
2.5 Baths


A year ago when Starcraft: Remastered was announced I decided to give this game a proper try and become at least average at it. The game had its 20 years anniversary in 2018.
Logitech Mouse Optical (M-UV55A) is my current mouse of choice. I have small hands, and it has a perfect shape for my fingertip grip. What works for me might not work for others though. Be careful.
 They also don't understand why they occasionally might win.
Is it okay to ignore your Facebook friends' birthday notifications or not? That's the question that was bothering me ever since the social networks became a real thing.
This year I added cacti and succulents to my hobbies list. They reduce my stress and I really looking at them. I'm a perfectionist and like to do everything properly, especially when it comes to the living things like plants.
I still have nothing useful to share with you guys, but I have some free time now, so I'd like to tell you about some things from the past.
Working with Oracle XE as a beginner I faced with many issues that took me hours or even days to fix. Here I'd like to mention two of them: ORA-12705 and ORA-12514.
During my Java Internship program at my new job we had to develop an enterprise-like project to learn some new things and development processes. Continious integration was a big part of it.
In this post I will talk about such simple and important thing like a hobby in our developers' lives. It is a great feeling to get lost into something whether it is your favorite book or a video game.
A few days ago I had an interesting home assignment at my university related to this topic. So I thought I could write a piece of software that's easy to use and share the code with you.
IoT is becoming more popular these days. There are plenty of powerful microcontrollers on the market that don't require you to be C, ASM or Electronics guru to make some pretty cool stuff. You can create Embedded Systems even in .NET.
Quite often I had to work with database providers other than Microsoft SQL Server. Sometimes it could be tricky. Here I will show you some basic steps to start your development in .NET using Oracle Database XE as your data storage.
In my previous post I showed how to open PPPoE connection automatically at Windows startup. However there were still some issues. One of them is to find a way to keep this connection alive.
Today my non-technical neighbor asked me to reconfigure her Internet connection. She used PPPoE because her ISP Rostelecom had told her that switching to PPPoE would solve all of her connection problems.
I was looking at my desktop while my army was dying from the night elf forces without my help. It took some time for me to switch back to the game, but in Warcraft III each second matters.
You're working with some documents, watching movie, listen to music on a background, playing StarCraft II or just left your computer on while you sleep to download some stuff (leagally of course) and BAM! Hello Windows Update.


| Status |
Developer Message |
User Message |
Code |
Details |
| 400 "Bad Request" |
The data submitted in the request was invalid. The developer message will provide more detailed information on the bad data. |
Bad Request - the application submitted invalid data. Please try again. |
1400 |
The application submitted invalid parameters or body in the API call. Check the swagger documentation for the API and read the developer error message returned by the API call. |
| 401 "Unauthorized" |
The application is not configured properly. Please check the credentials. |
The application or server is not configured properly. Please contact the application support. |
1401 |
Access to the API call was denied. This error can be resolved by easily checking: your application consumer key and credentials. Verify that you have access to the API by testing the API call in the developer portal. |
| 403 "Forbidden" |
The API call is valid, but the credentials don't have access to perform the operation. |
You do not have access to perform this operation. If this is incorrect, please contact application support. |
1403 |
Verify that the API credentials have access to the resource. Try performing this API call using the developer portal. |
| 404 "Not Found" |
Not Found - the resource requested was not found. Check the API call. |
Not Found - the information requested was not found. If this is incorrect, please contact application support. |
1404 |
The resource requested by the API call was not found. Check the documentation and trace the API call. |
| 500 "Internal Server Error" |
There was a problem with the API call. Check the documentation and trace the request. |
The application ran into an internal error. If the problem persists, please contact application support. |
1500 |
There was an error with the request. Check the documentation and trace the request. If the data submitted is causing the problem, contact the API developers. |


class Solution { public int furthestBuilding(int[] heights, int bricks, int ladders) { PriorityQueue<Integer> queue = new PriorityQueue<>((a, b) -> a-b); int currSum = 0; for (int j = 1; j < heights.length; j++) { if (heights[j] > heights[j-1]) { int diff = heights[j] - heights[j-1]; queue.add(diff); if (queue.size() > ladders) { currSum += queue.poll(); } if (currSum > bricks) { return j-1; } } } return heights.length-1; } }


All Files (85.54% covered at 1.42 hits/line)
50 files in total.
498 relevant lines.
426 lines covered and
72 lines missed
- 1
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
- 1
protect_from_forgery with: :exception
- 1
include ApplicationHelper
end
- 1
class EventsController < ApplicationController
- 1
include EventsHelper
- 1
def index
- 4
if params[:search]
- 1
@events = Event.search(params[:search])
else
- 3
@events = Event.upcoming_events
end
end
- 1
def show
- 1
@event = Event.find(params[:id])
end
- 1
def edit
- 2
require_login
- 2
@event = Event.find(params[:id])
- 2
if !can_edit(@event)
- 1
redirect_to manage_path
end
end
- 1
def manage_events
require_login
@events = current_user.events
end
- 1
def new
@event = Event.new
end
- 1
def create
params[:event][:published] = params[:event][:published] == "1"
venue = Venue.new(venue_params)
venue.region = Region.find(params[:event][:venue][:region])
ticket_type = TicketType.new(ticket_type_params)
@event = Event.new(event_params)
@event.category = Category.find(category_params)
@event.venue = venue
@event.ticket_types << ticket_type
current_user.events << @event
if venue.save && ticket_type.save && @event.save && current_user.save
flash[:success] = "Event created successfully"
redirect_to manage_path
else
flash[:success] =
"Error while create new evenue: #{venue.errors.full_messages.join(', ')}" +
"Error while create new ticket type: #{ticket_type.errors.full_messages.join(', ')}" +
current_user.errors.full_messages.join(', ') +
"Error while create new event: #{@event.errors.full_messages.join(', ')}"
render :controller => :events, :action => :new
end
end
- 1
def update
byebug
@event = Event.find(params[:id])
if can_edit(@event)
params[:event][:published] = params[:event][:published] == "1"
@event.venue.region = Region.find(params[:event][:venue][:region])
@event.category = Category.find(category_params)
if @event.venue.update(venue_params) && @event.update(event_params)
flash[:success] = "Event updated successfully"
redirect_to manage_path
else
flash[:success] =
"Error while create update evenue: #{@event.venue.errors.full_messages.join(', ')}" +
"Error while create update event: #{@event.errors.full_messages.join(', ')}"
render :controller => :events, :action => :edit, :id => @event.id
end
else
redirect_to manage_path
end
end
- 1
def publish
- 2
require_login
- 2
event = Event.find(params[:id])
- 2
if can_publish(event)
- 1
event.published = true;
- 1
event.save
- 1
flash[:success] = "Event #{event.name} published successfully"
else
- 1
flash[:error] = "You don't have permission to publish this event"
end
- 2
redirect_to manage_path
end
- 1
def remove_ticket_type
@event = Event.find(params[:event_id])
ticket_type = TicketType.find(params[:ticket_type_id])
if ticket_type.presence
ticket_type.destroy
flash[:success] = "Ticket type deleted successfully"
end
end
- 1
def new_ticket_type
@event = Event.find(params[:event_id])
ticket_type = TicketType.new(params.require(:ticket_type).permit(:name, :price, :max_quantity))
@event.ticket_types << ticket_type
if ticket_type.save
flash[:success] = "Ticket type added successfully"
else
flash[:error] = "Error while create new ticket type: #{ticket_type.errors.full_messages.join(', ')}"
end
end
- 1
private
- 1
def event_params
params.require(:event).permit(:name, :starts_at, :ends_at, :hero_image_url, :extended_html_description, :published)
end
- 1
def category_params
params[:event][:category].to_i
end
- 1
def venue_params
params[:event].require(:venue).permit(:name, :full_address)
end
- 1
def ticket_type_params
params[:event].require(:ticket_type).permit(:name, :price, :max_quantity)
end
end
- 1
class SessionsController < ApplicationController
- 1
def new
end
- 1
def create
@user = User.find_by_email(params[:user][:email])
if<EMAIL_ADDRESS>flash[:error] = "User with #{params[:user][:email]} is not exist."
render :action => :new
elsif @user.authenticate(params[:user][:password])
session[:user_id] = @user.id
flash[:success] = "Welcome<EMAIL_ADDRESS>redirect_to root_path
else
flash[:error] = @user.errors.full_messages.join(', ')
render :action => :new
end
end
- 1
def destroy
session[:user_id] = nil
redirect_to root_path
end
end
- 1
class UsersController < ApplicationController
- 1
def new
end
- 1
def create
@user = User.new(request_params)
respond_to do |format|
if @user.save
session[:user_id] = @user.id
flash[:success] = "Welcome<EMAIL_ADDRESS>#MessageMailer.welcome_email(@user, get_root_path).deliver_later
format.html {redirect_to root_path }
else
flash[:error] = @user.errors.full_messages.join(', ')
format.html { render :action => :new }
end
end
end
- 1
private
- 1
def request_params
params.require(:user).permit(:email, :name, :password, :password_confirmation)
end
end
- 1
module ApplicationHelper
- 1
def current_user
- 19
return nil if !session[:user_id] || !User.where(id: session[:user_id]).presence
- 11
@current_user ||= User.find(session[:user_id])
end
- 1
def signed_in?
- 16
current_user
end
- 1
def require_login
- 4
if !signed_in?
flash[:error] = 'Please login!'
redirect_to login_path
end
end
end
- 1
module EventsHelper
- 1
def header_background_image_url
- 1
"https://az810058.vo.msecnd.net/site/global/Content/img/home-search-bg-0#{rand(6)}.jpg"
end
- 1
def can_publish(event)
- 5
signed_in? && event.ticket_types.count > 0 && !event.published && event.user_id == current_user.id
end
- 1
def can_edit(event)
- 5
signed_in? && event.user_id == current_user.id
end
end
- 1
module SessionsHelper
end
- 1
module TicketsHelper
- 1
def format_price(price)
helper.number_to_currency(price, precision: 0, unit: "VNĐ", format: "%n %u")
end
- 1
private
- 1
def helper
@helper ||= Class.new do
include ActionView::Helpers::NumberHelper
end.new
end
end
- 1
module UsersHelper
end
- 1
class Category < ActiveRecord::Base
- 1
validates_inclusion_of :name, in: ['Entertainment', 'Learning', 'Everything Else']
- 1
validates_uniqueness_of :name
end
- 1
require 'textacular'
- 1
class Event < ActiveRecord::Base.extend(Textacular)
- 1
belongs_to :venue
- 1
belongs_to :category
- 1
has_many :ticket_types
- 1
has_one :user
- 1
validates_presence_of :extended_html_description, :venue, :category, :starts_at
- 1
validates_uniqueness_of :name, uniqueness: {scope: [:venue, :starts_at]}
- 1
def is_past_event?
return false if !self.ends_at
self.ends_at <= DateTime.now
end
- 1
def self.upcoming_events
- 4
where("ends_at > ? AND published = ?", DateTime.now, true)
end
- 1
def self.search(query)
- 2
basic_search(query).where('published = ?', true)
end
end
- 1
class Region < ActiveRecord::Base
- 1
validates_inclusion_of :name, in: ['Ho Chi Minh', 'Ha Noi', 'Binh Thuan', 'Da Nang', 'Lam Dong']
- 1
validates_uniqueness_of :name
end
- 1
class Ticket < ActiveRecord::Base
- 1
belongs_to :ticket_type
- 1
belongs_to :user
- 1
before_save :validate_number_of_ticket
- 1
private
- 1
def validate_number_of_ticket
- 2
raise "Quantity exceeds the max quantity (#{self.quantity} > #{self.ticket_type.max_quantity})" if self.quantity > self.ticket_type.max_quantity
end
end
- 1
class TicketType < ActiveRecord::Base
- 1
belongs_to :event
end
- 1
class User < ActiveRecord::Base
- 1
has_secure_password
- 1
has_many :tickets
- 1
has_many :events
end
- 1
class Venue < ActiveRecord::Base
- 1
belongs_to :region
- 1
validates_uniqueness_of :name
end
- 1
require File.expand_path('../boot', __FILE__)
- 1
require 'rails/all'
# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
- 1
Bundler.require(*Rails.groups)
- 1
module CsTemplate
- 1
class Application < Rails::Application
# Settings in config/environments/* take precedence over those specified here.
# Application configuration should go into files in config/initializers
# -- all .rb files in that directory are automatically loaded.
# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
# Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
# config.time_zone = 'Central Time (US & Canada)'
# The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
# config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
# config.i18n.default_locale = :de
# Do not swallow errors in after_commit/after_rollback callbacks.
- 1
config.active_record.raise_in_transactional_callbacks = true
end
end
- 1
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
- 1
require 'bundler/setup' # Set up gems listed in the Gemfile.
# Load the Rails application.
- 1
require File.expand_path('../application', __FILE__)
# Initialize the Rails application.
- 1
Rails.application.initialize!
- 1
Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb.
# The test environment is used exclusively to run your application's
# test suite. You never need to work with it otherwise. Remember that
# your test database is "scratch space" for the test suite and is wiped
# and recreated between test runs. Don't rely on the data there!
- 1
config.cache_classes = true
# Do not eager load code on boot. This avoids loading your whole application
# just for the purpose of running a single test. If you are using a tool that
# preloads Rails for running tests, you may have to set it to true.
- 1
config.eager_load = false
# Configure static file server for tests with Cache-Control for performance.
- 1
config.serve_static_files = false
- 1
config.static_cache_control = 'public, max-age=3600'
# Show full error reports and disable caching.
- 1
config.consider_all_requests_local = true
- 1
config.action_controller.perform_caching = false
# Raise exceptions instead of rendering exception templates.
- 1
config.action_dispatch.show_exceptions = false
# Disable request forgery protection in test environment.
- 1
config.action_controller.allow_forgery_protection = false
# Tell Action Mailer not to deliver emails to the real world.
# The :test delivery method accumulates sent emails in the
# ActionMailer::Base.deliveries array.
- 1
config.action_mailer.delivery_method = :test
# Randomize the order test cases are executed.
- 1
config.active_support.test_order = :random
# Print deprecation notices to the stderr.
- 1
config.active_support.deprecation = :stderr
# Raises error for missing translations
# config.action_view.raise_on_missing_translations = true
- 1
config.allow_concurrency = false
end
# Be sure to restart your server when you modify this file.
# Version of your assets, change this if you want to expire all your assets.
- 1
Rails.application.config.assets.version = '1.0'
# Add additional assets to the asset load path
# Rails.application.config.assets.paths << Emoji.images_path
# Precompile additional assets.
# application.js, application.css, and all non-JS/CSS in app/assets folder are already added.
# Rails.application.config.assets.precompile += %w( search.js )
- 1
Rails.application.config.assets.precompile += %w( bootstrap-notify.js )
# Be sure to restart your server when you modify this file.
# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
# Rails.backtrace_cleaner.remove_silencers!
# Be sure to restart your server when you modify this file.
- 1
Rails.application.config.action_dispatch.cookies_serializer = :json
# Be sure to restart your server when you modify this file.
# Configure sensitive parameters which will be filtered from the log file.
- 1
Rails.application.config.filter_parameters += [:password]
# Be sure to restart your server when you modify this file.
# Add new inflection rules using the following format. Inflections
# are locale specific, and you may define rules for as many different
# locales as you wish. All of these examples are active by default:
# ActiveSupport::Inflector.inflections(:en) do |inflect|
# inflect.plural /^(ox)$/i, '\1en'
# inflect.singular /^(ox)en/i, '\1'
# inflect.irregular 'person', 'people'
# inflect.uncountable %w( fish sheep )
# end
# These inflection rules are supported but not enabled by default:
# ActiveSupport::Inflector.inflections(:en) do |inflect|
# inflect.acronym 'RESTful'
# end
# Be sure to restart your server when you modify this file.
# Add new mime types for use in respond_to blocks:
# Mime::Type.register "text/richtext", :rtf
# Be sure to restart your server when you modify this file.
- 1
Rails.application.config.session_store :cookie_store, key: '_cs_template_session'
# Use this setup block to configure all options available in SimpleForm.
- 1
SimpleForm.setup do |config|
# Wrappers are used by the form builder to generate a
# complete input. You can remove any component from the
# wrapper, change the order or even add your own to the
# stack. The options given below are used to wrap the
# whole input.
- 1
config.wrappers :default, class: :input,
hint_class: :field_with_hint, error_class: :field_with_errors do |b|
## Extensions enabled by default
# Any of these extensions can be disabled for a
# given input by passing: `f.input EXTENSION_NAME => false`.
# You can make any of these extensions optional by
# renaming `b.use` to `b.optional`.
# Determines whether to use HTML5 (:email, :url, ...)
# and required attributes
- 1
b.use :html5
# Calculates placeholders automatically from I18n
# You can also pass a string as f.input placeholder: "Placeholder"
- 1
b.use :placeholder
## Optional extensions
# They are disabled unless you pass `f.input EXTENSION_NAME => true`
# to the input. If so, they will retrieve the values from the model
# if any exists. If you want to enable any of those
# extensions by default, you can change `b.optional` to `b.use`.
# Calculates maxlength from length validations for string inputs
- 1
b.optional :maxlength
# Calculates pattern from format validations for string inputs
- 1
b.optional :pattern
# Calculates min and max from length validations for numeric inputs
- 1
b.optional :min_max
# Calculates readonly automatically from readonly attributes
- 1
b.optional :readonly
## Inputs
- 1
b.use :label_input
- 1
b.use :hint, wrap_with: { tag: :span, class: :hint }
- 1
b.use :error, wrap_with: { tag: :span, class: :error }
## full_messages_for
# If you want to display the full error message for the attribute, you can
# use the component :full_error, like:
#
# b.use :full_error, wrap_with: { tag: :span, class: :error }
end
# The default wrapper to be used by the FormBuilder.
- 1
config.default_wrapper = :default
# Define the way to render check boxes / radio buttons with labels.
# Defaults to :nested for bootstrap config.
# inline: input + label
# nested: label > input
- 1
config.boolean_style = :nested
# Default class for buttons
- 1
config.button_class = 'btn'
# Method used to tidy up errors. Specify any Rails Array method.
# :first lists the first message for each field.
# Use :to_sentence to list all errors for each field.
# config.error_method = :first
# Default tag used for error notification helper.
- 1
config.error_notification_tag = :div
# CSS class to add for error notification helper.
- 1
config.error_notification_class = 'error_notification'
# ID to add for error notification helper.
# config.error_notification_id = nil
# Series of attempts to detect a default label method for collection.
# config.collection_label_methods = [ :to_label, :name, :title, :to_s ]
# Series of attempts to detect a default value method for collection.
# config.collection_value_methods = [ :id, :to_s ]
# You can wrap a collection of radio/check boxes in a pre-defined tag, defaulting to none.
# config.collection_wrapper_tag = nil
# You can define the class to use on all collection wrappers. Defaulting to none.
# config.collection_wrapper_class = nil
# You can wrap each item in a collection of radio/check boxes with a tag,
# defaulting to :span.
# config.item_wrapper_tag = :span
# You can define a class to use in all item wrappers. Defaulting to none.
# config.item_wrapper_class = nil
# How the label text should be generated altogether with the required text.
# config.label_text = lambda { |label, required, explicit_label| "#{required} #{label}" }
# You can define the class to use on all labels. Default is nil.
# config.label_class = nil
# You can define the default class to be used on forms. Can be overriden
# with `html: { :class }`. Defaulting to none.
# config.default_form_class = nil
# You can define which elements should obtain additional classes
# config.generate_additional_classes_for = [:wrapper, :label, :input]
# Whether attributes are required by default (or not). Default is true.
# config.required_by_default = true
# Tell browsers whether to use the native HTML5 validations (novalidate form option).
# These validations are enabled in SimpleForm's internal config but disabled by default
# in this configuration, which is recommended due to some quirks from different browsers.
# To stop SimpleForm from generating the novalidate option, enabling the HTML5 validations,
# change this configuration to true.
- 1
config.browser_validations = false
# Collection of methods to detect if a file type was given.
# config.file_methods = [ :mounted_as, :file?, :public_filename ]
# Custom mappings for input types. This should be a hash containing a regexp
# to match as key, and the input type that will be used when the field name
# matches the regexp as value.
# config.input_mappings = { /count/ => :integer }
# Custom wrappers for input types. This should be a hash containing an input
# type as key and the wrapper that will be used for all inputs with specified type.
# config.wrapper_mappings = { string: :prepend }
# Namespaces where SimpleForm should look for custom input classes that
# override default inputs.
# config.custom_inputs_namespaces << "CustomInputs"
# Default priority for time_zone inputs.
# config.time_zone_priority = nil
# Default priority for country inputs.
# config.country_priority = nil
# When false, do not use translations for labels.
# config.translate_labels = true
# Automatically discover new inputs in Rails' autoload path.
# config.inputs_discovery = true
# Cache SimpleForm inputs discovery
# config.cache_discovery = !Rails.env.development?
# Default class for inputs
# config.input_class = nil
# Define the default class of the input wrapper of the boolean input.
- 1
config.boolean_label_class = 'checkbox'
# Defines if the default input wrapper class should be included in radio
# collection wrappers.
# config.include_default_input_wrapper_class = true
# Defines which i18n scope will be used in Simple Form.
# config.i18n_scope = 'simple_form'
end
# Use this setup block to configure all options available in SimpleForm.
- 1
SimpleForm.setup do |config|
- 1
config.error_notification_class = 'alert alert-danger'
- 1
config.button_class = 'btn btn-default'
- 1
config.boolean_label_class = nil
- 1
config.wrappers :vertical_form, tag: 'div', class: 'form-group', error_class: 'has-error' do |b|
- 1
b.use :html5
- 1
b.use :placeholder
- 1
b.optional :maxlength
- 1
b.optional :pattern
- 1
b.optional :min_max
- 1
b.optional :readonly
- 1
b.use :label, class: 'control-label'
- 1
b.use :input, class: 'form-control'
- 1
b.use :error, wrap_with: { tag: 'span', class: 'help-block' }
- 1
b.use :hint, wrap_with: { tag: 'p', class: 'help-block' }
end
- 1
config.wrappers :vertical_file_input, tag: 'div', class: 'form-group', error_class: 'has-error' do |b|
- 1
b.use :html5
- 1
b.use :placeholder
- 1
b.optional :maxlength
- 1
b.optional :readonly
- 1
b.use :label, class: 'control-label'
- 1
b.use :input
- 1
b.use :error, wrap_with: { tag: 'span', class: 'help-block' }
- 1
b.use :hint, wrap_with: { tag: 'p', class: 'help-block' }
end
- 1
config.wrappers :vertical_boolean, tag: 'div', class: 'form-group', error_class: 'has-error' do |b|
- 1
b.use :html5
- 1
b.optional :readonly
- 1
b.wrapper tag: 'div', class: 'checkbox' do |ba|
- 1
ba.use :label_input
end
- 1
b.use :error, wrap_with: { tag: 'span', class: 'help-block' }
- 1
b.use :hint, wrap_with: { tag: 'p', class: 'help-block' }
end
- 1
config.wrappers :vertical_radio_and_checkboxes, tag: 'div', class: 'form-group', error_class: 'has-error' do |b|
- 1
b.use :html5
- 1
b.optional :readonly
- 1
b.use :label, class: 'control-label'
- 1
b.use :input
- 1
b.use :error, wrap_with: { tag: 'span', class: 'help-block' }
- 1
b.use :hint, wrap_with: { tag: 'p', class: 'help-block' }
end
- 1
config.wrappers :horizontal_form, tag: 'div', class: 'form-group', error_class: 'has-error' do |b|
- 1
b.use :html5
- 1
b.use :placeholder
- 1
b.optional :maxlength
- 1
b.optional :pattern
- 1
b.optional :min_max
- 1
b.optional :readonly
- 1
b.use :label, class: 'col-sm-3 control-label'
- 1
b.wrapper tag: 'div', class: 'col-sm-9' do |ba|
- 1
ba.use :input, class: 'form-control'
- 1
ba.use :error, wrap_with: { tag: 'span', class: 'help-block' }
- 1
ba.use :hint, wrap_with: { tag: 'p', class: 'help-block' }
end
end
- 1
config.wrappers :horizontal_file_input, tag: 'div', class: 'form-group', error_class: 'has-error' do |b|
- 1
b.use :html5
- 1
b.use :placeholder
- 1
b.optional :maxlength
- 1
b.optional :readonly
- 1
b.use :label, class: 'col-sm-3 control-label'
- 1
b.wrapper tag: 'div', class: 'col-sm-9' do |ba|
- 1
ba.use :input
- 1
ba.use :error, wrap_with: { tag: 'span', class: 'help-block' }
- 1
ba.use :hint, wrap_with: { tag: 'p', class: 'help-block' }
end
end
- 1
config.wrappers :horizontal_boolean, tag: 'div', class: 'form-group', error_class: 'has-error' do |b|
- 1
b.use :html5
- 1
b.optional :readonly
- 1
b.wrapper tag: 'div', class: 'col-sm-offset-3 col-sm-9' do |wr|
- 1
wr.wrapper tag: 'div', class: 'checkbox' do |ba|
- 1
ba.use :label_input
end
- 1
wr.use :error, wrap_with: { tag: 'span', class: 'help-block' }
- 1
wr.use :hint, wrap_with: { tag: 'p', class: 'help-block' }
end
end
- 1
config.wrappers :horizontal_radio_and_checkboxes, tag: 'div', class: 'form-group', error_class: 'has-error' do |b|
- 1
b.use :html5
- 1
b.optional :readonly
- 1
b.use :label, class: 'col-sm-3 control-label'
- 1
b.wrapper tag: 'div', class: 'col-sm-9' do |ba|
- 1
ba.use :input
- 1
ba.use :error, wrap_with: { tag: 'span', class: 'help-block' }
- 1
ba.use :hint, wrap_with: { tag: 'p', class: 'help-block' }
end
end
- 1
config.wrappers :inline_form, tag: 'div', class: 'form-group', error_class: 'has-error' do |b|
- 1
b.use :html5
- 1
b.use :placeholder
- 1
b.optional :maxlength
- 1
b.optional :pattern
- 1
b.optional :min_max
- 1
b.optional :readonly
- 1
b.use :label, class: 'sr-only'
- 1
b.use :input, class: 'form-control'
- 1
b.use :error, wrap_with: { tag: 'span', class: 'help-block' }
- 1
b.use :hint, wrap_with: { tag: 'p', class: 'help-block' }
end
- 1
config.wrappers :multi_select, tag: 'div', class: 'form-group', error_class: 'has-error' do |b|
- 1
b.use :html5
- 1
b.optional :readonly
- 1
b.use :label, class: 'control-label'
- 1
b.wrapper tag: 'div', class: 'form-inline' do |ba|
- 1
ba.use :input, class: 'form-control'
- 1
ba.use :error, wrap_with: { tag: 'span', class: 'help-block' }
- 1
ba.use :hint, wrap_with: { tag: 'p', class: 'help-block' }
end
end
# Wrappers for forms and inputs using the Bootstrap toolkit.
# Check the Bootstrap docs (http://getbootstrap.com)
# to learn about the different styles for forms and inputs,
# buttons and other elements.
- 1
config.default_wrapper = :vertical_form
- 1
config.wrapper_mappings = {
check_boxes: :vertical_radio_and_checkboxes,
radio_buttons: :vertical_radio_and_checkboxes,
file: :vertical_file_input,
boolean: :vertical_boolean,
datetime: :multi_select,
date: :multi_select,
time: :multi_select
}
end
# Be sure to restart your server when you modify this file.
# This file contains settings for ActionController::ParamsWrapper which
# is enabled by default.
# Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
- 1
ActiveSupport.on_load(:action_controller) do
- 1
wrap_parameters format: [:json] if respond_to?(:wrap_parameters)
end
# To enable root element in JSON for ActiveRecord objects.
# ActiveSupport.on_load(:active_record) do
# self.include_root_in_json = true
# end
- 1
Rails.application.routes.draw do
- 1
get 'venues/create'
- 1
get 'sessions/new'
- 1
get 'sessions/create'
- 1
get 'users/new'
- 1
get 'users/create'
- 1
root 'events#index'
- 1
get '/events/:event_id/tickets/thank_you' => 'tickets#thank_you'
- 1
resources :events do
- 1
resources :tickets
end
- 1
get 'signup' => 'users#new'
- 1
post 'signup' => 'users#create'
- 1
get 'login' => 'sessions#new'
- 1
post 'login' => 'sessions#create'
- 1
get 'logout' => 'sessions#destroy'
- 1
get 'manage' => 'events#manage_events'
- 1
post 'venues' => 'venues#create'
- 1
get 'events/publish/:id' => 'events#publish'
- 1
get 'events/:event_id/ticket_type/:ticket_type_id/delete' => 'events#remove_ticket_type'
- 1
post 'events/:event_id/ticket_type/new' => 'events#new_ticket_type'
# The priority is based upon order of creation: first created -> highest priority.
# See how all your routes lay out with "rake routes".
# You can have the root of your site routed with "root"
# root 'welcome#index'
# Example of regular route:
# get 'products/:id' => 'catalog#view'
# Example of named route that can be invoked with purchase_url(id: product.id)
# get 'products/:id/purchase' => 'catalog#purchase', as: :purchase
# Example resource route (maps HTTP verbs to controller actions automatically):
# resources :products
# Example resource route with options:
# resources :products do
# member do
# get 'short'
# post 'toggle'
# end
#
# collection do
# get 'sold'
# end
# end
# Example resource route with sub-resources:
# resources :products do
# resources :comments, :sales
# resource :seller
# end
# Example resource route with more complex sub-resources:
# resources :products do
# resources :comments
# resources :sales do
# get 'recent', on: :collection
# end
# end
# Example resource route with concerns:
# concern :toggleable do
# post 'toggle'
# end
# resources :posts, concerns: :toggleable
# resources :photos, concerns: :toggleable
# Example resource route within a namespace:
# namespace :admin do
# # Directs /admin/products/* to Admin::ProductsController
# # (app/controllers/admin/products_controller.rb)
# resources :products
# end
end
- 1
require "rails_helper"
- 1
require "shared_upcoming_event"
- 1
RSpec.describe EventsController, type: :controller do
- 1
describe "GET #index" do
- 1
include_context "shared context for up coming events"
- 1
it "responds successfully with HTTP status code 200 for" do
- 1
get :index
- 1
expect(response).to be_success
- 1
expect(response).to have_http_status(200)
end
- 1
it "render template index for" do
- 1
get :index
- 1
expect(response).to render_template("index")
end
- 1
it "load all upcoming events for" do
- 1
get :index
- 1
expect(assigns(:events)).to match_array([@upcomingEvent, @upcomingEvent2])
end
end
- 1
describe "GET #index?search=something" do
- 1
include_context "shared context for up coming events"
- 1
it "show the search result correctly" do
- 1
get :index, :search => 'Upcoming'
- 1
expect(assigns(:events)).to match_array(@upcomingEvent)
end
end
- 1
describe "GET #publish/:id" do
- 1
include_context "shared context for up coming events"
- 1
it "return error when try to publish event that don't have any ticket type" do
# login
- 1
session[:user_id] = @user.id
- 1
@user.events << @unpublishedEvent
- 1
get :publish, {:id => @unpublishedEvent.id}
- 1
expect(flash[:error]).to eq("You don't have permission to publish this event")
end
- 1
it "publish event successfully" do
# login
- 1
session[:user_id] = @user.id
- 1
@user.events << @unpublishedEvent
- 1
@unpublishedEvent.ticket_types << TicketType.create!(:name => "Normal", :price => 50000, :max_quantity => 10)
- 1
get :publish, {:id => @unpublishedEvent.id}
- 1
expect(flash[:success]).to eq("Event<EMAIL_ADDRESS>published successfully")
end
end
- 1
describe "GET #events/:id/edit" do
- 1
include_context "shared context for up coming events"
- 1
it "redirect to manage events screen if user don't have permission to edit event" do
# login
- 1
session[:user_id] = @user.id
- 1
get :edit, {id: @upcomingEvent.id}
- 1
expect(response).to redirect_to(manage_path)
end
- 1
it "show edit page when user has permission to edit event" do
# login
- 1
session[:user_id] = @user.id
- 1
@user.events << @upcomingEvent
- 1
get :edit, {id: @upcomingEvent.id}
- 1
expect(response).to render_template("edit")
end
end
end
- 1
require 'rails_helper'
- 1
RSpec.describe SessionsController, type: :controller do
- 1
describe "GET #new" do
- 1
it "returns http success" do
- 1
get :new
- 1
expect(response).to have_http_status(:success)
end
end
end
- 1
require 'rails_helper'
- 1
RSpec.describe UsersController, type: :controller do
- 1
describe "GET #new" do
- 1
it "returns http success" do
- 1
get :new
- 1
expect(response).to have_http_status(:success)
end
end
end
- 1
require 'rails_helper'
- 1
require "shared_upcoming_event"
- 1
RSpec.feature "Events", type: :feature do
- 1
include_context "shared context for up coming events"
- 1
it "go to booking page" do
- 1
visit<EMAIL_ADDRESS>- 1
click_button "BOOK NOW"
- 1
expect(page).to have_content @upcomingEvent.name
end
end
- 1
require "rails_helper"
# Specs in this file have access to a helper object that includes
# the EventsHelper. For example:
#
# describe EventsHelper do
# describe "string concat" do
# it "concats two strings with spaces" do
# expect(helper.concat_strings("this","that")).to eq("this that")
# end
# end
# end
# RSpec.describe EventsHelper, type: :helper do
# include_context "shared context for up coming events"
# it "loaded list of upcoming events successfully" do
# events = upcoming_events
# expect(events).to contain_exactly(@upcomingEvent)
# end
# end
- 1
require 'rails_helper'
# Specs in this file have access to a helper object that includes
# the SessionsHelper. For example:
#
# describe SessionsHelper do
# describe "string concat" do
# it "concats two strings with spaces" do
# expect(helper.concat_strings("this","that")).to eq("this that")
# end
# end
# end
- 1
RSpec.describe SessionsHelper, type: :helper do
- 1
pending "add some examples to (or delete) #{__FILE__}"
end
- 1
require 'rails_helper'
# Specs in this file have access to a helper object that includes
# the UsersHelper. For example:
#
# describe UsersHelper do
# describe "string concat" do
# it "concats two strings with spaces" do
# expect(helper.concat_strings("this","that")).to eq("this that")
# end
# end
# end
- 1
RSpec.describe UsersHelper, type: :helper do
- 1
pending "add some examples to (or delete) #{__FILE__}"
end
- 1
require 'rails_helper'
- 1
require "shared_upcoming_event"
- 1
RSpec.describe Event, type: :model do
- 1
include_context "shared context for up coming events"
- 1
it "loaded list of upcoming events successfully" do
- 1
events = Event.upcoming_events
- 1
expect(events).to match_array([@upcomingEvent, @upcomingEvent2])
end
- 1
it "search events by name" do
- 1
events = Event.search("Upcoming")
- 1
expect(events).to match_array(@upcomingEvent)
end
end
- 1
require 'rails_helper'
- 1
RSpec.describe Ticket, type: :model do
- 1
before(:each) do
- 2
@ticket_type = TicketType.create(:price => 50000, :name => "Normal", :max_quantity => 10)
end
- 1
it "create new ticket with quantity less than max quantity" do
- 1
ticket = Ticket.new(:quantity => 5)
- 1
ticket.ticket_type = @ticket_type
- 1
ticket.save
- 1
expect(ticket.errors.messages.length).to eq 0
end
- 1
it "create new ticket with quantity greater than max quantity will raise error" do
- 1
ticket = Ticket.new(:quantity => @ticket_type.max_quantity + 1)
- 1
ticket.ticket_type = @ticket_type
- 2
expect { ticket.save }.to raise_error("Quantity exceeds the max quantity (#{ticket.quantity} > #{@ticket_type.max_quantity})")
end
end
- 1
require 'rails_helper'
- 1
RSpec.describe User, type: :model do
- 1
pending "add some examples to (or delete) #{__FILE__}"
end
# This file is copied to spec/ when you run 'rails generate rspec:install'
- 1
ENV['RAILS_ENV'] ||= 'test'
- 1
require File.expand_path('../../config/environment', __FILE__)
# Prevent database truncation if the environment is production
- 1
abort("The Rails environment is running in production mode!") if Rails.env.production?
- 1
require 'spec_helper'
- 1
require 'rspec/rails'
# Add additional requires below this line. Rails is not loaded until this point!
# Requires supporting ruby files with custom matchers and macros, etc, in
# spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are
# run as spec files by default. This means that files in spec/support that end
# in _spec.rb will both be required and run as specs, causing the specs to be
# run twice. It is recommended that you do not name files matching this glob to
# end with _spec.rb. You can configure this pattern with the --pattern
# option on the command line or in ~/.rspec, .rspec or `.rspec-local`.
#
# The following line is provided for convenience purposes. It has the downside
# of increasing the boot-up time by auto-requiring all files in the support
# directory. Alternatively, in the individual `*_spec.rb` files, manually
# require only the support files necessary.
#
# Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
# Checks for pending migration and applies them before tests are run.
# If you are not using ActiveRecord, you can remove this line.
- 1
ActiveRecord::Migration.maintain_test_schema!
- 1
RSpec.configure do |config|
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
- 1
config.fixture_path = "#{::Rails.root}/spec/fixtures"
# If you're not using ActiveRecord, or you'd prefer not to run each of your
# examples within a transaction, remove the following line or assign false
# instead of true.
- 1
config.use_transactional_fixtures = true
# RSpec Rails can automatically mix in different behaviours to your tests
# based on their file location, for example enabling you to call `get` and
# `post` in specs under `spec/controllers`.
#
# You can disable this behaviour by removing the line below, and instead
# explicitly tag your specs with their type, e.g.:
#
# RSpec.describe UsersController, :type => :controller do
# # ...
# end
#
# The different available types are documented in the features, such as in
# https://relishapp.com/rspec/rspec-rails/docs
- 1
config.infer_spec_type_from_file_location!
# Filter lines from Rails gems in backtraces.
- 1
config.filter_rails_from_backtrace!
# arbitrary gems may also be filtered via:
# config.filter_gems_from_backtrace("gem name")
end
- 1
require 'rails_helper'
- 1
require "shared_upcoming_event"
- 1
RSpec.describe "routing to events", :type => :routing do
- 1
describe "/events" do
- 1
it "routes root to events#index" do
- 1
expect(:get => "/").to route_to(
:controller => "events",
:action => "index"
)
end
- 1
it "routes /events to events#index" do
- 1
expect(:get => "/events").to route_to(
:controller => "events",
:action => "index"
)
end
end
- 1
describe "/events/:id" do
- 1
include_context "shared context for up coming events"
- 1
it "routes /events/:id to events#show" do
- 1
expect(:get => "/events/#{@upcomingEvent.id}").to route_to(
:controller => "events",
:action => "show",
:id =><EMAIL_ADDRESS>)
end
end
end
- 1
require "spec_helper"
- 1
RSpec.shared_context "shared context for up coming events" do
- 8
before do
# Create Regions
- 13
['Ho Chi Minh', 'Ha Noi', 'Binh Thuan', 'Da Nang', 'Lam Dong'].each do |r|
- 65
Region.create(name: r)
end
# Create Categories
- 13
['Entertainment', 'Learning', 'Everything Else'].each do |c|
- 39
Category.create(name: c)
end
- 13
@user = User.create!(:name => "Admin", :email =><EMAIL_ADDRESS>:password => "1")
- 13
dalat = Venue.create({
name: 'Da Lat City',
full_address: 'Ngoc Phat Hotel 10 Hồ Tùng Mậu Phường 3, Thành phố Đà Lạt, Lâm Đồng, Thành Phố Đà Lạt, Lâm Đồng',
region: Region.find_by(name: 'Lam Dong')
})
- 13
@upcomingEvent = Event.create!(
:starts_at => 3.days.ago,
:ends_at => 3.days.from_now,
:venue => dalat,
:extended_html_description => "A upcoming event",
:category => Category.new,
:name => "Upcoming event",
:published => true
)
- 13
@upcomingEvent2 = Event.create!(
:starts_at => 3.days.ago,
:ends_at => 3.days.from_now,
:venue => Venue.new,
:extended_html_description => "This's new events",
:category => Category.new,
:name => "This's new events",
:published => true
)
- 13
@pastEvent = Event.create!(
:starts_at => 5.days.ago,
:ends_at => 2.days.ago,
:venue => Venue.new,
:extended_html_description => "Past event",
:category => Category.new,
:name => "Past event",
:published => true
)
- 13
@unpublishedEvent = Event.create!(
:starts_at => 3.days.ago,
:ends_at => 3.days.from_now,
:venue => dalat,
:extended_html_description => "An unpublished event",
:category => Category.new,
:name => "Unpublished event",
:published => false
)
end
end
- 1
require "spec_helper"
- 1
require "shared_upcoming_event"
- 1
RSpec.describe "events/index", :type => :view do
- 1
include_context "shared context for up coming events"
- 1
it "renders _card for each event" do
- 1
assign(:events, [
double(Event, :name => "Upcoming event 1", :hero_image_url => "images/some_img_1.jpg", :extended_html_description => "Some description 1"),
double(Event, :name => "Upcoming event 2", :hero_image_url => "images/some_img_2.jpg", :extended_html_description => "Some description 2")
])
- 1
render
- 1
expect(view).to render_template(:partial => "_card", :count => 2)
- 1
expect(rendered).to include("Upcoming event 1")
- 1
expect(rendered).to include("Upcoming event 2")
- 1
expect(rendered).to include("Some description 1")
- 1
expect(rendered).to include("Some description 2")
end
end
- 1
require 'rails_helper'
- 1
RSpec.describe "sessions/create.html.erb", type: :view do
- 1
pending "add some examples to (or delete) #{__FILE__}"
end
- 1
require 'rails_helper'
- 1
RSpec.describe "sessions/new.html.erb", type: :view do
- 1
pending "add some examples to (or delete) #{__FILE__}"
end
- 1
require 'rails_helper'
- 1
RSpec.describe "users/create.html.erb", type: :view do
- 1
pending "add some examples to (or delete) #{__FILE__}"
end
- 1
require 'rails_helper'
- 1
RSpec.describe "users/new.html.erb", type: :view do
- 1
pending "add some examples to (or delete) #{__FILE__}"
end
- 1
require 'rails_helper'
- 1
RSpec.describe "venues/create.html.erb", type: :view do
- 1
pending "add some examples to (or delete) #{__FILE__}"
end


Github Issue: #3777
When using the `showSelectAll` setting with no selectable options present, the Dropdown/Multiselect will not show the "Select All" option either.


Oil Change
Our routine oil changes will keep your engine running safe, strong and healthy.
Read MoreWhy is Maintenance Important?
Longer life, better durability, and greater performance
Preventive car care reduces wear and tear of the engine and other components that extend the life of your vehicle.
Check out these following articles on car maintenance:
Car Video Tutorials
Video# 1
Changing shocks and springs
your vehicle's shocks and struts follow a specific maintenance schedule. Experts say that shocks and struts should be replaced every 50,000 to 100,000 miles. However, that's just a general recommendation.Video# 2
Changing tires
Having insufficient tread can result in skidding and losing control of your vehicle. If the tread of your tires ever falls below 1/16 of an inch, you should definitely replace your tires.Video# 3
Changing oil
Routine oil and filter changes help remove particles and sludge and keep engines at peak condition and improves gas mileage.Video# 4


Parametric 3D building schematics created and updated in a game-like fashion
Building Area:
Building Length:
Building Width:
Number of Floors (not fully functional):
Floor Height:
Perimeter Depth meters:
Window Wall Ratio %:
Overhang Depth:
Orientation degrees:


If nothing is showing up when you load the page, please go here, download the extension, and then reload the page
Instructions for sending messages
1 Connect to the wifi name "builds-sec", the password is written on the whiteboard
2 Click on the three dots in the upper right corner of the screen
3 Click on "Cast..."
4 Select the chromecast name "Hank the Tank" and wait until it is successfully connected
5 Once you are connected, enter your message into the text box and hit the send message button


About Me Resume
Hi! I’m Clarissa. My pronouns are she/her/hers.  I am from
Southern Utah, a place so small you’ve probably never heard of it, called Spry. I grew up on a ranch, where I
learned to love horses, problem solve, and work hard.
I’m a mass appraiser by trade. Which means I appraise a lot of properties at once, for property taxes (yep,
I’m the dreaded tax 'man'). I love that I get to work with
large amounts of data, and GIS is the toy that keeps me going back to the office. The process of learning to
write SQL queries has been tough, but amazingly rewarding. I’m excited to learn more about coding, so I can
put it to use at work, and possibly volunteering for a non-profit.
My two dogs, Lottie and Tanna, are the light of my life; literally the reason I get out of bed in the morning. They are both mutts, that were rejected from working on the ranch. In my spare time I like to read, currently my favorite genre is Historical Fiction. I also like to joke that I’m a hooker, someone who crochets, I also knit. I make lots of hats, baby bibs and blankets, toys, and bags as gifts. From time to time I enjoy spending time with my nieces and nephews, whom I collectively call ‘The Grandkids’.


Main Street to Moorefield GAA Club
•Head Southwest on Edward Street to the Curragh
•Continue onto Moorefield Road
•Continue onto Ballymany Road/ R445
•At the Roundabout take the 3rd exit onto R413/ R445
•Continue to follow R413
•Go through the roundabout (To Kildare Town)
•Take a right turn after the Curragh Racecourse
•Go over the bridge
•Moorefield is on your left hand side
Folklore records that in 1882 two brothers, John O'Kelly of Moorefield Road and James O'Kelly of Ballymany were instrumental in forming the first football team in Newbridge. Calling themselves the JJ O'Kellys they played matches against Mountrice, Eyrefield, Monasterevin, Kildare town and Milltown. In 1884, when the GAA was formed, the club changed its name from JJ O'Kelly's to Moorefield, the name of a townland in southern Newbridge.


Student Result | Teacher
Toggle navigation
Logout
Main Category
Dashboard
Appearance
View Details
View Marks
View Attendance
View Schedule
User Change Password
Dashboard
View Details
View Marks
view Attendance
View Schedule


untest_2_hooks.lua
-- You can call a function to run before and after each test. -- It allows you to reset/cleanup your setup between each test. before_each = function () -- do stuff before each test -- e.g: move items back to chest, reset some condition, etc. end after_each = function () -- do stuff after each test end describe("The count() function", function () it("sould return a number", function () -- some test end) it("can take a item name", function () local result = super_inventory.count("minecraft:stone") assert(result == 64) end) end)


Open Source Telemedicine Platform
Overview
The Sana technology platform includes an extensive set of healthcare tools for the collection, transmission, storage, and analysis of medical data. When fully installed and configured, the tools provide an end-to-end system connecting remote healthcare workers to physicians, and managing medical data.
Key Features of the platform include:
- Multi-user mobile client with programmable workflow that provides decision support, directs remote workers in the collection of data, connection between workers and physicians, and integrates with point of care applications and devices.
- Middleware which provides a secure communication layer for secure, optimized transmission over poor or intermittent networks and allows for connection to a broad range of data storage and web applications.
- Host based data storage in a relational database along with web applications for accessing and managing data.
- Ready to deploy packages.
All Sana software products are available under an open-source license to increase availability and encourage community contribution.


Dua Lipa makes it two weeks at the top of the Official Irish Singles Chart with Don’t Start Now
Youtuber, rapper and boxer KSI scores this week's highest new entry.
by Jack WhiteDua Lipa is Number 1 of the Official Irish Singles Chart for a second week.
The lead single from Dua’s upcoming second album, Don’t Start Now increased its performance week-on-week to finish 1500 chart sales ahead of the competition. Don’t Start Now has so far reached Number 1 solely in Ireland, peaking at Number 2 in the UK and reaching the Top 10 in Australia, Hungary, Israel and New Zealand.
Niall Horan continues to climb with Nice To Meet Ya, up two to Number 7, while Meduza and Goodboys score their second Top 10 together; alongside Becky Hill, Lose Control lifts three to Number 8. Just outside at Number 12 is Arizona Xervas, who rises nine spots to Number 13 with Roxanne. Meanwhile, British DJ Endor is this week’s highest climber with Pump It Up which rockets 14 places to Number 28.
YouTuber KSI scores this week’s highest new entry with Down Like That; featuring Rick Ross, Lil Baby and S-X, the song debuts at Number 32 following his boxing match win over fellow content creator Logan Paul on November 9.
UK rappers Dave and J Hus debut back-to-back at 35 and 36 with Paper Cuts and Must Be respectively, and Ant Saunders makes his chart debut with Yellow Hearts, which is at 43 after gaining traction on social media app TikTok. Finally, English MC Fredo lands at 48 with Netflix & Chill.
See the full Official Irish Singles Chart Top 50
Listen to The Official Chart with Bláthnaid Treacy at 8pm every Friday on RTÉ 2FM.
© IRMA


Cross-boarder eCommerce
The client is one of America’s largest department stores and had identified China as a market for international expansion. The client wanted to use an online-only market entry model that would allow them to test the market before investing in traditional physical retailing models.
In this stage, we conducted researches of the eCommerce landscape in China, and found that nowadays China eCommerce is moving towards content and social driven business. Content is blooming in China and changing the pattern of consumption. The crossover between content and eCommerce becomes new trend. For example, the video and editorial content is blooming with increasing amount of new media platforms. Meanwhile, social media has become a powerful channel for initiating online purchases in China. It is also the new service hub of brands and retailers for customers.
1.1 Persona & Journey Mapping
We started project with customer insight. The 200+ survey responses and 20+ interview records supported us to design the persona and user journey
The journey clearly shows how the target customers usually shopping on the digital devices. It helped us find the opportunities for our products
Insight: she’s looking for ways to shine and to inspire new lifestyles.
Solution: tell Macy’s about yourself and we’ll show you a tailor made experience. Macy’s will help her manage the stress of modern life in a personalised, lifestyle-driven way by giving her the tools to create her own style.
She sees herself in xx
Insight: she wants a individualistic sense of style in a non-individualistic society.
Solution: Macy’s must help her feel herself every step of the way through personalisation, gamification and intuitive AI. This is a key feature to drive loyalty. We call this the Macy’s star. Her Macy’s star will be an icon for progress and membership points.
2.2 Design mockups
1.2 Workshop
Based on the previous research, we figured out the localized UX solutions for China market.
1.2 Sitemap & Wireframe
Based on the previous research, we figured out the localized UX solutions for China market.
For example, as client are going to bring the largest catalog into China, we enriched the product data and curated content to be relevant in the China market. In terms of product details, Chinese consumer prefer to review the rich content of product, so besides the base template which shows basic w2w info integrated from brand.com, we also proposed a rich template for hottest products, which will show the customized comprehensive info, including images and videos.
2.1 Art direction
We developed two concepts of art direction initially. By interviewing and collectiong the stakeholders' opnion, we finally define the following art direction.
2.2 Visual Design


Vivo Y5s announced in China; It's a rebranded Vivo Y19 - Gizchina.com
by Marco LancasterVivo Y5s announced in China; It’s a rebranded Vivo Y19
3 (60%) 2 votes
Vivo has announced today a new mid-range contender for the domestic market of China. The device in question carries the Vivo Y5s moniker, but you have been following the Chinese company in the Global scene you will be very familiar with it. Actually, the Y5s is a rebranded Vivo Y19, a device that was launched in Thailand and Vietnam during the last week.
Vivo Y5s specifications
Knowing this fact, there aren’t any differences. The Vivo Y5s bears the same 6.53″ FHD+ display with a teardrop notch atop housing the 16MP selfie snapper. Moving around to the back, we can easily spot a triple-camera setup. This particular setup comprises of 16MP main, 8MP ultrawide, and 2MP macro units. According to Vivo’s official information, the ultrawide cam allows you to capture pictures with a field of view of 120º. When it comes to the 2MP macro sensor, you’ll be able to capture objects from as close as 4cm.
Vivo’s romance with MediaTek continues with the Vivo Y5s since it sports the Helio P65 chipset. The horsepower is coupled with 6GB of RAM and 128GB of Internal Storage. Software side, the handset runs Android 9 Pie-based FunTouch OS 9.2 straight out the box. If you’re familiarized with Vivo’s traditional skin, then you know that Game Cube, Multi Turbo, and AI-based digital assistant Jovi are making a comeback. Last but not least, the device draws power from a generous 5,000mAh battery with 18W fast-charging.
The Y5s will be sold in China for CNY1,498 ($215/€190). However, Vivo still needs to disclose when customers will be able to purchase it from their website or local retailers.


I agree to Abide by the terms and conditions of admission prevailing at this hospital and hold myself responsible for payment of all bills of this patient before discharge from this hospital.


JuJu Smith-Schuster injury update: Steelers WR suffers concussion after helmet-to-helmet hits
by Dan BernsteinSteelers wide receiver Juju Smith-Schuster was forced out of Thursday's game againstthe Browns with a concussion after taking twohelmet-to-helmet hits on one play in the second quarter.
Cleveland defensive backs Greedy Williams and Morgan Burnett dealt the blows on a pass play over the middle.
Smith-Schuster walked to the locker room, where he was later diagnosed with the concussion.
TIMELINE: Browns, Steelers add another incident to AFC North's ugly decade
There wasn't an update on Smith-Schuster's status Friday, except for a tweet from his personal Twitter account.
"I will be ok and can’t wait to get back out on the field with my brothers," he said,
Want to thank everyone for the thoughts and prayers from the injury last night. I will be ok and can’t wait to get back out on the field with my brothers. pic.twitter.com/SV09EGwr4o
— JuJu Smith-Schuster (@TeamJuJu) November 15, 2019
">thanking fans for their support.
He followed up that tweet with another expressing speedy recoveries to teammates James Conner, Diontae Johnson, Artie Burns Jr. andOlasunkanmi Adeniyi, all of whom were injured in the 21-7 loss. Johnson joined Smith-Schuster in concussion protocol and was seen bleeding from his ear as he exited the field Thursday.
Smith-Schuster was placed inconcussion protocol on two occasions in 2017 when he was a rookie.
The 22-year-old receiver has made 17 touchdown catches in less than three NFL seasons and is considered a focal point of Pittsburgh's offense.


CRAZY/BEAUTIFUL ---------------
Nicole Oakley (Kirsten Dunst, "Bring It On") is the troubled, substance abusing daughter of a Congressman who attends high school in upscale Pacific Palisades. While performing community service cleaning the beach as payback for a D.W.I. conviction, Nicole's harassed by a group of Latino teens from a poorer part of town, but one of them, Carlos Nunez (Jay Hernandez), catches her eye. The good looking, polite young man also attends her high school - by travelling on public transportation for two hours each way, each day - because he wants a good education in order to attend Annapolis. These two are "Crazy/Beautiful."
Will the wild, rebellious girl drag down the fine, upstanding young man or will he snap her out of her self-destructive streak? "Crazy/Beautiful's" conflict resolution is too pat in Phil Hay and Matt Manfredi's ("Bug") script, but the two leads make the film somewhat engaging.
Of course, first you'll need accept that straight arrow Carlos would give a second glance to a girl who's usually drunk, gets him into detention at their second meeting, dances provocatively through the streets of his neighborhood, tries to bed him within view of her own father (who mistakes him for their housekeeper's nephew) and is disapproved of by his entire extended family. Once we're over this little hump, the filmmakers back off to show more of Nicole's free spirited, artistic side as well as the root of her problems.
Congressman Oakley takes an interest in the boy who wants to go to Annapolis and offers to sponsor him. Carlos unbelievably misses his scheduled meeting with the man, distracted by a beach outing with Nicole. When the two finally get together, he's warned to stay away from the troublemaking Nicole for his own good. For some odd reason, Carlos pays more heed to Nicole's father than his own family.
Director John Stockwell ("Under Cover") may be dealing with an implausible story, but he does get some fine performances from his cast. The talented Kirsten Dunst propels herself through the film in bleary, angry, defiance gradually letting her natural radiance peak through after time spent with Carlos. She's never looked rawer, sporting the bruised, vulnerable look of Jennifer Jason Leigh. Hernandez does his best to appear initially wary, but we never get a sense of the stress he's been under that would make his character jeopardize all he's worked for. Bruce Davison does a good job as the caring parent who's at wits end. Lucinda Jenney ("Thirteen Days") is simply shrewish as Nicole's new stepmom. Taryn Manning creates a fully fleshed character as Nicole's best friend Maddy, but the script just leaves her by the wayside.
"Crazy/Beautiful" is reminiscent of Antonia Bird's 1995 film "Mad Love" which starred Drew Barrymore as a manic depressive in love with the upstanding Chris O'Donnell. While this film is a cut above that abysmal effort, it's conflict is forced and the resolution is pat.
C
For more Reeling reviews visit www.reelingreviews.com
<EMAIL_ADDRESS><EMAIL_ADDRESS>The review above was posted to the
rec.arts.movies.reviews newsgroup (de.rec.film.kritiken for German reviews).
The Internet Movie Database accepts no responsibility for the contents of the
review and has no editorial control. Unless stated otherwise, the copyright
belongs to the author.
Please direct comments/criticisms of the review to relevant newsgroups.
Broken URLs inthe reviews are the responsibility of the author.
The formatting of the review is likely to differ from the original due
to ASCII to HTML conversion.
Related links: index of all rec.arts.movies.reviews reviews


The goal of this post is simply to trigger pagination, and see that we do not index the pagination results.


The next portion of this website should serve as a resource for the musicians involved with the event.
If you have a problem with your music being represented here, contact me.


Cheese Survey
Hole-y cow! Welcome, and thanks in advance for brieezing through our survey to help us decide what cheeses are gouda and which ones aren't worth your cheddar. Please don't be a muenster - fill out the form completely!
Hole-y cow! Welcome, and thanks in advance for brieezing through our survey to help us decide what cheeses are gouda and which ones aren't worth your cheddar. Please don't be a muenster - fill out the form completely!


Project about the visualization of the interactions between miners.
This is a Project developed during my last year at Third University of Rome. The scope of the project is to Visualize the Miners interactions. (Miner - a particular user who collaborate in the building of bitcoin blockchain).
We chose to develope two types of Visualization, once for the Macro-interactions and once for Micro-interactions (interactions on a singe block of the blockchain). In the macro-interactions Visualization it’s possible to view the interactions between miners over the time. In particular it is possible to view miners that collaborated in the same blocks. So we can see the nodes as the miners and the links as the collaboration between two miners.
In the micro-interactions Visualization instead, we can see a small number of blocks as the green nodes, the red nodes as the miners and a link between them if the miner mined the block.
Five filters have been developed to reduce the huge amount of informations.
After installation, you can open the index.html (firefox recommended) that will show up two panels and after the setting of the filters you can push one of the button of the views to see your graph.
Date
October 2014
See on GitHub
https://github.com/V1LL0/bitcoinVisualization
Authors and Contributors
This Project is developed by @V1LL0 and @Pausa90


{% extends "base_foundation.html" %} {% load i18n %} {% block content %}
{% blocktrans %} The following organizations are corporate members of the Django Software Foundation. If you are interested in becoming a corporate member of the DSF, you can find out more on our corporate membership page. {% endblocktrans %}
{{ member.description|linebreaksbr }}


:: com :: sun :: star :: configuration ::
|
| service SetAccess |
- Description
- provides access to a dynamic, homogeneous set of values or nested
trees within a hierarchy.
Also provides information about the template for elements.
Allows normalizing externally generated names.
Sets are dynamic containers within the hierarchy.
The number and names of contained elements are not fixed in advance,
but all elements have to be of one predetermined type.
- See also
- SetElement
Child objects of this service generally implement SetElement.
The template name returned by the child from
XTemplateInstance::getTemplateName()
corresponds to the name returned by the set from
XTemplateContainer::getElementTemplateName().
- See also
- GroupAccess
A complementary service that provides for static heterogeneous groups of
elements within the hierarchy.
|
| Included Services - Summary |
| HierarchyAccess |
is the basic service for accessing child and descendent nodes in a hierarchy.
(details)
|
| SimpleSetAccess |
is the basic service providing information about and access to elements
of a not necessarily hierarchical set.
(details)
|
| Exported Interfaces - Summary |
| ::com::sun::star::container::XContainer |
allows attaching listeners to this node to monitor changes to the set.
(details)
|
| Included Services - Details |
HierarchyAccess
- Description
- is the basic service for accessing child and descendent nodes in a hierarchy.
External names (from foreign namespaces) should be normalized using
::com::sun::star::util::XStringEscape::escapeString()
(if available) before using them as element names.
|
|
SimpleSetAccess
- Description
- is the basic service providing information about and access to elements
of a not necessarily hierarchical set.
Interface XTemplateContainer,
which is optional in SimpleSetAccess must always be implemented
in this service, if the elements are of object type.
|
|
| Exported Interfaces - Details |
::com::sun::star::container::XContainer
- Description
- allows attaching listeners to this node to monitor changes to the set.
In this service, support for notifications is mandatory.
|
|
Top of Page
Copyright © 2013, The Apache Software Foundation, Licensed under the Apache License, Version 2.0. Apache, the Apache feather logo, Apache OpenOffice and OpenOffice.org are trademarks of The Apache Software Foundation. Other names may be trademarks of their respective owners.


Make your own chat room and share with your friends - chat.techcentroid.com/ you room name
eg: http://chat.techcentroid.com/1245
And share with your firends, or you could simply hang out in the lobby.
It is free and open source and released under MIT license, go ahead you can even sell it if you can.
No need to sign-up or login, just get started instantly.
Now easily group chat with any number of people, just share the url of your room and that's it!