✨Extensible worker for Node.js that works with both Zeebe and Camunda BPM platforms powered by TypeScript ✨
We needed a framework to help us quickly build workers used to execute tasks. Zeebe provides a good fit with our stack. Until this is production ready, we are keeping the Camunda Bpm. Indeed, Zeebe is in developper preview. In order to make the transition smoother, we use this package. We can experiment and choose the Camunda platform we want without rewritting our business logic.
This package can be useful because:
docs
subdirectorynpm i workit-camunda
or using the generator below
This generator will help you during your development with this library. It provides handy tools.
npm i -g workit-cli
workit init
workit create task --file /your/path.bpmn
workit create task
Switching between Zeebe and the bpmn platform is easy as specifying a TAG
to the IoC.
const worker = IoC.get<Worker>(CORE_IDENTIFIER.worker, TAG.camundaBpm); // or TAG.zeebe
worker.start();
worker.run();
const manager = IoC.get<IWorkflowClient>(CORE_IDENTIFIER.client_manager, TAG.camundaBpm); // or TAG.zeebe
const fullpath = `${process.cwd()}/sample/BPMN_DEMO.bpmn`;
await manager.deployWorkflow(fullpath);
const manager = IoC.get<IWorkflowClient>(CORE_IDENTIFIER.client_manager, TAG.camundaBpm); // or TAG.zeebe
await manager.getWorkflows()
const manager = IoC.get<IWorkflowClient>(CORE_IDENTIFIER.client_manager, TAG.camundaBpm); // or TAG.zeebe
await manager.getWorkflow({ bpmnProcessId: "DEMO" });
const manager = IoC.get<IWorkflowClient>(CORE_IDENTIFIER.client_manager, TAG.camundaBpm); // or TAG.zeebe
await manager.updateVariables({
processInstanceId: "5c50c48e-4691-11e9-8b8f-0242ac110002",
variables: { amount: 1000 }
});
const manager = IoC.get<IWorkflowClient>(CORE_IDENTIFIER.client_manager, TAG.camundaBpm); // or TAG.zeebe
await manager.publishMessage({
correlation: {},
name: "catching",
variables: { amount: 100 },
timeToLive: undefined, // only supported for Zeebe
messageId: "5c50c48e-4691-11e9-8b8f-0242ac110002"
});
const manager = IoC.get<IWorkflowClient>(CORE_IDENTIFIER.client_manager, TAG.camundaBpm); // or TAG.zeebe
await manager.createWorkflowInstance({
bpmnProcessId: "MY_BPMN_KEY",
variables: {
hello: "world"
}
});
const manager = IoC.get<IWorkflowClient>(CORE_IDENTIFIER.client_manager, TAG.camundaBpm); // or TAG.zeebe
await manager.cancelWorkflowInstance("4651614f-4b3c-11e9-b5b3-ee5801424400");
const manager = IoC.get<IWorkflowClient>(CORE_IDENTIFIER.client_manager, TAG.camundaBpm); // or TAG.zeebe
await manager.resolveIncident("c84fce6c-518e-11e9-bd78-0242ac110003");
You can define many tasks to one worker. It will handle all messages and will route to the right tasks.
export class HelloWorldTask extends TaskBase<IMessage> {
// You can type message like IMessage<TBody, TProps> default any
public execute(message: IMessage): Promise<IMessage> {
const { properties } = message;
console.log(`Executing task: ${properties.activityId}`);
console.log(`${properties.bpmnProcessId}::${properties.processInstanceId} Servus!`);
// put your business logic here
return Promise.resolve(message);
}
}
enum LOCAL_IDENTIFIER {
// sample_activity must match the activityId in your bpmn
sample_activity= 'sample_activity'
}
// Register your task
IoC.bindTo(HelloWorldTask, LOCAL_IDENTIFIER.sample_activity);
You can even make complex binding like
IoC.bindTask(HelloWorldTaskV2, LOCAL_IDENTIFIER.activity1, { bpmnProcessId: BPMN_PROCESS_ID, version: 2 });
If you have installed workit-cli
, you can do workit create task
and everything will be done for you.
const worker = IoC.get<Worker>(CORE_IDENTIFIER.worker, TAG.zeebe); // or TAG.camundaBpm
worker.once('starting', () => {
// slack notification
});
worker.once('stopping', () => {
// close connections
});
worker.once('stopped', () => {
// slack notification
});
const handler = worker.getProcessHandler();
handler.on('message', (msg: IMessage) => {
// log/audit
});
handler.on('message-handled', (err: Error, msg: IMessage) => {
if (err) {
// something wrong
} else {
// everything is fine
}
});
worker.start();
worker.run(); // Promise
worker.stop(); // Promise
const workerConfig = {
interceptors: [
async (message: IMessage): Promise<IMessage> => {
// do something before we execute task.
return message;
}
]
};
IoC.bindToObject(workerConfig, CORE_IDENTIFIER.worker_config);
WorkIt integrates opentracing in order to provide instrumentations to developers. By default, we bound a NoopTracer
but you can provide your own and it must be compatible to opentracing interface. We use Domain Probe pattern in our Camunda clients. This way, we allow developers to bind their own and/or add their instrumentations like logs and metrics. We strongly recommand to use this kind of pattern in your task.
// Simply bind your custom tracer object like this
IoC.bindToObject(tracer, CORE_IDENTIFIER.tracer);
Now, you can access to spans
property in IMessage
object.
export class HelloWorldTask extends TaskBase<IMessage> {
public execute(message: IMessage): Promise<IMessage> {
const { properties, spans } = message;
// --------------------------
// You can use doamain probe pattern here.
const tracer = spans.tracer();
const context = spans.context();
const span = tracer.startSpan("HelloWorldTask.execute", { childOf: context });
span.log({ test: true });
// put your business logic here
span.finish();
return Promise.resolve(message);
}
}
You can look to sample
folder where we provide an example (parallel.ts) using Jaeger.
const configBase: ICamundaConfig = {
workerId: 'demo',
baseUrl: `__undefined__`,
topicName: 'topic_demo'
};
// For Camunda BPM platform
const bpmnPlatformClientConfig = { ...configBase, baseUrl: 'http://localhost:8080/engine-rest', maxTasks: 32, autoPoll: false, use: [] };
IoC.bindToObject(bpmnPlatformClientConfig, CORE_IDENTIFIER.camunda_external_config);
// For Zeebe platform
const zeebeClientConfig = { ...configBase, { baseUrl: 'localhost:2650', timeout: 2000 };
// Zeebe exporter (Elasticsearch instance)
const zeebeElasticExporterConfig = {
url: `http://localhost:9200`,
};
IoC.bindToObject(zeebeClientConfig, CORE_IDENTIFIER.zeebe_external_config);
IoC.bindToObject(zeebeElasticExporterConfig, CORE_IDENTIFIER.zeebe_elastic_exporter_config)
By default, we define simple strategy for sucess or failure. We strongly recommend you to provide yours as your app trigger specific exceptions. Strategies are automatically handled. If an exeption is bubble up from the task, failure strategy is raised, otherwise it's success.
TODO: PROVIDE SAMPLE
npm test
kubernetes/run
In your terminal
docker/run
docker run -d --name camunda -p 8080:8080 camunda/camunda-bpm-platform:latest
// Go: http://localhost:8080/camunda - user/password : `demo/demo`
We use SemVer for versioning. For the versions available, see the tags on this repository.
| workit-camunda | Zeebe | Camunda BPM |
|---|---|---|
| 2.2.0 | 0.20.x | 7.6 to latest |
| 2.1.0 | 0.19.x | 7.6 to latest |
| 2.0.1 | 0.18.x | 7.6 to latest |
| < 1.0.0 | <= 0.17.0 | 7.6 to latest |
See also the list of contributors who participated in this project.
Please read CONTRIBUTING.md for details on our code of conduct, and the process for submitting pull requests to us.
This project is licensed under the MIT License - see the LICENSE file for details
workit-cli
developmentGenerated using TypeDoc


{{ site.name }}
About
Facilities
Getting There
Join
Benefits
Blog
News
Events
Projects
Wiki
Rules
Policies
Code of Conduct
etc.


CelOS is a distribution for everyone, and so we make sure that you can change your theme, language, text-size and more so that you are the most comfortable at your computer!
CelOS is a distribution for everyone, and so we make sure that you can change your theme, language, text-size and more so that you are the most comfortable at your computer!


Talon for Twitter - FAQ, Support, and Tutorials
I recommend using the search bar at the top to help you find content, by keyword.I get a significant amount of emails, every day. No matter how fast I am to respond, if you can spend a minute to find what you are looking for, that means more development time for me, more features for you, and no waiting on a response to your question.


main.cpp Example File
graphicsview/boxes/main.cpp/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the demonstration applications of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:BSD$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission.   ** ** $QT_END_LICENSE$ ** ****************************************************************************/ //#include <GL/glew.h> #include "glextensions.h" #include "scene.h" #include <QtWidgets> #include <QGLWidget> class GraphicsView : public QGraphicsView { public: GraphicsView() { setWindowTitle(tr("Boxes")); setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform); //setRenderHints(QPainter::SmoothPixmapTransform); } protected: void resizeEvent(QResizeEvent *event) override { if (scene()) scene()->setSceneRect(QRect(QPoint(0, 0), event->size())); QGraphicsView::resizeEvent(event); } }; inline bool matchString(const char *extensionString, const char *subString) { int subStringLength = strlen(subString); return (strncmp(extensionString, subString, subStringLength) == 0) && ((extensionString[subStringLength] == ' ') || (extensionString[subStringLength] == '\0')); } bool necessaryExtensionsSupported() { const char *extensionString = reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS)); const char *p = extensionString; const int GL_EXT_FBO = 1; const int GL_ARB_VS = 2; const int GL_ARB_FS = 4; const int GL_ARB_SO = 8; int extensions = 0; while (*p) { if (matchString(p, "GL_EXT_framebuffer_object")) extensions |= GL_EXT_FBO; else if (matchString(p, "GL_ARB_vertex_shader")) extensions |= GL_ARB_VS; else if (matchString(p, "GL_ARB_fragment_shader")) extensions |= GL_ARB_FS; else if (matchString(p, "GL_ARB_shader_objects")) extensions |= GL_ARB_SO; while ((*p != ' ') && (*p != '\0')) ++p; if (*p == ' ') ++p; } return (extensions == 15); } int main(int argc, char **argv) { QApplication app(argc, argv); if ((QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_1_5) == 0) { QMessageBox::critical(0, "OpenGL features missing", "OpenGL version 1.5 or higher is required to run this demo.\n" "The program will now exit."); return -1; } int maxTextureSize = 1024; QGLWidget *widget = new QGLWidget(QGLFormat(QGL::SampleBuffers)); widget->makeCurrent(); if (!necessaryExtensionsSupported()) { QMessageBox::critical(0, "OpenGL features missing", "The OpenGL extensions required to run this demo are missing.\n" "The program will now exit."); delete widget; return -2; } // Check if all the necessary functions are resolved. if (!getGLExtensionFunctions().resolve(widget->context())) { QMessageBox::critical(0, "OpenGL features missing", "Failed to resolve OpenGL functions required to run this demo.\n" "The program will now exit."); delete widget; return -3; } // TODO: Make conditional for final release QMessageBox::information(0, "For your information", "This demo can be GPU and CPU intensive and may\n" "work poorly or not at all on your system."); widget->makeCurrent(); // The current context must be set before calling Scene's constructor Scene scene(1024, 768, maxTextureSize); GraphicsView view; view.setViewport(widget); view.setViewportUpdateMode(QGraphicsView::FullViewportUpdate); view.setScene(&scene); view.show(); return app.exec(); }


Git becomes much more valuable when multiple people can collaborate on the same project. This is accomplished by hosting the repo on a remote server. Users occasionally download new changes from the remote repo and upload new changes to the remote repo. Using git with a remote server or website differs slightly depending upon the installation. There are websites like github, gitlab, and gitbucket which will manage your remote repos for you; git can also be installed directly on private servers. Consult those sites for more information. For this section of the tutorial, I will show you the general commands which will be the same across all platforms. Sadly, you won’t be able to follow along like before.
We often don’t start new projects from scratch. Instead, we are contributing to mature codebases. Git allows us to make a local copy of a codebase by typing git clone <repo url>.
Once we have a local clone of the repo, it will function like the repo we created at the beginning of the tutorial. The only difference is that other users can make changes to the remote repo too. To download the newest changes from the remote repo type git pull. This is a combination of the commands git fetch(which grabs the newest changes from the remote repo) and git merge(which tries to merge those changes into your current branch. It may result in a merge conflict which you will have to solve by looking at the diff.
You can make changes to the local repo as shown earlier in this tutorial. Add your changed files and make a commit. To add these changes to the remote repo type git push. It may also result in merge conflicts that you will have to resolve.
Ending Tips
You’ve made it to the end of the tutorial. You now know enough about git to be dangerous. Here are two basic tips for how git should be used.
Never make changes directly on the master branch(origin). Always make a new branch and then merge those changes in when they are ready.
Before pushing your commits always pull from the server/website.
Be sure to review this tutorial if you’re unsure about anything or seek out other resources. I’ve included some of my favorite resources below that I consulted while building this website.
Additional Resources
git - the simple guide : This resource shows a detailed list of git commands and their functions.
Github - Git Guide: This resources shows detailed explanations of how git commands work and when to use them.
Pro Git: This book details how to the git program works, how to use it, and how to install git on your own server. Very detailed!


You are authorising:
{{details.conveyancer_name}}
{{details.conveyancer_address}}
To act on your behalf on:
{{details.property_road}}
- Title number
- {{ details.title_number }}
To make the following changes:
{{details.task}} property


--- layout: default title: Portfolio section_id: portfolio challenges: - image: images/design-400.png title: Design link_to: challenge-item-design.html klass: graphi-design desc: Design - image: images/protect-400.png title: Protect link_to: challenge-item-protect.html klass: graphi-design desc: Protect - image: images/orchestrate-400.png title: Orchestrate link_to: challenge-item-orchestrate.html klass: graphi-design desc: Orchestrate - image: images/deploy-400.png title: Deploy link_to: challenge-item-deploy.html klass: graphi-design desc: Deploy ---
Designs are in, and the judges put the participantes to the test at this point. Designers have had to justify architectural decisions that have gotten them to the second phase of the competition. This is where the competition starts to get even more tough.
Does your design stand up to physicial difficulties? Perhaps an all around disaster? This is where things begin to get even more interesting as participants must illustrate how they can adapt to challenges within the original designs.
Who knows, what could happen at this point. You may even find yourself building out resiliency in someone else's design. That's what it takes to be a Virtual Design Master.


{{ page.story.Title }} {{ page.story['Primary image caption'] }} {{ page.story['Primary image rights information'] }} You May Also Like There are 123 comments
{{ page.story['Primary image caption'] }} {{ page.story['Primary image rights information'] }} You May Also Like There are 123 comments


Last updated: 2021-10-12
Checks: 7 0
Knit directory: myTidyTuesday/
This reproducible R Markdown analysis was created with workflowr (version 1.6.2). The Checks tab describes the reproducibility checks that were applied when the results were created. The Past versions tab lists the development history.
Great! Since the R Markdown file has been committed to the Git repository, you know the exact version of the code that produced these results.
Great job! The global environment was empty. Objects defined in the global environment can affect the analysis in your R Markdown file in unknown ways. For reproduciblity it’s best to always run the code in an empty environment.
The command set.seed(20210907)
was run prior to running the code in the R Markdown file. Setting a seed ensures that any results that rely on randomness, e.g. subsampling or permutations, are reproducible.
Great job! Recording the operating system, R version, and package versions is critical for reproducibility.
Nice! There were no cached chunks for this analysis, so you can be confident that you successfully produced the results during this run.
Great job! Using relative paths to the files within your workflowr project makes it easier to run your code on other machines.
Great! You are using Git for version control. Tracking code development and connecting the code version to the results is critical for reproducibility.
The results in this page were generated with repository version 7382cfe. See the Past versions tab to see a history of the changes made to the R Markdown and HTML files.
Note that you need to be careful to ensure that all relevant files for the analysis have been committed to Git prior to generating the results (you can use wflow_publish
or wflow_git_commit
). workflowr only checks the R Markdown file, but you know if there are other scripts or data files that it depends on. Below is the status of the Git repository when the results were generated:
Ignored files:
Ignored: .Rhistory
Ignored: .Rproj.user/
Ignored: catboost_info/
Ignored: data/2021-10-11/
Ignored: data/CNHI_Excel_Chart.xlsx
Ignored: data/CommunityTreemap.jpeg
Ignored: data/Community_Roles.jpeg
Ignored: data/YammerDigitalDataScienceMembership.xlsx
Ignored: data/accountchurn.rds
Ignored: data/acs_poverty.rds
Ignored: data/advancedaccountchurn.rds
Ignored: data/airbnbcatboost.rds
Ignored: data/australiaweather.rds
Ignored: data/baseballHRxgboost.rds
Ignored: data/baseballHRxgboost2.rds
Ignored: data/fmhpi.rds
Ignored: data/grainstocks.rds
Ignored: data/hike_data.rds
Ignored: data/nber_rs.rmd
Ignored: data/netflixTitles2.rds
Ignored: data/spotifyxgboost.rds
Ignored: data/spotifyxgboostadvanced.rds
Ignored: data/us_states.rds
Ignored: data/us_states_hexgrid.geojson
Ignored: data/weatherstats_toronto_daily.csv
Untracked files:
Untracked: code/YammerReach.R
Untracked: code/work list batch targets.R
Note that any generated files, e.g. HTML, png, CSS, etc., are not included in this status report because it is ok for generated content to have uncommitted changes.
These are the previous versions of the repository in which changes were made to the R Markdown (analysis/Survival.Rmd
) and HTML (docs/Survival.html
) files. If you’ve configured a remote Git repository (see ?wflow_git_remote
), click on the hyperlinks in the table below to view the files as they were in that past version.
| File | Version | Author | Date | Message |
|---|---|---|---|---|
| Rmd | 7382cfe | opus1993 | 2021-10-12 | update publication date |
| html | aca705d | opus1993 | 2021-10-12 | Build site. |
| Rmd | 4fc6d48 | opus1993 | 2021-10-12 | add Jessice Streeter DC satRdays |
| html | bff04a3 | opus1993 | 2021-10-12 | Build site. |
| Rmd | aff51b1 | opus1993 | 2021-10-12 | add Logrank Test |
| html | 936619f | opus1993 | 2021-09-08 | Build site. |
| Rmd | edd4303 | opus1993 | 2021-09-08 | knit_global |
| html | d6bb4c2 | opus1993 | 2021-09-08 | Build site. |
| Rmd | b33c0f7 | opus1993 | 2021-09-08 | Add censoring image and Zeltzer playlist |
| html | c72b825 | opus1993 | 2021-09-07 | Build site. |
| Rmd | 9059f93 | opus1993 | 2021-09-07 | wflow_publish("analysis/Survival.Rmd") |
Survival analysis is one of the oldest subfields of statistics. Basic life-table methods, including techniques for dealing with censored data, were discovered before 1700, and in the early eighteenth century, the old masters - de Moivre working on annuities, and Daniel Bernoulli studying competing risks for the analysis of smallpox inoculation - developed the modern foundations of the field. Today survival analysis models are important in Engineering, Insurance, Marketing, Medicine, Econometrics, and many other application areas.
ZedStatistics episode 1 is a quick no-code, no-math video introduction:
As of this post’s publication, Justin Zeltzer has released 4 episodes to a playlist.
A simpler characterization might be time-to-event analysis. These are use cases where we are concerned with the time it takes for an event to occur after an exposure. As an example, an exposure might be the date of a medical diagnosis. Or it could be the moment of childbirth. Or the date of delivery of a new tractor to a customer.
Survival analysis data is aligned for all participants to zero at each participant’s exposure time. The event of interest could be death or the failure of a component of the tractor. Time-to-event data always consist of the distinct exposure start and distinct event end for each study participant.
A study subject may be censored due to:
Censored subjects still provide information so must be appropriately included in the analysis. Ignoring censoring leads to an overestimate of the overall survival probability, because the censored subjects only contribute information for part of the follow-up time, and then fall out of the risk set, thus pulling down the cumulative probability of survival.
In industry it is common to track component warranty claims and cost on machines sold. Warranty datasets are heavily censored because the study period rarely aligns with the warranty period for each machine delivered. The study time period and fleet population membership must be carefully considered and explicitly defined. In most cases, exposure is aligned to zero at the warranty start date.
The survival rate is proportion of the study population that has NOT (yet) experienced the event of interest divided by the whole study population membership within the study timeframe.
First, duration times are always positive. Recall that traditional linear regression models make a number of assumptions for independence and normality that are no longer valid in this space. There are distributions, like Weibull, that better represent the problem space. More on this topic later.
The survival
package is the cornerstone of the entire R survival analysis edifice. Not only is the package itself rich in features, but the object created by the Surv()
function, which contains failure time and censoring information, is the basic survival analysis data structure in R. Dr. Terry Therneau, the package author, began working on the survival package in 1986. The first public release, in late 1989, used the Statlib service hosted by Carnegie Mellon University. Thereafter, the package was incorporated directly into Splus, and subsequently into R.
Let’s look at a quick manual example graphically before moving on. The first thing to do is to use Surv()
to build the standard survival object. In this case, the variable time
is vector of durations, and the variable event
is a binary vector of 1’s for the event of interest and 0’s for lack of event at the end of the study period (censored).
time <- c(5, 6, 2, 4, 4)
event <- c(1, 0, 0, 1, 1)
Surv(time, event)
[1] 5 6+ 2+ 4 4
A simple way of depicting the survival rate of the population Kaplan-Meier estimator, or product limit estimator chart. A plot of the Kaplan–Meier estimator is a series of declining horizontal steps which, with a large enough sample size, approaches the true survival function for that population. The value of the survival function between successive distinct sampled observations (“clicks”) is assumed to be constant. Note that there is no drop denoted at the time points of censoring.
sobj <- data.frame(time = time, event = event)
km <- survfit(Surv(time, event) ~ 1, data = sobj) # the survfit object builds the kaplan-meier est
ggsurvplot(
fit = km, conf.int = FALSE,
risk.table = "nrisk_cumevents",
legend = "none"
) +
labs(
title = "Kaplan-Meier (KM) Curve",
subtitle = "Each step down represents an event of interest"
)
The ggfortify
package also contains methods for autoplotting simple survival plots.
ggfortify:::autoplot.survfit(km) +
labs(
title = "Kaplan-Meier (KM) Curve",
subtitle = "Each step down represents an event of interest"
)
It is important to note here that the KM curve is a non-parametric curve. That is, the curve is simply a description of the underlying data and that there are no parameters involved. Most use cases in this problem space ask that we model to predict the behavior of a population, or the behavior of a change in a treatment of the population. To do so will require that we introduce other concepts, like the hazard
parameter. More on this later.
All of the questions are expressed along the dimensions of the Survival Probability and the duration time to reach that threshold. In many cases, Survival quartiles convey a reasonable sense of the distribution of outcomes.
Jessica Streeter delivered a short 2020 talk covering other applications of survival analysis techniques, here:
The survival function can be expressed mathematically as the Probability that the duration is longer than t, or as 1 minus the probability of Failure for a duration longer than t.
\[S(t)=1-F(t)=P(T>t)\]
Let’s pause here and consider what the x-axis duration units can be. It would be easy to see how the duration would be calendar time in years, months, or even days. But survival problems can also be modeled in hours or minutes. And in some cases, series like a sequence of pitches in baseball or engine operating hours are suitable for survival analysis. A pitcher that is not pitching and an engine that is not running will not likely experience events of interest.
Let’s take a closer look at a German Breast Cancer dataset to explore how to answer the question “What is the probability that a breast cancer patient survives longer than 5 years?” The set includes 686 women tracked in a study along with characteristics of each patient. The censoring indicator cens
equals 1 for death and 0 for no death within the study timeframe (censored) and the time unit is in days.
data(GBSG2, package = "TH.data") # breast cancer patients, time to death
ggplot(GBSG2, aes(factor(cens))) +
geom_bar(fill = hrbrthemes::ipsum_pal()(1)) +
labs(
title = "German Breast Cancer Study Group 2",
caption = "source: GBSG2 dataset"
)
As noted above, with a large enough sample size, the KM curve approaches the true survival function for that population. We will return to this dataset to explore the impact of the study participants features on survival rates.
sobj <- Surv(GBSG2$time, GBSG2$cens)
km <- survfit(sobj ~ 1, data = sobj) # the survfit object builds the kaplan-meier est
ggsurvplot(
fit = km, conf.int = FALSE,
risk.table = "nrisk_cumevents",
legend = "none"
) + # when there is only one curve of all patients
labs(
title = "German Breast Cancer Study Group 2",
caption = "source: GBSG2 dataset",
x = "Time in days"
)
Many survival analysis questions start with some form of asking whether subsets of populations are statistically different from one another, given the available data. We have to be careful to avoid jumping immediately to causal conclusions. Justin Zeltzer’s fourth video walks through the math.
Survival analysis encompasses two complementary quantitative views, the survivor function, denoted by \(S(t)\), and the hazard function, denoted by \(h(t)\). The survivor function \(S(t)\) gives the probability that a person survives longer than some specified time \(t\): that is, \(S(t)\) gives the probability that the random variable \(T\) exceeds the specified time \(t\). The survivor function is fundamental to a survival analysis, because obtaining survival probabilities for different values of \(t\) provides crucial summary information from survival data.
The hazard function, denoted by \(h(t)\), is given by the formula: \(h(t)\) equals the limit, as \(\Delta{t}\) approaches zero, of a probability statement about survival, divided by \(\Delta{t}\), where \(\Delta{t}\) denotes a small interval of time.
\[ h(t)=\lim_{\Delta{t}\to{0}}\frac{P(t\le T < t + \Delta{t} | T \ge t)}{\Delta{t}} \]
Before getting into the specifics of the formula, let’s consider a conceptual interpretation. The hazard function \(h(t)\) gives the instantaneous potential per unit time for the event to occur, given that the individual has survived up to time \(t\). Note that, in contrast to the survivor function, which focuses on not failing, the hazard function focuses on failing, that is, on the event occurring. Thus, in some sense, the hazard function can be considered as giving the opposite side of the information given by the survivor function.
To get an idea of what we mean by instantaneous potential, consider the concept of velocity. If, for example, you are driving in your car and you see that your speedometer is registering 60 mph, what does this reading mean? It means that if in the next hour, you continue to drive this way, with the speedometer exactly on 60, you would cover 60 miles. This reading gives the potential, at the moment you have looked at your speedometer, for how many miles you will travel in the next hour. However, because you may slow down or speed up or even stop during the next hour, the 60-mph speedometer reading does not tell you the number of miles you really will cover in the next hour. The speedometer tells you only how fast you are going at a given moment; that is, the instrument gives your instantaneous potential or velocity.
Similar to the idea of velocity, a hazard function \(h(t)\) gives the instantaneous potential at time \(t\) for getting an event, like death or some disease of interest, given survival up to time \(t\). The “given” part, that is, surviving up to time \(t\), is analogous to recognizing in the velocity example that the speedometer reading at a point in time inherently assumes that you have already traveled some distance (i.e., survived) up to the time of the reading.
In mathematical terms, the given part of the formula for the hazard function is found in the probability statement in the numerator to the right of the limit sign. This statement is a conditional probability because it is of the form, “P of A, given B,” where the P denotes probability and where the long vertical line separating A from B denotes “given.” In the hazard formula, the conditional probability gives the probability that a person’s survival time, \(T\), will lie in the time interval between \(t\) and \(t + \Delta{t}\), given that the survival time is greater than or equal to \(t\). Because of the given sign here, the hazard function is sometimes called a conditional failure rate.
Be careful to note that the hazard is a rate rather than a probability. Note that in the hazard function formula, the expression to the right of the limit sign gives the ratio of two quantities. The numerator is the conditional probability we just discussed. The denominator is \(\Delta{t}\), which denotes a small time interval. By this division, we obtain a probability per unit time, which is no longer a probability but a rate. In particular, the scale for this ratio is not 0 to 1, as for a probability, but rather ranges between 0 and infinity, and depends on whether time is measured in days, weeks, months, or years, etc.
When we take the limit of the right-side expression as the time interval approaches zero, we are essentially getting an expression for the instantaneous probability of failing at time \(t\) per unit time. Another way of saying this is that the conditional failure rate or hazard function \(h(t)\) gives the instantaneous potential for failing at time \(t\) per unit time, given survival up to time \(t\).
As with a survivor function, the hazard function \(h(t)\) can be graphed as \(t\) ranges over various values. In contrast to a survivor function, the graph of \(h(t)\) does not have to start at 1 and go down to zero, but rather can start anywhere and go up and down in any direction over time. In particular, for a specified value of \(t\), the hazard function \(h(t)\) has the following characteristics:
Of the two functions we have considered, \(S(t)\) and \(h(t)\), the survivor function is more naturally appealing for analysis of survival data, simply because \(S(t)\) directly describes the survival experience of a study cohort. However, the hazard function is also of interest for the following reasons:
Regardless of which function \(S(t)\) or \(h(t)\) one prefers, there is a clearly defined relationship between the two. In fact, if one knows the form of \(S(t)\), one can derive the corresponding \(h(t)\), and vice versa.
In any actual data analysis, R / Stata / SAS / Matlab can make the numerical transformation from \(S(t)\) to \(h(t)\), or vice versa, without the user ever having to use either formula. The point here is simply that if you know either \(S(t)\) or \(h(t)\), you can get the other directly.
To create a parametric survival model in R, the survival object from above is simply fed into the survreg()
function of the {survival}
package. As a first pass demonstration here, we will use formula notation to model on none of the data features with ~ 1
. Model probabilities between 0.01 and 0.99 are fed into the model to predict the time at each, and the associated plot is shown here:
# Weibull model
wb <- survival::survreg(Surv(time, cens) ~ 1, GBSG2)
# Retrieve survival curve from model probabilities
surv <- seq(.99, .01, by = -.01)
# Get time for each probability
t <- predict(wb, type = "quantile", p = 1 - surv, newdata = data.frame(1))
# Create data frame with the information
surv_wb <- data.frame(
time = t, surv = surv,
upper = NA, lower = NA, std.err = NA
)
ggsurvplot_df(fit = surv_wb, surv.geom = geom_line, legend = "none") +
labs(
title = "German Breast Cancer Study Group 2",
subtitle = "Weibull model",
caption = "source: GBSG2 dataset",
x = "Time in days"
)
The base Weibull model curve is a smoothed parametric form of the stepped Kaplan-Meier curve that we saw earlier. The power of the parametric approach becomes apparent when we model on the differences in features within the dataset for inference. Recall in the German Breast Cancer dataset that it includes patient attributes including classifications for the size of the tumor tsize
and whether hormonal therapy was applied as horTh
.
GBSG2 %>%
head() %>%
knitr::kable()
| horTh | age | menostat | tsize | tgrade | pnodes | progrec | estrec | time | cens |
|---|---|---|---|---|---|---|---|---|---|
| no | 70 | Post | 21 | II | 3 | 48 | 66 | 1814 | 1 |
| yes | 56 | Post | 12 | II | 7 | 61 | 77 | 2018 | 1 |
| yes | 58 | Post | 35 | II | 9 | 52 | 271 | 712 | 1 |
| yes | 59 | Post | 17 | II | 4 | 60 | 29 | 1807 | 1 |
| no | 73 | Post | 35 | II | 1 | 26 | 65 | 772 | 1 |
| no | 32 | Pre | 57 | III | 24 | 0 | 13 | 448 | 1 |
Because the tumor size tsize
is numeric, we will project the 25th, 50th, and 75th quantile to understand the effect. Survival for each combination of features, or covariates, are modeled as survreg(Surv(time, cens) ~ horTh + tsize, data = GBSG2)
. Generally speaking, the steps to crafting the visualization are
wbmod <- survreg(Surv(time, cens) ~ horTh + tsize, data = GBSG2)
newdat <- expand.grid(
horTh = levels(GBSG2$horTh),
tsize = quantile(GBSG2$tsize, probs = c(0.25, 0.5, 0.75))
)
surv <- seq(0.99, 0.01, by = -0.01)
t <- predict(wbmod, type = "quantile", p = 1 - surv, newdata = newdat)
surv_wbmod_wide <- cbind(newdat, t)
# transpose the data frame
surv_wbmod <- reshape2::melt(surv_wbmod_wide,
id.vars = c("horTh", "tsize"),
variable.name = "surv_id", value.name = "time"
)
surv_wbmod$surv <- surv[as.numeric(surv_wbmod$surv_id)]
# add variables required by the plotting function
surv_wbmod[, c("upper", "lower", "std.err", "strata")] <- NA
ggsurvplot_df(surv_wbmod,
surv.geom = geom_line,
linetype = "horTh", color = "tsize", legend.title = NULL
) +
labs(
title = "German Breast Cancer Study Group 2",
subtitle = "Weibull models",
caption = "source: GBSG2 dataset",
x = "Time in days"
)
In addition to Weibull, the surveg()
function will model exponential, lognormal, gaussian, logistic, and loglogistic as parametric distributions on the data provided. These may be more suitable for small samples where prior information is known about the survival characteristics of the larger population.
In many applications of survival analysis, the interest focuses on how covariates may affect the outcome; in clinical trials, adjustment of treatment effects for effects of other explanatory variables may be crucial if the randomized groups are unbalanced with respect to important prognostic factors, and in epidemiological cohort studies, reliable effects of exposure may be obtained only if some adjustment is made for confounding variables. In these situations, a regression model is useful and the most important model for survival data is the Cox proportional hazards regression model.
cxmod <- coxph(Surv(time, cens) ~ horTh + tsize, data = GBSG2)
broom::tidy(cxmod, exp = TRUE) %>%
knitr::kable()
| term | estimate | std.error | statistic | p.value |
|---|---|---|---|---|
| horThyes | 0.6882602 | 0.1251764 | -2.984494 | 0.0028405 |
| tsize | 1.0153688 | 0.0035637 | 4.279772 | 0.0000187 |
Note that the model flags both horTh and tsize features as significant. However, some caution needs to be exercised in interpreting these results. While the Cox Proportional Hazard’s model is thought to be “robust”, a careful analysis would check the assumptions underlying the model. For example, the Cox model assumes that the covariates do not vary with time. In a vignette that accompanies the survival package Therneau, Crowson and Atkinson demonstrate that the Karnofsky score (karno) is, in fact, time-dependent so the assumptions for the Cox model are not met. The vignette authors go on to present a strategy for dealing with time dependent covariates.
And a data visual:
newdat <- expand.grid(
horTh = levels(GBSG2$horTh),
tsize = quantile(GBSG2$tsize, probs = c(0.25, 0.5, 0.75))
)
rownames(newdat) <- letters[1:6]
cxsf <- survfit(cxmod, data = GBSG2, newdata = newdat, conf.type = "none")
surv_cxmod0 <- surv_summary(cxsf)
surv_cxmod <- cbind(surv_cxmod0, newdat[surv_cxmod0$strata, ])
ggsurvplot_df(surv_cxmod,
fun = "cumhaz",
surv.geom = geom_line,
linetype = "horTh",
color = "tsize",
legend.title = NULL,
censor = FALSE
) +
labs(
title = "German Breast Cancer Study Group 2",
subtitle = "Cox Proportional Hazard models",
caption = "source: GBSG2 dataset",
x = "Time in days"
)
Data scientists who are accustomed to computing ROC curves to assess model performance should be interested in the Concordance statistic. The documentation for the survConcordance()
function in the survival
package defines concordance as “the probability of agreement for any two randomly chosen observations, where in this case agreement means that the observation with the shorter survival time of the two also has the larger risk score. The predictor (or risk score) will often be the result of a Cox model or other regression” and notes that: “For continuous covariates concordance is equivalent to Kendall’s tau, and for logistic regression is is equivalent to the area under the ROC curve.”
fit.test <- cox.zph(cxmod)
ggcoxzph(fit.test)
ggcoxdiagnostics(cxmod,
type = "deviance",
ax.scale = "linear.predictions"
)
ggcoxdiagnostics(cxmod,
type = "schoenfeld",
ax.scale = "time"
)
ggforest(cxmod, data = GBSG2)
The quantity of interest from a Cox regression model is a hazard ratio (HR). The HR represents the ratio of hazards between two groups at any particular point in time. The HR is interpreted as the instantaneous rate of occurrence of the event of interest in those who are still at risk for the event. It is not a risk, though it is commonly interpreted as such.
If you have a regression parameter \(\beta\) (from column estimate in our coxph) then HR = \(e^\beta\). Thus, a HR < 1 indicates reduced hazard of death whereas a HR > 1 indicates an increased hazard of death.
Additional resources
The survival
package also includes robust methods for adjusting survival models for confounding variables, multi-state models (i.e. healthy-illness-death), population contrasts, competing risks, and validation. Much more material can be found in the Vignettes.
sessionInfo()
R version 4.1.1 (2021-08-10)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 10 x64 (build 22000)
Matrix products: default
locale:
[1] LC_COLLATE=English_United States.1252
[2] LC_CTYPE=English_United States.1252
[3] LC_MONETARY=English_United States.1252
[4] LC_NUMERIC=C
[5] LC_TIME=English_United States.1252
attached base packages:
[1] splines stats graphics grDevices utils datasets methods
[8] base
other attached packages:
[1] survminer_0.4.9 ggpubr_0.4.0 survival_3.2-11 broom_0.7.9
[5] forcats_0.5.1 stringr_1.4.0 dplyr_1.0.7 purrr_0.3.4
[9] readr_2.0.2 tidyr_1.1.4 tibble_3.1.4 ggplot2_3.3.5
[13] tidyverse_1.3.1 workflowr_1.6.2
loaded via a namespace (and not attached):
[1] readxl_1.3.1 backports_1.2.1 systemfonts_1.0.2
[4] workflows_0.2.3 plyr_1.8.6 listenv_0.8.0
[7] digest_0.6.28 foreach_1.5.1 htmltools_0.5.2
[10] yardstick_0.0.8 viridis_0.6.1 parsnip_<IP_ADDRESS>0
[13] fansi_0.5.0 ggfortify_0.4.12 magrittr_2.0.1
[16] tune_0.1.6 tzdb_0.1.2 openxlsx_4.2.4
[19] recipes_0.1.17 globals_0.14.0 modelr_0.1.8
[22] gower_0.2.2 extrafont_0.17 R.utils_2.11.0
[25] extrafontdb_1.0 hardhat_0.1.6 rsample_0.1.0
[28] dials_0.0.10 colorspace_2.0-2 rvest_1.0.1
[31] textshaping_0.3.5 haven_2.4.3 xfun_0.26
[34] crayon_1.4.1 jsonlite_1.7.2 zoo_1.8-9
[37] iterators_1.0.13 glue_1.4.2 gtable_0.3.0
[40] ipred_0.9-12 R.cache_0.15.0 car_3.0-11
[43] Rttf2pt1_1.3.9 future.apply_1.8.1 abind_1.4-5
[46] scales_1.1.1 infer_1.0.0 DBI_1.1.1
[49] rstatix_0.7.0 Rcpp_1.0.7 gridtext_0.1.4
[52] viridisLite_0.4.0 xtable_1.8-4 GPfit_1.0-8
[55] foreign_0.8-81 km.ci_0.5-2 lava_1.6.10
[58] prodlim_2019.11.13 httr_1.4.2 ellipsis_0.3.2
[61] farver_2.1.0 R.methodsS3_1.8.1 pkgconfig_2.0.3
[64] nnet_7.3-16 sass_0.4.0 dbplyr_2.1.1
[67] utf8_1.2.2 reshape2_1.4.4 labeling_0.4.2
[70] tidyselect_1.1.1 rlang_0.4.11 DiceDesign_1.9
[73] later_1.3.0 munsell_0.5.0 cellranger_1.1.0
[76] tools_4.1.1 cachem_1.0.6 cli_3.0.1
[79] generics_0.1.0 evaluate_0.14 fastmap_1.1.0
[82] ragg_1.1.3 yaml_2.2.1 rematch2_2.1.2
[85] knitr_1.36 fs_1.5.0 workflowsets_0.1.0
[88] zip_2.2.0 survMisc_0.5.5 nlme_3.1-152
[91] future_1.22.1 whisker_0.4 R.oo_1.24.0
[94] xml2_1.3.2 compiler_4.1.1 rstudioapi_0.13
[97] curl_4.3.2 ggsignif_0.6.3 reprex_2.0.1
[100] lhs_1.1.3 bslib_0.3.1 stringi_1.7.5
[103] highr_0.9 gdtools_0.2.3 hrbrthemes_0.8.0
[106] lattice_0.20-44 Matrix_1.3-4 markdown_1.1
[109] styler_1.6.2 KMsurv_0.1-5 conflicted_1.0.4
[112] vctrs_0.3.8 tidymodels_0.1.4 pillar_1.6.3
[115] lifecycle_1.0.1 furrr_0.2.3 jquerylib_0.1.4
[118] cowplot_1.1.1 data.table_1.14.2 httpuv_1.6.3
[121] R6_2.5.1 promises_<IP_ADDRESS> gridExtra_2.3
[124] rio_0.5.27 parallelly_1.28.1 codetools_0.2-18
[127] MASS_7.3-54 assertthat_0.2.1 rprojroot_2.0.2
[130] withr_2.4.2 mgcv_1.8-36 ggtext_0.1.1
[133] parallel_4.1.1 hms_1.1.1 grid_4.1.1
[136] rpart_4.1-15 timeDate_3043.102 class_7.3-19
[139] rmarkdown_2.11 carData_3.0-4 git2r_0.28.0
[142] pROC_1.18.0 lubridate_1.8.0


{{ content | safe }}
Here are some bible passages that we believe are at the heart of what this icon is all about.
-
{% for item in passages %}
- {{item.reference}} - {{item.text}} {% endfor %}
Questions and Practices: How can we live in the light of {{title}}?
{{iconSettings.qintro}}
-
{% for item in questions %}
-
{{item.question}}
{% if item.practice %} {% set practice = collections.practices | findBySlug(item.practice) %} Find out more about {{practice.data.title}}
{% endif %}
{% endfor %}
How are you going to practice {{title}}?


We're going to access the twitter public timeline through a proxy and format it with a mustache template.
We've added a few features: a manual refresh button an an auto-refresh toggler/setter.


The input csv-like string should represent the serialized format of a binary tree using dfs(pre-order) traversal, where # signifies
a path terminator where no node exists below, e.g:
1,2,#,5,1,#,#,#,3,6,#,#,7,#,#equals to a tree of
1 / \ 2 3 / \ / \ # 5 6 7 / \ / \ / \ 1 # # # # # / \ # #
The sum of the longest path of your tree:


FactoryGirl is a Ruby library to create data for tests.
I read Arjan van der Gaag’s FactoryGirl Tips and Tricks post the other day and found myself disagreeing with a few of the points. Mainly the one where Arjan recommends not using randomized attribute values because they can cause unexpected results in tests.
A randomized attribute value could be something like
1 2 3 4 5 |
|
Whenever you generate a user for a test, you don’t know what gender that user will have unless you explicitly state it:
1 2 |
|
Or you could define and use a more specific factory (or use traits):
1 2 3 4 5 6 7 8 9 10 11 |
|
I think you should only ever rely on the :user
factory to give you a user. Possibly you could also assume that it’s a valid one, and that it has the object graph that a real user would have. But no specific, implicit set of valid attributes should be assumed.
If you’re writing a test that applies to users, you fabricate a :user
. If you’re writing a test that applies specifically to female users, you fabricate a :female_user
, or set that attribute. If you write a test that makes no mention of the user gender, it should pass no matter the gender.
Fixtures vs. factories
If you do assume certain attributes, your factory is more like the Ruby on Rails fixtures that many people use factories to get away from. If you’re writing a test that is explicitly for any user, what’s the value in implicitly knowing their sex? This post is making the case that there is value in making sure you don’t know. This is, of course, also one advantage of factories over fixtures.
Random failures
It’s true that randomized attributes means tests can fail randomly. That’s certainly not ideal. But the alternative is that your app has that same bug, only without ever failing.
Say you write not-at-all-contrived code like this:
1 2 3 4 5 6 7 8 9 10 |
|
You’ve made the mistake of assuming user genders are only ever “male” or “female”, but they can also be “other”. (As an aside, gender identity and gender choices in forms is interesting and complex – just these three options wouldn’t satisfy everyone.)
Now, if your tests always generate female users, this will probably never fail. But if attributes are randomized, you can catch mistakes. Maybe a request test suddenly blows up because something expected a string title but got a nil value.
Certainly, these failures can be a bit frustrating, because they’re harder to reproduce. But would you really prefer to have a perfectly reproducible case of not catching the issue at all? Instead your production users, with their less predictable data, will find the bugs for you.
Once you’ve discovered this bug, you should of course write a test specifically for it, and one that fails predictably. Randomized attributes are certainly no substitute for that. What they are is a safety net, making up somewhat for the fact that you will make mistakes.
Curiously, Arjan’s very next point is that you should test for explicit values, and not rely on factories to have certain implicit values. That is really much of my point. Randomized attribute values enforce this by not letting you rely on them even if you try.
Again, I’m not saying I think random test failures are great. Only that they’re better than having a bug but no test failures whatsoever.
Update – July 8, 2012 at 19:30 CEST:
Arjan’s post was updated to address these points:
One might argue (…) that random values help you discover bugs. While possible, that obviously means you have a bigger problem: holes in your test suite. (…) True, a cryptic error is better than no error, but randomised factories remain a poor substitute for proper unit tests, code review and TDD to prevent these problems.
Randomised factories are therefore not only not worth the effort, they even give you false confidence in your tests, which is worse than having no tests at all.
Even if you do “proper unit tests, code review and TDD” as diligently as anyone, you will make mistakes and have bugs. And given those bugs, you have a chance of finding them sooner by doing it the way I described. I think I made it pretty clear above, but I will reiterate that I don’t see randomized factories as a substitute for anything other than human infallibility. It’s one more safety net.
If your tests and code review are good enough, you won’t ever get the random test failures. You only get them when you mess up. Do TDD and code review, but do this too.
I think that Arjan’s argument about giving false confidence in your tests is the strongest one. I can only say that I do this precisely because I have little confidence in my tests, or anyone else’s. I don’t rig the extra safety net so I can take more risks; I do it because I know that sooner or later, no matter how hard I try, I’ll slip.
Update – July 9, 2012 at 08:15 CEST:
The random failures don’t even have to be random. Or rather, they don’t have to be hard to reproduce.
I just learned something from Mark Dodwell that I hadn’t realized: when you have RSpec or MiniTest randomize the test order (rspec --order random my_spec.rb
), the seed value that you get back isn’t just for recreating that test order. That seed applies to any use of Kernel#rand
, so it can make your random test failures reproducible too.


@* * Copyright 2016 HM Revenue & Customs * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *@ @(inflationProofForm: Form[models.InflationProof])(implicit request: Request[_]) @import uk.gov.hmrc.play.views.html._ @import uk.gov.hmrc.play.views.html.helpers._ @import views.html.helpers._ @import play.i18n._ @implicitFormInstance = @{ Some(inflationProofForm) } @pageScripts = { } @gmp_main(title = Messages.get("gmp.inflation_proof.title"), pageScripts = Some(pageScripts)) { @views.html.helpers.errorSummary(inflationProofForm)


Company profile - Canadian Company Capabilities
Third-Party Information Liability Disclaimer
Some of the information on this Web page has been provided by external sources. The Government of Canada is not responsible for the accuracy, reliability or currency of the information supplied by external sources. Users wishing to rely upon this information should consult directly with the source of the information. Content provided by external sources is not subject to official languages, privacy and accessibility requirements.
Toronto College of Technology
Legal/Operating Name:
Toronto College of Technology
Mailing Address:
200 Sheppard AveNORTH YORK, Ontario
M2N 3A9
Location Address:
200 Sheppard AveNORTH YORK, Ontario
M2N 3A9
Tel.:<PHONE_NUMBER>
Fax:<PHONE_NUMBER>
Logo
Company Profile
Toronto College of Technology is a leader in private education in Canada. Our multilevel study system with a wide choice of entry points offers a flexible and articulated educational path for students from all backgrounds. We have a team of highly qualified and dedicated academic and administrative staff to provide you with a superior learning experience, a friendly and multicultural college community and a full spectrum of life experiences.
At Toronto College of Technology, you will find all you need to succeed. Toronto College of Technology has three divisions: High School, Professional College & University Transfer Programs, and University & Graduate School. It is a home for the mind, the heart, and the spirit. The school program is based on the inherent belief that all people can continue to improve their capacity for greater creativity and intellectual accomplishment. The staff is committed to providing an enriched curricular and co-curricular program that develops the potential for success for every student throughout life.
Full profile
Full profile
Contact information
Company description
Product / Service / Licensing
The goal of this package courses is to instill the students with a solid understanding of not only the core concepts, but also how all the pieces fit together in complete multi-tier Internet business applications. The tremendous increase of interest in server-side technologies, including J2EE, XML, EJB and Microsoft .NET has shaped these course offerings. Designed for enterprise developers who wish to implement server-side business objects in Java and .NET, the courses address the needs of developers, from those new to Java and .NET and object-oriented programming, to those who need the most advanced training in J2EE and .NET. All these courses emphasize solving real-world problems with the goal of applying solutions right away.
The convergence of computing and telecommunications is creating a new kind of networking technology based on IP networks and multimedia applications. Networks today are expected to offer multimedia services anywhere and at any time. Within corporations, intranets support the interaction of people and the linking of these people to information systems. There is an increasing demand for mobility. People increasingly expect seamless access to global networks. IP networking is expected to be everywhere and to offer multimedia services of all types.
The CCNA, CCNP and MCSE certifications are widely recognized and valued in industry. This program also prepares students for the CCNA, MCSE and CCNP certification examinations.
Real-world experiences and Co-op practice are mixed with innovative teaching methods to ensure that you graduate with a comprehensive knowledge of Data Warehouse and Business Intelligence. At the end of the program, you will be able to work as a Data Architect; Data warehouse Analyst, Data Warehouse Specialist, and Business Intelligence Specialist.
This program is special designed for professionals who want to pursuit career in ERP Systems. Real-world experiences and Co-op practice are mixed with innovative teaching methods to ensure that you graduate with a comprehensive knowledge of ERP systems. At the end of the program, you will be able to work as a ERP systems analyst.
Real-world experiences and Co-op practice are mixed with innovative teaching methods to ensure that you graduate with a comprehensive knowledge and skills of Software Testing and Software Quality.
This program also includes software development components which are the essential part of software testing specialist. Graduates of the program also can work as an SQA Analyst, SQA Test Engineer, Software Tester and business/system analyst.
Real-world experiences and Co-op practice are mixed with innovative teaching methods to ensure that you graduate with a comprehensive knowledge and skills of Business Analysis and Project Management.
Foundational modules in Business and IT will be introduced in the 1st and 2nd year, with the focus in the final year on honing the requisite professional skills as well as the integration and application of knowledge and skills. E-business systems, Internet-enabled multimedia, network, servers and database management systems, information and knowledge management systems and enterprise resources planning will form the core curricular coverage in the final year. Experiential learning through programmers such as the six-month Business Industry Practicum in info-communication companies will provide you with ample exposure to the nuances of Internet business and the Knowledge Based Economy workplace.
Working closely with business information technology companies in a myriad range of projects, we ensure that you will be imbued with the latest knowledge and expertise while undergoing our relevant, practical and useful experiential training.
This diploma program is instructor-driven, allowing students to navigate quickly through theory and accounting software. The curriculum includes experiential lectures and workshops facilitated by specialized industry.
Who Should Participate?
The Business & Accounting program is designed for those who are interested in areas of accounting, office management, and small business. Students may start their own business and service companies or may move into marketing and sales.
Early Childcare Assistants lead children in activities to stimulate and develop their intellectual, physical and emotional growth. There is increasing demand in the industry for qualified individuals who have completed formal training such as that offered in this diploma program. Career opportunities exist in childcare centres, kindergartens, nursery schools and centres for exceptional children.
The Early Childcare Assistant (ECA) Diploma is a 945-hour credit program comprised of 455 hours of instructor-led training and 490 hours of volunteer field placement.
Program Duration: 38 weeks
Exam 70-271: Supporting Users and Troubleshooting a Microsoft Windows XP Operating System
Exam 70-272: Supporting Users and Troubleshooting Desktop Applications on a Microsoft Windows XP Operating System
Third-Party Information Liability Disclaimer
Some of the information on this Web page has been provided by external sources. The Government of Canada is not responsible for the accuracy, reliability or currency of the information supplied by external sources. Users wishing to rely upon this information should consult directly with the source of the information. Content provided by external sources is not subject to official languages, privacy and accessibility requirements.
Contacts
Contact information
Description
Company description
Products, services and licensing
Product / Service / Licensing
The goal of this package courses is to instill the students with a solid understanding of not only the core concepts, but also how all the pieces fit together in complete multi-tier Internet business applications. The tremendous increase of interest in server-side technologies, including J2EE, XML, EJB and Microsoft .NET has shaped these course offerings. Designed for enterprise developers who wish to implement server-side business objects in Java and .NET, the courses address the needs of developers, from those new to Java and .NET and object-oriented programming, to those who need the most advanced training in J2EE and .NET. All these courses emphasize solving real-world problems with the goal of applying solutions right away.
The convergence of computing and telecommunications is creating a new kind of networking technology based on IP networks and multimedia applications. Networks today are expected to offer multimedia services anywhere and at any time. Within corporations, intranets support the interaction of people and the linking of these people to information systems. There is an increasing demand for mobility. People increasingly expect seamless access to global networks. IP networking is expected to be everywhere and to offer multimedia services of all types.
The CCNA, CCNP and MCSE certifications are widely recognized and valued in industry. This program also prepares students for the CCNA, MCSE and CCNP certification examinations.
Real-world experiences and Co-op practice are mixed with innovative teaching methods to ensure that you graduate with a comprehensive knowledge of Data Warehouse and Business Intelligence. At the end of the program, you will be able to work as a Data Architect; Data warehouse Analyst, Data Warehouse Specialist, and Business Intelligence Specialist.
This program is special designed for professionals who want to pursuit career in ERP Systems. Real-world experiences and Co-op practice are mixed with innovative teaching methods to ensure that you graduate with a comprehensive knowledge of ERP systems. At the end of the program, you will be able to work as a ERP systems analyst.
Real-world experiences and Co-op practice are mixed with innovative teaching methods to ensure that you graduate with a comprehensive knowledge and skills of Software Testing and Software Quality.
This program also includes software development components which are the essential part of software testing specialist. Graduates of the program also can work as an SQA Analyst, SQA Test Engineer, Software Tester and business/system analyst.
Real-world experiences and Co-op practice are mixed with innovative teaching methods to ensure that you graduate with a comprehensive knowledge and skills of Business Analysis and Project Management.
Foundational modules in Business and IT will be introduced in the 1st and 2nd year, with the focus in the final year on honing the requisite professional skills as well as the integration and application of knowledge and skills. E-business systems, Internet-enabled multimedia, network, servers and database management systems, information and knowledge management systems and enterprise resources planning will form the core curricular coverage in the final year. Experiential learning through programmers such as the six-month Business Industry Practicum in info-communication companies will provide you with ample exposure to the nuances of Internet business and the Knowledge Based Economy workplace.
Working closely with business information technology companies in a myriad range of projects, we ensure that you will be imbued with the latest knowledge and expertise while undergoing our relevant, practical and useful experiential training.
This diploma program is instructor-driven, allowing students to navigate quickly through theory and accounting software. The curriculum includes experiential lectures and workshops facilitated by specialized industry.
Who Should Participate?
The Business & Accounting program is designed for those who are interested in areas of accounting, office management, and small business. Students may start their own business and service companies or may move into marketing and sales.
Early Childcare Assistants lead children in activities to stimulate and develop their intellectual, physical and emotional growth. There is increasing demand in the industry for qualified individuals who have completed formal training such as that offered in this diploma program. Career opportunities exist in childcare centres, kindergartens, nursery schools and centres for exceptional children.
The Early Childcare Assistant (ECA) Diploma is a 945-hour credit program comprised of 455 hours of instructor-led training and 490 hours of volunteer field placement.
Program Duration: 38 weeks
Exam 70-271: Supporting Users and Troubleshooting a Microsoft Windows XP Operating System
Exam 70-272: Supporting Users and Troubleshooting Desktop Applications on a Microsoft Windows XP Operating System


Figured I would show you guys our OpenEnergyMonitor system we've installed over the past year. We have over 30 nodes installed, most of them are installed next to our meter cupboards (we have three of them) and some are installed directly into the machine they're monitoring. Our main goal was to measure the power usage of our wave soldering and reflow soldering machine. Especially the wave soldering machine since this machine keeps it's solder bath at a standby temperature 24/7. We wanted to implement the TX nodes as clean as possible, so we did a little redesign of the hardware and made them fit in a industry standard din-rail mount enclosure. We also integrated the external transformer into the design to make installing multiple nodes easier without a bunch of adapters hanging around.
To collect all the data generated by the nodes we have 3 RPis in use. Each RPi sends the data to our dataserver, running emoncms.
Our enclosed nodes. The dipswitches are used to set the node ID. The last dipswitch (number 6) is used to setup the node for one single 3 phase measurement or 3 separate 1 phase measurements
3 inputs for the current clamps
We've made a batch of about 50 nodes
Most of them are installed next to a meter cupboard and measure directly on the circuit breakers
Inside the box
But some of them are also installed directly in the machine they're measuring
Some emonCMS screenshots:
Total power usage during the day, this usually hovers somewhere between 40kW and 60kW.
Most energy is used by our climate control systems and soldering machines:
Climate control
Our reflow and wave soldering machine.
The system has been working great and we already made some huge savings because of this system. Keep up the good work OpenEnergyMonitor!
Re: OpenEnergyMonitor system with over 30 nodes
This is ridiculously brilliant, more I want more, can you show me the insides and how can I ge hold of one of these ?
Re: OpenEnergyMonitor system with over 30 nodes
Wow, that looks amazing. Can we see inside? What hardware design have you used? Great work, very tidy implementation
Re: OpenEnergyMonitor system with over 30 nodes
+1 for the coolness and +1 for having a look at the modifications, if that is something you guys are planning on sharing.
I could use a couple of these (even 10 or so) if they come with a din rail mount case (so far here in Italy that has been the major objection to people potentially interested in the project: no din rail .. no party because it would require a separate custom box instead of some space in an already existing and available one)
Re: OpenEnergyMonitor system with over 30 nodes
Here are some pictures of the inside:
The hardware is more or less based on this schematic:
http://solderpad.com/openenergymon/emontx/
As you can see we've integrated the transformer into the design. More design modifications are:
• Integrated usb connector and usb <-> serial connector
• DC/DC converter to provide the logic supply voltage
• Dipswitches to select the node ID
• As much SMT components as possible
The only downside of our current design is that the transformer is too small to work properly. Because of the small size of the transformer it uses a very small wire size to be able to make enough windings around the core. Thus saturating the transformer very quickly, even with small loads. This results in a distorted sinus waveform making the power factor slightly inaccurate.
We have already tested some larger transformers which work perfect without saturating, but unfortunately these are quite a bit bigger. The casing has to increase to a 40mm width in stead of 22.5mm to fit these transformers.
Re: OpenEnergyMonitor system with over 30 nodes
I notice you have the CE mark on your unit? What certification process have you put the unit through? Would you be able to share your experience? This is something we are looking to achieve with the emonTx V3 in the near future.
Re: OpenEnergyMonitor system with over 30 nodes
It's not officially CE certified yet, but it complies with the low voltage directive and we've also done a quick EMC scan(we can do pre-compliance EMC tests here :) ) which it easily passed.
Re: OpenEnergyMonitor system with over 30 nodes
It's good to hear that a standard ATmega328 + RFM12B passes pre-compliance EMC. If you make any discoveries or have experiences please share. We will be doing EMC testing early next year
Re: OpenEnergyMonitor system with over 30 nodes
One of our RPis went corrupt after a power outage so I installed OEMGateway and pointed it to our dataserver to see how it works. All nodes started to send data again except for 2 nodes, node id 30 and 31. Could it be that the OEMgateway doesn't work with nodes from id 30 and up?
Re: OpenEnergyMonitor system with over 30 nodes
I think it's a case of the JeeLib protocol supports nodes 1-30 only: http://openenergymonitor.org/emon/buildingblocks/rfm12b2
(It appears that the original JeeLabs documentation is no longer available. Martin Harizanov has reproduced an outline of the packet structure here.)
Re: OpenEnergyMonitor system with over 30 nodes
We´re currently working on the next revision of our energy node. We have chosen to use a resistive voltage divider to measure the voltage instead of the the transformer + voltage divider. This results in a clean voltage measurement, without the distortion caused by the transformer. To do so we've used 2(so one can fail) 1M5 resistors in series, both in the line and neutral. This reduces the current to a safe level.
We're still looking to further improve our nodes, what would you guys like to see added in our (industrial version) energy nodes?
Re: OpenEnergyMonitor system with over 30 nodes
Sounds interesting, if you conduct any accuracy tests between the two methods please share. It would be interested to see how much difference this makes. Obviously isolation would be lost with the resistive technique.
Re: OpenEnergyMonitor system with over 30 nodes
Did some testing today:
Phase angle between the 230v input and the measuring resistor, no parallel capacitor.
Blue is the 230V input, yellow is the voltage across the measuring resistor
Almost no phase rotation, but some nasty spikes on the measured resistor
Phase angle between the 230v input and the measuring resistor, 470pF parallel capacitor
Slightly increased phase angle, spikes seem to be gone.
Same tests with 1nF and 10nF, no benefit over the 470pF capacitor:
Re: OpenEnergyMonitor system with over 30 nodes
Buenas a todos.
Disculpad que os pregunte en español, pero mi ingles es demasialdo malo....
Un proyecto muy interesante. te felicito por el trabajo. Solo me surge una duda (desde mi desconocimiento de electrónica). Si en lugar de utilizar un transformador de 0,35vA se utiliza uno de 6vA, ¿los resultados de medida serían más precisos?. Por otro lado... ¿sería posible utilizar ese transformador para alimentar un componente de la placa que necesita 9vdc?
Gracias.


Too use below - please make sure you have your Google Tag Manager debug Bar Active
There are many different types of events in Google Tag Manager:


[Lesson 4] The Complete Guide to Using Online Courses for Massive TrafficSent Tuesday, August 25, 2015
Written by Ankur Nagpal of FedoraMissed any of the last lessons? Here’s a link to all of
them so far.We know online courses.At Fedora we power 5,000+ online teachers and over 20,000 online courses. We have seen TONS of course launches across a wide spectrum of authors from Lewis Howes and Ryan Holiday to the dude that made thousands of dollars teaching Japanese bondage
(seriously).While it’s been cool to see people change their life by earning anywhere from a thousand bucks on […]
[Lesson 3] How to Develop Traffic Building Blogging HabitsSent Thursday, August 20, 2015
Written by Scott Britton of Life-LongLearnerWhat does giving out brownies in a co-working space have to do with building traffic?You’ll see in a minute.But first, what's the most common mistake people make when trying to use a blog to
get more traffic? Over-planning instead of just getting started.The best way to get started is to pick something you feel comfortable writing about and get
moving.Writing is like getting in shape. It sucks at first and can be really hard.  If you're an awesome Javascript developer then we want to hire you at SumoMe.Go here to learn more. If you know one, successfully refer one for a year of free Chipotle.Everyone wants to create content that gets noticed, that gets shared. And at some point in my life, I got good at the kind of words that resonate on social
media.Today we call this “optimizing social sharing,” and I’m going to show you how you our system for […]
[Lesson 1] How to Massively Increase Your Twitter Engagement and ReferralsSent Thursday, August 13, 2015
Written by Michael Kawula at Social QuantMost businesses struggle to make social “work.”Whether you’re trying to expand your presence on Twitter, Facebook, or any
other social media platform, the ultimate goal is to get more engagement from your audience. More retweets, more likes, more comments and shares.That extra engagement leads directly into the main goal: getting more web traffic.But if most businesses are doing it wrong, then how can you make sure you're doing it […]
[Lesson 0] The first step to getting your 1m visitorsSent Monday, August 10, 2015
Louis CK is one of
the funniest men alive right now.He fills up massive theatres, sells out in minutes, and is so well known that he makes millions selling his recordings on his site with no advertising.But he didn’t get there overnight. In 1984, he was getting on stage for the first time, and did so poorly that he didn’t try stand-up again for two years!Eventually he came back with a plan, worked his way through the ranks, and became
a massive success.You don’t get to one […]
[Traffic1M] Ask the Traffic Building Experts AnythingSent Thursday, August 6, 2015
Hey Traffic Builder,The first lesson is going out Monday, so get pumped!But before then, we’re still finalizing some of the course material and need to know one really important thing:What do you most want to learn most about traffic building?To figure that out, we have a reddit AMA going right now where most of our traffic building experts are going to drop in to answer your questions.Click here to join the AMAYou can ask them things like:How did they get their first […]