The game hexplode lets two players fight one another using exploding stacks of their tokens as means to take over enemy tokens. Over time, chain reactions become more and more common and as a result the game becomes difficult to predict. Here, I implement a ‘minimax’ algorithm to create a (very basic) computer player for this game. You can test your skills against it here
The Game
Hexplode is almost as old as space invaders. The game of was first created as a BASIC program for the BBC Micro written by J. Ansell in 1982. I started working on this game as part of the 2016 Man AHL coder prize. I am using their implementation here, which is openly available on GitHub. Their summary of the game is this:
Hexplode is played by 2 players on a board of hexagonal tiles. The players take turns to place a counter on the board, they can only play a counter in an empty tile or a tile they already own. When the number of counters on a given tile equals the number of adjacent tiles the tile hexplodes and the contents of the tile are equally distributed to its neighbours changing the ownership of neighbouring counters over to the current player in the process. This process can often generate a chain reaction. The winner is the player that removes all of their opponents counters from the board.
Man AHL ships their version with a flask app that allows us to run the game as a web server. This can be done either locally, or in the cloud. I have a version running on PythonAnywhere, which you can access at http://janlauge.pythonanywhere.com. Here is an example of what it looks like:
On the algorithm backend, the game is represented by a simple board state in the form of a
python dictionary. Each tile has a tile_id
, a score
(the number of counters on that tile),
an owner
(the ID of the player that owns the token on this tile),
and a list of neighbours
indicated by their respective ID
s.
board = {
<tile id>: {
'counters': <number of counters on tile or None>,
'player': <player id of the player who holds the tile or None>,
'neighbours': <list of ids of neighbouring tile>
},
...
}
The Algorithm
In a game-theoretical sense, hexplode is an adversarial, deterministic game with perfect information. This means that the players are pursuing opposing goals, that there is no element of chance or randomness, and that all information about the state of the game world is always available to all players.
All three of these are attributes that hexplode shares with chess. I therefore decided to start my work on the competition with a ‘MiniMax’ implementation. This algorithm uses a tree approach. Each branch is a possible move, each leaf represents the resulting board state. Board states in terminal leaves are evaluated one by one, as “game over” for either player (+/- infinity), or, if that does not apply, using a heuristic value function (see diagram below).
source: Wikimedia commons
Board State
Minimax is relatively straight-forward to implement. First, we need to be able to
calculate future board states as a function of our moves. We create a function
AddCounter
for this, which uses a list of scores, the board shape, the id of the
tile that the counter should be placed on, along with the player_id (the algorithm)
and the current player (the one placing the counter, because we want to be able to
simulate enemy moves as well). Note that this is a recursive function,
because placing a marker on a tile can create an instable board state with
as many counters on a tile as that tile has neighbours. In this case,
the tile will “hexplode”, distributing its counters to the neighbouring tiles.
This, in turn, could trigger subsequent hexplodes on those neighbouring tiles,
which would be handled by the respective recursions triggered by the function.
def AddCounter(scores, board, tile_id, player_id, player_current):
if (True in [score > 0 for score in scores.values()]) and (True in [score < 0 for score in scores.values()]):
#If player, counters are positive
if player_current == player_id:
add = +1
#If enemy, counters are negative
else:
add = -1
#If placing counter on own tile, increase counters
if (add > 0 and scores[tile_id] >= 0) or (add < 0 and scores[tile_id] <= 0):
counter = scores[tile_id] + add
#If placing counter on enemy tile, change and increase counters
else:
counter = (scores[tile_id] * -1) + add
#If field full, hexplode (recursive)
if abs(counter) == len(board[tile_id]["neighbours"]):
scores[tile_id] = 0
for neighbour in board[tile_id]["neighbours"]:
scores = AddCounter(scores, board, neighbour, player_id, player_current)
else:
scores[tile_id] = counter
return(scores)
else:
return(scores)
Growing Trees
Now that we can calculate and evaluate potential future board states, we can use this to
create a tree of move scenarios. A given board state allows for a number of moves
(“place a marker on any tile that is not an enemy tile”). When it is our turn,
we can make n_1
valid moves resulting in n_1
possible board states. Using
another recursion call we can calculate n_2
valid enemy moves with termination
conditions for a maximum depth (n_i
) and/or for a game-over situation
(one player looses all counters).
class Node(object):
def __init__(self, board, player_id, player_current, scores, depth, move=None):
self.player_current = player_current
self.move = move
self.scores = scores
#Check if game is over
if (True in [score > 0 for score in self.scores.values()]) and (True in [score < 0 for score in self.scores.values()]):
self.depth = depth
else:
self.depth = 0
#If this is not a terminal node, generate the children
if self.depth > 0:
#Prefix for use with score
if (self.player_current == player_id):
self.prefix = 1
else:
self.prefix = -1
self.children = []
self.CreateChildren(scores)
#If this is terminal node, calculate value
elif self.depth == 0:
#Get Value
self.value = CalculateValue(scores, player_id)
def CreateChildren(self, scores):
for tile_id in scores.keys():
if ((scores[tile_id] >= 0) and (self.prefix > 0)) or ((scores[tile_id] <= 0) and (self.prefix < 0)):
future_scores = copy(scores)
future_scores = AddCounter(future_scores, board, tile_id, player_id, self.player_current)
self.children.append(Node(
board,
player_id,
(self.player_current + 1) % 2,
future_scores,
self.depth -1,
tile_id))
Adding Value
So we have our tree of all possible future board configurations now.
However, how do we actually figure out which one is the most favourable or the
most likely scenario? This is where the Minimax algorithm comes into play.
Let’s assume for a second that we grew trees indefinitely, until each branch
reaches a “game-over” state where all counters belong to one player.
Furthermore, let’s say that we will assign a value to each of those terminal
branches: Inf
(positive infinity) for a branch in which we win, -Inf
(negative infinity) for a branch in which we loose.
In reality, however, we will not be able to calculate all terminal nodes. Consider this: A hexagonal board of side length 3 will have 19 tiles, equating to 19 possible moves in the first round. Each of these results in a board state with 18 possible moves for the enemy (361 board states in total), then 18 for us again (6517 board states in total), and so on and so forth. This quickly gets out of hand. We somehow need to keep the number of board states manageable.
One way to achieve this is to limit the depth of our tree and evaluate the “favourability” of each terminal leaf using a heuristic value function. In this example, let’s go for something simple, such as the number of markers that we have on the board, minus the number of enemy markers. If for a given board state we’re in the lead, the number will be positive. If we’re behind, the number will be negative.
def CalculateScores(board, player_id):
scores = {}
for tile_id, tile in board.items():
if tile["player"] == None:
scores[tile_id] = 0
elif tile["player"] == player_id:
scores[tile_id] = int(tile["counters"])
elif tile["player"] is not player_id:
scores[tile_id] = int(tile["counters"]) * -1
return(scores)
def CalculateValue(scores, player_id):
"""Heuristic value function to estimate how favourable
the given board state is for the player"""
# count counters
OwnCounters = 0
EnemyCounters = 0
for tile_id in scores:
if scores[tile_id] > 0:
OwnCounters += abs(scores[tile_id])
elif scores[tile_id] < 0:
EnemyCounters += abs(scores[tile_id])
# Check for game-over
if OwnCounters == 0:
#Lost
return(-maxsize)
elif EnemyCounters == 0:
#Won
return(maxsize)
else:
value = OwnCounters - EnemyCounters
return(value)
We can “back-propagate” these outcomes up the tree and assume that each player will always pick the move that will bring them closer towards a winning branch rather than a loosing branch. In other words, we will try to maximise the value, our enemy will try to minimize it. Since we take turns at the moves, it becomes Max, Min, Max, Min, ergo MiniMax. This can be coded up with yet another recursive approach. This time we use two functions that call one-another, and take the node tree object we created as an input variable.
def Maxvalue(node):
"""Function to identify most advantageous player move"""
if (node.depth == 0):
return node.value
else:
best_value = -maxsize
for child in node.children:
best_value = max(best_value, Minvalue(child))
return best_value
def Minvalue(node):
"""Function to identify most likely enemy move"""
if (node.depth == 0):
return node.value
else:
best_value = maxsize
for child in node.children:
best_value = min(best_value, Maxvalue(child))
return best_value
Putting it all Together
Finally, we can join up all these individual parts and make them talk to the
web app. The Minimax
function below takes the inputs board
, game_id
and
player_id
from the flask app hosting the game, calculates the future
possible board states by instanciating a Node
object, and then picks
the most favourable move from all moves currently possible by
evaluating the future scenarios.
def Minimax(board, game_id, player_id):
# Run algorithm
depth = 3
scores = CalculateScores(board, player_id)
moves = sum([abs(score) for score in scores.values()])
# If the game is only starting, pick first tile
if moves < 2:
possible_moves = {}
for tile_id, tile in board.items():
if tile["player"] is None:
possible_moves.setdefault(len(tile["neighbours"]), []).append(tile_id)
# Pick the moves closest to an explosion
best_move = possible_moves[min(possible_moves)][2]
return best_move
else:
node_tree = Node(board, player_id, player_id, scores, depth)
candidate_moves = {}
for child in node_tree.children:
candidate_moves[child.move] = Minvalue(child)
best_move = max(candidate_moves.keys(), key=(lambda k: candidate_moves[k]))
return best_move
I’ve included this function in my version of the web app running on pythonanywhere, so head over there and give it a go! http://janlauge.pythonanywhere.com
I hope this is mildly interesting and/or useful. I’d be glad for any feedback on my approach, the code (this was one of my first projects in python), and this post in general. Thanks to Man AHL for hosting this interesting challenge!


