A model building procedure to build parsimonious geoadditive model from a large number of covariates. Continuous, binary and ordered categorical responses are supported. The model building is based on component wise gradient boosting with linear effects, smoothing splines and a smooth spatial surface to model spatial autocorrelation. The resulting covariate set after gradient boosting is further reduced through backward elimination and aggregation of factor levels. The package provides a model based bootstrap method to simulate prediction intervals for point predictions. A test data set of a soil mapping case study in Berne (Switzerland) is provided.
| Version: | 0.1-2 |
| Depends: | R (≥ 2.14.0) |
| Imports: | mboost, mgcv, grpreg, MASS |
| Published: | 2017-07-23 |
| Author: | Madlene Nussbaum [cre, aut], Andreas Papritz [ths] |
| Maintainer: | Madlene Nussbaum <madlene.nussbaum at env.ethz.ch> |
| License: | GPL-2 | GPL-3 [expanded from: GPL (≥ 2)] |
| NeedsCompilation: | no |
| Materials: | NEWS |
| CRAN checks: | geoGAM results |
| Reference manual: | geoGAM.pdf |
| Package source: | geoGAM_0.1-2.tar.gz |
| Windows binaries: | r-devel: geoGAM_0.1-2.zip, r-release: geoGAM_0.1-2.zip, r-oldrel: geoGAM_0.1-2.zip |
| OS X binaries: | r-release: geoGAM_0.1-2.tgz, r-oldrel: geoGAM_0.1-2.tgz |
| Old sources: | geoGAM archive |
Please use the canonical form https://CRAN.R-project.org/package=geoGAM to link to this page.


{{extend 'layout.html'}}
{{=T("The")}} {{=T(module_name)}} {{=T("is an online bulletin board of missing and found people. It captures information about the people missing and found, as well as information of the person seeking them, increasing the chances of people finding each other. For example if two members of a family unit is looking for the head of the family, we can use this data at least to connect those two family members.")}}


