Contents Validating a Model Model Checking a Model TLC Model Checker Preferences If Something Crashes How TLC is Run The TLC Console View
You run the TLC model checker by clicking on the button. This button appears at the top of each model editor page. You can also run it from the TLC Model Checker menu or by pressing the F11 key. Before running TLC on the model, the Toolbox first validates the model, checking it for errors. Clicking on the button causes the Toobox to validate the model without running TLC on it.
The Toolbox does some validation of the model as you edit it. If that validation finds no errors, clicking on validate ( ) or run ( ) checks for other errors. The Toolbox reports any errors in the model that it finds by placing error balloons like this near the part of the model containing the error. Moving the mouse cursor on top of an error balloon will raise a message explaining the error. The Toolbox also puts an Errors Detected field at the top of the page. Moving the mouse cursor on top of it raises all the error messages for the page.
The Toolbox might report some model errors as being parsing errors in a
module named MC
. See the section
How TLC is Run below to find out how to interpret
such an error message.
Clicking on run will cause the Toolbox to validate the model and, if it finds no errors, to run TLC on the model. The Toolbox shows the following dialog while TLC is running:
You can view the progress of the run on the model editor's Model Checking Results Page. That page is automatically displayed when TLC starts running.
Note: If you check Always run in background on the dialog shown above,
that dialog will stop popping up when you run TLC.
To get it back, go to File/Preferences/General
and uncheck the
Always run in background preference.
You can stop TLC by clicking on the Cancel button of this dialog, or else on the button that is at the top of each model-editor page, next to the run and validate buttons.
If TLC finds an error, it stops and the Toolbox raises the TLC Errors View. (If you close the view, you can reopen it from the TLC Model Checker menu.) This view consists of the following two sections. (The relative sizes of those two sections can be changed by moving the cursor between them until it changes to an up-and-down arrow, and then clicking and dragging.)
MC
, see the section How TLC is
Run below.
On some systems, you might find that the Error View text is displayed in an unreadably small font. See the Preferences help page to find out how to change it.
This section contains three subsections: the Error-Trace Explorer, the Error-Trace viewer, and an expression view box. The error-trace explorer can be opened or closed with the + and - symbols. The relative sizes of these subsections can also be changed by dragging the boundary between them. You can drag the entire TLC Errors view out of the Toolbox window and make it a separate window, which you can enlarge if you want to see more of the error trace at once.
The Error-Trace Explorer allows the user to add expressions which will be evaluated at each state, and whose result will be included in the output seen in the Error-Trace viewer in bold text. Expressions can be:
The error-trace explorer allows you to view the values of expressions in each step of the trace. You just enter one or more expressions, which can contain primed as well as unprimed variables, and click on Explore. The values of the expressions will then be shown in the error trace. Clicking on Restore restores the original error trace. An error-trace expression may be given the name "id" by preceding it with "id ==". This defines id to equal that expression in subsequent error-trace explorer expressions.
The error-trace explorer allows you to form expressions from two built-in operators:
The operators _TETrace
and _TEPosition
in an error-trace expression are defined
as follows. When the expression is evaluated, _TETrace
equals the sequence of records such that
for every spec variable v
, the value of _TETrace[N].v
equals the value of v in
state number N
of the trace. When the expression is evaluated in state number N
,
the operator _TEPosition
equals N
.
The error-trace explorer works by running TLC on a file called TE.tla
If there is an error in an expression that you entered in the error-trace
explorer, then the Toolbox may report an error in that file. The file is in the
same folder as the file MC.tla
described
above. You may want to examine file TE.tla
if you can't figure out what the error in the expression is.
The Error-Trace viewer shows a structured view of the error trace produced by TLC. The view box shows the TLA+ version of the expression selected in the error trace. (It is ordinary text that can be copied and pasted elsewhere.)
The error trace consists of a sequence of states, where a state is a TLA+ expression
that describes the values of the variables. The trace viewer provides a tree-structured
view of the state, allowing you to examine the value of each variable and of each
subexpression of that value. (Left-click on the +
and - symbols to expand and hide subexpressions.)
This is helpful in viewing complex values.
Double clicking on a state line location will open up the spec window editor and highlight
that section of the spec; similar to in the Error View, holding down the CTRL, or ⌘ on macOS, key
while doing this will jump to the PlusCal original code if it exists.
Pressing the button with two horizontal arrows next to the
'Expand/Collapse All' button will "link" and "unlink" the trace viewer with the spec
editor; when linked, a single click on a location, or using the keyboard's arrow keys,
will change highlighted position like a double-click.
By default, the error trace is displayed starting with the initial state. You can reverse the order, so the initial state appears last, by clicking on either of the two column headings in the error trace display. Clicking again restores the normal order.
The trace viewer uses colors to indicate changes in the values of variables and in the values of their subexpressions from one state to the next. The color code is:
The error trace can be filtered to omit variables and expressions from the displayed states,
as well as hiding variables which have not had their values changed. By clicking on the filter button
found to the left of the expand-hide all button, the user is presented with a a dialog allowing them
to select from the set of variables and expressions found in the trace; alternatively, the user may
ALT-click on a variable or expression in the Error-Trace tree view which will then omit that
variable or expression.
On this dialog, the user may also select the visibility of the variables:
The background colors of the variables in this view change for the following cases:
The top line of a state's display in the error trace gives the location of the sub-action of the next-state
relation that generated the state (except for the first state, which is generated by the
initial predicate).
Double-clicking on that line takes you to the indicated location.
Right-clicking on that line displays a context menu which allows the user to run model checking commencing
from that described state.
The Toolbox's Preferences Menu allows you to select the following:
Controls whether or not the TLC Errors View is automatically popped up when running TLC produces an error. You will almost certainly want to use the default, which is to pop up the view.
A model is an object that is edited with a model editor. When the model is modified,
an asterisk appears in the model editor's tab, and the model can be saved by
typing Ctl+S
. This option allows you to choose whether or not
the Toolbox should validate the model when it is saved.
The model is automatically saved when you run or validate it, so you will
probably have no reason to save it explicitly.
Re-running a model erases the corresponding model checking results if any. With snapshots activate, the Toolbox maintains a history of the N most recent model runs. The value N is defined by Number of model snapshots to keep where zero disables snapshots completely. The history allows one to trace back the evolution of the specification and corresponding model.
Snapshots can also be deleted in the Spec Explorer as needed.
This is the value to which the Maximum JVM heap size parameter of a new model is set. See the description of that parameter in the How to run? section of the model editor's Overview Page help page.
The maximum number of states of a trace that is displayed in the Trace Explorer when TLC reports an error. If the trace has more states, only the last ones are shown. Double-clicking at the beginning of the trace displays additional states. The default value is 10000.
If you stop the Toolbox in some abnormal way while it is running TLC--for example, by using an operating system tool to kill its process--you may leave TLC running as a disembodied process. In that case, you should kill the TLC process. Otherwise, strange things will happen if you restart the Toolbox and try to run TLC from it on the model.
The Toolbox runs TLC on a module named MC
that it constructs
from the model. It writes the module file MC.tla
and
the TLC configuration file MC.cfg
when validating
the model (when you click on either run or validate).
If the spec is named SpecName
and the model is named ModName
, then these two
files are written in the subfolder SpecName.toolbox/ModName
.
At the same time that it writes those files, the Toolbox also writes into the same
folder a copy of each of the spec's module files.
These allow you to see the version
of the spec on which TLC was run, even after you have modified the spec.
You can view that version of the spec by selecting (any page of) the model,
clicking on the TLC Model Checker
menu at the top of the Toolbox window,
and then clicking on Open Saved Module
.
It is a sad fact of life that most computer programs, including the Toolbox, have bugs. A Toolbox bug may cause TLC to stop running without either indicating that it succeeded or reporting an error. (You know that the TLC run succeeded if the General section of the Model Checking Results Page says that TLC is not running and the top entry of its Statistics section's State space progress table shows a queue size of 0.) If that page's Progress Output section doesn't explain what happened, the place to look next is the Toolbox's TLC Console View. You can open that view from the Toolbox's TLC Model Checker menu.
The TLC Console View contains all the output that TLC has produced when running this model. (You can clear the console with the view's botton.) However, each TLC output message appears between pairs of lines such as:
@!@!@STARTMSG 2200:0 @!@!@ @!@!@ENDMSG 2200 @!@!@
Toolbox bugs that would cause you to look at the TLC Console View are quite rare. You can help make that even rarer by reporting problems.


Biography
My name is Cristian Habib, but everyone calls me Bade, including my family. I was born in Alamogordo, New Mexico in 1993. At age 5, I moved to Colorado. At 19, I joined the Navy. My job was system administration and later penetration testing. I moved to Seattle after getting out of the Navy in 2018. I then went to South Seattle College and Seattle Central College. I recently got my Associate's degree with a focus in Psychology. My current goals are to finish up to 401 at Code Fellows, get a job in the tech industry as a software developer, and finish a personal RPG project.
Work Experience & Education
- United States Navy
- South Seattle College
- Seattle Central College
Bade's Top Ten Videogames
- Torment: Numenera
- Legend Of Zelda: Breath Of The Wild
- Armello
- Mass Effect 2
- Baldur's Gate
- Neverwinter Nights
- One Shot
- League Of Legends
- City Of Heroes
- Undertale


| File | Statements | Branches | Functions | Lines | |||||
|---|---|---|---|---|---|---|---|---|---|
| src/ | 86.62% | 123/142 | 77.5% | 31/40 | 85.19% | 23/27 | 83% | 83/100 | |
| src/components/article/ | 58.69% | 152/259 | 40.57% | 43/106 | 35% | 28/80 | 52.83% | 112/212 | |
| src/components/auth/ | 66.67% | 126/189 | 64.91% | 37/57 | 50.88% | 29/57 | 62.09% | 95/153 | |
| src/components/main/ | 72.97% | 189/259 | 72.41% | 84/116 | 42.25% | 30/71 | 61.88% | 99/160 | |
| src/components/profile/ | 47.58% | 128/269 | 33.9% | 40/118 | 26.32% | 20/76 | 39.56% | 89/225 |


The debug console. Only exists when the game is built in Debug Mode. The game will handle using this class. Can be summoned by default with the ~ key.
More...
|
| void | Summon () |
| | Summons the Debugger. More...
|
| |
| void | ShowPerformance (int level) |
| | Display performance information at a specified detail level. Set to 0 to disable. 5 is the most detailed. More...
|
| |
| void | LogTag (string tag) |
| | Toggle the logging of a specific tag. If the tag is off, it will be turned on, and vice versa. More...
|
| |
| void | EnableCommandGroup (string group) |
| | Enables commands in a specific group to be used. More...
|
| |
| void | DisableCommandGroup (string group) |
| | Disables commands in a specific group. More...
|
| |
| void | Log (string tag, object str, bool timestamp=true) |
| | Writes log data to the console. More...
|
| |
| void | Log (object str, bool timestamp=true) |
| | Writes log data to the console. More...
|
| |
| void | Error (string message) |
| | Send an error message to the debugger. Only really makes sense when the debugger is currently open, so probably want to call this from an OtterCommand method when something goes wrong. More...
|
| |
| void | Watch (string str, object obj) |
| | Add a variable to the watch list of the debug console. This must be called on every update to see the latest value! More...
|
| |
| void | RegisterCommands () |
| | Refreshes the available commands by finding any methods tagged with the OtterCommand attribute. Don't do this a lot. More...
|
| |
|
| bool | IsOpen [get, set] |
| | If the debug console is currently open. More...
|
| |
| bool | Visible [get, set] |
| | If the debug console is currently visible. More...
|
| |
| float | DebugCameraX [get, set] |
| | The offset of the camera X set by debug camera mode. More...
|
| |
| float | DebugCameraY [get, set] |
| | The offset of the camera Y set by debug camera mode. More...
|
| |
| int | LiveConsoleSize [get, set] |
| | The size of the live console in lines. If 0 the live console is hidden. More...
|
| |
The debug console. Only exists when the game is built in Debug Mode. The game will handle using this class. Can be summoned by default with the ~ key.
| void Otter.Debugger.DisableCommandGroup |
( |
string |
group | ) |
|
Disables commands in a specific group.
- Parameters
-
| void Otter.Debugger.EnableCommandGroup |
( |
string |
group | ) |
|
Enables commands in a specific group to be used.
- Parameters
-
| void Otter.Debugger.Error |
( |
string |
message | ) |
|
Send an error message to the debugger. Only really makes sense when the debugger is currently open, so probably want to call this from an OtterCommand method when something goes wrong.
- Parameters
-
| message | The message to show. |
| void Otter.Debugger.Log |
( |
string |
tag, |
|
|
object |
str, |
|
|
bool |
timestamp = true |
|
) |
| |
Writes log data to the console.
- Parameters
-
| tag | The tag to associate the log with. |
| str | The string to add to the console. |
| timestamp | Include a timestamp with the item. |
| void Otter.Debugger.Log |
( |
object |
str, |
|
|
bool |
timestamp = true |
|
) |
| |
Writes log data to the console.
- Parameters
-
| str | The string to add to the console. |
| timestamp | Include a timestamp with the item. |
| void Otter.Debugger.LogTag |
( |
string |
tag | ) |
|
Toggle the logging of a specific tag. If the tag is off, it will be turned on, and vice versa.
- Parameters
-
| void Otter.Debugger.RegisterCommands |
( |
| ) |
|
Refreshes the available commands by finding any methods tagged with the OtterCommand attribute. Don't do this a lot.
| void Otter.Debugger.ShowPerformance |
( |
int |
level | ) |
|
Display performance information at a specified detail level. Set to 0 to disable. 5 is the most detailed.
- Parameters
-
| level | The level of detail. 0 for disabled, 5 for the most detailed. |
| void Otter.Debugger.Summon |
( |
| ) |
|
| void Otter.Debugger.Watch |
( |
string |
str, |
|
|
object |
obj |
|
) |
| |
Add a variable to the watch list of the debug console. This must be called on every update to see the latest value!
- Parameters
-
| str | The label for the value. |
| obj | The value. |
Reference to the active instance of the debugger.
| Key Otter.Debugger.ToggleKey = Key.Tilde |
The key used to summon and dismiss the debug console.
| float Otter.Debugger.DebugCameraX |
|
getset |
The offset of the camera X set by debug camera mode.
| float Otter.Debugger.DebugCameraY |
|
getset |
The offset of the camera Y set by debug camera mode.
| bool Otter.Debugger.IsOpen |
|
getset |
If the debug console is currently open.
| int Otter.Debugger.LiveConsoleSize |
|
getset |
The size of the live console in lines. If 0 the live console is hidden.
| bool Otter.Debugger.Visible |
|
getset |
If the debug console is currently visible.
The documentation for this class was generated from the following file:
- Otter/Utility/Debugger.cs


When reviewing systems papers (and sometimes even when reading published papers) I frequently come across highly misleading use of benchmarks. I'm not saying that the authors intend to mislead the reader, it's just as likely incompetence. But that isn't an excuse.
I call such cases benchmarking crimes. Not because you can go to jail for them (but probably should?) but because they undermine the integrity of the scientific process. Rest assured, if I'm a reviewer of your paper, and you commit one of those, you're already most of the way into rejection territory. The rest of the work must be pretty damn good to be forgiven a benchmarking crime (and even then you'll be asked to fix it up in the final version).
The following list is work in progress, I'll keep adding to it as I come across (or remember) more systems benchmarking crimes...
This is the mother of all benchmarking crimes: using a biased set of benchmarks to (seemingly) prove a point, which might be contradicted by a broader coverage of the evaluation space. It's a clear indication of at best gross incompetence or at worst an active attempt to deceive.
There are several variants of this crime, I list the most prominent ones. Obviously, not all instances of this are equally bad, in some cases it may just be a matter of degree of thoroughness, but in its most blatant form, this is a truly hideous crime.
A fair evaluation of a technique/design/implementation that is supposed to improve performance must actually demonstrate two things:
Both are important! You cannot easily argue that you've gained something if you improve performance at one end and degrade it at another.
Reality is that techniques that improve performance generally require some degree of extra work: extra bookkeeping, caching, etc. These things always have a cost, and it is dishonest to pretend otherwise. This is really at the heart of systems: it's all about picking the right trade-offs. A new technique will therefore almost always introduce some overheads, and you need to demonstrate that they are acceptable.
If you innovation does lead to a degree of degradation, then you need to analyse it, and build a case that it is acceptable given the other benefits. If, however, you only evaluate the scenarios where your approach is beneficial, you are being deceptive. No ifs, no buts.
I see this variant (which can actually be an instance of the previous one) frequently with SPEC benchmarks. These suites have been designed as suites for a reason: to be representative of a wide range of workloads, and to stress various aspects of a system.
However, it is also true that it is often not possible to run all of SPEC on an experimental system. Some SPEC programs require large memories (they are designed to stress the memory subsystem!) and it may be simply impossible to run them on a particular platform, particularly an embedded system. Others are FORTRAN programs, and a compiler may not be available.
Under such circumstances, it is unavoidable to pick a subset of the suite. However, it must then be clearly understood that the results are of limited value. In particular, it is totally unacceptable to quote an overall figure of merit (such as average speedup) for SPEC if a subset is used!
If a subset is used, it must be well justified. There must be convincing explanation for each missing program. And the discussion must be careful not to read too much into the results, keeping in mind that it is conceivable that any trend observed by the subset used could be reverted by programs not in the subset.
Where the above rules are violated, the reader is bound to suspect that the authors are trying to hide something. I am particularly allergic to formulations like “we picked a representative subset” or “typical results are shown”. There is no such thing as a “representative” subset of SPEC, and the ”typical” results are most likely cherry-picked to look most favourable. Expect no mercy for such a crime!
Lmbench is a bit of a special case. Its license actually forbids reporting partial results, but a complete lmbench run produces so many results that it is impossible to report in a conference paper. On the other hand, as this is a collection of micro-benchmarks which are probing various aspects of the OS, one generally understands what each measures, and may only be interested in a subset for good reasons. In that case, running the particular lmbench test has the advantage of measuring a particular system aspect in a well-defined, standardised way. This is probably OK, as long as not too much is being read into the results (and Larry McVoy doesn't sue you for license violation...)
A variant of this crime is arbitrarily picking benchmarks from a huge set. For example, when describing an approach to debug or optimise Linux drivers, there are obviously thousands of candidates. It may be infeasible to use them all, and you have to pick a subset. However, I want to understand why you picked the particular subset. Note that arbitrary is not the same as random, so a random pick would be fine. However, if your selection contains many obscure or outdated devices, or is heavily biased towards serial and LED drivers, then I suspect that you have something to hide.
This variant can again be viewed as an example of the first. Here the range of the input parameter is picked to make the system look good, but the range is not representative of a real workload. For example, the diagram on the right shows pretty good scalability of throughput as a function of load, and without any further details this looks like a nice result.
Things look a bit different when we put the graph into context. Say this is showing the throughput (number of transactions per second) of a database system with a varying number of clients. So far so good.
Is it still so good if I'm telling you that this was measured on a 32-core machine? What we see then is that the throughput scales almost linearly as long as there is at most one client per core. Now that is not exactly a typical load for a database. A single transaction is normally insufficient for keeping a core busy. In order to get the best of your hardware, you'll want to run the database so that there are in average multiple clients per core.
So, the interesting data range starts where the graph ends! What happens if we increase the load into the really interesting range is shown in the graph on the left. Clearly, things no longer look so rosy, in fact, scalability is appalling!
Note that, while somewhat abstracted and simplified, this is not a made-up example, it is taken from a real system, and the first diagram is equivalent to what was in a real publication. And the second diagram is essentially what was measured independently on the same system. Based on a true story, as they say...
Micro-benchmarks specifically probe a particular aspect of a system. Even if they are very comprehensive, they will not be representative of overall system performance. Macro-benchmarks (representing real-world workloads) must be used to provide a realistic picture of overall performance.
In rare cases, there is a particular operation which is generally accepted to be critical, and where significant improvements are reasonably taken as an indication of real progress. An example is microkernel IPC, which was long known to be a bottleneck, and reducing cost by an order of magnitude can therefore be an important result. And for a new microkernel, showing that it matches the best published IPC performance can indicate that it is competitive.
Such exceptions are rare, and in most cases it is unacceptable to make arguments on system performance based only on micro-benchmarks.
This vicious crime is committed by probably 10% of papers I get to review. If the throughput of a system is degraded by a certain percentage, it does not at all follow that the same percentage represents the overhead that was added. Quite to the contrary, in many cases the overhead is much higher. Why?
Assume you have a network stack which under certain circumstances achieves a certain throughput, and a modified network stack achieves 10% less throughput. What's the overhead introduced by the modification?
Without further information, it is impossible to answer that question. Why is throughput degraded? In order to answer that question, we need to understand what determines throughput in the first place. Assuming that there's more than enough incoming data to process, the amount of data the stack can handle depends mostly on two factors: processing (CPU) cost and latency.
Changes to the implementation (not protocols!) will affect processing cost as well as latency, but their effect on throughput is quite different. As long as CPU cycles are available, processing cost should have negligible effect on throughput, while latency may (packets will be dropped if not processed quickly enough). On the other hand, if the CPU is fully loaded, increasing processing cost will directly translate into latency.
Networks are actually designed to tolerate a fair amount of latency, so they shouldn't really be very sensitive to it. So, what's going on when throughput drops?
The answer is that either latency has grown substantially to show up in reduced throughput (likely much more than the observed degradation in throughput), or the CPU has maxed out. And if a doubling of latency results in a 10% drop of throughput, calling that “10% overhead” is probably not quite honest, is it?
If throughput was originally limited by CPU power (fully-loaded processor) then a 10% throughput degradation can be reasonably interpreted as 10% increased CPU cost, and that can be fairly called “10% overhead”. However, what if on the original system the CPU was 60% loaded, and on the modified system it's maxed out at 100% (and that leading to the performance degradation)? Is that still “10% overhead”?
Clearly not. A fair way to calculate overhead in this case would be to look at the processing cost per bit, which is proportional to CPU load divided by throughput. And on that measure, cost has gone up by 85%. Consequently, I would call that an 85% overhead!
A variant of this is to off-load some processing on a “free” core, and not including the load on that extra core in the processing cost. That's just cheating.
The bottom line is that incomplete information is presented which prevented us from really assessing the overhead/cost, and lead to a huge under-estimation. Throughput comparisons must always be accompanied by a comparison of complete CPU load. For I/O throughput, the proper way to compare is in terms of processing time per bit!

This one is confusing percentage with percentage points, regularly practiced (out of incompetence) by the media. That doesn't excuse doing the same in technical publications.
So the authors' modified system increases processing overheads from 6% (for the original system) to 13% (for theirs) and they sheepishly claim they only added 7% overhead. Of course, that's complete bullocks! They more than doubled the overhead, their system is less than half as good as the original!
Similarly, if your baseline system has a CPU utilisation of 26%, and your changes result in a utilisation of 46%, you haven't increased load by 20%, you almost doubled it! The dishonesty in the 20% claim becomes obvious if you consider what would happen if the same experiments were run on a machine exactly half as powerful: load would go from 52% to 92%, clearly not a 20% increase!
A particularly brazen example of creative accounting of overheads is in this paper (published in Usenix ATC, a reputable conference). In Table 3, the latency of the stat system call goes up from 0.39μs to 2.28μs, almost a six-fold increase. Yet the authors call it an “82.89% slowdown”! (Also note the pseudo accuracy; this is not a crime, but an indication of inability to understand numbers.)
Raw averages, without any indication of variance, can be highly misleading, as there is no indication of the significance of the results. Any difference between results from different systems might be just random.
In order to indicate significance, it is essential that at least standard deviations are quoted. Systems often behave in a highly deterministic fashion, in which case the standard deviation of repeated measurements may be very small. In such a case it might be sufficient to state that, for example, “all standard deviations were below 1%”. In such a case, if the effect we are looking at is, say, 10%, the reader can be reasonably comfortable with the significance of the results.
If in doubt use Student's t-test to check the significance.
Also, if you fit a line to data, quote at least a regression oefficient (unless it's obvious that there are lots of points nd the line passes right through all of them).
The arithmetic mean is generally not suitable for deriving an overall score from a set of different benchmarks (except where the absolute execution times of the various benchmarks have real significance). In particular the arithmetic mean has no meaning if individual benchmark scores are normalised (eg against a baseline system).
The proper way to average (i.e. arrive at a single figure of merit) is to use the geometric mean of scores [Fleming & Wallace, CACM (29), p 218].
It is sometimes unavoidable to base an evaluation on a simulated system. However, this is extremely dangerous, as a simulation is always a model, and contains a set of assumptions.
It is therefore essential to ensure that the simulation model does not make any simplifying assumption which will impact the performance aspect you are looking for. And, it is equally important to make it clear to the reader/reviewer that you really have made sure that the model is truly representative with respect to your benchmarks.
It is difficult to give general advice on how to do this. My best advice is to put yourself into the shoes of the reader, and even better to get an outsider to read your paper and check whether you have really made a convincing case.
I see people using benchmarks that are supposed to prove the point, when in fact they say almost nothing (and the only thing they could possibly show is truly aweful performance). Examples:
This one seems outright childish, but that doesn't mean you don't see it in papers submitted by (supposedly) adults. Someone is trying to demonstrate the multiprocessor scalability of their system by running many copies of SPEC CPU benchmarks.
Of course, these are uniprocessor programs which do not communicate. Further more, they perform very few system calls, and thus do not exercise the OS or underlying communication infrastructure. They should scale perfectly (at least for low processor counts). If not, there's serious brokenness in the OS or hardware. Real scalability tests would run workloads which actually communicate across processors and use system calls.
Again, this seems idiotic (or rather, is idiotic) but I've seen it nevertheless. People trying to demonstrate that their changes to a NIC driver or networking stack has low performance impact, by measuring the performance degradation of a CPU-intensive benchmark. Again, the only thing this can possibly prove is that performance sux, namely if there is any degradation at all!
This is a fairly widespread crime, and it's frankly an embarrassment for our discipline.
Systems work frequently uses models which have to be calibrated to operating conditions (eg. platform, workloads, etc). This is done with some calibration workloads. Then the system is evaluated, running an evaluation workload, to show how accurate the model is.
It should go without saying, but apparently doesn't, that the calibration and evaluation workloads must be different! In fact, they must be totally disjoint. It's incredible how many authors blatantly violate this simple rule.
Of course, the results of using the same data for calibration and validation are likely that the model appears accurate, after all, it's been designed to fit the experimental results. But all such an experiment can show is how well the model fits the existing data. It implies nothing about the predictive power of the model, yet prediction of future measurements is what models are all about!
This crime is related to the above. A typical case is comparing different virtualization approaches by only showing the performance of the two virtualized systems, without showing the real baseline case, which obviously is the native system. It's comparison against native which determines what's good or bad, not comparison against an arbitrary virtualization solution!
Consider the baseline carefully. Often it is the state-of-the-art solution. Often it is the optimal (or theoreticaly best) solution or a hardware limit (assuming zero software overhead). The optimal solution is usually impossible to implement in a system, because it requires knowledge of the future or magic zero-cost software, but it can often be computed “outside” the system and is an excellent base for comparison. In other cases the correct baseline it is in some sense an unperturbed system (as in the virtualization example above).
This is a variant of the above crime, but that doesn't make it rare. It might be exciting to you that you have improved the performance of your system over last year's paper, but I find it much less exciting. I want to see the significance, and that means comparing against some accepted standard.
At least this crime is less harmful that others in that it is pretty obvious, and rarely will a reviewer fall for it.
There's a variant of this crime which is more subtle: evaluating a model against itself. Someone builds a model of a system, making a number of simplifying assumptions, not all of them obviously valid. They build a solution for that problem, and then evaluate that solution on a simulated system that contains the exact same assumptions. The results look nice, of course, but they are also totally worthless, as there they are lacking the most basic reality check. This one I find a lot in papers which are already published. Depressing...
Doing benchmarks on your competitors yourself is tricky, and you must go out of your way to ensure that you do not treat them unfairly. I'm sure you tweaked your system as well as you could, but did you really go through the same effort with the alternative?
In order to reassure the reader/reviewer that you have been fair, describe clearly what you have done with the competitor system, e.g. fully describe all configuration parameters, etc. Be particularly circumspect if your results do not match any published data about the competitor system. If in doubt, contact the authors of that system to confirm that your measurements are fair.
Again, I have seen a case of this case of benchmarking abuse in a published paper, in that case the “competitor” system was mine. The authors of the paper failed to present any data on how they ran my system, and I strongly suspect that they got it wrong. For example, the default configuration of our open-source release had debugging enabled. Turning off that option (which, of course, you would in any production setting and any serious performance evaluation) improves performance massively.
The bottom line is that extreme care must be taken when doing your own benchmarking of a competitor system. It is easy to run someone else's system sub-optimally, and using sub-optimal results as a basis for comparison is highly unethical and probably constitutes scientific misconduct. And sloppiness is no excuse in such a case!
For reproducibility it is essential that the evaluation platform is well-specified, including all characteristics that may influence the results. Platform incorporates hardware and software.
Details depend a fair bit on what is being evaluated, but at the very least I expect to see the processor architecture, number of cores and clock rate, and memory sizes. For benchmarks involving networking the throughput supported by the NIC and switches if any. For benchmarks that exercise the memory system it is generally important to specify sizes and associativities of all levels of cache. In generaal it is good practice the list the model number of the CPU, core type and microarchitecture.
The same holds for the software. Specify the operating system and (where used) hypervisor are you running on, including release number. Compiler versions are often also relevant, as may be the version of other tools.
When running a benchmarking suite (such as SPEC) it is generally not sufficient to just quote the overall figure of merit of that suite. Instead, it is essential to show performance of the individual sub-benchmarks. Suites are designed to cover a range of load conditions, and some may benefit from your work while others are degraded. Only providing the overall score can at worst hide problems, and at best reduces the insights that can be obtained from the evaluation.
Always give complete result, not just ratios (unless the denominator is a standard figure). At best, seeing only relative numbers leaves me with a doubt as to whether the figures make sense at all, I'm robbed of a simple way to perform a sanity check. At worst, it can cover up that a result is really bad, or really irrelevant.
One of the worst instances I've seen of this crime was not in a paper I was reviewing, but one that was actually published. It compared the performance of two systems by showing the ratio of overheads: a ratio of two relative differences. This is too much relativity to read anything out of the numbers.
For example, assume that the overhead of one system is twice that of another. By itself, that tells us very little. Maybe we are comparing a tenfold with a twentyfold overhead. If so, who cares? Both are most likely unusable. Or maybe the overhead of one system is 0.1%, who cares if the other one has 0.2% overhead? The bottom line is we have no idea how significant the result is, yet the representation implies that it is highly significant.
The below benchmarking rules is what I tell my students. It's somewhat OS-oriented, but the basic principles apply generally.
With colleagues at VU Amsterdam I recently published a (non peer-reviewed) study of benchmarking crimes in the system security literature, with interesting results. It contains a further category that is not relevant to most systems work, but definitely to security work.
In my Advanced Operating Systems course I have a lecture on performance evaluation, which discusses many of these benchmarking crimes, and gives other useful hints on benchmarking and performance analysis.
If you are a student or early-career researcher, you might also be interested in my style guide for papers and theses.
|
Gernot Heiser<EMAIL_ADDRESS>Created 2010-01-05, last modified 2018-10-05, last validated 2018-10-05. |


{% extends "bootstrap/base.html" %} {% block content %}
Using Machine Learning to recommend players
Club : {{club}}
Position: {{pos}}
Overall: {{overall}}
{% endfor %}Recommended players which are similar to {{name}}:
{{name}}
Club : {{pred_club}}
Position: {{pred_pos}}
Overall: {{pred_oa}}


EBD - Easton Bible DIctionary
Treasure cities
TREASURE CITIES
"TREASURE CITIES "store cities which the Israelites built for the Egyptians (
Exodus 1:11
). (See PITHOM.) Towns in which the treasures of the kings of Judah were kept were so designated (
1 Chronicles 27:25
).
"TREASURE CITIES "store cities which the Israelites built for the Egyptians (Exodus 1:11). (See PITHOM.) Towns in which the treasures of the kings of Judah were kept were so designated (1 Chronicles 27:25).


|
back |
Math Cats' Privacy Policy
|
| Math Cats respects your privacy. Math Cats complies with COPPA (the Children's Online Privacy Protection Act). You may use online forms to send ideas, contest entries, pet stories, and number stories to Math Cats without using an e-mail address. Math Cats does not seek and will not post your last name (unless you and your parents specifically request that it be posted). If you include your e-mail address, it is used only once, to inform you when your contribution is posted. If you send an e-mail message to Math Cats, your address will be used only once to reply to your message. Messages posted in the Math Cats mailroom are edited to remove personal identifying information. If you sign up to receive Math Cats News, your e-mail address will be used only to send new issues to you. If you are under the age of 13 and you wish to receive Math Cats News or to correspond more than once with Math Cats, you need to have a parent send an e-mail message to Math Cats giving permission for this. Your name, e-mail address, and any other personal information will never be divulged to a third party.
Math Cats does not collect any addresses or phone numbers, with one small exception. If you are a winner in the monthly Math Cats' writing contest, then a message will be sent to the e-mail address supplied with your entry, asking your parent(s) three things: Math Cats does not use cookies. Most links leading away from Math Cats to other educational sites and resources are located in the Grownup Cats' section of Math Cats. There are also links on the Awards page leading to the educational awarding sites. Math Cats takes care only to link to safe, educational sites. There is only one human who has access to the information you send to Math Cats: Wendy Petti, the creator of Math Cats. Feel free to contact Math Cats if you have any questions about this Privacy Policy.
|
| © copyright 2002 - by Wendy Petti of Math Cats. All Rights Reserved. |


Random Quote Machine
A Free Code Camp Project
I collect some quotes about humor or nonsense for this project. Please click the "New Quote" button, and have fun.
New Quote
Tweet it!


This Howto shows how to create and use dialogs from a (resource) DLL with Venster.
At the moment an external resource compiler/dialog editor is required.
In this Howto
we will use VisualC++ 6.0 to create a resource dll (see folder 'test/resdll' for an example resource dll)
The file 'test/test_dialog.py' contains an example of the following procedure:
Create a resource only DLL project with Visual C++, instructions can be found at MSDN
Use visual studio to draw/design a dialog.
Create a new python class derived from 'wtl.Dialog'
Override 'OnInitDialog' to obtain references to the controls in your dialog
Implement Command Handlers to perform actions in the dialog


DIYRENO.sg is the first and only platform that connect residential and commercial property owners directly with contractors or suppliers of specialized trade bypassing the middleman to fit out their property, thus, resulting in lower cost for owners and higher profit for contractors and suppliers.
Our Mission
To Business Owner:
Our mission is to make it easy to do business for business owners by reducing miscommunication via 3rd party and showcase their products and services with tools necessary to reach audience for their products and services
To Property Owner:
One- Stop sourcing
DIYRENO.sg brings you products and services in over 40 trades specialized in fitting out property via our easy to use educative platform that showcase all products and services in their respective classified icon.


Contrary to popular belief, Lorem Ipsum is not simply random text.
SHARE TO
RECENT NEWS
ANALYTICS
WALLET


class: center, middle, inverse, title-slide # ETC3250: Resampling ## Semester 1, 2020 ###
Professor Di Cook
Econometrics and Business Statistics
Monash University ### Week 3 (b) --- ## Model assessment
     --- ## Validating models    A set of `\(n\)` observations are randomly split into a training set (blue, containing observations 7, 22, 13, ...) and a validation set (yellow, all other observations not in training set). Drawback: Only one split of data made, may not adequately estimate test error. .font_tiny[(Chapter5/5.1.pdf)] --- class: split-two .column[.pad50px[ ## Validating models
 Want to choose best degree of polynomial, for `\(\mbox{mpg}=\beta_0+\beta_1f(\mbox{horsepower})+\varepsilon\)` ``` ## [1] 1 3 5 7 9 10 12 13 15 19 20 21 22 23 26 ``` ]] .column[.content.vmiddle.center[  ]] --- class: split-two .column[.pad50px[ ## Validating models
 Want to choose best degree of polynomial, for `\(\mbox{mpg}=\beta_0+\beta_1f(\mbox{horsepower})+\varepsilon\)` ``` ## [1] 2 5 6 8 10 11 12 13 15 18 20 23 25 27 28 ``` ]] .column[.content.vmiddle.center[  ]] --- class: split-two .column[.pad50px[ ## Validating models
 Want to choose best degree of polynomial, for `\(\mbox{mpg}=\beta_0+\beta_1f(\mbox{horsepower})+\varepsilon\)` ``` ## [1] 4 5 7 9 10 11 13 14 16 17 18 21 22 24 25 ``` ]] .column[.content.vmiddle.center[  ]] --- class: split-two .column[.pad50px[ ## Validating models
 Want to choose best degree of polynomial, for `\(\mbox{mpg}=\beta_0+\beta_1f(\mbox{horsepower})+\varepsilon\)` ``` ## [1] 1 2 4 5 8 10 16 17 19 22 24 26 27 29 30 ``` ]] .column[.content.vmiddle.center[  ]] --- class: middle

The .orange[variability] between different draws of test sets can be .orange[large]. This can provide poor choice of model, or misleading estimate of error. --- ## LOOCV Leave-one-out (LOOCV) cross-validation: `\(n\)` validation sets, each with .orange[ONE] observation left out.    --- ## LOOCV Leave-one-out (LOOCV) cross-validation: `\(n\)` validation sets, each with .orange[ONE] observation left out. For each set, `\(i=1, ..., n\)`, compute the `\(MSE_{i}\)`. The LOOCV estimate for the test MSE is the average of these `\(n\)` test error estimates: `$$CV_{(n)} = \frac{1}{n}\sum_{i=1}^n MSE_{i}$$` --- ## LOOCV There is a computational shortcut, for linear or polynomial models, where not all `\(n\)` models need to be fitted. `$$CV_{(n)} = \frac{1}{n}\sum_{i=1}^n \frac{(y_i-\hat{y})^2}{1-h_i}$$` where `\(h_i=\frac{1}{n}+\frac{(x_i-\bar{x})^2}{\sum_{i'}^n(x_{i'}-\bar{x})^2}\)` (known as *leverage* from regression diagnostics). --- ## k-fold cross validation 1. Divide the data set into k different parts. 2. Remove one part, fit the model on the remaining `\(k − 1\)` parts, and compute the MSE on the omitted part. 3. Repeat `\(k\)` times taking out a different part each time    .font_tiny[(Chapter 5/ 5.5)] --- ## k-fold cross validation 1. Divide the data set into k different parts. 2. Remove one part, fit the model on the remaining `\(k − 1\)` parts, and compute the MSE on the omitted part. 3. Repeat `\(k\)` times taking out a different part each time `$$CV_{(k)} = \frac{1}{k}\sum_{i=1}^n \frac{(y_i-\hat{y})^2}{1-h_i}$$` - LOOCV is a special case of `\(k\)`-fold cross-validation. - Bias-variance trade-off: - one vaidation set overestimates test error, LOOCV approximately unbiased estimates, `\(k\)`-fold CV intermediate - LOOCV has higher variance than does `\(k\)`-fold CV - choice of `\(k=5\)` or `\(10\)` is a compromise --- ## Classification      .font_tiny[(Chapter 5/ 5.7)] --- ## Classification    Black line is .black[10-fold CV]; .blue[training] and TRUE .orange[test] error for different choices of polynomial (left) and KNN classifier (right). .font_tiny[(Chapter 5/ 5.8)] --- layout: false ## Bootstrap procedure - Draw `\(B\)` independent bootstrap samples `\(X^{*(1)}, \dots, X^{*(B)}\)` from `\(\hat P\)`: `$$X_1^{*(b)}, \dots, X_n^{*(b)} \sim \hat P \quad b = 1, \dots, B.$$` - Evaluate the bootstrap replications: `$$\hat \theta^{*(b)} = s(X^{*(b)}) \quad b = 1, \dots, B.$$` - Estimate the quantity of interest from the distribution of the `\(\hat \theta^{*(b)}\)` --- ## Example - boostrap model - Fit the model on a set of bootstrap samples, and then keep track of how well it predicts the original dataset `$$\text{Err}_{\text{boot}} = \frac1B \frac1N \sum_{b = 1}^B \sum_{i = 1}^N L(y_i, \hat f^{*b}(x_i))$$` - Each of these bootstrap data sets is created by sampling with replacement, and is the same size as our original dataset. As a result .orange[some observations may appear more than once in a given bootstrap data set and some not at all]. --- ## Out of bag (OOB) error For estimating error, only .orange[use predictions from bootstrap samples not containing that observation]. The leave-one-out bootstrap estimate of prediction error can be defined as `$$\text{Err}_{\text{loo-boot}} = \frac1N \sum_{i = 1}^N \frac{1}{|C^{-i}|}\sum_{b \in C^{-i}} \ L(y_i, \hat f^{*b}(x_i))$$` where `\(C^{-i}\)` is the set of indices of the bootstrap samples `\(b\)` that do not contain observation `\(i\)`. --- ## Uses and variants of the boostrap - Common uses: - Computing standard errors for complex statistics - Prediction error estimation - Bagging (Bootstrap aggregating) ML models - Types of bootstrap based on different assumptions: - block bootstrap - sieve bootstrap - smooth bootstrap - residual bootstrap - wild bootstrap --- layout: false # 👩💻 Made by a human with a computer ### Slides at [https://monba.dicook.org](https://monba.dicook.org). ### Code and data at [https://github.com/dicook/Business_Analytics](https://github.com/dicook/Business_Analytics).
 ### Created using [R Markdown](https://rmarkdown.rstudio.com) with flair by [**xaringan**](https://github.com/yihui/xaringan), and [**kunoichi** (female ninja) style](https://github.com/emitanaka/ninja-theme).

This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.


Who is doing what and where in the Typhoon Maysak response.
Status
What
Who (Top 20)
Where
Data table


Single date & appointment booking
Booking multiple appointments
Recurring booking & resource allocation


Installation Instructions
Ideally, JA++ is installed without having JA+ already installed.
If JA+ is installed, you will have to remove it to avoid conflicts
If you already have JA+ installed
- Remove the JA+ GLA animations from your GameData/base folder
- Remove clientPlugin_v*.pk3 from GameData/japlus
- Place the downloaded files in GameData/japlus
- Start the game with +set fs_game "japlus" as your command line arguments (e.g. .bat file, shortcut, with UU)
If you don't have JA+ installed
- Place the downloaded files in GameData/japlus
- Start the game with +set fs_game "japlus" as your command line arguments (e.g. .bat file, shortcut, with UU)
Download Links
JA++ is available for Windows, Mac and Linux; you will have to select the correct files for your operating system and CPU architecture (i.e. 32 bit, 64 bit)
Runs best on OpenJK


Welcome to Tech Connect!
Use the search fields below to learn abou any class at Oakland Tech!
Search
Choose A Subject
Math
English
Science
Arts


DJ N.Gattuso
About
N.Gattuso is a professional DJ for private events and club events. Nicholas grew up in the mobile DJ industry learning everything about the field from his father, owner and CEO of Stardust Productions; 35 years of knowledge and experience has been passed down from father to son. At the age of 15, Nicholas officially began DJing at events. Seven years later, N.Gattuso is familiar with music of all styles and ages and is prepared to play for any crowd. With the keen ability of reading the crowd, reaching customer satisfaction and, many years of experience, N.Gattuso is the DJ needed for your event!
Services
DJ / VDJ
Specialized DJ/VDJ for weddings, corporate and, many more private events
Club DJ/VDJ
Repertoire of music and music videos containing the best songs of all ages and styles.
Equipment
Equipped with sound and lighting gear perfect for your event


|
NUC472_NUC442_BSP V3.03.004
The Board Support Package for NUC472/NUC442
|
Macros | |
| #define | I2C_SET_CONTROL_REG(i2c, u8Ctrl) |
| This macro sets the I2C control register at one time. More... | |
| #define | I2C_START(i2c) |
| This macro only set START bit to the control register of I2C module. More... | |
| #define | I2C_STOP(i2c) |
| This macro only set STOP bit to the control register of I2C module. More... | |
| #define | I2C_WAIT_READY(i2c) |
| This macro will return when I2C module is ready. More... | |
| #define | I2C_GET_DATA(i2c) |
| This macro returns the data stored in data register of I2C module. More... | |
| #define | I2C_SET_DATA(i2c, u8Data) |
| This macro writes the data to data register of I2C module. More... | |
| #define | I2C_GET_STATUS(i2c) |
| This macro returns the status of I2C module. More... | |
| #define | I2C_GET_TIMEOUT_FLAG(i2c) |
| This macro returns time-out flag. More... | |
| #define | I2C_GET_WAKEUP_FLAG(i2c) |
| This macro returns wakeup flag. More... | |
| #define | I2C_CLEAR_WAKEUP_FLAG(i2c) ((i2c)->WKSTS |= I2C_WKSTS_WKIF_Msk ) |
| This macro clears wakeup flag. More... | |
Functions | |
| uint32_t | I2C_Open (I2C_T *i2c, uint32_t u32BusClock) |
| This function make I2C module be ready and set the wanted bus clock. More... | |
| void | I2C_Close (I2C_T *i2c) |
| This function closes the I2C module. More... | |
| void | I2C_ClearTimeoutFlag (I2C_T *i2c) |
| This function clears the time-out flag. More... | |
| void | I2C_Trigger (I2C_T *i2c, uint8_t u8Start, uint8_t u8Stop, uint8_t u8Si, uint8_t u8Ack) |
| This function sets the control bit of the I2C module. More... | |
| void | I2C_DisableInt (I2C_T *i2c) |
| This function disables the interrupt of I2C module. More... | |
| void | I2C_EnableInt (I2C_T *i2c) |
| This function enables the interrupt (EI bit) of I2C module. More... | |
| uint32_t | I2C_GetBusClockFreq (I2C_T *i2c) |
| This function returns the real bus clock of I2C module. More... | |
| uint32_t | I2C_SetBusClockFreq (I2C_T *i2c, uint32_t u32BusClock) |
| This function sets bus frequency of I2C module. More... | |
| uint32_t | I2C_GetIntFlag (I2C_T *i2c) |
| This function gets the interrupt flag of I2C module. More... | |
| uint32_t | I2C_GetStatus (I2C_T *i2c) |
| This function returns the status of I2C module. More... | |
| uint32_t | I2C_GetData (I2C_T *i2c) |
| This function returns the data stored in data register of I2C module. More... | |
| void | I2C_SetData (I2C_T *i2c, uint8_t u8Data) |
| This function writes the data to data register of I2C module. More... | |
| void | I2C_SetSlaveAddr (I2C_T *i2c, uint8_t u8SlaveNo, uint8_t u8SlaveAddr, uint8_t u8GCMode) |
| Configure slave address and enable GC mode. More... | |
| void | I2C_SetSlaveAddrMask (I2C_T *i2c, uint8_t u8SlaveNo, uint8_t u8SlaveAddrMask) |
| Configure the mask of slave address. The corresponding address bit is "Don't Care". More... | |
| void | I2C_EnableTimeout (I2C_T *i2c, uint8_t u8LongTimeout) |
| This function enables timeout function and configures DIV4 function to support long timeout. More... | |
| void | I2C_DisableTimeout (I2C_T *i2c) |
| This function disables time-out function. More... | |
| void | I2C_EnableWakeup (I2C_T *i2c) |
| This function enables the wakeup function of I2C module. More... | |
| void | I2C_DisableWakeup (I2C_T *i2c) |
| This function disables the wakeup function of I2C module. More... | |
| #define I2C_CLEAR_WAKEUP_FLAG | ( | i2c | ) | ((i2c)->WKSTS |= I2C_WKSTS_WKIF_Msk ) |
| #define I2C_GET_DATA | ( | i2c | ) |
| #define I2C_GET_STATUS | ( | i2c | ) |
| #define I2C_GET_TIMEOUT_FLAG | ( | i2c | ) |
| #define I2C_GET_WAKEUP_FLAG | ( | i2c | ) |
| #define I2C_SET_CONTROL_REG | ( | i2c, | |
| u8Ctrl | |||
| ) |
| #define I2C_SET_DATA | ( | i2c, | |
| u8Data | |||
| ) |
| #define I2C_START | ( | i2c | ) |
| #define I2C_STOP | ( | i2c | ) |
| #define I2C_WAIT_READY | ( | i2c | ) |
| void I2C_ClearTimeoutFlag | ( | I2C_T * | i2c | ) |
| void I2C_Close | ( | I2C_T * | i2c | ) |
| void I2C_DisableInt | ( | I2C_T * | i2c | ) |
| void I2C_DisableTimeout | ( | I2C_T * | i2c | ) |
| void I2C_DisableWakeup | ( | I2C_T * | i2c | ) |
| void I2C_EnableInt | ( | I2C_T * | i2c | ) |
| void I2C_EnableTimeout | ( | I2C_T * | i2c, |
| uint8_t | u8LongTimeout | ||
| ) |
| void I2C_EnableWakeup | ( | I2C_T * | i2c | ) |
| uint32_t I2C_GetBusClockFreq | ( | I2C_T * | i2c | ) |
| uint32_t I2C_GetData | ( | I2C_T * | i2c | ) |
| uint32_t I2C_GetIntFlag | ( | I2C_T * | i2c | ) |
| uint32_t I2C_GetStatus | ( | I2C_T * | i2c | ) |
| uint32_t I2C_Open | ( | I2C_T * | i2c, |
| uint32_t | u32BusClock | ||
| ) |
| uint32_t I2C_SetBusClockFreq | ( | I2C_T * | i2c, |
| uint32_t | u32BusClock | ||
| ) |
| void I2C_SetData | ( | I2C_T * | i2c, |
| uint8_t | u8Data | ||
| ) |
| void I2C_SetSlaveAddr | ( | I2C_T * | i2c, |
| uint8_t | u8SlaveNo, | ||
| uint8_t | u8SlaveAddr, | ||
| uint8_t | u8GCMode | ||
| ) |
Configure slave address and enable GC mode.
| [in] | i2c | is the base address of I2C module. |
| [in] | u8SlaveNo | is the set number of salve address. |
| [in] | u8SlaveAddr | is the slave address. |
| [in] | u8GCMode | GC mode enable or not. Valid values are: |
| void I2C_SetSlaveAddrMask | ( | I2C_T * | i2c, |
| uint8_t | u8SlaveNo, | ||
| uint8_t | u8SlaveAddrMask | ||
| ) |
| void I2C_Trigger | ( | I2C_T * | i2c, |
| uint8_t | u8Start, | ||
| uint8_t | u8Stop, | ||
| uint8_t | u8Si, | ||
| uint8_t | u8Ack | ||
| ) |
This function sets the control bit of the I2C module.
| [in] | i2c | is the base address of I2C module. |
| [in] | u8Start | sets START bit to I2C module. |
| [in] | u8Stop | sets STOP bit to I2C module. |
| [in] | u8Si | sets SI bit to I2C module. |
| [in] | u8Ack | sets ACK bit to I2C module. |


@import tags._ @(account: Account) @help(account, 1){
@messages.at("help.lesson_creation")
In the home page, move your mouse on ‘Create Lesson’ Link. The dropdown list will be appeared, choose ‘Tutors’ option.
You will see a dialog popped up. you must enter your lesson title and press ‘Submit’ button.
In the lesson basic Information page, you must fill in lesson title, brief and category. For coaching class, you must set the size of your class which must be not more than 5 students. You may select the text to change its style.

In the lesson image page, you must upload at least one lesson image. The image must be the explanation of your lesson.
In the lesson image page, you must upload at least one lesson image. The image must be the explanation of your lesson.
In the lesson session page, you should see all the lesson sessions. And Clicking ‘Create a Session’ button to create a new session.
You should see a dialog popped up, and you must fill in the session title, brief, start date time and duration. If the lesson has chapters, you may put the lesson under a chapter.
In the lesson price page, you must set the lesson price. The currency is Singapore Dollar.
You may set the promotion price, promotion period and promotion reason by expanding the ‘Offer Bar’.
You may set free lesson sessions to attractive more users, and the maximum free lesson must be not more than three.

After your set basic information, images, sessions and price of the lesson, you may want to publish the lesson. By doing this, you just press ‘Publish’ button. It will appear in the home page immediately.


Number input demo
Current value
0
Add
Subtract
Use "add" and "subtract" buttons, or up and down arrows, to add or subtract 10, respectively.
Demo inspired by
Heydon Pickering's Practical ARIA examples


Convert the angle COMMON_RADIANS
radians into degrees.
COMMON_DEGREES°
To convert from radians to degrees, you multiply by 180^{\circ}
and then divide by \pi
.
COMMON_RADIANS \times \frac{180^{\circ}}{\pi} = COMMON_DEGREES^{\circ}
Convert the angle NUM_RADIANS radians into degrees. (Round to the nearest degree.)
round(NUM_DEGREES)°
To convert from radians to degrees, you multiply by 180^{\circ}
and then divide by \pi
.
NUM_RADIANS \times \frac{180^{\circ}}{\pi} = NUM_DEGREES^{\circ}


| thiem |
Estimates T with Thiem's formula for
steady state flow in an ideal confined aquifer for two observations |
thm |
Estimates T with Thiem's formula for steady state
flow in an ideal confined or unconfined aquifer for two and more observations |
deg |
Estimates T and c with de Glee's formula for steady
state flow in an ideal half-confined aquifer for two and more observations |
| thc_std |
Computes the discharge for a well located
close to a constant head boundary with the Dupuit's formula |
| lei_std |
Computes the discharge for a well located
close to a constant head boundary with the solution of |
| tcn_std |
Computes the discharge for a well located
between a constant head and a no flow boundaries |


--- title: Title layout: default ---
Like a modern code version of the mythical beast with 100 serpent heads, Typhoeus runs HTTP requests in parallel while cleanly encapsulating handling logic.
Get Started! » Join the Mailing List » Contribute »Built around libcurl and libcurl-multi to achive the best performance, is ready to process multiple simultaneous requests, cache responses. Built with FFI, therefore ready for use with any Ruby implementation.
Typhoeus is ready to memoize your requests, has built-in caching mechanisms, allows you to avoid hitting remote APIs while testing by providing stubs for specific urls or patterns.
Is able to handle to handle HTTP timeouts, follow HTTP redirects, handle file uploads, parallel execution, many different types HTTP authentication, secure connections. Everything you may possibly want from your HTTP client and a bit more.


We got mices!
- exploit vertical e-markets
- transition robust networks
- morph e-business deliverables
- deliver leading-edge channels
- visualize user-centric bandwidth
- cultivate value-added supply-chains
- brand magnetic metrics
- repurpose holistic content
- benchmark distributed interfaces
- embrace vertical applications


Question:
The following connections are made between the wolves and their habitats. Which is
not
correct?


Our story
Some stories have happy endings. Let ours be never-ending.
-
Dedication
Soviet Union 1980
S Our story wouldn't be complete without our beloved parents. Back in those days, they were all exchange students, hers to Ukraine, his to Czechoslovakia. We wouldn't be where we are today, without their devotion, relentless hard work and a pinch of good luck afforded by the course of history!
-
Story begins
Oxford Oct 2010
When we first met, on the grounds of Worcester college, it was a late summer afternoon. Or at least it felt like that. She just started her first year, he was in his final. And both were equally clueless about where their lives would go!
-
Proposal
London Nov 2014
After a couple of years of medium-distance relationship, we were finally reunited in London, a city we were hoping will become newest of our many homes. Knowing that she was always up for a challenge, he took her to a restaurant atop the bright London skyline, with a puzzle to solve. Though it was a cold winter day, the "yes" in his ears and the ring on her finger both felt warm, just like that late summer day.
-
Next Chapter
Oxford Sep 2017
Almost 7 years later, we will find ourselves here in this place, where we first met and where we joined our lives together. We still have no clue what lies ahead of us, but here we are again, ready to do it once again. We are incredibly honoured that you could be with us to share this moment!
-
...and
forever
after


Now that your seeds have sprouted, you can't wait to watch them grow.
Drag and drop what you need to give your plants to help them along the way!


A happy man marries the girl he loves, but a happier man loves the girl he marries.
~ Afrikan proverb


{% extends "base.html" %} {% block javascript %} {% endblock %} {% block content %}
Expresso is an interactive tool to analyze, edit and compare text styles in English created by Mikhail Panko. The first version was built in 2014 on top of the Natural Language Toolkit library. In 2019 Expresso was upgraded to use spaCy — a powerful and fast library for advanced Natural Language Processing, which relies on neural network models. The new NLP library allowed to speed up text analysis, improve metrics accuracy, and add new metrics based on syntactic structure of sentences.
Expresso uses entered texts only to calculate style-related metrics and display back in the tool to the same user. No texts are recorded, stored or shared in any way to protect user privacy.
If you have any comments or suggestions, please, drop me a line at<EMAIL_ADDRESS>Check out Expresso code on GitHub.
If you enjoy Expresso and would like to support server costs and further development, you can make a donation at paypal.me/MikhailPanko.


The Maps API is a free service, available for any web site that is free to consumers. Please see the terms of service for more information.
Businesses that charge fees for access, track assets or build internal applications must use Google Maps API Premier, which provides enhanced features, technical support and a service-level agreement.
Alter the appearance of the standard map styles in the API, customizing the colors and display of features and elements!
Create custom panoramas and display them using the Street View service in the Maps Javascript API V3!
Documentation on Fusion Table Layers, allowing you to display geographic data on your map!
Google Maps has a wide array of APIs that let you embed the robust functionality and everyday usefulness of Google Maps into your own website and applications, and overlay your own data on top of them:
Embed a Google Map in your webpage using JavaScript. Manipulate the map and
add content through many services.
Version 3 -
Version 2
Use this ActionScript API to embed a Google Map in your Flash-based web page
or app. Manipulate the Map in three dimensions and add content through many services.
Learn more
Embed a true 3D digital globe into your web page. Take your visitors anywhere
on the Earth (even below the ocean) without leaving your web page.
Learn more
Embed a fast and simple Google Maps image in your web page or mobile site without
requiring JavaScript or any dynamic page loading.
Learn more
Use URL requests to access geocoding, directions, elevation, and places
information from client applications, and manipulate the results in JSON or XML.
Learn more


We are here to help you to create a bright future. Your job search goal will be to find and secure that job. This site reaching out to help you in your job search as we walk down that path . The key to your personal success involves using the appropriate techniques to gain a competitive edge by putting this information to use. This site is not a one-size-fits-all formula. It requires your interaction and your personal touch.


HALLOWEEN H20
Reviewed by Harvey Karten, Ph.D. Dimension Films Director: Steve Miner Writers: Robert Zappia, Matt Greenberg, Kevin Williamson Cast: Jamie Lee Curtis, Michelle Williams, Josh Hartnett, Adam Arkin, Jodi Lyn O'Keefe, Adam Hann-Byrd,LL Cool J.
When John Carpenter's "Halloween" (also featuring Jamie Lee Curtis) hit the screens in 1978, it scared the heck out of people who thought they were too sophisticated to be fazed by horror films. Roger Ebert called it an "absolutely merciless thriller, a movie so violent and scary that I would compare it to 'Psycho.'" "Halloween" was about a six-year-old kid who commits a murder at the beginning of the movie and is counseled by a psychiatrist who recommends--as psychiatrists are not usually wont to do--that the kid stay in jail for a long long time. The kid's name is Michael Myers, he had killed his brother, and though he is thought to be dead, his sister, Laurie Strode, fears for her life. For two decades, Myers has not shown his face in town, seeming to confirm that he is no longer with us, but now, on October 31, 1998, he is doing what he does best. In his attempt to get at his sister, now in her late thirties and the head mistress of an exclusive prep school in California, he must first clear away a few other people whose predicament is that they are seen as buffers to the frightened and enraged Strode (Jamie Lee Curtis). Some time back, Laurie had changed her name to Keri Tate, has been unsuccessful at fighting her problems with alcohol and prescription drugs, and is much too protective of her 17-year-old son, John (Josh Hartnett).
"Halloween H20" is yet another sequel that cannot match up to the glories of its precursor and, in fact, is considerably less hair-raising than recent horror films like "Scream," "Scream 2," and even "Mimic." Directed by Steve Miner--who is unable to mine the "Psycho"-like terror of John Carpenter's original, "Halloween H20" spends much of its brief 85 minutes' duration establishing the atmosphere of a quiet town which harbors the exclusive and secluded high school presided over by Keri Tate. She has taken a mere guidance counselor, Will Brennan (Adam Arkin) as a lover, and against the usual rules of pedagogy includes her own son in her literature class. The story, scripted by three people(!), strives for metaphoric content, highlighting a class discussion of the novel "Frankenstein" (which only one student seems to have read), but otherwise lays no claim to cerebral satisfactions.
Several flaws are responsible for this picture's relative lack of nail-biting tension. For one, Miner has mined the conventions of the genre leaving little for originality. Principal among these protocols is the repetition of false alarms, as when a guy would seeming sneak up to a potential victim, lay his hand on her shoulder, and amid her screams turn out to be no-one more dangerous than the next-door neighbor. For another, the chief villain, Michael Myers (Chris Durand), commits his murders purely for reasons never known to the audience. He may be having fun as he butchers his victims, but given the white Halloween mask he never removes, we see no expression on his face when he commits mayhem, nor do we know a thing about him except that he's a psycho. He has no conscience and presumably feels no pain; so where is the thrill of acquiring retribution over him?
Like other creeps in the genre, this mosntrous guy never runs after his intended victims but rather walks like the Frankenstein monster and as a result misses out on some juicy killings; nor does he make his profession easier by using anything more lethal than a kitchen knife. Only one murder is shown in vivid, close-up horror; that of quarry who does not simply roll over and die when stabbed but who actually has frightening tremors during his brief but eerie death-rattle.
LL Cool J plays a nice guy, a security guard who is an aspiring novelist and spends much time on duty phoning his woman with chapters from his salacious works-in-progress. He's not the sort of fellow whom the audience would allow to be sliced up, so not to worry. As the high school sweethearts John and Molly, Josh Hartnett and Michelle Williams are from stereotype city. John does not exactly get a chance to shine when he's given lines like "Mom, you've got to let me live my own life." As the adult sweethearts, Tate and Brennan seem made for each other. Tate, an alcoholic prone to hysteria, is too flawed to sympathize with, and Brennan turns in a stick-like performance this time around. What's more Steve Miner gives us a teasing glimpse of what he could have done with this movie by flashing a few seconds of "Scream" on the teens' TV screen; "Do you want to die tonight?" Now that's scary.
Rated R. Running time: 85 minutes. (C) Harvey Karten 1998
The review above was posted to the
rec.arts.movies.reviews newsgroup (de.rec.film.kritiken for German reviews).
The Internet Movie Database accepts no responsibility for the contents of the
review and has no editorial control. Unless stated otherwise, the copyright
belongs to the author.
Please direct comments/criticisms of the review to relevant newsgroups.
Broken URLs inthe reviews are the responsibility of the author.
The formatting of the review is likely to differ from the original due
to ASCII to HTML conversion.
Related links: index of all rec.arts.movies.reviews reviews


EasyCluster is a remote execution / clustering module for Python.
Possible uses include:
EasyCluster uses setuptools for installation. To install, run:
python setup.py build
sudo python setup.py install
If you do not have setuptools installed, it will be downloaded for you.
EasyCluster works by having a single master script connect to one or more servers running SSH or the cluster service. The master can then call Python functions on the remote service or send code to execute.
See easycluster_demo.py
for an example of how to use most of the features.
Since version 0.22.1, SSH is the preferred method of connecting to servers on all platforms except Windows. When using SSH, the server does not need to have easycluster installed - it only needs to have SSH and either Python 2.6, 2.7, or 3.2+. When using SSH, you should use SSH private keys and an SSH agent, otherwise SSH will prompt for a password whenever it connects.
If you don't want to use SSH, e.g. you need to run the server on Windows and don't want to run Cygwin, you will need to generate a secret key that is shared between the client and server. This key is used to authenticate requests, but does not encrypt data, therefore it should only be used on a trusted, firewalled network, not openly on the Internet. If you want to use EasyCluster to coordinate systems in remote geographic areas, consider using a VPN or SSH tunnel. The EasyCluster service operates over a single TCP port, so most tunneling solutions will work.
The easiest way to use EasyCluster is to use Client.from_spec:
>>> rmt =<EMAIL_ADDRESS>>>> rmt = ThreadedClient.from_spec('user@example.com:rpython=python2.7')
The connection spec looks like this::
[user@]host[:port][:opt=val]...
The 'host' can be a hostname, IPv4 address, or bracketed IPv6 address.
For compatibility reasons, SSH is only used if the 'user' field is present. If you want to use SSH without specifying a user name, pass ':ssh=yes' as an option.
For standalone servers, the key is determined by specifying either the 'kf' or 'key' options.
If ':compress=1' is specified, then compression is enabled for the connection.
Example connection specifications::
<EMAIL_ADDRESS># Using SSH
'example.com:ssh=yes' # Using SSH without a user name (let SSH choose)
'example.com:ssh=/usr/local/bin/ssh' # Using a custom SSH path
'user@<IP_ADDRESS>:9999' # IPv4 address on non-standard port
'user@[2001:db8::2]' # IPv6 addresses must be in brackets
'example.com:kf=secret.key' # Connecting to a standalone server using a key from a file
'example.com:9999:key=s3cret' # Using a key directly, with non-standard port
The recommended way of allowing the user of your script to specify remote
options is to use optparse
:
# File: connect_example.py
import sys
import optparse
import easycluster
options = optparse.OptionParser(description='Do some stuff')
easycluster.add_key_options(options)
opts, args = options.parse_args()
default_key = easycluster.key_from_options(opts)
remotes = []
for spec in args:
params = easycluster.parse_connection_spec(spec, default_key=default_key)
rmt = easycluster.Client(**params)
remotes.append(rmt)
This example allows a user to specify a default key using -k
(if multiple
servers use the same key), but allows the user to specify individual keys if
necessary:
python do_stuff.py -k common.key host1 host2 oddhost:kf=key_for_oddhost.key
You can also specify a different TCP port to connect to. This is useful if you want to use SSH tunnels:
ssh host1 -N -f -L 11001:localhost:11999
ssh host2 -N -f -L 11002:localhost:11999
python do_stuff.py -k common.key localhost:11001 localhost:11002
The master script can connect to the same server multiple times. Each connection
creates a separate process with a clean environment. The master can also create
a "local" instance using easycluster.server.spawn_local()
, which starts a new
server process without having to run a separate server.
The most straightforward way to execute code remotely is to define functions in
a string, and call define_common()
:
>>> from easycluster import *
>>> define_common('''
... def addvals(a, b):
... return a + b
... def subvals(a, b):
... return a - b
... ''')
>>> key = read_key_file('secret.key')
>>> rmt = Client(key, 'localhost')
>>> rmt.addvals(3, 4)
7
>>> rmt.subvals(15, 4)
11
Any functions or classes you define in in the block of code passed to
define_common
can be called on the remote side. You can also call functions in
classes defined in standard library modules:
>>> rmt.subprocess.call(['/bin/echo', 'hello'])
>>>
This example won't actually echo anything to your terminal - echo
is executed
on the server, so if you have the server open in a terminal, you will see it
echoed there.
The block of code you pass to define_common is also evaluated on the client, so
functions, classes, and class instances can be pickled by reference and passed
back and forth between client and server. By default, a virtual module called
easycluster.remote_code
is created to store the definitions. You can import
this module on the client if you want to run a function on both client and
server, or create a instance of a class that will be passed to the server by
value:
>>> from easycluster.remote_code import addvals, subvals
>>> addvals(1, 2)
3
>>>
You can change the name of the module by specifying a different second parameter
to define_common
. Remember that since this code is executed in the context of
a different module, you won't have access to global variables and imported
modules from your master script:
>>> import os
>>> define_common('''
... def hello():
... os.system('echo hello')
... ''')
...
>>> rmt.hello()
Traceback (most recent call last):
...
NameError: global name 'os' is not defined
>>>
You must remember to import whatever modules you need to use inside of your define_common block. Of course, the libraries you import must be available on the remote system too - EasyCluster will not copy them over.
If the remote code raises an exception, the exception will be pickled up and
re-raised on the client, along with a stack trace. By default, the stack trace
will be printed to STDERR, because otherwise it would be lost - the stack trace
generated by raising the exception on the client only goes as far as the proxy
wrapper. If you don't want exceptions to be printed, you can subclass Client
and override report_exception
. For a single request, you can also set
origexc
to False
or 'quiet'
(see the section on Parallel Execution below).
By default, if you call a function on the server, and it returns a value, that value will be pickled, and a new copy of the object will be created on the client. This is fine for simple values such as strings, integers, tuples, dictionaries, etc., but a lot of objects can't or shouldn't be pickled; instead, EasyCluster allows you to mark classes as "server objects" that are not pickled, but remain on the server and are referenced by the client.
When the returned data structure is reconstructed on the client, any "server objects" are converted into "proxy" objects. Calling a method on this proxy calls the corresponding method on the server. These proxy objects can also be passed as arguments to other functions on the same connection, and will be unserialized as the original object on the server.
>>> define_common('''
... class TestObject1(ServerObject):
... def __init__(self, val):
... self.val = val
... def getval(self):
... return self.val
... def newobj(self):
... return TestObject1(self.val + 1)
...
... def get_object_vals(lst):
... return [obj.val for obj in lst]
... ''')
>>>
>>> # Call this on every connection after calling define_common.
>>> rmt.update_definitions()
>>>
>>> obj1 = rmt.TestObject1(100)
>>> obj1
<RemoteProxy for oid 1 on localhost:11999>
>>> obj1.getval()
100
>>> obj2 = obj1.newobj()
>>> obj2
<RemoteProxy for oid 2 on localhost:11999>
>>> obj2.getval()
101
>>> rmt.get_object_vals[obj1, obj2]
[100, 101]
>>>
Classes can indicate that they should be proxied rather than copied by
inheriting from ServerObject
. Existing classes which are unaware of EasyCluster
can be registered on the server by calling make_server_class
.
There are two ways classes can specify which methods and attributes to export:
Specifying export_methods
, export_attrs
, or export_attrs_cache
. Classes
which inherit from ServerObject
but do not specify a proxy class will have
one dynamically created when they are first referenced. The server will
examime the class to determine which methods and attributes should be
exported.
If the class has a class attribute called export_methods
, then the proxy
class will only have wrappers for those methods.
If export_methods
is not defined (default), or the special value '@auto'
is in the list of exported method names, then the class will be examined,
and all defined methods will be automatically added to the list.
The export_attrs
class attribute works the same way: if it is defined,
wrapper properties will be created on the proxy object for each
attribute. If export_attrs
is not defined, or '@auto'
is included in
export_attrs, then a special __getattr__
is defined on the proxy which
will forward attribute accesses to the server.
If you know that an attribute contains data which will not change over the
lifetime of the object, you can put it in export_attrs_cache
. The client
will cache the value of the attribute the first time it is accessed, and
won't access it again.
Defining a proxy class directly. This is the most flexible way of exporting methods and attributes. This allows you to not only define proxy methods and attributes, but allows you to:
Implement simple methods on the client. For example, most iterators simply
return self
from __iter__
. In fact, easycluster provides a proxy class
you can inherit from called SelfIterProxy which does this.
Make your proxy object inherit from some other class so that
isinstance(prox, clas)
returns True
.
Example of both methods:
>>> define_common('''
... class TestObject2(TestObject1):
... export_methods = ('getval',)
... export_attrs = ('val',)
...
... class TestObject3Proxy(RemoteProxy):
... proxy_methods = ('getval',)
... proxy_attrs = ('val',)
...
... class TestObject3(TestObject1):
... proxy_class = TestObject3Proxy
... ''')
>>>
>>> rmt.update_definitions()
>>> obj2 = rmt.TestObject2(200)
>>> obj2.val
200
>>> obj2.getval()
200
>>> obj2.non_existant_method()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'dynamic_proxy_getval_val' object has no attribute 'non_existant_method'
>>>
>>> define_common('''
... ''')
>>> rmt.update_definitions()
>>> obj3 = rmt.TestObject3(300)
>>> type(obj3)
<class 'easycluster_code.TestObject3Proxy'>
>>> obj3.val
300
If you have a built-in class or a class from a library module that you want to
treat as a "server object", you can call easycluster.make_server_class()
in your
define_common block:
>>> define_common('''
... import array
... make_server_class(array.array)
... ''')
>>> rmt.update_definitions()
>>> rmt_array = rmt.array.array('B', 1234)
You can pass export_methods
, export_attrs
, export_attrs_cache
, and
proxy_class
to make_server_class
; they have the same meaning as defined for
ServerObject.
There is also a function called make_singleton
, which behaves like
make_server_class
, except it operates on a single instance of a class; if that
instance is returned, it will be proxied, but other instances of the same class
will be pickled.
Usually, clustering implies you want to execute code in parallel on multiple systems. By default, calling remote code suspends execution of the master script while the remote code is executing. However, there are several ways to execute remote code in parallel.
The simplest way to do this is to use a non-blocking response:
>>> rmt2 = Client(key, 'otherhost')
>>> r1 = rmt.addvals(5, 8, nonblocking=True)
>>> r2 = rmt2.addvals(14, 18, nonblocking=True)
>>> r1.wait()
13
>>> r2.wait()
32
>>>
Passing nonblocking=True
to any proxy method causes it to immediately return a
special "non-blocking response" object which has a wait()
method. The wait()
method waits until the code has finished executing on the remote server and
returns the response value. If the remote side raised an exception, wait()
will raise the same exception (unless you pass origexc
-- see below).
You can also use the convenience functions eval_multi
, call_multi
, and
call_method_multi
to call the same function in parallel on multiple systems:
>>> call_multi([rmt, rmt2], 'addvals', 2, 3)
[5, 5]
>>>
This function calls a specific function on multiple systems, waits for all of the responses, then returns a list of their responses.
Besides nonblocking
, there are other common keyword arguments that can be
passed to remote calls:
oncomplete
- If this is specified, then the remote call will return
immediately, and will call this function when the remote call completes. This
can be either a function which will be called as func(response)
, or a tuple
of (func, arg1, arg2, ...)
which will be called as func(response, arg1,
arg2, ...)
. If you're using the standard Client
class, completion functions
will not be called until something calls read_response()
on the client
object, or calls wait()
on a non-blocking response associated with the
client. If you're using ThreadedClient
, completion functions are called from
the thread which reads responses from the server.
onerror
- Identical to oncomplete, but called with a RemoteException
instance instead of a return value when the remote call raises an
exception. If oncomplete
is specified, but onerror
is not, the
oncomplete
function is called in both cases.
threadid
- An arbitrary integer specifying the thread on the server to run
the request in. If not specified, the current default will be used. The
default can be changed by calling set_default_thread()
on the client
object. If the specified thread does not exist on the server, it is
created. If the threadid is the special constant easycluster.SINGLE
, a new
thread is created on the server for this request, then exits.
origexc
- If True
(default), and the request raises an exception, it will
print the remote stack trace to the screen and raise the original
exception. If it is False
, a RemoteException
is raised instead. If it is
the value 'quiet'
, then the original exception is raised without a stack
trace being printed. RemoteException
instances have the two attributes:
orig
, the original exception; and text
, the stack trace on the server.
You can start multiple threads on the same server by using non-blocking
responses with threadid
:
>>> r1 = rmt.addvals(101, 102, nonblocking=True, threadid=1)
>>> r2 = rmt.addvals(222, 333, nonblocking=True, threadid=2)
>>> r3 = rmt.addvals(555, 888, nonblocking=True, threadid=3)
>>> [r1.wait(), r2.wait(), r3.wait()]
[203, 555, 1443]
If your master script is already multi-threaded, you can use ThreadedClient
to automatically manage server threads for you.
The ThreadedClient
class starts a separate thread to read responses from the
server. Because of this, completion functions are called as soon as the remote
call returns, and the thread actively monitors the server to ensure that it
hasn't gone down or locked up.
ThreadedClient
will detect if you call remote functions from a separate thread
in your master script, and will start a corresponding thread on the server to
handle your request:
>>> import threading
>>> tc1 = ThreadedClient(key, 'host1')
>>> tc2 = ThreadedClient(key, 'host2')
>>>
>>> def client_thread(id, a, b):
... print 'Thread %d: starting' % id
... val1 = tc1.addvals(a, b)
... print 'Thread %d: tc1 returned %r' % (id, val1)
... val2 = tc2.addvals(a, b)
... print 'Thread %d: tc2 returned %r' % (id, val2)
... print 'Thread %d: finished' % id
...
>>> def run_threads():
... t1 = threading.Thread(target=client_thread, args=(1, 200, 500))
... t2 = threading.Thread(target=client_thread, args=(2, 300, 600))
... t1.start(); t2.start()
... t1.join(); t2.join()
...
>>> run_threads()
Thread 1: starting
Thread 2: starting
Thread 1: tc1 returned 700
Thread 2: tc1 returned 900
Thread 1: tc2 returned 700
Thread 2: tc2 returned 900
Thread 1: finished
Thread 2: finished
>>>
Once threads in your master script exit, ThreadedClient
will detect it and
stop the corresponding thread on the server.
On POSIX systems (Linux, BSD, Solaris), a command called easycluster
should be
installed in /usr/local/bin
. On Windows, the main entry point is installed
under %PYTHON%\scripts\easycluster.exe
. With Python 2.7 and 3.2, you can also
run python -m easycluster
.
 Both the server and the client need this keyfile to be able to communicate:
easycluster -g secret.key
This will create a new file, called 'secret.key' which is readable only by the user that created it. You can then run the server with:
easycluster -S -k secret.key
If you don't want to see every remote call logged, run:
easycluster -S -k secret.key -c QuietServer
You can have the easycluster service start automatically on boot on Windows, Solaris, and Linux (Redhat, Debian, Ubuntu, and SuSE have been tested):
easycluster --install
This will register a service with the system which will start on the next
boot. You can unregister it with easycluster --uninstall
. Once the service is
registered, you can start and stop it with easycluster --start
and
easycluster --stop


[1]
marvellous location but does not trade on this advantage by offering a lower standard of service .
[2]
romance deal for our 43th anniversary , according to my husband , was very good value .


|
Iceman The first major obstacle was optional and about half the people skipped it, but after that we started hitting obstacles that weren't optional. The Iceman struck fast freezing us in our tracks. | |
|
Old Miner After Carbonate, we dropped into Chism Gulch and stopped for lunch at the base of Heckman Hill, aka Widowmaker Hill. Heckman Hill is the most challenging part of the Old Miner and it requires lots of throttle no matter what modifications you may have made to your vehicle. | |
|
Mount Moriah Mount Moriah starts out with a rocky and muddy hill climb and continues on with some wicked off-camber sections. The hill climb isn't too tough, but the off-camber sections require careful driving. After the off-camber secion, I was heading down a steep decent when smoke started pouring out of my dash. |