You've made it this far, so you may as well reach out!
Get in touch with me for project collaborations, questions about career, and especially job opportunities!
Guess where I am in this pic?
Email: kshep425@gmail.com


Welcome! Doerlist is a simple and fast todo list for busy people. Take a full feature tour to see how doerlist can help.
Certain random text that are related to random text that are related to random text that are related to random text that are related to random text that are related to random text that are related to.
Certain random text that are related to random text that are related to random text that are related to random text that are related to random text that are related to random text that are related to.
Certain random text that are related to random text that are related to random text that are related to random text that are related to random text that are related to random text that are related to.
Not convinced?
The best way to find out is to try it out yourself.
Sign up (The money is fully refundable in three days.)
Be sure to check out sixteen features of Doerlist.
If you are a writer, designer or programmer, we need your help at the beta program! Join doerlist's beta program by sending an email to<EMAIL_ADDRESS>Read: What is a beta program?
Advice for doerlist? Question or problem? contact support@doerlist.com


Uses of Package
com.jme.material
-
Classes in com.jme.material used by com.jme.asset Class Description Material Material
describes the rendering style for a givenGeometry
. -
Classes in com.jme.material used by com.jme.font Class Description Material Material
describes the rendering style for a givenGeometry
. -
Classes in com.jme.material used by com.jme.material Class Description Material Material
describes the rendering style for a givenGeometry
.MaterialDef Describes a J3MD (Material definition).MatParam Describes a material parameter.MatParamTexture RenderState RenderState
specifies material rendering properties that cannot be controlled by a shader on aMaterial
.RenderState.BlendEquation BlendEquation
specifies the blending equation to combine pixels.RenderState.BlendEquationAlpha BlendEquationAlpha
specifies the blending equation to combine pixels for the alpha component.RenderState.BlendFunc BlendFunc
defines the blending functions for use withBlendMode.Custom
.RenderState.BlendMode BlendMode
specifies the blending operation to use.RenderState.FaceCullMode FaceCullMode
specifies the criteria for faces to be culled.RenderState.StencilOperation StencilOperation
specifies the stencil operation to use in a certain scenario as specified inRenderState.setStencil(boolean, com.jme.material.RenderState.StencilOperation, com.jme.material.RenderState.StencilOperation, com.jme.material.RenderState.StencilOperation, com.jme.material.RenderState.StencilOperation, com.jme.material.RenderState.StencilOperation, com.jme.material.RenderState.StencilOperation, com.jme.material.RenderState.TestFunction, com.jme.material.RenderState.TestFunction)
RenderState.TestFunction TestFunction
specifies the testing function for stencil test function.ShaderGenerationInfo this class is basically a struct that contains the ShaderNodes informations in an appropriate way to ease the shader generation process and make it faster.Technique Represents a technique instance.TechniqueDef Describes a technique definition.TechniqueDef.LightMode Describes light rendering mode.TechniqueDef.LightSpace Define in what space the light data should be sent to the shader.TechniqueDef.ShadowMode -
Classes in com.jme.material used by com.jme.material.logic Class Description TechniqueDef Describes a technique definition. -
Classes in com.jme.material used by com.jme.material.plugins Class Description MaterialDef Describes a J3MD (Material definition).MatParam Describes a material parameter.TechniqueDef Describes a technique definition. -
Classes in com.jme.material used by com.jme.post Class Description Material Material
describes the rendering style for a givenGeometry
. -
Classes in com.jme.material used by com.jme.renderer Class Description Material Material
describes the rendering style for a givenGeometry
.MatParamOverride MatParamOverride
is a mechanism by whichmaterial parameters
can be overridden on the scene graph.RenderState RenderState
specifies material rendering properties that cannot be controlled by a shader on aMaterial
.RenderState.BlendEquation BlendEquation
specifies the blending equation to combine pixels.RenderState.BlendEquationAlpha BlendEquationAlpha
specifies the blending equation to combine pixels for the alpha component.RenderState.BlendFunc BlendFunc
defines the blending functions for use withBlendMode.Custom
.RenderState.BlendMode BlendMode
specifies the blending operation to use.RenderState.FaceCullMode FaceCullMode
specifies the criteria for faces to be culled.RenderState.StencilOperation StencilOperation
specifies the stencil operation to use in a certain scenario as specified inRenderState.setStencil(boolean, com.jme.material.RenderState.StencilOperation, com.jme.material.RenderState.StencilOperation, com.jme.material.RenderState.StencilOperation, com.jme.material.RenderState.StencilOperation, com.jme.material.RenderState.StencilOperation, com.jme.material.RenderState.StencilOperation, com.jme.material.RenderState.TestFunction, com.jme.material.RenderState.TestFunction)
RenderState.TestFunction TestFunction
specifies the testing function for stencil test function.TechniqueDef.LightMode Describes light rendering mode. -
Classes in com.jme.material used by com.jme.renderer.opengl Class Description RenderState RenderState
specifies material rendering properties that cannot be controlled by a shader on aMaterial
. -
Classes in com.jme.material used by com.jme.scene Class Description Material Material
describes the rendering style for a givenGeometry
.MatParamOverride MatParamOverride
is a mechanism by whichmaterial parameters
can be overridden on the scene graph. -
Classes in com.jme.material used by com.jme.scene.plugins Class Description MaterialList A map from material name to a material. -
Classes in com.jme.material used by com.jme.shader Class Description ShaderGenerationInfo this class is basically a struct that contains the ShaderNodes informations in an appropriate way to ease the shader generation process and make it faster.TechniqueDef Describes a technique definition. -
Classes in com.jme.material used by com.jme.shadow Class Description Material Material
describes the rendering style for a givenGeometry
.RenderState RenderState
specifies material rendering properties that cannot be controlled by a shader on aMaterial
. -
Classes in com.jme.material used by com.jme.system Class Description RenderState RenderState
specifies material rendering properties that cannot be controlled by a shader on aMaterial
. -
Classes in com.jme.material used by com.jme.util Class Description Material Material
describes the rendering style for a givenGeometry
.