A JS9 Web site can define analysis tools that will be loaded into the user's JS9 Analysis menu by the server-side helper. These analysis tasks are then executed by the back-end (CGI or node.js) server using the original FITS data, with results being sent back to the browser for display.
To learn how to install the back-end helper, see: Installing a Server-side Helper.
Analysis tools are defined in files contained in the analysis-plugins directory. If a file in this directory ends with a ".json" extension, it is assumed to be an analysis definition file. The following sample analysis definition files will be found in the analysis-plugins directory by default:
Analysis definition files are in JSON format (http://www.json.org/) and consist of an array of JavaScript objects, one for each analysis tool. The properties which define an analysis tool are:
The action string contains the command to execute. For security reasons, this action is never executed directly. Instead, the first argument of the command must be a wrapper script contained in the analysis-wrappers directory. The js9Xeq wrapper script contained therein is the default script for running JS9 analysis. It is assumed that the second argument in the action string is a command id, which is executed within the command-processing case statement of the js9Xeq. This wrapper script checks for valid commands and arguments, and then executes the specified command in a way that protects against malicious attack. You can modify this script to meet your needs by adding case statements for each of the new tasks you want to run.
Alternatively, you can run your analysis tasks through your own wrapper script, by placing it in the analysis-wrappers directory.  Obviously you can use js9Xeq as an example and modify it to suit your needs.
In either case, note that execution of a wrapper script is accomplished by pre-pending the path of the analysis wrapper directory to the wrapper script name and executing that full pathname directly. This prevents a would-be attacker from executing anything except the wrapper itself. Obviously, you still have to be careful to avoid insecure shell coding in your wrapper script. See The World Wide Web Security FAQ for advice on writing CGI scripts.
The action command line can contain macros (strings prefixed with the $ character) that will be expanded by the browser before the action is sent to the server for processing. Typically, these macros are used to specify filenames, regions, and (possibly) user parameters. The following intrinsic macros are defined:
funcnts $filename $sregions $bregions
Many analysis tasks do not require the user to select parameter options and can can be executed immediately. Other command require user-selected options. These latter options should be put into a Web form, whose location is specified by the purl option. See the params/histplot.html file for an example.
Parameter options in a parameter form should have unique ids. These ids can then be added as macros to the action command line by prefixing them with a $. For example, the histplot command is:
js9Xeq histplot '$filename[$regions]' '$norm $bwidth' $column $binsHere, the norm, bwidth, column, and bins parameters are taken from the Web form for histplot. The $filename and $regions macros are intrinsic to JS9.
The input element of the analysis form should run the JS9.SubmitAnalysis() command, which will serialize the form, pass it to the macro expander, and then send the resulting command string to the server for execution. See histplot.html for sample syntax.
The rtype property determine how JS9 handles return values:
{ "color": "green", "label" : "surf_bri(...) vs. avg_radius(...)", "points" : {"errorbars" : "y", "yerr" : {"show" : "true", "color" : "red"}}, "data": [[x1, y1, e1], [x2, y2, e2], ... [xn, xn, en]] }while the histogram plot contains only x and y values:
{ "color": "blue", "label" : "counts vs. ...bin", "data": [[x1, y1], [x2, y2], ... [xn, xn]] }If your analysis task generates one of these two plot formats, JS9 will display the plot data. Plotting is still somewhat experimental and rudimentary. We will be adding features with time (e.g. ability to change scales between linear and log). Please work with us to improve plotting support.
Finally, the hidden value determines whether or not a task is put into the Analysis menu. If hidden value is true, the analysis task is not shown. However, it still is available to the JS9.RunAnalysis() routine. The fits2png command in the fits2png.json definition file is an example of a hidden command: it is run indirectly by JS9 and need not be listed as a user task.
By default, server-side JS9 analysis tasks are executed using the Analysis menu, but they also can be executed directly from the Web page using HTML elements (buttons, forms, etc.) To do this, a Web page author simply create the desired interface and calls either JS9.RunAnalysis() (for buttons, menus, etc.) or JS9.SubmitAnalysis() (for forms). These are described below. See the js9analysis.html page for an example.
The JS9.RunAnalysis() routine is used to execute an analysis task and return the results for further processing within the Web page. The JS9.SubmitAnalysis() routine works similarly, but it is used with a form: it automatically serializes the form values and passes them to the analysis macro expander so that these values can be put into the analysis command line. The calling sequences for these routines are similar:
JS9.RunAnalysis(aname, [js9div], [options], returnFunc); JS9.SubmitAnalysis(this, aname, [js9div], returnFunc);where:
http://api.jquery.com/serializeArray/
The returnFunc() routine is a callback function to process the returned data from the analysis task. The calling sequence is:
returnFunc(stdout, stderr, aobj)where:


Share your Star Wars thoughts to see who your new soulmate will be
Name
Image URL
Empire Strikes Back is the best Star Wars Movie
1
2
3
4
5
Han shot first
1
2
3
4
5
All of the CG added to the original movies is horrible
1
2
3
4
5
The Last Jedi is a pretty good movie
1
2
3
4
5
Mark Hamill is a very good actor
1
2
3
4
5
I am incredibly excited for the upcoming Star Wars movie
1
2
3
4
5
Tie Fighters are the coolest spaceships in any movie
1
2
3
4
5
Star Wars really needs more sandy planets
1
2
3
4
5
Hans death was enough to put a tear in my eye
1
2
3
4
5
Star Wars is better then The Lord of the Rings
1
2
3
4
5
Find a friend!
Your new best friend!
See other friends


CoBUG Class Information
Information for classes offered during the CoBUG meetings.
Current Class:
Archived Classes:
Date
Name
Course Info
2014-04-16
OpenBSD From Source
Connect Info


index
|
up
|
prev
|
next
ThisNode Class
Definition at line
513
of
Expression.hpp
Constructors
ThisNode
(
const
Span
& span_)
Member Functions
void
Accept
(
Visitor
& visitor)
override
Node
*
Clone
(
CloneContext
& cloneContext)
const override
std::string
ToString
()
const override
Constructor Details
ThisNode Constructor
cmajor::ast::ThisNode::ThisNode(
const
Span
& span_)
Definition at line
1215
of
Expression.cpp
:
1215
:
Node
(
NodeType
::
thisNode
,
span_
)
1216
{
1217
}
Declaration at line
516
of
Expression.hpp
Member Function Details
Accept Member Function
void
cmajor::ast::ThisNode::Accept(
Visitor
& visitor)
override
Definition at line
1224
of
Expression.cpp
:
1225
{
1226
visitor
.
Visit
(
*
this
)
;
1227
}
Declaration at line
518
of
Expression.hpp
Base class overridden functions:
cmajor::ast::Node::Accept
Calls:
cmajor::ast::Visitor::Visit
Clone Member Function
Node
* cmajor::ast::ThisNode::Clone(
CloneContext
& cloneContext)
const override
Definition at line
1219
of
Expression.cpp
:
1220
{
1221
return
new
ThisNode
(
GetSpan
(
)
)
;
1222
}
Declaration at line
517
of
Expression.hpp
Base class overridden functions:
cmajor::ast::Node::Clone
ToString Member Function
std::string cmajor::ast::ThisNode::ToString()
const override
Definition at line
1229
of
Expression.cpp
:
1230
{
1231
return
"this"
;
1232
}
Declaration at line
519
of
Expression.hpp
Base class overridden functions:
cmajor::ast::Node::ToString
index
|
up
|
prev
|
next


--- layout: page title: Get ChRIS Running permalink: /join-us/get-chris-running sidebar: false ---
This tutorial is based on the README files for the ChRIS backend repository and the ChRIS UI repository. Where these instructions may end up differing with those resources, the README files will always be the most up-to-date and correct. We provide this tutorial as a single comprehensive document to get you started.
docker
user group. After installing Docker, do the following in a terminal:
sudo groupadd docker
sudo usermod -aG docker $USER
After you've met the pre-requisites, you'll need to the ChRIS backend up and running. (The ChRIS backend is also called CUBE, an acronym for ChRIS Ultron Back End.) This is the core of ChRIS, not including its web interface (we'll get that working after.)
We're going to set up a development version of ChRIS. (It will use the default Django development server and therefore is not suitable for production.) If you are interested in setting ChRIS up for production, please refer to the README in the CUBE repository.
Open up a terminal on your system and follow these steps:git clone https://github.com/FNNDSC/ChRIS_ultron_backend
cd ChRIS_ultron_backend
./unmake.sh ; sudo rm -fr FS; rm -fr FS; ./make.sh
./unmake.sh ; sudo rm -fr FS; rm -fr FS; ./make.sh -U -I -s
You can later remove all the backend containers and release storage volumes with:
$ cd ChRIS_ultron_backEnd $ sudo rm -r FS $ ./unmake.sh
Now that you have CUBE, the ChRIS backend, running, it's time to get the ChRIS web-based UI working. The ChRIS UI is written primarily in TypeScript and React, and uses the PatternFly React pattern library.
Open up a terminal on your system and follow these steps:$ git clone https://github.com/FNNDSC/ChRIS_ui.git
cd ChRIS_ui
docker run --rm -it -v $(pwd):/home/localuser -p 3000:3000 -u $(id -u):$(id -g) --name chris_ui fnndsc/chris_ui:dev
http://localhost:3000
Now that you've got a got both the ChRIS backend and ChRIS front end running, why not set up the ChRIS store?
If you want to work on the ChRIS store, or need to test loading plugins into a ChRIS instance, you'll need to get the ChRIS store running on your system. Here's how.


{%extends 'base.html'%} {% load humanize %} {%block content%} {{block.super}}
Posted by: {{post.user.username| title}}
Caption: {{post.caption}}
{{comment.user.username}} {{comment.comment | title}} {{comment.pub_date | naturaltime}}


"Light Makes Right"
March 26, 1988
Volume 1, Number 5
Compiled by
All contents are copyright (c) 1988, all rights reserved by the individual authors
Archive locations: anonymous FTP at
ftp://ftp-graphics.stanford.edu/pub/Graphics/RTNews/,
wuarchive.wustl.edu:/graphics/graphics/RTNews, and many others.
You may also want to check out the Ray Tracing News issue guide and the ray tracing FAQ.
As far as ray tracing goes, a few companies announced products. The AT&T Pixel Machine now has two rendering packages, PICLIB and RAYLIB (these may be merged into one package someday - I would guess that separate development efforts caused the split [any comments, Leonard?]). With the addition of some sort of VM capability, this machine becomes pretty astounding in its ray tracing performance (in case you didn't get to SIGGRAPH last year, they had a demo of moving by mouse a shiny ball on top of the mandrill texture map: about a frame per second ray trace on a small part of the screen). HP announced its new graphics accelerator, the TurboSRX, and with it the eventual availability of a ray tracing and (the first!) radiosity package as an extension to their Starbase graphics library. Ardent and their Dore' package were sadly missing. Apollo was also noticeable for their non-appearance. Sun TAAC was there, showing off some ray traced pictures but seemingly not planning to release a ray tracer (the salesman claiming that whoever bought a TAAC would simply write their own). Stellar was there with their supercomputer workstation - interesting, but no ray-tracing in sight. Anyone else note anything of ray-tracing (or other) interest?
back to contents
# Roman Kuchkuda # Megatek alias roman_kuchkuda \<EMAIL_ADDRESS>New people:
I saw Gray at NCGA and got his email address. He worked on ray tracing at RPI and is at Cray:
# Gray Lorig - volumetric data rendering, sci-vi, and parallel & vector # architectures. # Cray Research, Inc. # 1333 Northland Drive # Mendota Heights, MN 55120 #<PHONE_NUMBER> alias gray_lorig<EMAIL_ADDRESS>By way of introduction, this from Erik Jansen:
I visited the Helsinki University of Technology last week and found there a lot of ray tracing activities going on. They are even reviving their old EXCELL system (Markku Tamminen did a PhD work on a spatial index based on an adaptive binary space subdivision in '81-'82, I met him in '81 and '82 and we talked at these occasions about ray tracing and spatial subdivision. In his PhD thesis (1982) there is a ray tracing algorithm given for the EXCELL method (EXtendible CELL method). I decided to implement the algorithm for ray tracing polygon models. That implementation failed because I could only use our PDP-11 at that time and I could have about ten cells in internal memory - too less for effective coherence. The program spend 95% of its time on swapping. So far the history). I told them about the RT-news and they are very interested to receive it. I will mail them (Charles Woodward, Panu Rekola, e.o.) your address, so that they can introduce themselves to the others.
# # Panu Rekola - spline intersection, illumination models, textures # Helsinki University of Technology # Laboratory of Information Processing Science # Room Y229A # SF-02150 Espoo # Finland #<EMAIL_ADDRESS>(or<EMAIL_ADDRESS>alias panu_rekola hpfcrs!hpfcla!hpda!uunet!mcvax!hutcs!pre
Panu Rekola writes:
I just received a message from Erik Jansen (Delft) in which he told me that you take care of a mailing list called "Ray Tracing News". (I already sent a message to Andrew Glassner on the same topic because Erik told me to contact him when he visited us some weeks ago.)  I have previously worked here in a CAD project (where I wrote my MSc thesis on FEM elements) and since about a year I have been responsible of our graphics. Even though my experience in the field is quite short I suppose I have learned a lot while all people want to see their models in color and with glass etc., visualization has been the bottleneck in our CAD projects.
As an introduction to the critical members of the mailing list you could tell that I am a filter who read unstandard input from the models created by other people, manipulates the data with the normal graphics methods, and outpus images. The special features of our ray tracer are the EXCELL spatial directory (which has been optimized for ray tracing during the last few weeks), a new B-spline (and Bezier) algorithm, methods to display BR models with curved surfaces (even blend surfaces, although this part yet unfinished). The system will be semi-commercially used in a couple of companies soon (e.g. car and tableware industry).
back to contents
From Jeff Goldsmith:
Sorry I haven't responded sooner, but movie-making has taken up all my time recently.
With respect to pre-sorting, etc. It is important to note that the preprocessing time must be MUCH smaller than the typical rendering time. So far this has been true, and even more so for animation.
O(n) in my writing (explicitly in print) means linear in the number of objects in the scene. Obviously, it is quite likely that the asymptotic time complexity (a.t.c.) of any ray tracing algorithm will be different for the number of rays. Excluding ray coherence methods and hybrid z-buffer/ray tracing methods, the current a.t.c. is O(n) in the number of rays for ray tracing. Actually, I think it is the same for these other methods because the hybrid methods just eliminate some of the rays from consideration and leave the rest to be just as hard and the coherence methods don't eliminate more than, say, 1/2 of the rays, I think. In any event, for the a.t.c. to become sub-linear, there can be no such fraction, right?
About space tracing: I think that I said that finding the closest intersection is an O(log n) problem. I agree, though, that that statement is not completely correct. Bucket sort methods, for example, can reduce the a.t.c. below log n. Also, global sort time (preprocessing) can distribute some of the computation across all rays, which can reduce the time complexity. What about the subdivide on the fly methods? (e.g.: Arvo and Kirk) How do they fit in the scheme of things? I think your evaluation of the space tracing methods is correct, though the space complexity becomes important here, too. Also, given a "full" space (like Fujimoto's demos,) the time complexity is smaller. That leads to the question, "What if the time complexity of an algorithm depends on its input data?" Standard procedure is to evaluate "worst case" complexity, but we are probably interested in "average case" or more likely, "typical case." Also, it would be worthwhile and interesting to understand which algorithms do better with which type of data. We need to quantify this answer when trying to find good hybrid schemes. (The next generation?)
At SIGGRAPH '87 we had a round table and each answered the question, "what would you like to see happen to ray tracing in the next year." My choice was to see something proven about ray tracing. It sounds like you are interested in that too. Any takers?
back to contents
With respect to the conversation about octree testing, I've only done one try at that. I just tested 9 points against the implicit representation of the surface. (8 corners and the middle.) I didn't use it for ray tracing (I even forget what for) but I suspect that antialiasing will hide most errors generated that way.
Jim Blinn came up with a clever way to do edges and minima/ maxima of quadric surfaces using (surprise) homogeneous coordinates. I don't think there ever was a real paper out of it, but he published a tutorial paper in the Siggraph '84 tutorial notes on "The Mathematics of Computer Graphics." That technique works for any quadric surface (cylinders aren't bounded, though) under any homogeneous transform (including perspective!) He also talks about how to render these things using his method. I tried it; it works great and is incredibly fast. I didn't implement many of his optimizations and can draw a texture mapped cylinder (no end caps) that fills the screen (512x512) on a VAX 780 in under a minute.
As to how this applies to ray tracing, he gives a method for finding the silhouette of a quadric as well as minima and maxima. It allows for easy use of forward differencing, so should be fast enough to "render" quadrics into an octree.
Bob Conley did a volume-oriented ray tracer for his thesis. I don't remember the details, but there'll be a long note about it that I'll pass on. He mentions that his code can do index of refraction varying over position. He uses a grid technique similar to Fujimoto's.
back to contents
Linear-time Voxel Walking for Octrees
Here is a new way to attack the problem of "voxel walking" in octrees (at least I think it's new). By voxel walking I mean identifying the successive voxels along the path of a ray. This is more for theoretical interest than anything else, though the algorithm described below may actually be practical in some situations. I make no claims about the practicality, however, and stick to theoretical time complexity for the most part.
For this discussion assume that we have recursively subdivided a cubical volume of space into a collection of equal-sized voxels using a BSP tree -- i.e. each level imposes a single axis-orthogonal partitioning plane. The algorithm is much easier to describe using BSP trees, and from the point of view of computational complexity, there is basically no difference between BSP trees and octrees. Also, assuming that the subdivision has been carried out to uniform depth throughout simplifies the discussion, but is by no means a prerequisite. This would defeat the whole purpose because we all know how to efficiently walk the voxels along a ray in the context of uniform subdivision -- i.e. use a 3DDDA.
Assuming that the leaf nodes form an NxNxN array of voxels, any given ray will pierce at most O(N) voxels. The actual bound is something like 3N, but the point is that it's linear in N. Now, suppose that we use a "re-traversal" technique to move from one voxel to the next along the ray. That is, we create a point that is guaranteed to lie within the next voxel and then traverse the hierarchy from the root node until we find the leaf node, or voxel, containing this point. This requires O( log N ) operations. In real life this is quite insignificant, but here we are talking about the actual time complexity. Therefore, in the worst case situation of following a ray through O( N ) voxels, the "re-traversal" scheme requires O( N log N ) operations just to do the "voxel walking." Assuming that there is an upper bound on the number of objects in any voxel (i.e. independent of N), this is also the worst case time complexity for intersecting a ray with the environment.
In this note I propose a new "voxel walking" algorithm for octrees (call it the "partitioning" algorithm for now) which has a worst case time complexity of O( N ) under the conditions outlined above. In the best case of finding a hit "right away" (after O(1) voxels), both "re-traversal" and "partitioning" have a time complexity of O( log N ). That is:
BEST CASE: O(1) voxels WORST CASE: O(N) voxels searched before a hit. searched before a hit. +---------------------------------------------------+ | | Re-traveral | O( log N ) O( N Log N ) | | | Partitioning | O( log N ) O( N ) | | | +---------------------------------------------------+
The new algorithm proceeds by recursively partitioning the ray into little line segments which intersect the leaf voxels. The top-down nature of the recursive search ensures that partition nodes are only considered ONCE PER RAY. In addition, the voxels will be visited in the correct order, thereby retaining the O( log N ) best case behavior.
Below is a pseudo code description of the "partitioning" algorithm. It is the routine for intersecting a ray with an environment which has been subdivided using a BSP tree. Little things like checking to make sure the intersection is within the appropriate interval have been omitted. The input arguments to this routine are:
Node : A BSP tree node which comes in two flavors -- a partition node or a leaf node. A partition node defines a plane and points to two child nodes which further partition the "positive" and "negative" half-spaces. A leaf node points to a list of candidate objects.
P : The ray origin. Actually, think of this as an endpoint of a 3D line segment, since we are constraining the "ray" to be of finite length.
D : A unit vector indicating the ray direction.
len : The length of the "ray" -- or, more appropriately, the line segment. This is measured from the origin, P, along the direction vector, D.
The function "Intersect" is initially passed the root node of the BSP tree, the origin and direction of the ray, and a length, "len", indicating the maximum distance to intersections which are to be considered. This starts out being the distance to the far end of the original bounding cube.
==============================================
FUNCTION Intersect( Node, P, D, len ) RETURNING "results of intersection"
IF Node is NIL THEN RETURN( "no intersection" )
IF Node is a leaf THEN BEGIN
intersect ray (P,D) with objects in the candidate list
RETURN( "the closest resulting intersection" )
END IF
dist := signed distance along ray (P,D) to plane defined by Node
near := child of Node in half-space which contains P
IF 0 < dist < len THEN BEGIN /* the interval intersects the plane */
hit_data := Intersect( near, P, D, dist )
IF hit_data <> "no intersection" THEN RETURN( hit_data )
Q := P + dist * D /* 3D coords of point of intersection */
far := child of Node in half-space which does NOT contain P
RETURN( Intersect( far, Q, D, len - dist ) )
END IF
ELSE RETURN( Intersect( near, P, D, len ) )
END
=========================================================
As the BSP tree is traversed, the line segments are chopped up by the partitioning nodes. The "shrinking" of the line segments is critical to ensure that only relevent branches of the tree will be traversed.
The actual encodings of the intersection data, the partitioning planes, and the nodes of the tree are all irrelevant to this discussion. These are "constant time" details. Granted, they become exceedingly important when considering whether the algorithm is really practical. Let's save this for later.
A naive (and incorrect) proof of the claim that the time complexity of this algorithm is O(N) would go something like this:
The voxel walking that we perform on behalf of a single ray is really just a search of a binary tree with voxels at the leaves. Since each node is only processed once, and since a binary tree with k leaves has k - 1 internal nodes, the total number of nodes which are processed in the entire operation must be of the same order as the number of leaves. We know that there are O( N ) leaves. Therefore, the time complexity is O( N ).
But wait! The tree that we search is not truly binary since many of the internal nodes have one NIL branch. This happens when we discover that the entire current line segment is on one side of a partitioning plane and we prune off the branch on the other side. This is essential because there are really N**3 leaves and we need to discard branches leading to all but O( N ) of them. Thus, k leaves does not imply that there are only k - 1 internal nodes. The quention is, "Can there be more than O( k ) internal nodes?".
Suppose we were to pick N random voxels from the N**3 possible choices, then walk up the BSP tree marking all the nodes in the tree which eventually lead to these N leaves. Let's call this the subtree "generated" by the original N voxels. Clearly this is a tree and it's uniquely determined by the leaves. A very simple argument shows that the generated subtree can have as many as 2 * ( N - 1 ) * log N nodes. This puts us right back where we started from, with a time complexity of O( N log N ), even if we visit these nodes only once. This makes sense, because the "re-traversal" method, which is also O( N log N ), treats the nodes as though they were unrelated. That is, it does not take advantage of the fact that paths leading to neighboring voxels are likely to be almost identical, diverging only very near the leaves. Therefore, if the "partitioning" scheme really does visit only O( N ) nodes, it does so because the voxels along a ray are far from random. It must implicitly take advantage of the fact that the voxels are much more likely to be brothers than distant cousins.
This is in fact the case. To prove it I found that all I needed to assume about the voxels was connectedness -- provided I made some assumptions about the "niceness" of the BSP tree. To give a careful proof of this is very tedious, so I'll just outline the strategy (which I *think* is correct). But first let's define a couple of convenient terms:
1) Two voxels are "connected" (actually "26-connected") if they meet at a face, an edge, or a corner. We will say that a collection of voxels is connected if there is a path of connected voxels between any two of them.
2) A "regular" BSP tree is one in which each axis-orthogonal partition divides the parent volume in half, and the partitions cycle: X, Y, Z, X, Y, Z, etc. (Actually, we can weaken both of these requirements considerably and still make the proof work. If we're dealing with "standard" octrees, the regularity is automatic.)
Here is a sequence of little theorems which leads to the main result:
THEOREM 1: A ray pierces O(N) voxels.
THEOREM 2: The voxels pierced by a ray form a connected set.
THEOREM 3: Given a collection of voxels defined by a "regular" BSP tree, any connected subset of K voxels generates a unique subtree with O( K ) nodes.
THEOREM 4: The "partitioning" algorithm visits exactly the nodes of the subtree generated by the voxels pierced by a ray. Furthermore, each of these nodes is visited exaclty once per ray.
THEOREM 5: The "partitioning" algorithm has a worst case complexity of O( N ) for walking the voxels pierced by a ray.
Theorems 1 and 2 are trivial. With the exception of the "uniqueness" part, theorem 3 is a little tricky to prove. I found that if I completely removed either of the "regularity" properties of the BSP tree (as opposed to just weakening them), I could construct a counterexample. I think that theorem 3 is true as stated, but I don't like my "proof" yet. I'm looking for an easy and intuitive proof. Theorem 4 is not hard to prove at all. All the facts become fairly clear if you see what the algorithm is doing. Finally, theorem 5, the main result, follows immediately from theorems 1 through 4.
SOME PRACTICAL MATTERS:
Since log N is typically going to be very small -- bounded by 10, say -- this whole discussion may be purely academic. However, just for the heck of it, I'll mention some things which could make this a (maybe) competative algorithm for real-life situations (in as much as ray tracing can ever be considered to be "real life").
First of all, it would probably be advisable to avoid recursive procedure calls in the "inner loop" of a voxel walker. This means maintaining an explicit stack. At the very least one should "longjump" out of the recursion once an intersection is found.
The calculation of "dist" is very simple for axis-orthogonal planes, consisting of a subtract and a multiply (assuming that the reciprocals of the direction components are computed once up front, before the recursion begins).
A nice thing which falls out for free is that arbitrary partitioning planes can be used if desired. The only penalty is a more costly distance calculation. The rest of the algorithm works without modification. There may be some situations in which this extra cost is justified.
Sigh. This turned out to be much longer than I had planned...
>>>>>> A followup message:
Here is a slightly improved version of the algorithm in my previous mail. It turns out that you never need to explicitly compute the points of intersection with the partitioning planes. This makes it a little more attractive.
-- Jim
FUNCTION BSP_Intersect( Ray, Node, min, max ) RETURNING "intersection results"
BEGIN
IF Node is NIL THEN RETURN( "no intersection" )
IF Node is a leaf THEN BEGIN /* Do the real intersection checking */
intersect Ray with each object in the candidate list discarding those farther away than "max."
RETURN( "the closest resulting intersection" )
END IF
dist := signed distance along Ray to plane defined by Node
near := child of Node for half-space containing the origin of Ray
far := the "other" child of Node -- i.e. not equal to near.
IF dist > max OR dist < 0 THEN /* Whole interval is on near side. */
RETURN( BSP_Intersect( Ray, near, min, max ) )
ELSE IF dist < min THEN /* Whole interval is on far side. */
RETURN( BSP_Intersect( Ray, far , min, max ) )
ELSE BEGIN /* the interval intersects the plane */
hit_data := BSP_Intersect( Ray, near, min, dist ) /* Test near side */
IF hit_data indicates that there was a hit THEN RETURN( hit_data )
RETURN( BSP_Intersect( Ray, far, dist, max ) ) /* Test far side. */
END IF
END
related previous discussion of topic
back to contents
________
Given a ray-tracer which has some basic efficiency scheme in use, how can we make it faster? Some of my tricks are below - what are yours?
[HBV stands for Hierarchical Bounding Volumes]
Speed-up #1: [HBV and probably Octree] Keep track of the closest intersection distance. Whenever a primitive (i.e. something that exists - not a bounding volume) is hit, keep its distance as the maximum distance to search. During further intersection testing use this distance to cut short the intersection calculations.
Speed-up #2: [HBV and possibly Octree] When building the ray tree, keep the ray-tree around which was previously built. For each ray-tree node, intersect the object in the old ray tree, then proceed to intersect the new ray tree. By intersecting the old object first you can usually obtain a maximum distance immediately, which can then be used to aid Speed-up #1.
Speed-up #3: When shadow testing, keep the opaque object (if any) which shadowed each light for each ray-tree node. Try these objects immediately during the next shadow testing at that ray-tree node. Odds are that whatever shadowed your last intersection point will shadow again. If the object is hit you can immediately stop testing because the light is not seen.
Speed-up #4: When shadow testing, save transparent objects for later intersection. Only if no opaque object is hit should the transparent objects be tested.
Speed-up #5: Don't calculate the normal for each intersection. Get the normal only after all intersection calculations are done and the closest object for each node is know: after all, each ray can have only one intersection point and one normal. (Saving intermediate results is recommended for some intersection calculations.)
Speed-up #6: [HBV only] When shooting rays from a surface (e.g. reflection, refraction, or shadow rays), get the initial list of objects to intersect from the bounding volume hierarchy. For example, a ray beginning on a sphere must hit the sphere's bounding volume, so include all other objects in this bounding volume in the immediate test list. The bounding volume which is the father of the sphere's bounding volume must also automatically be hit, and its other sons should automatically be added to the test list, and so on up the object tree. Note also that this list can be calculated once for any object, and so could be created and kept around under a least-recently-used storage scheme.
back to contents
The puzzle: Actually, I lied. This technique can cause a subtle error. Do you know what shading error the above technique would cause? [hint: assume the Hall model is used for shading].
back to contents
I updated my edition (the Second) with these corrections, which was generally a time drain: my advice is to keep the errata sheets in this edition, checking them only if you are planning to use an algorithm. However, the third edition corrections are mercifully short.
____
From: "David F. Rogers"<EMAIL_ADDRESS>From: David F. Rogers<EMAIL_ADDRESS>Subject: PECG correction Date: Thu, 10 Mar 88 13:21:11 EST
Correction list for PECG 2/26/86 David F. Rogers
There have been 3 printings of this book to date. The 3rd printing occurred in approximately March 85.
To see if you have the 3rd printing look on page 386, 3rd line down and see if the word magenta is spelled correctly. If it is, you have the 3rd printing. If not, then you have the 2nd or 1st printing.
To see if you have the 2nd printing look on page 90. If the 15th printed line in the algorithm is
while Pixel(x,y) <> Boundary value
you have the 2nd printing. If not you have the 1st printing.
Please send any additional corrections to me at
Professor David F. Rogers Aerospace Engineering Department United States Naval Academy Annapolis, Maryland 21402
uucp:decvax!brl-bmd!usna!dfr arpa:dfr@usna
_____________________________________________________________
Known corrections to the third printing:
Page Para./Eq. Line Was Should be72 2 11 (5,5) (5,1) 82 1 example 4 (8,5) delete 100 5th equation upper limit on integral should be 2 vice 1 143 Fig. 3-14 yes branch of t < 0 and t > 1 decision blocks should extend down to Exit-line invisible 144 Cyrus-Beck algorithm 7 then 3 then 4 11 then 3 then 4 145 Table 3-7 1 value for w [2 1] [-2 1] 147 1st eq. 23 V sub e sub x j V sub e sub y j
______________________________________________________________
Known corrections to the second printing: (above plus)
text:
19 2 5 Britian Britain 36 Eq. 3 10 replace 2nd + with = 47 4 6 delta' > 0 delta'< = 0 82 1 6 set complement 99 1 6 multipled multiplied 100 1 6 Fig. 2-50a Fig. 2-57a 100 1 8 Fig. 2-50b Fig. 2-57b 122 write for new page 186 2 6 Fig. 3-37a Fig. 3-38a 186 2 9 Fig. 3-38 Fig. 3-38b 187 Ref. 3-5 to appear Vol. 3, pp. 1-23, 1984 194 Eq. 1 xn + xn - 224 14 lines from bottom t = 1/4 t = 3/4 329 last eq. -0.04 -0.13 next to last eq. -0.04 twice -0.13 twice 3rd from bottom 0.14 -0.14 330 1st eq. -0.09 -0.14 2nd eq. -0.09 -0.14 3rd eq. -0.17 -0.27 4th eq. 0.36 0.30 5.25 4.65 last eq. 5.25 4.65 332 4 beta < beta > 6 beta < beta > 355 2nd eq. w = s(u,w) w = s(theta,phi) 385 2 5 magneta magenta 386 3 magneta magenta
algorithms: (send self-addressed long stamped envelope for xeroxed corrections)
97 Bresenham 1 insert words first quadrant after modified 10 remove () 12 1/2 I/2 14 delta x x sub 2 117 Explicit 18 Icount = 0 delete clipping 18 insert m = Large 120 9 P'2 P'1 12 insert after Icount = 0 end if 13 insert after 1 if Icount <> 0 then neither end P' = P0 14 removed statement label 1 15 >= > 17 delete 18 delete 43 y> yT> 122-124 Sutherland- write for new pages Cohen 128 midpoint 4 insert after initialize i i = 1 129 6 i = 1 delete 6 insert save original p1 Temp = P1 8 i = 2 i > 2 11,12 save original.. delete Temp = P1 14 add statement label 2 130 19-22 delete 24 i = 2 i = i + 1 29 <> <> 0 33 P1 P 143 3 wdotn Wdotn 144 20 >= > 176 Sutherland- 1 then 5 then 4 Hodgman 177 9 4 x 4 2 x 2 198 floating 21,22 x,y Xprev,Yprev horizon 199 4 Lower Upper 200 11-19 rewrite as if y < Upper(x) and y > Lower(x) then Cflag = 0 if y> = Upper(x) then Cflag = 1 if y< = Lower(x) then Cflag = -1 29 delete 31 Xinc (x2-x1) 36 step Xinc step 1 201 4 delete 6 Xinc = 0 (x2-x1) = 0 12 Y1 - Y1 + Slope - 12 insert after Csign = Ysign 13 Yi = Y1 Yi = Y1 + Slope 13 insert after Xi = X1 + 1 14-end rewrite as while(Csign = Ysign) Yi = Yi + Slope Xi = Xi + 1 Csign = Sign(Yi - Array(Xi)) end while select nearest integer value if |Yi -Slope -Array(Xi - 1)| <= |Yi - Array(Xi)| then Yi = Yi - Slope Xi = Xi -1 end if end if return 258 subroutine Compute N i 402 HSV to Rgb 12 insert after end if 25 end if delete 404 HLS to RGB 2 M1 = L*(1 - S) M2 = L*(1 + S) 4 M1 M2 6 M2 = 2*L - M1 M1 = 2*L - M2 10-12 =1 =L 18 H H + 120 19 Value + 120 Value 22 H H - 120 23 Value - 120 Value 405 RGB to HLS 22 M1 + M2 M1 - M2 figures: 77 Fig. 2-39a interchange Edge labels for scanlines 5 & 6 Fig. 2-39b interchange information for lists 1 & 3, 2 & 4 96 Fig. 2-57a,b y sub i + 1 y sub(i+1) 99 Fig. 2-59 abcissa of lowest plot should be xi vice x 118 Fig. 3-4 first initialization block - add m = Large add F entry point just above IFLAG = -1 decision block 119 to both IFLAG=-1 blocks add exit points to F 125 Fig. 3-5 line f - interchange Pm1 & Pm2 128 Fig. 3-6a add initialization block immediately after Start initialize i, i=1 immediately below new initialization block add entry point C in Look for the farthest vissible point from P1 block - delete i=1 in decision block i = 2 - change to i > 2 129 Fig. 3-6b move return to below Save P1 , T = P1 block remove Switch end point codes block in Reset counter block replace i=2 with i=i + 1 180 Fig. 3-34b Reverse direction of arrows of box surrounding word Start. 330 Fig. 5-16a add P where rays meet surface 374 Fig. 5-42 delete unlabelled third exit from decision box r ray? 377 Fig. 5-44 in lowest box I=I+I sub(l (sub j)) replace S with S sub(j) _________________________________________________________________________
Known corrections to the first printing:
90,91 scan line seed write for xeroxed corrections fill algorithm
back to contents


-
oslo.config
— Parses config options from command line and config files.
-
oslo.db
— Provides database connectivity.
-
oslo.i18n
— Internationalization and translation utilities.
-
oslo.messaging
— Provides inter-process communication.
-
oslotest
— Provides a unit test and fixture framework.
-
cliff
— Builds command-line programs in Python.
-
pbr
— Manages setuptools packaging needs in a consistent way.
-
PyCADF
— Creates CADF events to capture cloud-related events.
-
stevedore
— Manages dynamic plug-ins for Python applications.
-
TaskFlow
— Makes task execution easy, consistent, and reliable.


This screen gathers information about which images you would like to view or make changes to. These images must have been previously added via the Process New Images screen or they must have been published to the Bioimages website already.
This is the unique ID of the agent whose images you wish to load. Usually this will be the unique ID of the person entering information into this software. This setting is also used as the default agent in when creating a new determination later in the software. You may have already have been given a unique ID. The most common forms are either your last name plus first and possibly second initial (e.g. John Doe -> doej). If you do not already have a unique ID, click the Create New ID button and fill out the required information.
Click this button and locate the folder containing the images you wish to load. The default setting is to only load images that have been added or modified locally. In other words, images that have metadata that differs from what is on the Bioimages website; changes you have been working on. If you want to load all of your images for viewing, even ones that have already been published to Bioimages, check the box 'Load all records for selected agent, including for images previously submitted'.
For most users that is all that needs to be done. By clicking Continue the selected images and metadata will show up on the data entry screen.
There are a few more advanced options. One advanced option is to load everyone's images by checking the box. There is a placeholder thumbnail for any images that you do not have locally so that you may still look at their metadata.
The Selected folder is root of namespace folders checkbox is useful if you are loading images from multiple namespaces. Check this box then in step 2. Select image folder select the parent directory that contains the namespace folders that you are loading images from. This option goes well with the 'Load everyone's iamges' checkbox assuming you have images from other photographers on your computer.
Lastly there is an option to clear the thumbnail cache. The cache is used to store thumbnail versions of the images you load. It serves two purposes: to speed up loading the Data Entry screen (the screen after you click Continue from this screen) and to continue showing thumbnails of images you have viewed before even if you no longer have those images on your computer any longer. There are two reasons you may want to clear the cache. If you have edited the appearance of an image (e.g. cropping it) after you have loaded it with this software, the thumbnail will still show the old version of the image. Clearing the thumbnail cache will fix this. Another reason, although unlikely for most users, is that if you load tens of thousands of images with this software then the thumbnail cache will grow to several hundred megabytes in size. If you rarely view that many files (e.g. maybe it was a one-time thing that you loaded so many) you may clear the cache to free up disk space.


Post a Job, it's easy and free! |
|
|
Hey {memberFname},
We notice that you haven't posted any Jobs yet. Don't be afraid to take the plunge - it's easy and free.
✓Website and E-commerce development
✓ Logo design
✓ Wordpress theme and custom CSS
✓ Copywriting and Social media management
✓ Telesales, Accounting and Legal work
✓ Brand identity and illustrations
✓ Mobile Application
✓ Brochure, Flyer and leaflet
✓ Animation and Infographic
✓ Search Engine Optimization and SEM
Whether you need something from the above or pretty much anything else, PPH has skilled freelancers eagerly waiting to help you.
|
Best Regards The PeoplePerHour Support Ninjas |


A package to play with X-rays
The xray package currently has three modules:
Warning
The documentation of this package is still very poor, use with care... and add some love to the docs if you have time.
Create a list of all HklPlanes. This should move to the HklPlane class as a static method.
Compute the ellipsis associated with the given zone axis. All lattice planes sharing this zone axis will diffract along that ellipse.
| Parameters: |
|
|---|---|
| Returns data: | the (u, v) data (in pixel unit) representing the ellipsis. |
Compute the wavelength corresponding to the first order reflection of a given lattice plane.
| Parameters: |
|
|---|---|
| Returns tuple: | A tuple of the wavelength value and the corresponding Bragg angle. |
Plot the transmitted intensity of a X-ray beam through a given material.
Parameters:
mat The material (Chemical composition, eg. ‘Al’)
ts a list of thickness values of the material in mm (1.0 by default)
rho density of the material in g/cm^3 (1.0 by default)
unit unit for the energy column (keV by default)
energy_lim energy bounds in the plot (1, 100 by default)
display display the plot or save an image of the plot (False by default)


[ht::head {IMDV Entries} ]
:navtop
+callout-info
You can add markers that represent other entries in your RAMADDA.
-callout
:heading Entry Markers
The Entry Marker and the Multi Entry allow you to add markers
for RAMADDA entries. Clicking on the marker will show some content
from that entry.
For example, RAMADDA supports 3D Models as an entry type.
Choosing New->Entry Marker and adding it to the map will add a marker. Clicking on that marker
will show a 3D view of the model:
[ht::screenshot images/entrymarker.png]
When adding a marker for an entry that has geolocation you will be prompted if you want to
use the entry's latitide/longitude as the position for the marker or if you want to position
the marker manually. If you opt to use the entry's position then, if the position of the entry
is changed, that change is reflected in the map. You can manually move the marker and that new
position will then be used. Likewise, the name and label for the marker is taken from the entry
name. If the name of the entry changes then that will be reflected in the map. This can be changed
by bringing up the properties for the entry marker:
[ht::screenshot images/entrymarker2.png]
:heading Data Displays
RAMADDA provides very rich capabilities to show data in maps, e.g.
on ramadda.org.
These displays are accomplished through RAMADDA's wiki
facility. You can import one or more map data displays into an IMDV.
:p
First, upload your data to RAMADDA and create a map display for that data
using RAMADDA's wiki facility.
Next, from the IMDV New menu select Data and select the data you uploaded.
The IMDV will extract from you data's wiki the arguments for a map display.
These will be shown and can be edited if needed. Here we've selected some aircraft
track data:
[ht::screenshot images/newdata.png]
With the result map:
[ht::screenshot images/data1.png]
The map display properties can be edited through the Edit form.
Other data displays can be added and overlaid on the IMDV map.
:p
You can play around with this by importing the file
https://ramadda.org/repository/a/userguide_showing_data_in_maps
to your RAMADDA. This is an export of the example showing Colorado aircraft crashes and
Colorado mines on
ramadda.org.


|
JavaTM 2 Platform Standard Ed. 5.0 |
|||||||||
| PREV CLASS NEXT CLASS | FRAMES NO FRAMES | |||||||||
| SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |
java.lang.Object java.text.Bidi
public final class Bidi
This class implements the Unicode Bidirectional Algorithm.
A Bidi object provides information on the bidirectional reordering of the text used to create it. This is required, for example, to properly display Arabic or Hebrew text. These languages are inherently mixed directional, as they order numbers from left-to-right while ordering most other text from right-to-left.
Once created, a Bidi object can be queried to see if the text it represents is all left-to-right or all right-to-left. Such objects are very lightweight and this text is relatively easy to process.
If there are multiple runs of text, information about the runs can be accessed by indexing to get the start, limit, and level of a run. The level represents both the direction and the 'nesting level' of a directional run. Odd levels are right-to-left, while even levels are left-to-right. So for example level 0 represents left-to-right text, while level 1 represents right-to-left text, and level 2 represents left-to-right text embedded in a right-to-left run.
| Field Summary | |
|---|---|
static int |
DIRECTION_DEFAULT_LEFT_TO_RIGHT
Constant indicating that the base direction depends on the first strong directional character in the text according to the Unicode Bidirectional Algorithm. |
static int |
DIRECTION_DEFAULT_RIGHT_TO_LEFT
Constant indicating that the base direction depends on the first strong directional character in the text according to the Unicode Bidirectional Algorithm. |
static int |
DIRECTION_LEFT_TO_RIGHT
Constant indicating base direction is left-to-right. |
static int |
DIRECTION_RIGHT_TO_LEFT
Constant indicating base direction is right-to-left. |
| Constructor Summary | |
|---|---|
Bidi(AttributedCharacterIterator paragraph)
Create Bidi from the given paragraph of text. |
|
Bidi(char[] text,
int textStart,
byte[] embeddings,
int embStart,
int paragraphLength,
int flags)
Create Bidi from the given text, embedding, and direction information. |
|
Bidi(String paragraph,
int flags)
Create Bidi from the given paragraph of text and base direction. |
| Method Summary | |
|---|---|
boolean |
baseIsLeftToRight()
Return true if the base direction is left-to-right. |
Bidi |
createLineBidi(int lineStart,
int lineLimit)
Create a Bidi object representing the bidi information on a line of text within the paragraph represented by the current Bidi. |
int |
getBaseLevel()
Return the base level (0 if left-to-right, 1 if right-to-left). |
int |
getLength()
Return the length of text in the line. |
int |
getLevelAt(int offset)
Return the resolved level of the character at offset. |
int |
getRunCount()
Return the number of level runs. |
int |
getRunLevel(int run)
Return the level of the nth logical run in this line. |
int |
getRunLimit(int run)
Return the index of the character past the end of the nth logical run in this line, as an offset from the start of the line. |
int |
getRunStart(int run)
Return the index of the character at the start of the nth logical run in this line, as an offset from the start of the line. |
boolean |
isLeftToRight()
Return true if the line is all left-to-right text and the base direction is left-to-right. |
boolean |
isMixed()
Return true if the line is not left-to-right or right-to-left. |
boolean |
isRightToLeft()
Return true if the line is all right-to-left text, and the base direction is right-to-left. |
static void |
reorderVisually(byte[] levels,
int levelStart,
Object[] objects,
int objectStart,
int count)
Reorder the objects in the array into visual order based on their levels. |
static boolean |
requiresBidi(char[] text,
int start,
int limit)
Return true if the specified text requires bidi analysis. |
String |
toString()
Display the bidi internal state, used in debugging. |
| Methods inherited from class java.lang.Object |
|---|
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait |
| Field Detail |
|---|
public static final int DIRECTION_LEFT_TO_RIGHT
public static final int DIRECTION_RIGHT_TO_LEFT
public static final int DIRECTION_DEFAULT_LEFT_TO_RIGHT
public static final int DIRECTION_DEFAULT_RIGHT_TO_LEFT
| Constructor Detail |
|---|
public Bidi(String paragraph, int flags)
paragraph
- a paragraph of textflags
- a collection of flags that control the algorithm. The
algorithm understands the flags DIRECTION_LEFT_TO_RIGHT, DIRECTION_RIGHT_TO_LEFT,
DIRECTION_DEFAULT_LEFT_TO_RIGHT, and DIRECTION_DEFAULT_RIGHT_TO_LEFT.
Other values are reserved.public Bidi(AttributedCharacterIterator paragraph)
The RUN_DIRECTION attribute in the text, if present, determines the base direction (left-to-right or right-to-left). If not present, the base direction is computes using the Unicode Bidirectional Algorithm, defaulting to left-to-right if there are no strong directional characters in the text. This attribute, if present, must be applied to all the text in the paragraph.
The BIDI_EMBEDDING attribute in the text, if present, represents embedding level information. Negative values from -1 to -62 indicate overrides at the absolute value of the level. Positive values from 1 to 62 indicate embeddings. Where values are zero or not defined, the base embedding level as determined by the base direction is assumed.
The NUMERIC_SHAPING attribute in the text, if present, converts European digits to other decimal digits before running the bidi algorithm. This attribute, if present, must be applied to all the text in the paragraph.
paragraph
- a paragraph of text with optional character and paragraph attribute informationTextAttribute.BIDI_EMBEDDING
,
TextAttribute.NUMERIC_SHAPING
,
TextAttribute.RUN_DIRECTION
public Bidi(char[] text, int textStart, byte[] embeddings, int embStart, int paragraphLength, int flags)
text
- an array containing the paragraph of text to process.textStart
- the index into the text array of the start of the paragraph.embeddings
- an array containing embedding values for each character in the paragraph.
This can be null, in which case it is assumed that there is no external embedding information.embStart
- the index into the embedding array of the start of the paragraph.paragraphLength
- the length of the paragraph in the text and embeddings arrays.flags
- a collection of flags that control the algorithm. The
algorithm understands the flags DIRECTION_LEFT_TO_RIGHT, DIRECTION_RIGHT_TO_LEFT,
DIRECTION_DEFAULT_LEFT_TO_RIGHT, and DIRECTION_DEFAULT_RIGHT_TO_LEFT.
Other values are reserved.| Method Detail |
|---|
public Bidi createLineBidi(int lineStart, int lineLimit)
lineStart
- the offset from the start of the paragraph to the start of the line.lineLimit
- the offset from the start of the paragraph to the limit of the line.public boolean isMixed()
public boolean isLeftToRight()
public boolean isRightToLeft()
public int getLength()
public boolean baseIsLeftToRight()
public int getBaseLevel()
public int getLevelAt(int offset)
offset
- the index of the character for which to return the level
public int getRunCount()
public int getRunLevel(int run)
run
- the index of the run, between 0 and getRunCount()
public int getRunStart(int run)
run
- the index of the run, between 0 and getRunCount()
public int getRunLimit(int run)
run
- the index of the run, between 0 and getRunCount()
public static boolean requiresBidi(char[] text, int start, int limit)
text
- the text containing the characters to teststart
- the start of the range of characters to testlimit
- the limit of the range of characters to test
public static void reorderVisually(byte[] levels, int levelStart, Object[] objects, int objectStart, int count)
index
from
objectStart
up to objectStart + count
in the objects array will be reordered into visual order assuming
each run of text has the level indicated by the corresponding element
in the levels array (at index - objectStart + levelStart
).
levels
- an array representing the bidi level of each objectlevelStart
- the start position in the levels arrayobjects
- the array of objects to be reordered into visual orderobjectStart
- the start position in the objects arraycount
- the number of objects to reorderpublic String toString()
toString
in class Object
|
JavaTM 2 Platform Standard Ed. 5.0 |
|||||||||
| PREV CLASS NEXT CLASS | FRAMES NO FRAMES | |||||||||
| SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |
Copyright © 2004, 2010 Oracle and/or its affiliates. All rights reserved. Use is subject to license terms. Also see the documentation redistribution policy.


<
Next version of Ox>
<
Previous version of Ox>
Ox 3.30: new features and fixes
New features and enhancements
- intersection index, exclusion index
- Improved MaxSimplex error messages; check for vDelta=0
- Threes example for mingw C/C++ compiler
- dayofcalender and dayofweek can now be used in the
opposite direction
- set default fuzziness to 1e-13, and made range()
for non-integer arguments independent of fuzziness settings.
- extended QuadPack with QAW? functions and QPWARN
- added oxprintlevel to switch printing off
- extended oxwarning
- third/fourth argument of many random
number generators can now be an r x c matrix.
- Can now do indexed assignment to int/double,
e.g. decl x = 1; x[0] = 2;
- String concatenation and substring now use
actual size, rather than up to ending \0.
- Now allowing string with embedded \0 as well
as octal escape sequences.
- feof previously returned non-zero after an attempt
to read past the end of the file. Now it will return TRUE
if the next read will be past the end of the file.
Problems in version 3.20 which have been fixed in version 3.30:
- sortc(zeros(0,1)) leads to crash
- ranwishart was incomplete and useless.
- vech of scalar returned zero.
- Database::RemoveObsIf() and Database::Grow()
would result in GetYear2() and GetSample2() to be out by
one observation.
- Use of -i.. switch under Linux/Unix could lead to a crash.
- MaxSQP: equality constraints only: merit function
could become .NaN if the weights of the inequality constraints
(eventhough they should be irrelevant) end up at zero.
- Database class: for monthly data, the first seasonal
variable did not correspond to January.
- calls of type var->class::function was not allowed
inside other classes.
- Calls to SetDraw before any drawing functions would
be ignored when running via oxl.
- outer(mx,<>,'o') gave empty matrix error message
- deleter(x, 0); also deletes missing values,
but should only delete rows with zeros. Same for deletec.
- densities/probabilities of distributions
defined over (0,Inf) sometimes returned
the wrong value for arguments in (-Inf,0].
- invert,invertsym,invertgen return empty matrix
if argument is empty matrix.
-
OxGauss (thanks to Sébastien Laurent)
- seqm is wrong; seqa(10,0,3) is wrong
- "string"$x; didn't work
- loadd for dat or dht/dat datafile didn't work
- string * ones(r,c) was not allowed.
- improved dstat, scalerr, indcv, indices
- a[b[j]] type expressions could go wrong
- format with precision 0 didn't work
- load x,y; didn't work
- load at external level now also declares variables if necessary
- token(" ") would have index error
- added screen off; screen on;
- added ndpchk, ndpclex, ndpcntrl back in
- ismiss({}) should return TRUE
- clear,clearg,close,declare,delete,external: separating , is optional
- quoted string with linebreaks was not treated correctly yet.
- ignoring Ctrl+Z (\x1a)
- save path=^spath AA; didn't work (aa would be OK)
- trace 0; skipped
- "aap" -noot; now allowed
- indices, indices2, import, ols
- eqsolve, qnewton
- some more pgraph improvements
- following didn't work:
declare _penalt ?= 1;
declare _penalt ?= 0;
- 1./x now doesn't give warning anymore
- column_vector .^ row_vector is allowed
- implicit let with matrix dimensions now allowed, e.g.: m[2,2] = {1 2,3 4};
- undefined variable now treated as function unless followed
by = or [. This allows (e.g.) forward reference to graphset
or function without arguments.
- fixed bug with declaration of library variables when loading a
library inside a function.
- declare and external now allowed inside function
- created autoloading of undefined functions (as .src, .g or .oxgauss)
- ftos didn't allow leading and trailing text;
- shiftr didn't shift left properly (negative shift)
- shiftr didn't do `tabular' version
- xpnd was wrong (not equivalent to unvech)
- load/loadd/loads had fclose missing
- 0$+x didn't work of x was matrix with strings
- lnpdfn was wrong; added lnpdfnmvn
- load/loadm/loads/loadd now allow filename without extension
- some improvements in graphp: improved bar,hist,histp;
added loglog,logx,logy; all graphs now shown in new windows
- load would only accept constant matrix dimensions
- ^Filename in load/save would not work because of uppercase
- declare matrix b, c; was not allowed, only single declaration.
- format always expected width,precision arguments
- proc(0) foo(a); would print 0.000 if called as: foo(a); instead of call foo(a);
- for loop would not work with negative increments
- x[1 ] would give error message (cause by space before ])
- x = 1; x[1] = 2; would give an error message:
Runtime error: 'int' cannot index this type
- \000 in a string was not recognized
- .NE/.LE/.GE didn't work, while .ne/.le/.ge did
- filesa,files
Ox version 3.30.
©
JA Doornik
This file last changed .


Our platform is the best
Even though we know our platform is far superior to all other in all aspects we still encourage you to try these other higley aclaimed platoform to see just how incredibly superior our platform is. We have spent many years devloping a our platform to be the best in both usability and performance
When you eventually realize that our platform is by far the best, we have special offers just for you. You can collect these offers by signing upp to our mailing list on the contact page
4 reasons we are better than our competitors
- Design
- Usability
- Customer support
- Performance


Using Weechat with Glowing Bear for IRC
July 2, 2019
Last month, I had a new addition to my toolbox - Glowing Bear, which has been a really nice improvement, allowing me to access Weechat (hosted on a server) through my browser. Here’s how I set it up.
But, before we begin - the curious folks might ask, “What had you been using all this time?”
Previously, I could directly ssh using mosh - mobile
shell, which supports intermittent connectivity, which is to say that it allows
me to retain the session if the network breaks in between. into my server,
and attach to a screen
session which ran weechat, using the command:
mosh USERNAME@SERVER_IP -- screen -D -RR weechat
“This is pretty neat, why would you want to change it?
“Latency” - It was not pleasant, so much so, that I started running two instances of weechat - one locally for chatting, and the one on the server for listening to messages when AFK Away From Keyboard . It was getting pretty unmanageable, so I decided to look for alternatives. Luckily, one of my friends, Armageddon, pointed me towards Glowing Bear - which provides a nice web frontend to weechat.
Setting Up Glowing Bear
Glowing Bear has pretty decent documentation available at https://www.glowing-bear.org/#!/.
The basic architecture is somewhat similar to the pub-sub architecure - weechat ‘relays’ (publishes) all messages at a particular port on a machine where glowing bear can then ‘listen’ for the messages (subscribe).
“Can’t other people listen to my messages?”
If you’re running glowing bear with a local instance of weechat, you shouldn’t worry too much. However, if connecting to a remote instance, you must encrypt all communications between your browser and WeeChat.
Since Glowing Bear uses TLS for encryption, it means that we need to put up a signed certificate. They recommend using Let’s Encrypt for getting a certificate, which is really easy. Just install certbot and run:
certbot certonly --standalone -d DOMAIN_NAME
Once the certificates are generated, the only thing was to make them visible to weechat:
mkdir -p ~username/.weechat/ssl
cat /etc/letsencrypt/live/DOMAIN_NAME/{fullchain,privkey}.pem > ~username/.weechat/ssl/relay.pem
chown -R username:username ~username/.weechat/ssl/
Now, the only issue with me was that I did not have superuser access to the box I was running weechat into, and therefore could not access cert files. But, After talking to my wonderful host at insomnia247.nl: coolFire, I came to know that certificates I’m using for my Apache VHost should be enough to encrypt my communication (through port 443) and I need not start an encrypted relay from weechat. coolFire was also gracious enough to throw in some voodoo of course, by which I mean that I didn’t understand it and give me a custom URL for running my weechat instance.
Now, let’s start a WeeChat relay:
/set relay.network.password y0ur_StRonG-pa$sw0rd:of*choice
/relay add weechat 9001 # Note that this is NOT encrypted.
For connecting to Glowing Bear, I use port 443 - which allows me to encrypt my connection. Note that this isn’t entirely safe, because the fellow users on my host can still monitor port 9001, which is unecrypted and only protected by a password. But, I can manage this level of risk! :-)
Icing over cake
I run glowing bear on qutebrowser, through which I can access the whole interface without ever having to leave the comfort of my keyboard. \o/
Further TODO’s
Glowing Bear’s notification system is a little weird - it just stops notifying me out of the blue. Remember my friend, Armagaeddon - he actually has a weechat plugin for channeling remote notifications to local systems, but it turned out that the script will take some additional work to work with macOS.
Another thing that I want to do is employ a chat logger - I’ve had some pretty interesting conversation with people, and they just wash away as soon as I restart weechat. This should be pretty easy to do, but I’ve had too much on my plate to care right now.


{% extends "base.html" %} {% load staticfiles %} {% block extra_css %} {% endblock %} {% block title %}Getting Started Permabots{% endblock %} {% block content %}
Get straight to building bots. Avoid the complexity of each instant message service and focus on your bot app
This tutorial will have you building and deploying a chatbot that look for users and fetches some information from Github for Telegram, Kik and Facebook Messenger platforms in minutes.
The tutorial assumes that you have:
This tutorial uses the Permabots API, so you need to set API token in header, Authentication: Token api_token
. However you can fulfill all this tutorial with the web dashboard.
A Permabot has all the chatbot logic. With the same definition it works with several instant messaging platforms. Create a bot in Permabots with a given name.
POST /api/v1/bots/ HTTP/1.1
Host: www.permabots.com
Authorization: Token yourpermabotstoken
Content-Type: application/json
{
"name": "Permabots GitHub Tutorial"
}
{
"id": "799e96f2-93eb-44eb-918c-c5bd14560c54",
"name": "Permabots GitHub Tutorial",
"created_at": "2016-04-20T10:46:04.179353Z",
"updated_at": "2016-04-20T10:46:04.179384Z",
"telegram_bot": null,
"kik_bot": null
}
Follow the instructions to create a Telegram bot. Permabots only requires token
.
POST /api/v1/bots/799e96f2-93eb-44eb-918c-c5bd14560c54/telegram/ HTTP/1.1
Host: www.permabots.com
Authorization: Token yourpermabotstoken
Content-Type: application/json
{
"token": "your_telegram_bot_token",
"enabled": true
}
{
"id": "92a0e12c-9512-4aae-a4e6-2ebeb3fb3328",
"token": ""your_telegram_bot_token",
"created_at": "2016-04-20T10:49:57.295249Z",
"updated_at": "2016-04-20T10:49:57.295303Z",
"enabled": true,
"info": {
"first_name": "PermaGithub",
"last_name": null,
"username": "PermaGithubBot"
}
}
Follow the instructions to create a Kik bot. Permabots only requires username
and api key
.
POST /api/v1/bots/799e96f2-93eb-44eb-918c-c5bd14560c54/kik/ HTTP/1.1
Host: www.permabots.com
Authorization: Token yourpermabotstoken
Content-Type: application/json
{
"api_key": "your_kik_api_key",
"username": "permagithubtutorial",
"enabled": true
}
{
"id": "8e51a392-c464-4225-99e7-ff3d1189ec34",
"api_key": "your_kik_api_key",
"created_at": "2016-04-20T10:50:23.252650Z",
"updated_at": "2016-04-20T10:50:23.252683Z",
"enabled": true,
"username": "permagithubtutorial"
}
Follow the instructions to create a Facebook Messenger bot. Permabots only requires Page Access Token
. However you need to set
webhook url in your facebook account. Take id
generated in permabots an use it to generate Callback Url https://permabots.herokuapp.com/processing/messengerbot/permabots_messenger_bot_id/
and Verify Token.
POST /api/v1/bots/799e96f2-93eb-44eb-918c-c5bd14560c54/messenger/ HTTP/1.1
Host: www.permabots.com
Authorization: Token yourpermabotstoken
Content-Type: application/json
{
"token": "your_page_access_token",
"enabled": true
}
{
"id": "8e51aa92-c664-4cz25-9re7-ffy8d1189ec34",
"token": "your_page_access_token",
"created_at": "2016-04-20T10:50:28.252650Z",
"updated_at": "2016-04-20T10:50:28.252683Z",
"enabled": true,
}
In this example we should use 8e51aa92-c664-4cz25-9re7-ffy8d1189ec34
in Facebook Apps dashboard as Verify Token
and for Callback Url generation https://permabots.herokuapp.com/processing/messengerbot/8e51aa92-c664-4cz25-9re7-ffy8d1189ec34/
These bots are created already enabled
but it is useful to disable it until you have already built and consider it as ready.
When a message is received a handler is selected to attend it generating a response. A handler defines how this response is built.
POST /api/v1/bots/799e96f2-93eb-44eb-918c-c5bd14560c54/handlers/ HTTP/1.1
Host: www.permabots.com
Authorization: Token yourpermabotstoken
Content-Type: application/json
{
"name": "Wellcome",
"enabled": true,
"pattern": "/start|Hi|Hello|hi|hello",
"response": {"text_template": "Wellcome to PermaGithub Tutorial bot {{ emoji.waving_hand_sign}} \\n Which github username do you want me to look for?",
"keyboard_template": ""
}
}
{
"id": "82bb4c1b-3a4e-4f52-bed4-0f1ddf2a62c6",
"created_at": "2016-05-04T14:21:05.251207Z",
"updated_at": "2016-05-04T14:21:05.251230Z",
"name": "Wellcome",
"pattern": "/start|Hi|Hello|hi|hello",
"enabled": true,
"request": null,
"response": {
"text_template": "Wellcome to PermaGithub Tutorial bot {{ emoji.waving_hand_sign}} \\n Which github username do you want me to look for?",
"keyboard_template": ""
},
"target_state": null,
"source_states": [],
"priority": 0
}
Note: Permabots identifies with /start
when chat starts. This is Telegram original method but Permabot uses for Kik too.
A wellcome message is set as response. In this case only a text response is defined but keyboards can be part of it.
A context is used to parametrize handlers. Some context data is available just when handler starts its processing and other is attached as a result of the processing.
Our bot is requesting for Github username
in wellcome handlers. Create a handler with a Github request generated dynamically with context
POST /api/v1/bots/799e96f2-93eb-44eb-918c-c5bd14560c54/handlers/ HTTP/1.1
Host: www.permabots.com
Authorization: Token yourpermabotstoken
Content-Type: application/json
{
"name": "Username",
"enabled": true,
"pattern": "(?P<username>\\w+)",
"request": {"url_template": "https://api.github.com/users/{% verbatim %}{{pattern.username }}{% endverbatim %}",
"method": "Get"},
"response": {"text_template": "{% verbatim %}{% if response.status == 404 %}{{ pattern.username }} not found {{ emoji.black_question_mark_ornament}} Try with another one.{% else %}{% if service == 'telegram' %}{{ response.data.login }}{% else %}{{ response.data.login }} with url {{ response.data.html_url }}{% endif %}{% endif %} it has {{ response.data.public_repos }} public repos {{ emoji.public_address_loudspeaker }} and {{ response.data.followers}} followers {{ emoji.family}} \\n View repos or go back{% endverbatim %}",
"keyboard_template": "{% verbatim %}{% if response.status == 200 %}[['Repos'],['Back']]{% endif %}{% endverbatim %}"
}
}
{
"id": "1861cdd7-72aa-413e-b628-328c7087d00b",
"created_at": "2016-05-04T14:22:38.264460Z",
"updated_at": "2016-05-04T14:22:38.264492Z",
"name": "Username",
"pattern": "(?P<username>\\w+)",
"enabled": true,
"request": {
"url_template": "https://api.github.com/users/{% verbatim %}{{pattern.username }}{% endverbatim %}",
"method": "Get",
"data": null,
"url_parameters": [],
"header_parameters": []
},
"response": {
"text_template": "{% verbatim %}{% if response.status == 404 %}{{ pattern.username }} not found {{ emoji.black_question_mark_ornament}} Try with another one.{% else %}{% if service == 'telegram' %}{{ response.data.login }}{% else %}{{ response.data.login }} with url {{ response.data.html_url }}{% endif %}{% endif %} it has {{ response.data.public_repos }} public repos {{ emoji.public_address_loudspeaker }} and {{ response.data.followers}} followers {{ emoji.family}} \\n View repos or go back{% endverbatim %}",
"keyboard_template": "{% verbatim %}{% if response.status == 200 %}[['Repos'],['Back']]{% endif %}{% endverbatim %}"
},
"target_state": null,
"source_states": [],
"priority": 0
}
Emoticons are attached to context as emoji
. Use any emoticon from this table and use description in lower case and replacing spaces with _
. Notice how we use it in our example {% verbatim %}{{emoji.back_with_leftwards_arrow_above}}{% endverbatim %}}
.
Check the pattern, it has a regular expression (?P<username>\\w+)
to get the word as a variable to later use it for generating the request to Github API. Patterns use regular expressions using python syntax. Variables obtained in pattern are attached to context in pattern
variable.
Some times more than one handler pattern can match the message received. To resolve this collision you can set priority weights. Higher the value is higher is the priority
A handler can use a http request as part of its processing. Data returned by request is attached to context as response.data
. Request status code is also available in response.status
.
The response is generated with context. Jinja2 is used as template engine.
In our example, text response is generated using data returned by Github API. We also set a keyboard response to let the user get some of the Github user info. Notice the format is an array of arrays.
At this moment the bot is capable of getting Github user information but it can’t decide whether /start
message is username or the starting command. To tell bot when to execute handlers we must use states.
We can design the state machine of the example
The diagram give us some clues of what we still need to define. It is obvious we need three states ('User', 'User Detail' and 'Repo Detail') but also that we need six handlers. Notice when receiving a 404
error is not handler.
Let's create the states
POST /api/v1/bots/799e96f2-93eb-44eb-918c-c5bd14560c54/states/ HTTP/1.1
Host: www.permabots.com
Authorization: Token yourpermabotstoken
Content-Type: application/json
{
"name": "Username"
}
{
"id": "5bf426f6-3cd3-4999-ad4a-d282e107860e",
"created_at": "2016-05-04T14:22:54.272625Z",
"updated_at": "2016-05-04T14:22:54.272657Z",
"name": "Username"
}
POST /api/v1/bots/799e96f2-93eb-44eb-918c-c5bd14560c54/states/ HTTP/1.1
Host: www.permabots.com
Authorization: Token yourpermabotstoken
Content-Type: application/json
{
"name": "User Detail"
}
{
"id": "dfdab2ff-d50c-4d6f-8e47-fc4ab5399559",
"created_at": "2016-05-04T14:23:10.262180Z",
"updated_at": "2016-05-04T14:23:10.262211Z",
"name": "User Detail"
}
POST /api/v1/bots/799e96f2-93eb-44eb-918c-c5bd14560c54/states/ HTTP/1.1
Host: www.permabots.com
Authorization: Token yourpermabotstoken
Content-Type: application/json
{
"name": "Repo"
}
{
"id": "fce06ff0-889f-400c-a01a-99f90c9f48be",
"created_at": "2016-05-04T14:23:24.058554Z",
"updated_at": "2016-05-04T14:23:24.058601Z",
"name": "Repo"
}
Each handler sets a new state, target_state
, if all processing was correct but also needs a list of states, source_states
, when it can be executed.
Let's update our handlers with target_state
and source_states
.
PUT /api/v1/bots/799e96f2-93eb-44eb-918c-c5bd14560c54/handlers/82bb4c1b-3a4e-4f52-bed4-0f1ddf2a62c6/ HTTP/1.1
Host: www.permabots.com
Authorization: Token yourpermabotstoken
Content-Type: application/json
{
"target_state": {"name": "Username"}
}
{
"id": "82bb4c1b-3a4e-4f52-bed4-0f1ddf2a62c6",
"created_at": "2016-05-04T14:21:05.251207Z",
"updated_at": "2016-05-04T14:24:14.510917Z",
"name": "Wellcome",
"pattern": "/start|Hi|Hello|hi|hello",
"enabled": true,
"request": null,
"response": {
"text_template": "{% verbatim %}Wellcome to PermaGithub Tutorial bot {{ emoji.waving_hand_sign}} \\n Which github username do you want me to look for?{% endverbatim %}",
"keyboard_template": ""
},
"target_state": {
"id": "5bf426f6-3cd3-4999-ad4a-d282e107860e",
"created_at": "2016-05-04T14:22:54.272625Z",
"updated_at": "2016-05-04T14:22:54.272657Z",
"name": "Username"
},
"source_states": [],
"priority": 0
}
PUT /api/v1/bots/799e96f2-93eb-44eb-918c-c5bd14560c54/handlers/1861cdd7-72aa-413e-b628-328c7087d00b/ HTTP/1.1
Host: www.permabots.com
Authorization: Token yourpermabotstoken
Content-Type: application/json
{
"target_state": {"name": "User Detail"}
}
{
"id": "1861cdd7-72aa-413e-b628-328c7087d00b",
"created_at": "2016-05-04T14:22:38.264460Z",
"updated_at": "2016-05-04T14:24:35.748834Z",
"name": "Username",
"pattern": "(?P<username>\\w+)",
"enabled": true,
"request": {
"url_template": "https://api.github.com/users/{% verbatim %}{{pattern.username }}{% endverbatim %}",
"method": "Get",
"data": null,
"url_parameters": [],
"header_parameters": []
},
"response": {
"text_template": "{% verbatim %}{% if response.status == 404 %}{{ pattern.username }} not found {{ emoji.black_question_mark_ornament}} Try with another one.{% else %}{% if service == 'telegram' %}{{ response.data.login }}{% else %}{{ response.data.login }} with url {{ response.data.html_url }}{% endif %}{% endif %} it has {{ response.data.public_repos }} public repos {{ emoji.public_address_loudspeaker }} and {{ response.data.followers}} followers {{ emoji.family}} \\n View repos or go back{% endverbatim %}",
"keyboard_template": "{% verbatim %}{% if response.status == 200 %}[['Repos'],['Back']]{% endif %}{% endverbatim %}"
},
"target_state": {
"id": "dfdab2ff-d50c-4d6f-8e47-fc4ab5399559",
"created_at": "2016-05-04T14:23:10.262180Z",
"updated_at": "2016-05-04T14:23:10.262211Z",
"name": "User Detail"
},
"source_states": [],
"priority": 0
}
POST /api/v1/bots/799e96f2-93eb-44eb-918c-c5bd14560c54/handlers/1861cdd7-72aa-413e-b628-328c7087d00b/sourcestates/ HTTP/1.1
Host: www.permabots.com
Authorization: Token yourpermabotstoken
Content-Type: application/json
{
"name": "Username"
}
{
"id": "5bf426f6-3cd3-4999-ad4a-d282e107860e",
"created_at": "2016-05-04T14:22:54.272625Z",
"updated_at": "2016-05-04T14:22:54.272657Z",
"name": "Username"
}
When setting a state, the context used for that processing is stored associated to that state in state_context
. Then we can keep clean keyboards and still generate requests with context.
Remember the state machine diagram and set the rest of handlers. Notice how we use context associated to the state.
POST /api/v1/bots/799e96f2-93eb-44eb-918c-c5bd14560c54/handlers/ HTTP/1.1
Host: www.permabots.com
Authorization: Token yourpermabotstoken
Content-Type: application/json
{
"name": "Repos",
"enabled": true,
"pattern": "Repos",
"request": {"url_template": "{% verbatim %}https://api.github.com/users/{{state_context.username.pattern.username}}/repos", "method": "Get"}{% endverbatim %},
"response": {"text_template": "Select a repository",
"keyboard_template": "{% verbatim %}[['Back']{% for repo in response.data %}{% if loop.first %},{% endif %}['{{repo.name}}']{% if not loop.last %},{% endif %}{% endfor%}]{% endverbatim %}"
},
"target_state": {"name": "Repo"}
}
{
"id": "dbb5d6f1-1a51-4db0-a9f3-b639a4064a94",
"created_at": "2016-05-04T14:25:11.670401Z",
"updated_at": "2016-05-04T14:25:11.670424Z",
"name": "Repos",
"pattern": "Repos",
"enabled": true,
"request": {
"url_template": "{% verbatim %}https://api.github.com/users/{{state_context.username.pattern.username}}/repos{% endverbatim %}",
"method": "Get",
"data": null,
"url_parameters": [],
"header_parameters": []
},
"response": {
"text_template": "Select a repository",
"keyboard_template": "{% verbatim %}[['Back']{% for repo in response.data %}{% if loop.first %},{% endif %}['{{repo.name}}']{% if not loop.last %},{% endif %}{% endfor%}]{% endverbatim %}"
},
"target_state": {
"id": "fce06ff0-889f-400c-a01a-99f90c9f48be",
"created_at": "2016-05-04T14:23:24.058554Z",
"updated_at": "2016-05-04T14:23:24.058601Z",
"name": "Repo"
},
"source_states": [],
"priority": 0
}
POST /api/v1/bots/799e96f2-93eb-44eb-918c-c5bd14560c54/handlers/dbb5d6f1-1a51-4db0-a9f3-b639a4064a94/sourcestates/ HTTP/1.1
Host: www.permabots.com
Authorization: Token yourpermabotstoken
Content-Type: application/json
{
"name": "User Detail"
}
{
"id": "dfdab2ff-d50c-4d6f-8e47-fc4ab5399559",
"created_at": "2016-05-04T14:23:10.262180Z",
"updated_at": "2016-05-04T14:23:10.262211Z",
"name": "User Detail"
}
POST /api/v1/bots/799e96f2-93eb-44eb-918c-c5bd14560c54/handlers/ HTTP/1.1
Host: www.permabots.com
Authorization: Token yourpermabotstoken
Content-Type: application/json
{
"name": "Back from User Detail",
"enabled": true,
"pattern": "Back",
"response": {"text_template": "Type github username do you want me to search?",
"keyboard_template": ""
},
"target_state" : {"name": "Username"}
}
{
"id": "f9458cb7-db8a-4280-a951-d12c107ca707",
"created_at": "2016-05-04T14:26:06.774088Z",
"updated_at": "2016-05-04T14:26:06.774120Z",
"name": "Back from User Detail",
"pattern": "Back",
"enabled": true,
"request": null,
"response": {
"text_template": "Type github username do you want me to search?",
"keyboard_template": ""
},
"target_state": {
"id": "5bf426f6-3cd3-4999-ad4a-d282e107860e",
"created_at": "2016-05-04T14:22:54.272625Z",
"updated_at": "2016-05-04T14:22:54.272657Z",
"name": "Username"
},
"source_states": [],
"priority": 0
}
POST /api/v1/bots/799e96f2-93eb-44eb-918c-c5bd14560c54/handlers/f9458cb7-db8a-4280-a951-d12c107ca707/sourcestates/ HTTP/1.1
Host: www.permabots.com
Authorization: Token yourpermabotstoken
Content-Type: application/json
{
"name": "User Detail"
}
{
"id": "dfdab2ff-d50c-4d6f-8e47-fc4ab5399559",
"created_at": "2016-05-04T14:23:10.262180Z",
"updated_at": "2016-05-04T14:23:10.262211Z",
"name": "User Detail"
}
POST /api/v1/bots/799e96f2-93eb-44eb-918c-c5bd14560c54/handlers/ HTTP/1.1
Host: www.permabots.com
Authorization: Token yourpermabotstoken
Content-Type: application/json
{
"name": "Repo Detail",
"enabled": true,
"pattern": "(?P<repo>.+)",
"request": {"url_template": "{% verbatim %}https://api.github.com/repos/{{state_context.username.pattern.username}}/{{ pattern.repo }}{% endverbatim %}",
"method": "Get"},
"response": {"text_template": "{% verbatim %}{% if response.status == 404 %} Repository {{ pattern.repo }} from {{ pattern.username}} not found {{ emoji.cross_mark}}\\n Select one from menu{% else %} {% if service == 'telegram' %} {{ response.data.name }}: {{ response.data.description}}{% else %} {{ response.data.name}} with url {{response.data.html_url }}: {{ response.data.description }}{% endif %}\\n Select repo or go back{% endif %}{% endverbatim %}",
"keyboard_template": "{% verbatim %}[['Back']{% for repo in state_context.user_detail.response.data %}{% if loop.first %},{% endif %}['{{repo.name}}']{% if not loop.last %},{% endif %}{% endfor%}]{% endverbatim %}"
}
}
{
"id": "fa00fc42-48f2-4668-a9b5-e37aceda26e1",
"created_at": "2016-05-04T14:27:29.766527Z",
"updated_at": "2016-05-04T14:27:29.766570Z",
"name": "Repo Detail",
"pattern": "(?P.+)",
"enabled": true,
"request": {
"url_template": "{% verbatim %}https://api.github.com/repos/{{state_context.username.pattern.username}}/{{ pattern.repo }}{% endverbatim %}",
"method": "Get",
"data": null,
"url_parameters": [],
"header_parameters": []
},
"response": {
"text_template": "{% verbatim %}{% if response.status == 404 %} Repository {{ pattern.repo }} from {{ pattern.username}} not found {{ emoji.cross_mark}}\\n Select one from menu{% else %} {% if service == 'telegram' %} {{ response.data.name }}: {{ response.data.description}}{% else %} {{ response.data.name}} with url {{response.data.html_url }}: {{ response.data.description }}{% endif %}\\n Select repo or go back{% endif %}{% endverbatim %}",
"keyboard_template": "{% verbatim %}[['Back']{% for repo in state_context.user_detail.response.data %}{% if loop.first %},{% endif %}['{{repo.name}}']{% if not loop.last %},{% endif %}{% endfor%}]{% endverbatim %}"
},
"target_state": null,
"source_states": [],
"priority": 0
}
POST /api/v1/bots/799e96f2-93eb-44eb-918c-c5bd14560c54/handlers/fa00fc42-48f2-4668-a9b5-e37aceda26e1/sourcestates/ HTTP/1.1
Host: www.permabots.com
Authorization: Token yourpermabotstoken
Content-Type: application/json
{
"name": "Repo"
}
}
{
"id": "fce06ff0-889f-400c-a01a-99f90c9f48be",
"created_at": "2016-05-04T14:23:24.058554Z",
"updated_at": "2016-05-04T14:23:24.058601Z",
"name": "Repo"
}
POST /api/v1/bots/799e96f2-93eb-44eb-918c-c5bd14560c54/handlers/ HTTP/1.1
Host: www.permabots.com
Authorization: Token yourpermabotstoken
Content-Type: application/json
{
"name": "Back from Repo Detail",
"enabled": true,
"pattern": "Back",
"request": {"url_template": "{% verbatim %}https://api.github.com/users/{{ state_context.username.pattern.username}}{% endverbatim %}",
"method": "Get"},
"response": {"text_template": "{% verbatim %}{% if service == 'telegram' %}{{ response.data.login }}{% else %}{{ response.data.login }} with url {{ response.data.html_url}}{% endif %} it has {{ response.data.public_repos }} public repos and {{ response.data.followers}} followers\\n View repos or go back{% endverbatim %}",
"keyboard_template": "{% verbatim %}{% if response.status == 200 %}[['Repos'],['Back']]{% endif %}{% endverbatim %}"
},
"target_state": {"name": "User Detail"},
"priority": 1,
}
{
"id": "72264903-0748-45fd-b9a4-78a2e1185f22",
"created_at": "2016-05-04T14:28:18.617941Z",
"updated_at": "2016-05-04T14:28:18.617965Z",
"name": "Back from Repo Detail",
"pattern": "Back",
"enabled": true,
"request": {
"url_template": "{% verbatim %}https://api.github.com/users/{{ state_context.username.pattern.username}}{% endverbatim %}",
"method": "Get",
"data": null,
"url_parameters": [],
"header_parameters": []
},
"response": {
"text_template": "{% verbatim %}{% if service == 'telegram' %}{{ response.data.login }}{% else %}{{ response.data.login }} with url {{ response.data.html_url}}{% endif %} it has {{ response.data.public_repos }} public repos and {{ response.data.followers}} followers\\n View repos or go back{% endverbatim %}",
"keyboard_template": "{% verbatim %}{% if response.status == 200 %}[['Repos'],['Back']]{% endif %}{% endverbatim %}"
},
"target_state": {
"id": "dfdab2ff-d50c-4d6f-8e47-fc4ab5399559",
"created_at": "2016-05-04T14:23:10.262180Z",
"updated_at": "2016-05-04T14:23:10.262211Z",
"name": "User Detail"
},
"source_states": [],
"priority": 1
}
POST /api/v1/bots/799e96f2-93eb-44eb-918c-c5bd14560c54/handlers/72264903-0748-45fd-b9a4-78a2e1185f22/sourcestates/ HTTP/1.1
Host: www.permabots.com
Authorization: Token yourpermabotstoken
Content-Type: application/json
{
"name": "Repo"
}
{
"id": "fce06ff0-889f-400c-a01a-99f90c9f48be",
"created_at": "2016-05-04T14:23:24.058554Z",
"updated_at": "2016-05-04T14:23:24.058601Z",
"name": "Repo"
}
Notice how we set priority to this handler ir order to avoid collisions. Otherwise it will take "Back" as parameter to look for repository details.
Permabots allow you to declare key value variables shared in all bot.
We need to generate client_key
and client_secret_key
from Github. Not to get banned quickly.
POST /api/v1/bots/799e96f2-93eb-44eb-918c-c5bd14560c54/env/ HTTP/1.1
Host: www.permabots.com
Authorization: Token yourpermabotstoken
Content-Type: application/json
{
"key": "client_id",
"value": "yourgithubclientid"
}
{
"id": "e2c2a556-a493-4594-9e4a-f7966a8945c6",
"created_at": "2016-05-04T14:29:40.825853Z",
"updated_at": "2016-05-04T14:29:40.825902Z",
"key": "client_id",
"value": "yourgithubclientid"
}
POST /api/v1/bots/799e96f2-93eb-44eb-918c-c5bd14560c54/env/ HTTP/1.1
Host: www.permabots.com
Authorization: Token yourpermabotstoken
Content-Type: application/json
{
"key": "client_secret",
"value": "yourgithubclientsecret"
}
{
"id": "0f65b649-c95f-41a7-b600-9f06c713132e",
"created_at": "2016-05-04T14:29:40.825853Z",
"updated_at": "2016-05-04T14:29:40.825902Z",
"key": "client_secret",
"value": "yourgithubclientsecret"
}
Environment variables are attached in context and used to render templates {% verbatim %}{{env.client_id }}{% endverbatim %}.
Handler requests can have some parameters in the url and in the header. In our bot we should attach some url parameters to the Github request to avoid getting banned quickly. Don't hard code these values, use env
.
 Visit API docs to learn more about Permabots.
Some more upcoming docs will explain how to use Hooks
. A mechanism to send messages to clients as notifications when your API requires.
You can try this bot with your Telegram client or search permagithubtutorial
with your Kik client.


This is part of the series The CDPH Way—Becoming the best at getting better.
For background, here is an overview slide set and lean reporting templates.
In 1998, Melanie Tervalon and Jann Murray-García published a groundbreaking article that challenged the concept of “cultural competency” with the concept of “cultural humility” [1,2].
Cultural humility is committing to lifelong learning, critical self-reflection, and personal and institutional transformation. Accepting cultural humility means accepting that we can never be fully culturally competent. Cultural humility is the foundation for establishing trust and respectful relationships, and for managing differences and conflict. Cultural humility means
- committing to lifelong learning and critical self-reflection;
- realizing our power, privilege, and prejudices (biases) (includes conscious and non-conscious [implicit] biases);
- redressing power imbalances for respectful partnerships; and
- promoting institutional accountability.
Power is the capacity or ability to direct or influence the behavior of others, the course of events, or the allocation of resources. Power comes from positional, moral, or relational authority. Authority is granted by appointment or earned by trust and credibility. It is exercised by embodying universal values (humility, compassion, equity, dignity), or by persuasion, manipulation, or deceit. The dynamics and impacts of power are multi-dimensional, context dependent, cumulative, and can be subtle. For example, the mere presence of a boss can unintentionally shut down subordinates.
Privilege is a form of unearned power that comes from social advantage. All of us have some form of privilege. Privilege exists because of sociopolitical systems and cultural norms that create, reinforce, and amplify power inequities, explicitly or implicitly. For example, in the US, if you are like me: male, heterosexual, cisgender, or have lighter skin color, you have more privilege. You do not choose privilege, but you can acknowledge it, and, more importantly, you can make “the noble choice to forgo your status, [and to] use your influence for the good of others before yourself” — this is humility.
For our purposes, biases are preferences, cognitive processes, or inferences that shape our mental models, knowledge, attitudes, beliefs, and behaviors in ways that cause or contribute to inequities in power, privilege, opportunities, or outcomes for ourselves and/or others. Biases can be known to you and others (open), known to you and not others (hidden), known to others but not you (blind spot), or not known to you and others (unknown).1
Implicit biases account for the unknown and blind spot biases, and are the most challenging type of bias because we all have them, and they are difficult to identify, measure, and mitigate. For example, ambiguous hiring criteria are susceptible to implicit biases. Without unambiguous, objective criteria, hiring someone you “trust” is driven, unintentionally, by implicit biases.2
Learn more about cultural humility from the following outstanding videos.
Cultural Humility video (edited to 6 min)
Cultural Humility video (complete 30 min)
References
Footnotes
To learn more study “JoHari Window in Interpersonal Communication”: Video lecture by Dr. Lori Zakel, Professor and Chair of the Communication Department at Sinclair College, Dayton, Ohio. Available at https://youtu.be/-7FhcvoVK8s.↩
To learn more study “JoHari Window in Interpersonal Communication”: Video lecture by Dr. Lori Zakel, Professor and Chair of the Communication Department at Sinclair College, Dayton, Ohio. Available at https://youtu.be/-7FhcvoVK8s.↩


Talented Cambuslang figure skater represents Team GB at junior level
She performed at the Tirnavia Ice Cup in Slovakia last week.
by Jonathan Geddes, https://www.dailyrecord.co.uk/authors/jonathan-geddes/A talented Cambuslang figure skater has taken the next step in her budding career after representing her country at junior level.
Taylor McLeod, 15, was one of the British athletes competing in the Tirnavia Ice Cup in Slovakia at the weekend.
The Stonelaw High pupil, a member of East Kilbride Ice Figure Skating Club, finished eighth overall in the contest, where she was competing against teenagers up to four years older than her.
And her proud dad Simon was thrilled at her achievements.
He told the Reformer: “This was a big step up for Taylor and this is the level she will now be competing at until she is 19.
“She surpassed everything that we were expecting with how she performed – we had been thinking that it would just be to learn and anything else would be a bonus, but she skated really well, in both her categories.”
Taylor’s contest was made up of two disciplines and saw the teenager first take part in the short programme before then tackling the free skating event the following day.
Her combined score of 91.58 saw her take eighth place and represented a great learning experience for Taylor.
Simon said: “She knows where she has to improve, and I think she has come back with more confidence.
“Just seeing the other skaters and what they were doing, and all the hard work they had to put in, it shows her where she has to develop for the future.”
The Tirnavia Ice Cup was streamed live online, and after being shared on local Cambuslang Facebook pages, a host of good luck messages for the community flooded in.
That made a big difference to Taylor before she took to the ice.
Simon added: “The response we were getting online was phenomenal, there were so many nice messages.
“I think it gave her a boost to see all these people wishing her well. She’s used to getting good luck messages from people she knows through figure skating, but this was obviously a bit wider than that and there was something really nice about seeing the local community all showing their support.
“Taylor’s quite shy, and I don’t think really understands just how good she actually is at skating, so everything cheering her on took her back a bit.”
Taylor’s appearance came almost four years to the day since she first represented Team GB, which also took place in Slovakia.


Münchner are a friendly bunch. Don't be shy.
Come join some of our regulars, including these fine folks for dinner, beers and friendly chats.
Sorry, there was a problem loading data from Twitter. Please try again later.