Madan was visiting the bank for the 3rd time this week and was clearly frustrated by the long serpentine queues. These lines not only lasted for hours but also caused people to enduringly argue whether the prime minister’s stand on demonetization was correct or not. Many people had come forward to distribute water and a pack of glucose biscuits to those waiting in the lines, which to a certain extent assuaged Madan’s anger and gave him the energy to debate on this national level raging issue. One of the things he heard that money hoarders were trying convert their black money to white was using unsuspecting individual’s KYC documents. This got him thinking that at right this moment, most of the bank branches were sitting on lakhs of KYC documents which could be used by these wrongdoers for converting their black money to white.
Just like Madan, we have many times in our life submitted KYC documents for various purposes like
- Applying for a loan
- Applying for credit/debit card
- Opening accounts at various institutions
- For different kind of transactions And many other reasons
What happens to all these documents submitted for KYC? Are they destroyed in case the intended purpose are not carried out?
Well the answer of this question is subjective and changes from company to company. However many a times we have noticed that we get calls, SMSs and emails stating that we are eligible for Credit cards, eligible for automobile insurance or personal loans, for vacation packages; all these from companies you would never have heard of. Given that your personal data could be utilized for other purposes which were never intended, there is a need to safeguard your personal details.
I myself used to submit various documents initially which lead to incessant calls. Most of them used to start by stating that I had applied for so and so product or service and I would end up raising complaints for a really long time. This gave rise to the practice of stating the purpose on the KYC documents. Recently I met with a friend who was an entrepreneur. During our conversation, I received another one of those marketing SMS. Upon seeing this SMS my friend told me about how he came up with the idea of a KYC stamp where one not only states the purpose and signature, but also captures and other essential details. Since as an owner of an enterprise, his details were utilized frequently for various office related purposes and the application of this stamp had made his life immensely easy.
The stamp captured the following details:
- Date
- Purpose
- Signature
- Name of the company it is addressed to
- Disclaimer (which states that that the document cannot be used for any other purpose
Since the use of this stamp the number of unnecessary calls and SMSs had drastically reduced and my friend was able to sleep without any stress of his documents being misused. The stamp can be adopted not only by individuals but also by various corporations and smaller institutions for their day-to-day activities and will help curb the overall menace of illicit use of KYC documents.


Info
JavaScript natually fits for querying a SPARQL endpoint which provides a
REST service returning the result in the JSON format. The d3sparql.js library provides
functions executing a SPARQL query by Ajax call
(XMLHttpRequest) and visulaizing results by the D3 library. Basically, this library
transforms the SPARQL Query Results JSON Format (aka.
application/sparql-results+json) into several JSON formats which major D3 layouts can accept. Many of the examples
are borrowed from bl.ocks.org and bost.ocks.org.
The d3sparql.js library is distributed under the same license as D3.js's
(BSD license).
Demo
You can try out some examples from the menu on the top of this page.
Note
Todos


Hello, I'm finally getting around to installing the components I ordered a couple months back and I am encountering some issues. Here is what I ordered and received:
- emonBase with USB power adapter
- (2) emonTxV3 units with AC power adapters (rf node 7 and 8)
- emonTH (rf node 23)
I installed and powered up both emonTxV3 units each with 4 CTs attached. Each now flashes a red LED once every ten seconds which as far as I can tell is operating as expected.
I have the emonBase connected via Ethernet. I have accessed it from the emoncms web page of the device where I created an account and started looking around.
So now for the issues:
- Per the emonPi/emonBase Setup page, I should be able to SSH to the emonBase to shut it down but when I try to SSH to it I get a permission denied. I used the name and password that I specified when creating an account through the emoncms web page. Am I supposed to use something else?
- My three nodes (7, 8, and 23) which I would expect to be active are all shown as inactive on the nodes page. Why? Here is some emonhub.log output:
2016-03-24 18:47:12,514 DEBUG RFM2Pi 1157 From Node : 7
2016-03-24 18:47:12,515 DEBUG RFM2Pi 1157 Values : [45, -38, 56, 52, 122.62, 300, 300, 300, 300, 300, 300, 1]
2016-03-24 18:47:12,515 DEBUG RFM2Pi 1157 RSSI : -44
2016-03-24 18:47:12,516 DEBUG RFM2Pi 1157 adding frame to buffer => [1458845232, 7, 45, -38, 56, 52, 122.62, 300, 300, 300, 300, 300, 300, 1, -44]
2016-03-24 18:47:12,517 DEBUG RFM2Pi 1157 Sent to channel' : ToEmonCMS
2016-03-24 18:47:13,623 DEBUG RFM2Pi 1158 NEW FRAME : OK 23 197 0 0 0 180 1 31 0 1 0 0 0 (-28)
2016-03-24 18:47:13,625 DEBUG RFM2Pi 1158 Timestamp :<PHONE_NUMBER>.62
2016-03-24 18:47:13,625 DEBUG RFM2Pi 1158 From Node : 23
2016-03-24 18:47:13,626 DEBUG RFM2Pi 1158 Values : [19.700000000000003, 0, 43.6, 3.1, 1]
2016-03-24 18:47:13,626 DEBUG RFM2Pi 1158 RSSI : -28
2016-03-24 18:47:13,627 DEBUG RFM2Pi 1158 adding frame to buffer => [1458845233, 23, 19.700000000000003, 0, 43.6, 3.1, 1, -28]
2016-03-24 18:47:13,628 DEBUG RFM2Pi 1158 Sent to channel' : ToEmonCMS
2016-03-24 18:47:14,337 DEBUG RFM2Pi Discarding RX frame 'unreliable content'? 142 158 7 110 104 225 228 145 21 94 255 48 86 101 255 154 148 47 161 138 45 (-96)
2016-03-24 18:47:15,947 DEBUG RFM2Pi 1159 NEW FRAME : OK 8 0 0 1 0 0 0 1 0 30 48 184 11 184 11 184 11 184 11 184 11 184 11 1 0 0 0 (-37)
2016-03-24 18:47:15,950 DEBUG RFM2Pi 1159 Timestamp :<PHONE_NUMBER>.95
2016-03-24 18:47:15,951 DEBUG RFM2Pi 1159 From Node : 8
2016-03-24 18:47:15,951 DEBUG RFM2Pi 1159 Values : [0, 1, 0, 1, 123.18, 300, 300, 300, 300, 300, 300, 1]
2016-03-24 18:47:15,952 DEBUG RFM2Pi 1159 RSSI : -37
2016-03-24 18:47:15,953 DEBUG RFM2Pi 1159 adding frame to buffer => [1458845235, 8, 0, 1, 0, 1, 123.18, 300, 300, 300, 300, 300, 300, 1, -37]
2016-03-24 18:47:15,953 DEBUG RFM2Pi 1159 Sent to channel' : ToEmonCMS
2016-03-24 18:47:20,374 DEBUG RFM2Pi Discarding RX frame 'unreliable content'? 62 99 159 252 127 239 60 148 119 183 2 205 98 185 191 189 217 225 227 226 253 (-98)
2016-03-24 18:47:21,786 DEBUG RFM2Pi Discarding RX frame 'unreliable content'? 101 38 17 154 7 94 49 207 19 183 174 214 73 45 184 5 135 185 40 185 157 (-97)
2016-03-24 18:47:22,396 DEBUG RFM2Pi 1160 NEW FRAME : OK 7 44 0 219 255 55 0 54 0 210 47 184 11 184 11 184 11 184 11 184 11 184 11 1 0 0 0 (-45)
2016-03-24 18:47:22,400 DEBUG RFM2Pi 1160 Timestamp :<PHONE_NUMBER>.4
2016-03-24 18:47:22,401 DEBUG RFM2Pi 1160 From Node : 7
2016-03-24 18:47:22,402 DEBUG RFM2Pi 1160 Values : [44, -37, 55, 54, 122.42, 300, 300, 300, 300, 300, 300, 1]
2016-03-24 18:47:22,403 DEBUG RFM2Pi 1160 RSSI : -45
2016-03-24 18:47:22,404 DEBUG RFM2Pi 1160 adding frame to buffer => [1458845242, 7, 44, -37, 55, 54, 122.42, 300, 300, 300, 300, 300, 300, 1, -45]
2016-03-24 18:47:22,405 DEBUG RFM2Pi 1160 Sent to channel' : ToEmonCMS
2016-03-24 18:47:23,514 DEBUG RFM2Pi Discarding RX frame 'unreliable content'? 59 24 163 189 186 188 119 252 206 205 145 76 30 12 246 12 3 109 214 213 116 (-103)
Thanks, Tom
Re: Solved - New installation questions
With respect to issue two, I did an Update emonPi which produced a bunch of output but did not change the nodes' state after waiting for several minutes. Just for the fun of it I decided to do the Update emonPi a second time and this time it produced less output but some things were still updated. I then checked the nodes and fortunately my three nodes were now active.
I will continue with my setup...
Re: Solved - New installation questions
1. The emoncms loging is different to SSH. The default ssh login is user: 'pi' and password 'raspberry'. Recommend chancing password ASAP.
2. Good work. Yup, emonPi update will pull in the latest node decoders. See this guide for how emonHub nodedecoders work:
https://github.com/openenergymonitor/emonhub/blob/emon-pi/configuration.md
Re: Solved - New installation questions
Thank you. My system is now up and collecting data. I have new questions/comments but I'll start a new thread. - Tom


yes. Well the staking loop needs to be inside its own thread and it needs a diffrent way to be switched on and off, that way PoW mining can have some threads aswell.. but once I got staking working this good, I really didnt want to touch it again, it was no easy task to get it in a usable state.
And a pool that switches only when diff wall is down, is well... I dont know what that would do to the chain, I think it would effectivly over time reduce PoW difficulty.


Deep Belief Networks¶
Note
This section assumes the reader has already read through Classifying MNIST digits using Logistic Regression and Multilayer Perceptron and Restricted Boltzmann Machines (RBM). Additionally it uses the following Theano functions and concepts: T.tanh, shared variables, basic arithmetic ops, T.grad, Random numbers, floatX. If you intend to run the code on GPU also read GPU.
Note
The code for this section is available for download here.
Deep Belief Networks¶
[Hinton06] showed that RBMs can be stacked and trained in a greedy manner to form so-called Deep Belief Networks (DBN). DBNs are graphical models which learn to extract a deep hierarchical representation of the training data. They model the joint distribution between observed vector x and the \ell hidden layers h^k as follows:
(1)P(x, h^1, \ldots, h^{\ell}) = \left(\prod_{k=0}^{\ell-2} P(h^k|h^{k+1})\right) P(h^{\ell-1},h^{\ell})
where x=h^0, P(h^{k-1} | h^k) is a conditional distribution for the visible units conditioned on the hidden units of the RBM at level k, and P(h^{\ell-1}, h^{\ell}) is the visible-hidden joint distribution in the top-level RBM. This is illustrated in the figure below.
The principle of greedy layer-wise unsupervised training can be applied to DBNs with RBMs as the building blocks for each layer [Hinton06], [Bengio07]. The process is as follows:
1. Train the first layer as an RBM that models the raw input x = h^{(0)} as its visible layer.
2. Use that first layer to obtain a representation of the input that will be used as data for the second layer. Two common solutions exist. This representation can be chosen as being the mean activations p(h^{(1)}=1|h^{(0)}) or samples of p(h^{(1)}|h^{(0)}).
3. Train the second layer as an RBM, taking the transformed data (samples or mean activations) as training examples (for the visible layer of that RBM).
4. Iterate (2 and 3) for the desired number of layers, each time propagating upward either samples or mean values.
5. Fine-tune all the parameters of this deep architecture with respect to a proxy for the DBN log- likelihood, or with respect to a supervised training criterion (after adding extra learning machinery to convert the learned representation into supervised predictions, e.g. a linear classifier).
In this tutorial, we focus on fine-tuning via supervised gradient descent. Specifically, we use a logistic regression classifier to classify the input x based on the output of the last hidden layer h^{(l)} of the DBN. Fine-tuning is then performed via supervised gradient descent of the negative log-likelihood cost function. Since the supervised gradient is only non-null for the weights and hidden layer biases of each layer (i.e. null for the visible biases of each RBM), this procedure is equivalent to initializing the parameters of a deep MLP with the weights and hidden layer biases obtained with the unsupervised training strategy.
Justifying Greedy-Layer Wise Pre-Training¶
Why does such an algorithm work ? Taking as example a 2-layer DBN with hidden layers h^{(1)} and h^{(2)} (with respective weight parameters W^{(1)} and W^{(2)}), [Hinton06] established (see also Bengio09]_ for a detailed derivation) that \log p(x) can be rewritten as,
(2)\log p(x) = &KL(Q(h^{(1)}|x)||p(h^{(1)}|x)) + H_{Q(h^{(1)}|x)} + \\ &\sum_h Q(h^{(1)}|x)(\log p(h^{(1)}) + \log p(x|h^{(1)})).
KL(Q(h^{(1)}|x) || p(h^{(1)}|x)) represents the KL divergence between the posterior Q(h^{(1)}|x) of the first RBM if it were standalone, and the probability p(h^{(1)}|x) for the same layer but defined by the entire DBN (i.e. taking into account the prior p(h^{(1)},h^{(2)}) defined by the top-level RBM). H_{Q(h^{(1)}|x)} is the entropy of the distribution Q(h^{(1)}|x).
It can be shown that if we initialize both hidden layers such that W^{(2)}={W^{(1)}}^T, Q(h^{(1)}|x)=p(h^{(1)}|x) and the KL divergence term is null. If we learn the first level RBM and then keep its parameters W^{(1)} fixed, optimizing Eq. (2) with respect to W^{(2)} can thus only increase the likelihood p(x).
Also, notice that if we isolate the terms which depend only on W^{(2)}, we get:
\sum_h Q(h^{(1)}|x)p(h^{(1)})
Optimizing this with respect to W^{(2)} amounts to training a second-stage RBM, using the output of Q(h^{(1)}|x) as the training distribution, when x is sampled from the training distribution for the first RBM.
Implementation¶
To implement DBNs in Theano, we will use the class defined in the Restricted Boltzmann Machines (RBM) tutorial. One can also observe that the code for the DBN is very similar with the one for SdA, because both involve the principle of unsupervised layer-wise pre-training followed by supervised fine-tuning as a deep MLP. The main difference is that we use the RBM class instead of the dA class.
We start off by defining the DBN class which will store the layers of the MLP, along with their associated RBMs. Since we take the viewpoint of using the RBMs to initialize an MLP, the code will reflect this by seperating as much as possible the RBMs used to initialize the network and the MLP used for classification.
class DBN(object):
"""Deep Belief Network
A deep belief network is obtained by stacking several RBMs on top of each
other. The hidden layer of the RBM at layer `i` becomes the input of the
RBM at layer `i+1`. The first layer RBM gets as input the input of the
network, and the hidden layer of the last RBM represents the output. When
used for classification, the DBN is treated as a MLP, by adding a logistic
regression layer on top.
"""
def __init__(self, numpy_rng, theano_rng=None, n_ins=784,
hidden_layers_sizes=[500, 500], n_outs=10):
"""This class is made to support a variable number of layers.
:type numpy_rng: numpy.random.RandomState
:param numpy_rng: numpy random number generator used to draw initial
weights
:type theano_rng: theano.tensor.shared_randomstreams.RandomStreams
:param theano_rng: Theano random generator; if None is given one is
generated based on a seed drawn from `rng`
:type n_ins: int
:param n_ins: dimension of the input to the DBN
:type hidden_layers_sizes: list of ints
:param hidden_layers_sizes: intermediate layers size, must contain
at least one value
:type n_outs: int
:param n_outs: dimension of the output of the network
"""
self.sigmoid_layers = []
self.rbm_layers = []
self.params = []
self.n_layers = len(hidden_layers_sizes)
assert self.n_layers > 0
if not theano_rng:
theano_rng = MRG_RandomStreams(numpy_rng.randint(2 ** 30))
# allocate symbolic variables for the data
# the data is presented as rasterized images
self.x = T.matrix('x')
# the labels are presented as 1D vector of [int] labels
self.y = T.ivector('y')
self.sigmoid_layers
will store the feed-forward graphs which together form
the MLP, while self.rbm_layers
will store the RBMs used to pretrain each
layer of the MLP.
Next step, we construct n_layers
sigmoid layers (we use the
HiddenLayer
class introduced in Multilayer Perceptron, with the only modification
that we replaced the non-linearity from tanh
to the logistic function
s(x) = \frac{1}{1+e^{-x}}) and n_layers
RBMs, where n_layers
is the depth of our model. We link the sigmoid layers such that they form an
MLP, and construct each RBM such that they share the weight matrix and the
hidden bias with its corresponding sigmoid layer.
for i in range(self.n_layers):
# construct the sigmoidal layer
# the size of the input is either the number of hidden
# units of the layer below or the input size if we are on
# the first layer
if i == 0:
input_size = n_ins
else:
input_size = hidden_layers_sizes[i - 1]
# the input to this layer is either the activation of the
# hidden layer below or the input of the DBN if you are on
# the first layer
if i == 0:
layer_input = self.x
else:
layer_input = self.sigmoid_layers[-1].output
sigmoid_layer = HiddenLayer(rng=numpy_rng,
input=layer_input,
n_in=input_size,
n_out=hidden_layers_sizes[i],
activation=T.nnet.sigmoid)
# add the layer to our list of layers
self.sigmoid_layers.append(sigmoid_layer)
# its arguably a philosophical question... but we are
# going to only declare that the parameters of the
# sigmoid_layers are parameters of the DBN. The visible
# biases in the RBM are parameters of those RBMs, but not
# of the DBN.
self.params.extend(sigmoid_layer.params)
# Construct an RBM that shared weights with this layer
rbm_layer = RBM(numpy_rng=numpy_rng,
theano_rng=theano_rng,
input=layer_input,
n_visible=input_size,
n_hidden=hidden_layers_sizes[i],
W=sigmoid_layer.W,
hbias=sigmoid_layer.b)
self.rbm_layers.append(rbm_layer)
All that is left is to stack one last logistic regression layer in order to
form an MLP. We will use the LogisticRegression
class introduced in
Classifying MNIST digits using Logistic Regression.
self.logLayer = LogisticRegression(
input=self.sigmoid_layers[-1].output,
n_in=hidden_layers_sizes[-1],
n_out=n_outs)
self.params.extend(self.logLayer.params)
# compute the cost for second phase of training, defined as the
# negative log likelihood of the logistic regression (output) layer
self.finetune_cost = self.logLayer.negative_log_likelihood(self.y)
# compute the gradients with respect to the model parameters
# symbolic variable that points to the number of errors made on the
# minibatch given by self.x and self.y
self.errors = self.logLayer.errors(self.y)
The class also provides a method which generates training functions for each
of the RBMs. They are returned as a list, where element i is a
function which implements one step of training for the RBM
at layer
i.
def pretraining_functions(self, train_set_x, batch_size, k):
'''Generates a list of functions, for performing one step of
gradient descent at a given layer. The function will require
as input the minibatch index, and to train an RBM you just
need to iterate, calling the corresponding function on all
minibatch indexes.
:type train_set_x: theano.tensor.TensorType
:param train_set_x: Shared var. that contains all datapoints used
for training the RBM
:type batch_size: int
:param batch_size: size of a [mini]batch
:param k: number of Gibbs steps to do in CD-k / PCD-k
'''
# index to a [mini]batch
index = T.lscalar('index') # index to a minibatch
In order to be able to change the learning rate during training, we associate a Theano variable to it that has a default value.
learning_rate = T.scalar('lr') # learning rate to use
# begining of a batch, given `index`
batch_begin = index * batch_size
# ending of a batch given `index`
batch_end = batch_begin + batch_size
pretrain_fns = []
for rbm in self.rbm_layers:
# get the cost and the updates list
# using CD-k here (persisent=None) for training each RBM.
# TODO: change cost function to reconstruction error
cost, updates = rbm.get_cost_updates(learning_rate,
persistent=None, k=k)
# compile the theano function
fn = theano.function(
inputs=[index, theano.In(learning_rate, value=0.1)],
outputs=cost,
updates=updates,
givens={
self.x: train_set_x[batch_begin:batch_end]
}
)
# append `fn` to the list of functions
pretrain_fns.append(fn)
return pretrain_fns
Now any function pretrain_fns[i]
takes as arguments index
and
optionally lr
– the learning rate. Note that the names of the parameters
are the names given to the Theano variables (e.g. lr
) when they are
constructed and not the name of the python variables (e.g. learning_rate
). Keep
this in mind when working with Theano. Optionally, if you provide k
(the
number of Gibbs steps to perform in CD or PCD) this will also become an
argument of your function.
In the same fashion, the DBN class includes a method for building the
functions required for finetuning ( a train_model
, a validate_model
and a test_model
function).
def build_finetune_functions(self, datasets, batch_size, learning_rate):
'''Generates a function `train` that implements one step of
finetuning, a function `validate` that computes the error on a
batch from the validation set, and a function `test` that
computes the error on a batch from the testing set
:type datasets: list of pairs of theano.tensor.TensorType
:param datasets: It is a list that contain all the datasets;
the has to contain three pairs, `train`,
`valid`, `test` in this order, where each pair
is formed of two Theano variables, one for the
datapoints, the other for the labels
:type batch_size: int
:param batch_size: size of a minibatch
:type learning_rate: float
:param learning_rate: learning rate used during finetune stage
'''
(train_set_x, train_set_y) = datasets[0]
(valid_set_x, valid_set_y) = datasets[1]
(test_set_x, test_set_y) = datasets[2]
# compute number of minibatches for training, validation and testing
n_valid_batches = valid_set_x.get_value(borrow=True).shape[0]
n_valid_batches //= batch_size
n_test_batches = test_set_x.get_value(borrow=True).shape[0]
n_test_batches //= batch_size
index = T.lscalar('index') # index to a [mini]batch
# compute the gradients with respect to the model parameters
gparams = T.grad(self.finetune_cost, self.params)
# compute list of fine-tuning updates
updates = []
for param, gparam in zip(self.params, gparams):
updates.append((param, param - gparam * learning_rate))
train_fn = theano.function(
inputs=[index],
outputs=self.finetune_cost,
updates=updates,
givens={
self.x: train_set_x[
index * batch_size: (index + 1) * batch_size
],
self.y: train_set_y[
index * batch_size: (index + 1) * batch_size
]
}
)
test_score_i = theano.function(
[index],
self.errors,
givens={
self.x: test_set_x[
index * batch_size: (index + 1) * batch_size
],
self.y: test_set_y[
index * batch_size: (index + 1) * batch_size
]
}
)
valid_score_i = theano.function(
[index],
self.errors,
givens={
self.x: valid_set_x[
index * batch_size: (index + 1) * batch_size
],
self.y: valid_set_y[
index * batch_size: (index + 1) * batch_size
]
}
)
# Create a function that scans the entire validation set
def valid_score():
return [valid_score_i(i) for i in range(n_valid_batches)]
# Create a function that scans the entire test set
def test_score():
return [test_score_i(i) for i in range(n_test_batches)]
return train_fn, valid_score, test_score
Note that the returned valid_score
and test_score
are not Theano
functions, but rather Python functions. These loop over the entire
validation set and the entire test set to produce a list of the losses
obtained over these sets.
Putting it all together¶
The few lines of code below constructs the deep belief network:
numpy_rng = numpy.random.RandomState(123)
print('... building the model')
# construct the Deep Belief Network
dbn = DBN(numpy_rng=numpy_rng, n_ins=28 * 28,
hidden_layers_sizes=[1000, 1000, 1000],
n_outs=10)
There are two stages in training this network: (1) a layer-wise pre-training and (2) a fine-tuning stage.
For the pre-training stage, we loop over all the layers of the network. For
each layer, we use the compiled theano function which determines the
input to the i
-th level RBM and performs one step of CD-k within this RBM.
This function is applied to the training set for a fixed number of epochs
given by pretraining_epochs
.
#########################
# PRETRAINING THE MODEL #
#########################
print('... getting the pretraining functions')
pretraining_fns = dbn.pretraining_functions(train_set_x=train_set_x,
batch_size=batch_size,
k=k)
print('... pre-training the model')
start_time = timeit.default_timer()
# Pre-train layer-wise
for i in range(dbn.n_layers):
# go through pretraining epochs
for epoch in range(pretraining_epochs):
# go through the training set
c = []
for batch_index in range(n_train_batches):
c.append(pretraining_fns[i](index=batch_index,
lr=pretrain_lr))
print('Pre-training layer %i, epoch %d, cost ' % (i, epoch), end=' ')
print(numpy.mean(c, dtype='float64'))
end_time = timeit.default_timer()
The fine-tuning loop is very similar to the one in the Multilayer Perceptron tutorial,
the only difference being that we now use the functions given by
build_finetune_functions
.
Running the Code¶
The user can run the code by calling:
python code/DBN.py
With the default parameters, the code runs for 100 pre-training epochs with mini-batches of size 10. This corresponds to performing 500,000 unsupervised parameter updates. We use an unsupervised learning rate of 0.01, with a supervised learning rate of 0.1. The DBN itself consists of three hidden layers with 1000 units per layer. With early-stopping, this configuration achieved a minimal validation error of 1.27 with corresponding test error of 1.34 after 46 supervised epochs.
On an Intel(R) Xeon(R) CPU X5560 running at 2.80GHz, using a multi-threaded MKL library (running on 4 cores), pretraining took 615 minutes with an average of 2.05 mins/(layer * epoch). Fine-tuning took only 101 minutes or approximately 2.20 mins/epoch.
Hyper-parameters were selected by optimizing on the validation error. We tested unsupervised learning rates in \{10^{-1}, ..., 10^{-5}\} and supervised learning rates in \{10^{-1}, ..., 10^{-4}\}. We did not use any form of regularization besides early-stopping, nor did we optimize over the number of pretraining updates.
Tips and Tricks¶
One way to improve the running time of your code (given that you have
sufficient memory available), is to compute the representation of the entire
dataset at layer i
in a single pass, once the weights of the
i-1-th layers have been fixed. Namely, start by training your first
layer RBM. Once it is trained, you can compute the hidden units values for
every example in the dataset and store this as a new dataset which is used to
train the 2nd layer RBM. Once you trained the RBM for layer 2, you compute, in
a similar fashion, the dataset for layer 3 and so on. This avoids calculating
the intermediate (hidden layer) representations, pretraining_epochs
times
at the expense of increased memory usage.


class: center, middle, inverse, title-slide # Recap II ### R for Data Science
www.therbootcamp.com
### November 2018 --- layout: true
 Geneva, November 2018                                           www.therbootcamp.com
 # Essentials: The 24 Lessons of the R Bootcamp .pull-left4[ 1. Everything is an object 2. Use `<-` to create/change objects 3. Name objects using `_` 4. Objects have classes 5. Everything happens through functions 6. Functions have (default) arguments 7. Functions expect certain object classes 8. View help files using `?` 9. Study errors and warnings 10. Data is stored in data frames 11. Select variables (vectors) using `$` 12. Use RStudio and projects 13. Use editor and shortcuts 14. First load packages and data 15. Use auto-complete 16. Comment and format for readability ] --- # 3 Object types for data .pull-left4[ R has 3 main data objects... <high>`list`</high> - R's multi-purpose container - Can carry any data, incl. lists - Often used for function outputs <high>`data_frame`</high> - R's spreadsheet - Specific type of `list` - Typical data format - For multi-variable data sets <high>`vectors`</high> - R's data container - Actually carries the data - Contain data of 1 of many types ] .pull-right55[  ] --- # Data Input/Output .pull-left45[ Raw data can come in many shapes and sizes, but <high>R's got you covered</high>.

 .pull-left65[ | Package | Description| |:----------------|:-------------------------------------------------------| | `readr`| `.csv`, `.txt`, etc. | | `haven`| `.sav`, `.sas7bdat`, `.dta` | | `readxl` | `.xls`, `.xlsx` | | `R.matlab` | `.mat` | | `jsonlite` | `.json` | | `rvest` | `.html` | | `XML`, `xml2` | `.xml` | ] ] .pull-right45[  ] --- # Finding the file path .pull-left4[ 1 - Identify the file path using the <high>auto-complete</high>. 2 - Initiate auto-complete and browse through the folder structure by placing the cursor between two quotation marks and using the <high>tab key</high>.

 3 - Auto-complete begins with the project folder - <high>place your data inside your project folder!</high> ] .pull-right55[  ] --- .pull-left45[ # What is wrangling? <high>Transform</high> Change column names Add new columns <high>Organise</high> Sort data by columns Merging data from two separate dataframes Move data between columns and rows <high>Aggregate</high> Group data and summarise ] .pull-right5[

 ] --- # Wrangling .pull-left4[ 1 - Start by assigning your result to a new object to save it! 2 - "Keep the pipe <high>%>%</high> going" to continue working with your data frame. 3 - The output of dplyr functions will (almost) always be a <high>tibble</high>. 4 - You can almost always include <high>multiple operations</high> within each function. ] .pull-right55[ ```r # Assign result to baslers_agg baslers_agg <- baselers %>% # Change column names with rename() rename(age_years = age, weight_kg = weight) %>% # PIPE! # Select specific rows with filter() filter(age_years < 40) %>% # PIPE! # Create new columns witb mutate() mutate(debt_ratio = debt / income) %>% # PIPE! # Group data with group_by() group_by(sex) %>% # PIPE! # Calculate summary statistics with summarise() summarise(income_mean = mean(income), debt_mean = mean(debt), dr_mean = mean(dr)) ``` ] --- # Stats? There is a package for that! .pull-left45[
 | Package| Models| |------:|:----| | `stats`|Generalized linear model| | `afex`| Anovas| | `lme4`| Mixed effects regression| | `rpart`| Decision Trees| | `BayesFactor`| Bayesian statistics| | `igraph`| Network analysis| | `neuralnet`| Neural networks| | `MatchIt`| Matching and causal inference| | `survival`| Longitudinal survival analysis| | ...| Anything you can ever want!| ] .pull-right5[

 ] --- # Basic structure of statistical functions .pull-left4[ Statistical functions always require a <high>data frame</high> called `data`, e.g.,... |sex | age| height| weight| income| |:------|---:|------:|------:|------:| |male | 44| 174.3| 113.4| 6300| |male | 65| 180.3| 75.2| 10900| |female | 31| 168.3| 55.5| 5100|
 They also require a <high>formula</high> that specifies a <high>dependent</high> variable (y) as a function of one or more <high>independent</high> variables (x1, x2, ...) in the form:
formula = y ~ x1 + x2 +...
 ] .pull-right55[ How to create a statistical object: ```r # Example: Create regression object (my_glm) my_glm <- glm(formula = income ~ age + height, data = baselers) ``` ![](https://raw.githubusercontent.com/therbootcamp/Erfurt_2018June/master/_sessions/_image/formula_description.png) ] --- # What is machine learning? .pull-left55[ ### Algorithms autonomously learning from data. Given data, an algorithm tunes its <high>parameters</high> to match the data, understand how it works, and make predictions for what will occur in the future.

 ] .pull-right4[

 ] --- # Today
Schedule


Fixed #12 VerbosePreference
can be any value.
Fixed #10 Tight loop in EndProcessing()
Count
accepts one or two values. One is as usual. Two values limit the number
of required pipelines also taking into account the number of processors. (Too
many pipelines on machines with many cores is not always optimal.)
Corrected the test/demo script Test-ProgressTotal.ps1.
Minor performance tweaks on creation of runspaces.
Fixed duplicated debug, warning, and verbose messages (v1.4.2).
Pipeline runspaces are created with the host used by Split-Pipeline
. As a
result, some host features can be used by pipeline scripts, e.g. Write-Host
and even Write-Progress
, see Test-Progress*.ps1
in the project repository.
If the minimum Load
is less than 1 then the parameter is treated as omitted.
Potentially incompatible change. By default, i.e. when Load
is omitted, the
whole input is collected and split evenly between parallel pipelines. This way
seems to be the most effective in simple cases. In other cases, e.g. on large
or slow input, Load
should be used in order to enable processing of input
parts and specify their limits.
Corrected input item count in Refill
mode in verbose statistics.
Refactoring of ending, closing, and stopping.
Removed the obsolete switch Auto
and pieces of old code.
Reviewed automatic load balancing, made it the default and less aggressive
(potentially incompatible change). The obsolete switch Auto
still exists
but it is ignored. Use the parameter Load
in order to specify part limits.
E.g. -Load N,N
tells to use N items per pipeline, i.e. no load balancing.
In order words: a) Auto
is slightly redundant with Load
; b) not using
Auto
, e.g. forgetting, often causes less effective work. Auto
will be
removed in the next version.
Improved stopping (e.g. by [Ctrl-C]
):
Finally
script should work on stopping.Amended verbose messages. They are for:
Added processing of StopProcessing()
which is called on [Ctrl-C]
. Note that
stopping is normally not recommended. But in some cases "under construction" it
may help, e.g. #3.
Debug streams of parallel pipelines are processed as well and debug messages are propagated to the main pipeline, just like errors, warnings, and verbose messages.
New parameter ApartmentState
.
Help. Mentioned why and when to use Variable
, Function
, and Module
. Added
the related example.
Minor cosmetic changes in help and code. The API seems to be stabilized and no issues were found for a while. Changed the status from "beta" to "release".
Refactoring and minor improvements.
Revision of parameters and automatic load balancing (mostly simplification). Joined parameters Load and Limit into the single parameter Load (one or two values). Removed parameters Cost (not needed now) and Queue (Load is used in order to limit the queue).
Minor tweaks.
Refilled input makes infinite loops possible in some scenarios. Use the new
parameter Filter
in order to exclude already processed objects and avoid
loops.
New switch Refill
tells to refill the input queue from output. [ref]
objects are intercepted and added to the input queue. Other objects go to
output as usual. See an example in help and
Test-Refill.ps1.
Tweaks in feeding parallel pipelines and automatic tuning of load.
New switch Order
tells to output part results in the same order as input
parts arrive. Thus, although order of processing is not predictable, output
order can be made predictable. This feature open doors for more scenarios.
Added checks for Stopping
in EndProcessing
(faster stop on Ctrl+C
).
Tweaks, including related to PowerShell V3 CTP2.
New switch Auto
is used in order to determine Load values automatically during
processing. Use Verbose
in order to view some related information. Yet another
new parameter Cost
is used together with Auto
; it is introduced rather for
experiments.
This is the first of v0 series (pre-release versions). Cmdlet parameters and behaviour may change.
The cmdlet Split-Pipeline passes simple tests and shows good performance gain in a few practical scenarios.
Failures, errors, warnings, and verbose messages from parallel pipelines are trivial, straightforward, and perhaps not useful enough for troubleshooting.


ApplicationArea Class
A component used to wrap the application and handle all the global events
Uses as a normal application controller
Item Index
Methods
Methods
addBroadcaster
()
private
Check if the new subscribed element has already an error in the system and show it
addError
(
-
element
-
message
An override of method {{#crossLink "ValidationListener/addError:method"}}{{/crossLink}}
Parameters:
-
element
HTMLElementThe DOM element with error -
message
StringThe error message
afterRenderValidationHandler
()
private
Customizations of the view of the component. Listen to 'didInsertElement' event
buildError
(
private
-
element
-
message
Build the error store in {{#crossLink "ParentListener/errors:property"}}{{/crossLink}}
Parameters:
-
element
HTMLElementThe DOM element with error -
message
StringThe error message
getErrorContainer
()
private
goToError
(
-
evnt
Method called when the user click on the error. It scrolls and place the focus where the error is
Parameters:
-
evnt
jQuery.EventEvent which contains in its data the DOMElement which triggered it
initializeListener
()
private
Initialization of component. Listen to 'init' event
initializeValidationListener
()
private
Initialization of component. Listen to 'init' event
prepareErrorContainer
()
private
Bind ARIA roles and properties in order to make the errors accesible to assitive technologies
Prepare the collapsible error panel
processAction
(
public
-
action
-
params
An override of method {{#crossLink "ParentListener/processAction:method"}}{{/crossLink}}
Parameters:
-
action
StringThe name of the action triggered by the {{#crossLink "ChildBroadcaster"}}{{/crossLink}} -
params
MixedThe paremters needed to handle this action
removeBroadcaster
(
public
-
broadcasterElement
Used by the {{#crossLink "ChildBroadcaster"}}{{/crossLink}} to unsubscribe itself as a broadcaster.
Parameters:
-
broadcasterElement
ObjectThe {{#crossLink "ChildBroadcaster/broadcasterElement:property"}}{{/crossLink}} of the {{#crossLink "ChildBroadcaster"}}{{/crossLink}}
removeError
(
-
element
An override of method {{#crossLink "ValidationListener/removeError:method"}}{{/crossLink}}
Parameters:
-
element
HTMLElementThe DOM element with error
renderErrors
()
It append to the error container every error in the system
toggleCollapse
(
-
evnt
Method called when the user click on the error buttom. It collapse/expand the error panel
Parameters:
-
evnt
jQuery.Event
validateAllElements
()
Boolean
public
Trigger the validation on all elements.
Returns:
Boolean:
True when all elements were valid
Properties
broadcasters
Array
An array of {{#crossLink "ChildBroadcaster/broadcasters:property"}}{{/crossLink}} with the
subscribed {{#crossLink "ChildBroadcaster"}}{{/crossLink}} instances
Default: []
errorContainerId
String
Id of the HMTL div where to wrap the errors.
Override this property for custom id
Default: 'error-handler-errors'
errorHeader
String
The h2 label which will have the error container
This is needed for assitive technologies and provide
a better accessibility of the webpage
Override this property for custom title
Default: 'Errors'
errors
Array
Array of current errors. Every error is an object like follow:
error: {
id: [id of the element with error],
prefix: [the prefix of the error message in this priority: (label - element.name - Error)]
element: [the DOM element with error],
message: [the current error message]
}
Default: []
hasElementWithError
Boolean
public
Computed property. Usage: this.get('hasElementWithError')
True if there is any child with error
isParentListener
Boolena
private
Property read by every {{#crossLink "ChildBroadcaster"}}{{/crossLink}} in order to know if
this parent is a listener or not
Default: true
listener
Object
An read only abstraction of this class only with the methods we would like
to provide to our {{#crossLink "ChildBroadcaster"}}{{/crossLink}}
wereAllElementsValidated
Boolean
public
Computed property. Usage: this.get('wereAllElementsValidated')
True if all the {{#crossLink "ValidatableElement"}}{{/crossLink}} were validated
at least once


Last updated: July 13, 2019
Please read these Terms and Conditions ("Terms", "Terms and Conditions") carefully before using the http://delcanio-bot.herokuapp.com website (the "Service") operated by delCanio bot ("us", "we", or "our").
Your access to and use of the Service is conditioned on your acceptance of and compliance with these Terms. These Terms apply to all visitors, users and others who access or use the Service.
By accessing or using the Service you agree to be bound by these Terms. If you disagree with any part of the terms then you may not access the Service. The Terms and Conditions agreement for delCanio bot has been created with the help of TermsFeed.
Our Service may contain links to third-party web sites or services that are not owned or controlled by delCanio bot.
delCanio bot has no control over, and assumes no responsibility for, the content, privacy policies, or practices of any third party web sites or services. You further acknowledge and agree that delCanio bot shall not be responsible or liable, directly or indirectly, for any damage or loss caused or alleged to be caused by or in connection with use of or reliance on any such content, goods or services available on or through any such web sites or services.
We strongly advise you to read the terms and conditions and privacy policies of any third-party web sites or services that you visit.
These Terms shall be governed and construed in accordance with the laws of Argentina, without regard to its conflict of law provisions.
Our failure to enforce any right or provision of these Terms will not be considered a waiver of those rights. If any provision of these Terms is held to be invalid or unenforceable by a court, the remaining provisions of these Terms will remain in effect. These Terms constitute the entire agreement between us regarding our Service, and supersede and replace any prior agreements we might have between us regarding the Service.
We reserve the right, at our sole discretion, to modify or replace these Terms at any time. If a revision is material we will try to provide at least 15 days notice prior to any new terms taking effect. What constitutes a material change will be determined at our sole discretion.
By continuing to access or use our Service after those revisions become effective, you agree to be bound by the revised terms. If you do not agree to the new terms, please stop using the Service.
If you have any questions about these Terms, please contact us.


Skip to content Pull requests Issues Marketplace Explore @Kylin-Schroeder 0 0 0 Kylin-Schroeder/kylin-schroeder.github.io Code Issues 0 Pull requests 0 Projects 0 Wiki Insights Settings kylin-schroeder.github.io/index.html cbdc2e0 a day ago @Kylin-Schroeder Kylin-Schroeder added google analytics ID 55 lines (45 sloc) 1.73 KB


Online IP tools
http://ipv4info.com
http://searchdns.netcraft.com/
https://dnsdumpster.com/
https://ipstack.com/
https://mmoapi.com/cloudflare-ip-resolver/
https://pentest-tools.com/information-gathering/find-subdomains-of-domain#
https://suip.biz
https://webhosting.info/whois/<IP_ADDRESS>
https://whatismyipaddress.com/ip-tools
https://www.dnsstuff.com/
www.ipneighbour.com


What might go wrong inside the outer try{}
block
which would cause an exception?
(1) One of the files might not open. (2) There might be an error in reading from a file. (3) There might be an error in writing to a file. (4) One of the files might not close.
All of those problems are IOExceptions
so the outer try{}
could catch them all
with one catch{}
block.
But this one block would not be very specific about
which type of error it caught.
The constructors for FileInputStream
and FileOutputStream
throw FileNotFoundException
when there is a problem.
Its catch{}
block
should preceed the one for IOException
.
Here is the program so far:
. . . . try { instr = outstr = try { } catch ( EOFException eof ) { } } catch( ______________________ ) { } catch( ______________________ ) { }


Copyright © 2021 STMicroelectronics
This software component is licensed by ST under BSD 3-Clause license, the “License”; You may not use this component except in compliance with the License. You may obtain a copy of the License at:
https://opensource.org/licenses/BSD-3-Clause
The STM32Cube HAL and LL, an STM32 abstraction layer embedded software, ensure maximized portability across STM32 portfolio.
The portable APIs layer provides a generic, multi instanced and simple set of APIs to interact with the upper layer (application, libraries and stacks). It is composed of native and extended APIs set. It is directly built around a generic architecture and allows the build-upon layers, like the middleware layer, to implement its functions without knowing in-depth the used STM32 device. This improves the library code reusability and guarantees an easy portability on other devices and STM32 families.
The Low Layer (LL) drivers are part of the STM32Cube firmware HAL that provides a basic set of optimized and one-shot services. The Low layer drivers, contrary to the HAL ones are not fully portable across the STM32 families; the availability of some functions depends on the physical availability of the relative features on the product. The Low Layer (LL) drivers are designed to offer the following features:
Fourth alpha release of HAL and LL drivers for STM32U575xx / STM32U585xx devices
None
None
None
None


CSPICE_CCIFRM returns the frame name, frame id, and center associated with
a given frame class and class id.
Given:
frclss is the class or type of the frame. This identifies which
subsystem will be used to perform frame transformations.
[1,n] = size(frclss); int32 = class(frclss)
clssid is the ID code used for the frame within its class. This
may be different from the frame ID code.
[1,n] = size(clssid); int32 = class(clssid)
the call:
[frcode, frname, center, found] = cspice_ccifrm( frclss, clssid )
returns:
frcode is the frame ID code for the reference frame
identified by `frclss' and `clssid'.
[1,n] = size(frcode); int32 = class(frcode)
frname is the name of the frame identified by
`frclss' and `clssid'.
[1,n] = size(frname); char = class(frname)
If `frname' does not have enough room to hold
the full name of the frame, the name will be truncated
on the right.
center is the body ID code for the center of the reference
frame identified by `frclss' and `clssid'.
[1,n] = size(center); int32 = class(center)
found is true if a valid frame specification
corresponding to the input frame class and frame class
ID is available, in which case the other outputs are
valid. Otherwise, `found' is returned with the value
false.
[1,1] = size(found); logical = class(found)
Any numerical results shown for this example may differ between
platforms as the results depend on the SPICE kernels used as input
and the machine specific arithmetic implementation.
function ccifrm_t
frcode1 = cspice_namfrm( 'ITRF93');
[center1, clss, clss_ID, found] = cspice_frinfo( frcode1 );
[frcode2, frname, center2, found] = cspice_ccifrm( clss, clss_ID );
if ( ~found )
error('No joy' )
end
fprintf( 'Class : %d\n', clss )
fprintf( 'Class ID : %d\n', clss_ID )
fprintf( 'Fame name : %s\n', frname )
fprintf( 'Frame Code: %d\n', frcode2 )
fprintf( 'Center ID : %d\n', center2 )
end
Matlab outputs:
Class : 2
Class ID : 3000
Fame name : ITRF93
Frame Code: 13000
Center ID : 399
This routine allows the user to determine the frame associated
with a given frame class and class ID code. The kernel pool is
searched first for a matching frame; if no match is found, then
the set of built-in frames is searched.
Since the neither the frame class nor the class ID are primary
keys, searching for matching frames is a linear (and therefore
typically slow) process.
For important details concerning this module's function, please refer to
the CSPICE routine ccifrm_c.
MICE.REQ
FRAMES.REQ
-Mice Version 1.0.0, 01-03-2017, ML (JPL), EDW (JPL)
Find info associated with a frame class and class id
Map frame class and class id to frame info
Map frame class and class id to frame name, id, and center
|


Fortune Cookies
JavaScript Applications Exam, 10 September 2015
Implement a SPA application for fortune cookies.
Application description
The application must provide the following functionality
- Users can Register, Login and Logout in the application
- Users provide
username
and password
- Logged-in users can:
- Share a new fortune cookie
- Providing
text
and category
- Re-share an existing fortune cookie
- This can be either:
- A fortune cookie, shared by this user
- A fortune cookie, shared by other user
- Like or dislike a fortune cookie
- Get their hourly fortune cookie
- A random cookie from all shared cookies
- This cookie is changed every hour
- i.e. if the user asks for their fortune cookie at 11:30 and then again at 11:45, their fortune cookie will be the same
- or if the user asks for their fortune cookie at 11:30 and then again at 12:00, the two fortune cookies may be different
- It depends on the total count of fortune cookies
- All users (even not logged in) can see fortune cookies, that are shared by any user
- Cookies can be:
- Sorted by
likes
or shareDate
- Filtered by a single
category
- i.e. show only the fortune cookies in a given
category
Application routes
Implement at least the following routes in your app:
#/
- Redirects to
#/home
#/home
- Shows all fortune cookies
- Available to all users, logged-in or not
- Provides a way to sort the cookies by
likes
or shareDate
- Provides a way to filter fortune cookies by
category
#/home?category=CCCC
- Shows only the fortune cookies in category CCC
#/my-cookie
- Shows the current hourly fortune cookie for the logged-in user
Application requirements
Mandatory provide a good User Experience(UX) * No need to be pretty, just usable * Please do not make your colleagues wonder where to click, to share a fortune cookie
Mandatory use extensively the following libraries:
- jQuery
- For AJAX
- For DOM manipulation
- Handlebars.js
- For view templates
Do NOT use any of the following: * AngularJS * KendoUI framework * Data-binding, routing, ViewModels, etc... * Durandal * Backbone.js * Ember.js * Batman.js
You can use libraries for: * Notifications * toastr or any other * UI components * jQueryUI, KendoUI UI components, Twitter Bootstrap * Utils frameworks: * Moment, Underscore/Lodash * Libs for encryption * etc... * Routers * Only Sammy.js is allowed * Module loading * System.js, RequireJS or other
Server routes
Users
api/users
- GET
- POST
- Registers a new user
- Needs username and passHash to be sent in the body of the request
api/auth
- PUT
- Logs in an user
- Needs username and passHash to be sent in the body of the request
- If the request is valid returns username and authKey
Fortune Cookies
api/cookies
- GET
- Returns all shared fortune cookies
- POST
- Shares or re-shares a new fortune cookie
- User must be logged-in
- Needs text, category, img to be sent in the body of the request and the current user's authKey as a header with name:
x-auth-key
img
is a string to an online image
img
is optional and if not sent, a default batman image will be provided
api/cookies/:id
- PUT
- Likes or dislikes a fortune cookie
- Needs
type
to be sent in the body of the request
type
can only have values 'like' or 'dislike'
My Fortune Cookies
api/my-cookie
- GET
- Returns the hourly fortune cookie
Categories
api/categories
- GET
- Returns an array with all categories
Deliverables
- ZIP all your code, including the server
- Remove only the
node_modules
folder
- Send the ZIP file on the page, provided in http://telerikacademy.com
Constraints and validation
- Username
- A string
- Has length between 6 and 30
- Can contain only Latin letters, digits and the characters '_' and '.'
- Fortune Cookie Text
- A string
- Has length between 6 and 30
- Can contain any characters
- Fortune Cookie Category
- A string
- Has length between 6 and 30
- Can contain any characters
- Fortune Cookie Img
- A string
- Must be a valid url address