WHO Tuberculosis Data & ggplot2
Original post date: March 03 2017
For this post, as similar to previous ones, I give a guide through the process I took to organize the data, a nifty function I created to search the documentation and a visualization of the data using ggplot2.
![Electron micrograph of Mycobacterium tuberculosis](/post/who-tb-data-ggplot2/mycobacterium20tuberculosis20030.jpg)
What is Tuberculosis?
Tuberculosis (TB) is a nasty disease caused by the bacterium Mycobacterium tuberculosis. It was first described by Hippocrates and has a history concurrent with human civilization. Individuals infected with TB usually do not develop active disease but if they develop active TB, they can on average infect 8-10 people. Most of the time when we hear of TB, we think of the infection within the lungs, but I learned during my time volunteering in a medical clinic in Peru that TB can manifest in other sites of the body (extra-pulmonary TB). This bacterium has infected roughly a third of the world’s population and is a top 10 cause of death around the globe.
There are two major modern concerns with TB…
- TB and HIV co-infection, where there is a disproportionate mortality rate by TB with HIV infected individuals. HIV infects CD4+ T-cells, which are essential for an appropriate immune response to combat TB. This relationship has been reported in patients.
- Multi-drug resistant TB (MDR-TB) is a growing public health concern that threatens the control of TB infection throughout the world. There have been reports of extensive-drug resistant TB (XDR-TB) which is resistant to the standard treatment of isoniazid and rifampin alongside any fluoroquinolone and at least one secondary-treatment drug. Fewer treatment options put patients under rigorous and strenuous regimens and present a risk of transmission to others.
Data Retrieval
The data I used for this post is taken from the World Health Organization from this link to the TB data. Specifically I used the data dictionary and TB burden estimates. When you click these links, they generate a comma-delimited file (.csv) and date-stamp the file. I downloaded these files back in February 2016. Just remember where you save these in your local directory so you can read them into R for the near future.
Getting Started
The code I use for my posts can be found on my GitHub account , open for free use and adaptation. I’m always open to comments and suggestions on how to improve my code or even a completely different method to reach the same goal. Optimization of R programming is something I am working towards bit by bit.
After setting up your working directory, read your comma-delimited files using the read.csv()
function. The WHO files are conveniently formatted so there is no need for elaborate arguments for headers, field separators or assigning missing values.
TB.burden <- read.csv("TB_burden_countries_2016-02-18.csv") #TB burden dataset
TB.dic <- read.csv("TB_data_dictionary_2016-02-18.csv") #TB documentation dictionary
Customized Search Function
While completing an R assignment for one of my classes, I ran into the readline()
function which allows for some interactive functionality within R. The reason I created this interactive custom search function is because of the fact that the column variables in the TB burden .csv file are not completely straightforward and it’s annoying to manually search through the file itself in Microsoft Excel. So instead of memorizing all of them (only to forget after I write 10 lines of code), I decided to create this function whenever I start to write code for a new plot and need to remind myself the exact description of the variable I am working with…
TB.search <- function (x){ #
look <- names(x) #assign the names/column names of the subsetted data
message("Matching variable names found in the documentation files")
TB.d <- as.character(TB.dic[,4]) # conversion to character to have "clean" output
out <- look[look %in% TB.dic[,1]] #assignment of vector: which names of the selected subset are in the documentation file
print(out) #check which variable names from dictionary match the input
message("Above includes all names for variable names found in the documentation files") #message prompt for output
z <- readline("Search Variable Definition (CASE-SENSITIVE): ") #interactive read-in of variable name
if (z %in% out){ # NEED TO MAKE THE CONDITION TO SEPARATE integer(0) from real integer values
print(TB.d[grep(paste0("^(",z,"){1}?"),TB.dic[,1])]) #print the definition found in TB.d
}else{
repeat{ #repeat the line below for readline() if exact match of doesn't exist
y<-readline("Please re-input (press 'ESC' to exit search): ") #second prompt
if (y %in% out) break # the condition that ends the repeat, that the input matches a name in the documentation
}
print(TB.d[grep(paste0("^",y,"{1}?"),TB.dic[,1])]) #print the definition found in documentation file TB.dic
}
}
I’m only going to highlight a couple things in the code above. I converted the definitions found in the documentation file because the original data type was a factor
. This was a problem with the print output because it would show all the unnecessary information on the number of factors and values of the factors I had no interest in. Secondly I ended up using a repeat
in my if
statement to prompt the user if they incorrectly typed in a variable name in the console. This
link
provides some helpful information on the repeat
loop. Other then that, I used
regular expression
to specify the search to match what was actually in the documentation file.
Cleaning Data
As with all data, it doesn’t come in the form that you always want it in. Luckily the WHO TB data wasn’t in bad shape and I just converted all integer valued columns into numeric types using a simple loop.
#convert all the rows with type 'integer' to 'numeric
for (k in 1:length(names(TB.burden))){
if (is.integer(TB.burden[,k])){
TB.burden[,k] <- as.numeric(TB.burden[,k])
}
}
After that, I used the mapvalues()
function from the plyr
package to change the levels in the country variable. I used this because the basic functions in R require me to specify all the levels in the factor and using 219 country names seemed tedious. Quite simply, I just listed the old names I wanted to change and created a respective character vector of the the new country names.
library(plyr)
TB.burden$country <- (mapvalues((TB.burden$country), from = c(
"Bolivia (Plurinational State of)",
"Bonaire, Saint Eustatius and Saba",
"China, Hong Kong SAR",
"China, Macao SAR",
"Democratic People's Republic of Korea",
"Democratic Republic of the Congo",
"Iran (Islamic Republic of)",
"Lao People's Democratic Republic",
"Micronesia (Federated States of)",
"Republic of Korea",
"Saint Vincent and the Grenadines",
"Sint Maarten (Dutch part)",
"The Former Yugoslav Republic of Macedonia",
"United Kingdom of Great Britain and Northern Ireland",
"United Republic of Tanzania",
"Venezuela (Bolivarian Republic of)",
"West Bank and Gaza Strip")
, to = c(
"Bolivia",
"Caribbean Netherlands",
"Hong Kong",
"Macao",
"North Korea",
"DRC",
"Iran",
"Laos",
"Micronesia",
"South Korea",
"St. Vincent &amp;amp; Grenadines",
"Sint Maarten",
"Former Yugoslav (Macedonia)",
"UK &amp;amp; Northern Ireland",
"Tanzania",
"Venezuela",
"West Bank and Gaza")
))
I threw in some random subsetting into the code to pull out values for specific questions (ie. what was the estimated prevalence per 100,000 people of TB in Peru during 2014). You can see it in the actual code in the GitHub repository .
Visualizing the Data
I was interested in what estimated rates of TB were by WHO region, so I ran a simple loop to assign new variable names to each region (this is not the best practice IMO but it does the trick).
for (i in levels(TB.burden$g_whoregion)){ #selection of the WHO regions (AFR, AMR, EMR, EUR, SEA, WPR)
nam <- paste0(i,"_whoregion") #creation of the name based on acronyms from levels
assign(nam, subset(TB.burden,TB.burden$g_whoregion %in% paste(i))) #assigning each level a subset based on the region
}
ls() #just to show what variables are stored...
#look for AFR_whoregion, AMR_whoregion, EMR_whoregion, EUR_whoregion, SEA_whoregion, WPR_whoregion
Now we set up the themes we want to use for ggplot2.
I set the year scale for the legends, customized the text on the axes and assigned dark_t
to be a dark, black-grey background and light_t
as a simple, white-grey background theme
.
ctext <- theme(axis.ticks = element_blank(),
plot.title=element_text(family="Verdana"),
axis.text.x=element_text(size=9,family="Verdana"), #http://www.cookbook-r.com/Graphs/Fonts/#table-of-fonts
axis.title.x=element_text(size=10),
axis.text.y=element_text(size=7.5,family="Verdana"),
axis.title.y-element_text(size=10,family="Verdana"),
legend.title=element_text(size=9,family="Verdana",vjust=0.5), #specify legend title color
legend.text=element_text(size=7,family="Verdana",face="italic")
)
dark_t <- theme_minimal()+
theme(
plot.background = element_rect(fill="#191919"), #plot background
panel.border = element_blank(), #removes border
panel.background = element_rect(fill = "#000000",colour="#000000",size=2), #panel background and border
panel.grid = element_line(colour = "#333131"), #panel grid colours
panel.grid.major = element_line(colour = "#333131"), #panel major grid color
panel.grid.minor = element_blank(), #removes minor grid
plot.title=element_text(size=16, face="bold",family="Verdana",hjust=0,vjust=1,color="#E0E0E0"), #set the plot title
plot.subtitle=element_text(size=12,face=c("bold","italic"),family="Verdana",hjust=0.01,color="#E0E0E0"), #set subtitle
axis.text.x = element_text(size=9,angle = 0, hjust = 0.5,vjust=1,margin=margin(r=10),colour="#E0E0E0"), # axis ticks
axis.title.x = element_text(size=11,angle = 0,colour="#E0E0E0"), #axis labels from labs() below
axis.text.y = element_text(size=9,margin = margin(r=5),colour="#E0E0E0"), #y-axis labels
legend.title=element_text(size=11,face="bold",vjust=0.5,colour="#E0E0E0"), #specify legend title color
legend.background = element_rect(fill="#262626",colour="#383838", size=.5), #legend background and cborder
legend.text=element_text(colour="#E0E0E0")) + #legend text colour
# plot.margin=unit(c(t=1,r=1.2,b=1.2,l=1),"cm")) #custom margins
ctext
light_t <- theme(legend.background = element_rect(fill="grey95",colour="grey70", size=.5),
plot.title=element_text(size=16, face="bold",family="Verdana",hjust=0,vjust=1), #set the plot title
plot.subtitle=element_text(size=12,face=c("bold","italic"),family="Verdana",hjust=0.01), #set subtitle
panel.grid.minor = element_blank()) + #removes minor grid)
ctext
# specify scale for year variable
year.scale <- c(1990,1995,2000,2005,2010,2014) # used for breaks below
For the next plots, I’ll only be focusing on the WHO Region of Africa. Two notes on the code below for the plots: 1) I used the forcats
package
to reverse the order of the countries on the y-axis. This package is useful when using ggplot2 for categorical data. 2) For the legend scales, I used the comma()
function in the scales
package to include the comma’s for every thousand. The following code displays the estimated prevalence, mortality and incidence (per 100,000 people) for cases from each country in the WHO Africa Region.
#PREVALENCE per 100k
library(forcats) #https://blog.rstudio.org/2016/11/14/ggplot2-2-2-0/
pAFR <-ggplot(AFR_whoregion,aes(y=fct_rev(country),x=e_prev_100k)) + # prevalence (100k)
labs(title="WHO | Tuberculosis Data",
subtitle="Africa Region", x="Estimated Prevalence (per 100,000)",y="",colour="#E0E0E0") +
geom_point(shape=20,aes(colour=year,fill=year),alpha=0.6,size=3) +
scale_y_discrete(expand=c(0.002, 1))+
scale_x_continuous(limits=c(0,1500),labels=scales::comma)+
scale_fill_gradient(guide_legend(title="Year"),breaks=year.scale,low="#F9FA00",high="#8C00E6") + #assigns colours to fill in aes
scale_colour_gradient(guide_legend(title="Year"),breaks=year.scale,low="#F9FA00",high="#8C00E6") + #assigns colours to colour in aes
dark_t
#MORTALITY (including HIV) per 100k e_inc_tbhiv_100k
mAFR <- ggplot(AFR_whoregion,aes(y=fct_rev(country),x= e_mort_exc_tbhiv_100k)) + # Mortality exclude HIV (100k)
labs(title="WHO | Tuberculosis Data",
subtitle="Africa Region",x="Estimated Mortality excluding HIV (per 100,000)",y="",colour="#E0E0E0")+
geom_point(shape=20,aes(colour=year,fill=year),alpha=0.6,size=3) +
scale_y_discrete(expand=c(0.002, 1)) +
#scale_x_continuous(limits=c(0,250),labels=scales::comma) +
scale_fill_gradient(guide_legend(title="Year"),breaks=year.scale,low="#F9FA00",high="#8C00E6") + #assigns colours to fill in aes
scale_colour_gradient(guide_legend(title="Year"),breaks=year.scale,low="#F9FA00",high="#8C00E6") + #assigns colours to colour in aes
dark_t
#INCIDENCE per 100k
iAFR <- ggplot(AFR_whoregion,aes(y=fct_rev(country),x= e_inc_100k)) + # Mortality exclude HIV (100k)
labs(title="WHO | Tuberculosis Data",
subtitle="Africa Region",x="Estimated Incidence (per 100,000)",y="",colour="#E0E0E0")+
geom_point(shape=20,aes(colour=year,fill=year),alpha=0.6,size=3) +
scale_y_discrete(expand=c(0.002, 1)) +
scale_x_continuous(limits=c(0,1500),labels=scales::comma) +
scale_fill_gradient(guide_legend(title="Year"),breaks=year.scale,low="#F9FA00",high="#8C00E6") + #assigns colours to fill in aes
scale_colour_gradient(guide_legend(title="Year"),breaks=year.scale,low="#F9FA00",high="#8C00E6") + #assigns colours to colour in aes
dark_t
Now the plots in the order of estimated prevalence, incidence and mortality…
In the plots, the color yellow refers to a year closer to 1990 where purple is more recent towards 2014. Based on this we can see the relative changes over time on the estimated TB prevalence, incidence and mortality. Let’s focus on the prevalence and incidence plots – we can see most of the countries have lower estimated TB prevalences over time. The most drastic decreases can be seen in Central African Republic and Niger. We can also see that Lesotho, South Africa and Swaziland have increased estimated TB prevalence during the 1990-2014 time period. Namibia is an interesting one because it seems that the estimated TB prevalence increased then decreased roughly half way. To accurately visualize this trend in Namibia, we would need a choose a different method to better visualize this (a simple line plot).
Remember these plots are just a simple qualitative way to compare trends but doesn’t capture the full picture. I’ve learned that your method of visualizing data depends on which narrative of the data you want to highlight. These graphics could be used to see which countries have had the largest changes over time or as an example, identify countries who have improved (or failed) their national TB control, using estimated TB incidence as a proxy. Are TB control or prevention systems working in these countries? Based on allocated resources or programs, are the changes in line with the goals to reduce the global burden of TB .
You can tinker with the code to select which countries or regions you want to compare. I only displayed the plots for the WHO Africa Region but the other regions also looked interesting. You can adapt this code for the other WHO regions to see what the trends look like.
Closing Thoughts
I hope this post was informative and you learned something about TB around the world. Despite this disease being preventable and curable, it remains a real threat for many people around the world. There are groups fighting TB around the world, just one close to Boston is the endTB partnership. Check out their website and see the groups (PIH, MSF) involved in the work of combating MDR-TB.
As always I’m open to comments and suggestions on improving my code and graphics. If anyone has questions related to the code – send me a message, I’ll be more than happy to help. I’ve learned so much from online resources and communities like StackOverflow and would always want to help those new to using R.


Preparation time
1-2 hours
Cooking time
30 mins to 1 hour
Serves
Serves 2
For the salt crust, mix the salt, herbs, eggs and water in a bowl.
Add the flour and slowly mix together until the dough is firm and elastic. Wrap the dough in cling film and leave to rest in the fridge for at least one hour.
Unwrap the dough and place onto a large, lightly floured work surface. Roll out the dough to about 0.5cm/¼in thick, or until it's large enough to wrap around the chicken (approximately 30cm/12in diameter).
For the chicken, preheat the oven to 220C/430F/Gas 8.
Stuff the cavity of the chicken with the rosemary, thyme, lemon and garlic and season the skin of the chicken with freshly ground black pepper.
Place the chicken, breast side down, in the centre of the rolled out dough. Wrap the dough around the chicken to seal completely. Pinch the edges of the dough together to seal the crust.
Turn the dough-wrapped chicken over and place on a baking tray, dough seam-side down.
Place in the oven to cook for 25 minutes. Remove from the oven and leave to rest for a further 25 minutes.
Meanwhile, to make the sauce, heat a frying pan over a medium heat until hot. Add the butter and the shallot and sweat for one minute.
Add the peas, broad beans and mousseron mushrooms and cook for 2-3 mintues.
Add the Sauternes wine and Chardonnay vinegar, increase the heat and simmer until the liquid is reduced by two-thirds.
Add the stock and simmer until the liquid is reduced by half.
Add the crème fraîche, season with salt and freshly ground black pepper and stir in the chervil.
When ready to serve, crack open the salt crust and remove the chicken. Wipe the chicken with kitchen paper to remove any excess salt.
Using a sharp knife, remove both the breasts from the carcass, taking care to keep them whole and keep the skin on.
Heat a frying pan over a medium heat until hot, add the butter and fry the chicken breasts, skin side down, until golden-brown and heated through.
To serve, spoon the pea, broad bean and mushroom sauce evenly among each of two warm serving plates. Top each with a chicken breast and serve.


CUDA programming model is designed to fully expose parallel capabilities of NVIDIA GPUs. Even though the language is devoted to general purpose computing, it still requires the programmer to follow a set of paradigms arising from the GPU architecture. CUDA provides a few easily understood abstractions that allow the programmer to focus on algorithmic efficiency and develop scalable parallel applications by expressing the parallelism explicitly. It provides three key abstractions as hierarchy of thread groups, shared memories, and synchronization barrier that provide a clear parallel structure to conventional C code for one thread of the hierarchy.
l 0.55
The abstractions guide the programmer to partition the problem into coarse sub-problems that can be solved independently in parallel, and then into finer pieces that can be solved cooperatively in parallel. The programming model scales transparently to large numbers of processor cores: a compiled CUDA program executes on any number of processors, and only the runtime system needs to know the physical processor count (See figure [automatic-scalability]).


The driver goes up to Ellie's door every Friday at the same time. Ellie always greets her with a smile saying "Are you here for me? Let me just collect my things." The driver explains that she's there to take her to her hair appointment.
Recently, ITNMontereyCounty had a member sign on who needed the service only for a couple of months while he recovered from open heart surgery. Robert needed us three times a week to get to and from his cardiac rehab appointments. Though this was a temporary thing for him, he was moved by how much it impacted his life.


G80
Overview
The G80 SoC is a low-cost System on Chip part of the GHI Electronics SurfaceMount Compute Modules (SCM) line. This modules can be programmed in .NET C# and Visual Basic using TinyCLR OS or .NET Micro Framework.
Pricing, purchasing and other information can be found on the G80 Page on our main website.
Ordering Part Number
- G80 SoC: G80SC-SM-501
- G80 Dev Board: G80DB-SM-483
Specifications
| Spec | Value |
|---|---|
| Processor | STM32F427VGT6 |
| Speed | 180 MHz |
| Internal RAM | 256 KByte (SRAM) |
| Internal Flash | 1 MByte |
| Package | LQFP100 14 x 14 mm |
| Temperature Range | -40C to +85C |
Note: Resources are shared between your application and the operating system.
Peripherals
- TinyCLR OS ready
- .NET Micro Framework
- RoHS Lead Free
- 180 MHz ARM Cortex-M4 STM32F427VGT6
- 156 Kbytes available RAM
- 256 Kbytes available flash
- 78 GPIO
- 16 interrupt capable GPIO
- 2 SPI
- 1 I2C
- 4 UART
- 2 CAN
- 26 PWM
- 16 12-bit analog input
- 4-bit SD/MMC memory card interface
- Low power modes
- LQFP6100 14 x 14 mm
- RTC
- Watchdog
- Threading
- USB host
- USB client
- TCP/IP with SSL
- Full .NET socket interface
- Ethernet
- PPP
- Graphics
- Images
- Fonts
- Controls
- File System
- Full .NET file interface
- SD cards
- USB drives
- Native extensions
- Runtime Loadable Procedures
- Device register access
- Signal controls
- Generation
- Capture
- Pulse measurement
G80 Pinout
Many signals on the G80 are multiplexed to offer multiple functions on a single pin. Developers can decide on the pin functionality to be used through the provided libraries. Any pin with no name, function, or note must be left unconnected.
Footprint
The chip is standard LQFP100 14x14mm. See the STM32F427VGT6 datasheet for exact footprint.
Device Startup
The G80 is held in reset when the reset pin is low. Releasing it will begin the system startup process.
There are three different components of the device firmware:
- GHI Bootloader: initializes the system, updates TinyCLR when needed, and executes TinyCLR.
- TinyCLR: loads, debugs, and executes the managed application.
- Managed application: the program developed by the customer.
Which components get executed on startup can be control by manipulating the LDR0 pin. It is pulled high on startup. When low, the device waits in the GHI Bootloader. Otherwise, the managed application is executed. LDR1 is reserved for future use.
Additionally, the communications interface between the host PC and the G80 is selected on startup through the MODE pin, which is pulled high on startup. The USB interface is selected when MODE is high and COM1 is selected when MODE is low.
The above discussed functions of LDR0, LDR1, and MODE are only during startup. After startup, they return to the default GPIO state and are available to use as GPIO in the user application
TinyCLR OS
TinyCLR OS provides a way to program the G80 in C# or Visual Basic from the Microsoft Visual Studio integrated development environment. To get started you must first install the firmware on the G80 (instructions below) and then go to the TinyCLR Getting Started page for instructions.
Loading the Firmware
- Activate the bootloader, hold the LDR0 signal low while resetting the board.
- Open TinyCLR Config tool.
- Click the loader tab.
- Select the correct COM port. If you are not seeing it then the device is not in the loader mode.
- Click the
Update to Latest
button.
You can also update the firmware manually. Download the firmware and learn how to use the GHI Bootloader manually.
Start Coding
Now that you have installed the firmware on the G80, you can setup your host computer and start programming. Go to the TinyCLR Getting Started page for instructions.
Code Samples
For some examples of using TinyCLR, take a look at the TinyCLR Samples repo. You may also find the TinyCLR tutorials useful.
Native Code
TinyCLR OS also lets you use native code that works alongside your managed application. Native code can be used to provide improved performance or access to advanced features not exposed through TinyCLR. For more information check out Native Code on TinyCLR.
The memory area reserved for native code in TinyCLR OS on G80 starts at 0x2002F000 and its length is 0xFF8.
.NET Micro Framework
It is possible to still use .NET Micro Framework (NETMF). Details are on the NETMF Introduction page. The NETMF Getting Started page covers NETMF from setup of the host computer to program deployment on both an emulator and target device.
Datasheet
This documentation page replaced the legacy datasheet PDF but it is here for reference.
CAN Bit Timing Settings
The following CAN bit timing parameters were calculated for a G80 driving the TJA1050T CAN driver chip. See the Configuring the Bus section of the CAN Tutorial for more information.
| Baud | Propagation | Phase1 | Phase2 | Baudrate Prescaler | Synchronization Jump Width | Use Multi Bit Sampling | Sample Point | Max Osc. Tolerance | Max Cable Length |
|---|---|---|---|---|---|---|---|---|---|
| 33.333K | 1 | 12 | 2 | 90 | 1 | False | 86.7% | 0.33% | 2145M |
| 83.333K | 1 | 12 | 2 | 36 | 1 | False | 86.7% | 0.33% | 825M |
| 125K | 1 | 12 | 2 | 24 | 1 | False | 86.7% | 0.33% | 531M |
| 250K | 1 | 12 | 2 | 12 | 1 | False | 86.7% | 0.33% | 238M |
| 500K | 1 | 12 | 2 | 6 | 1 | False | 86.7% | 0.33% | 91M |
| 1M | 1 | 12 | 2 | 3 | 1 | False | 86.7% | 0.33% | 18M |
Note: Maximum Oscillator Tolerance and Maximum Cable Length are theoretical maximums and must be tested to ensure reliability.
Design Considerations
Required Pins
Exposing the following pins is required in every design to enable device programming, updates, and recovery:
- LDR0
- LDR1
- Reset
- Desired debug interface(s)
- MODE if required to select a debug interface
Power Supply
A typical clean power source, suited for digital circuitry, is needed to power the G80. Voltages should be within at least 10% of the needed voltage. Decoupling capacitors of 0.1 μF are needed near every power pin. Additionally, a large capacitor, typically 47 μF, should be near the G80 if the power supply is more than few inches away.
Crystals
The G80 requires an external 12 MHz crystal and associated circuitry to function. For the RTC to function, a 32,768 Hz crystal and circuitry are required. Please see the processor’s documentation for advanced information.
Interrupt Pins
Interrupts are only available on 16 pins at any given time. Of those 16 pins, the pin number must be unique. For example: PA1 and PB1 cannot both be used as interrupts at the same time, but PA1 and PB2 can.
Reset
The reset pin is not pulled in any direction. Designs must be sure to use an appropriate pull-up resistor.
G80 Development Board
The G80 Dev Board is an excellent starting point and reference design for anyone interested in evaluating and developing with the G80.
Legal
License
This product with its accompanying firmware are licensed royalty-free for commercial and noncommercial use. Using the provided firmware on a non-official product requires additional licensing. The provided documentation/schematics/libraries/sources are not to be used in any manner outside for the benefit of implementing and using this GHI Electronics product into your design.
 GHI ELECTRONICS LINE OF PRODUCTS ARE NOT DESIGNED FOR LIFE SUPPORT APPLICATIONS. SPECIFICATIONS, PRICE AND AVAILABILITY ARE SUBJECT TO CHANGE WITHOUT ANY NOTICE.
You can also visit our main website at www.ghielectronics.com and our community forums at forums.ghielectronics.com.


Title
Subtitle
Chart Explanation
Some explanatory text would follow.
Data Tables
Some data tables would follow.
Methodology
Some methodology text would follow.
Some explanatory text would follow.
Some data tables would follow.
Some methodology text would follow.


|
App Engine Python SDK
v1.6.9 rev.445
The Python runtime is available as an experimental Preview feature.
|
Public Member Functions | |
| def | __init__ |
| def | __call__ |
| def | Validate |
| def | ToValue |
Public Attributes | |
| default | |
Static Public Attributes | |
| expected_type = object | |
Validator base class. Though any callable can be used as a validator, this class encapsulates the case when a specific validator needs to hold a particular state or configuration. To implement Validator sub-class, override the validate method. This class is permitted to change the ultimate value that is set to the attribute if there is a reasonable way to perform the conversion.
| def google.appengine.api.validation.Validator.__init__ | ( | self, | |
default = None |
|||
| ) |
Constructor. Args: default: Default assignment is made during initialization and will not pass through validation.
| def google.appengine.api.validation.Validator.__call__ | ( | self, | |
| value, | |||
key = '???' |
|||
| ) |
Main interface to validator is call mechanism.
| def google.appengine.api.validation.Validator.ToValue | ( | self, | |
| value | |||
| ) |
Convert 'value' to a simplified collection or basic type. Subclasses of Validator should override this method when the dumped representation of 'value' is not simply <type>(value) (e.g. a regex). Args: value: An object of the same type that was returned from Validate(). Returns: An instance of a builtin type (e.g. int, str, dict, etc). By default it returns 'value' unmodified.
| def google.appengine.api.validation.Validator.Validate | ( | self, | |
| value, | |||
key = '???' |
|||
| ) |
Override this method to customize sub-class behavior. Args: value: Value to validate. key: Name of the field being validated. Returns: Value if value is valid, or a valid representation of value.


--- layout: base-en id: support-bitcoin title: Support Bitcoin - Bitcoin ---
Bitcoin is a protocol that was born from a small community and has grown fast since. There are a lot of things you can do to help Bitcoin to spread and improve over time.
Obviously, using Bitcoin is the first thing you can do to help its development. There are most probably many cases where it can make your life easier. And you can accept payment in Bitcoin yourself.
You can join the Bitcoin network by keeping the original software running on your computer. You can also do some Bitcoin mining to make the network more secure by helping to process transactions.
Bitcoin is open source.  Or you can also build amazing new services or software that use Bitcoin.
The easiest way to help is to donate a few bitcoins or join the Bitcoin Foundation. The Foundation funds a salary for the maintainer of the core Bitcoin software, organizes conferences, and provides other important resources.
Speak about Bitcoin to interested people. Write about it on your blog. Tell your favorite shops you would like to pay with Bitcoin. Or be creative and make yourself a nice Bitcoin T-shirt.
 You can help keep the wiki accurate and up-to-date.
Bitcoin is already translated in many languages. However you can translate it in new languages as well as improving existing translations. Translations in the Bitcoin wiki would be very welcome!
You can join Bitcoin communities to give help to new users. And you can talk about Bitcoin with other people and learn more about it every day.


Starbucks offering buy one, get one free on Thursday afternoon when you order through the app
by WPTV StaffStarbucks fans are in for a double treat on Thursday.
The coffee chain is rolling out a buy one, get one free deal, offering a free drink if you buy one that's at least a grande size.
To get the deal, you have to be at a participating store between 2 p.m. and 7 p.m., and you have to place your order through the Starbucks app.
The offer includes both traditional favorites and holiday specials, such as the Eggnog Latte and Peppermint Mocha.
The deal is part of the company's Happy Hour promotion that's available on select Thursdays.
To download the Starbucks app, click here.
This story was originally published by WPTV in West Palm Beach, Florida.


Police: 6 jailed in stolen vehicle arrests in Waunakee within 4 hours
by Brandon ArbuckleWAUNAKEE, Wis. - Officials said six people have been jailed in stolen vehicle arrests in Waunakee within four hours this week.
According to a news release from the Waunakee Police Department, the first incident took place Tuesday at 11:25 p.m.
Police were sent to the Southbridge neighborhood after a report that two male subjects ages 20-21 were attempting to enter vehicles. The men were found in a vehicle and later taken into custody.
The second incident happened Wednesday at 3:09 a.m. Authorities were dispatched to the Meadowbrook neighborhood for another report of a subject trying to enter vehicles.
The suspect ran away when police arrived, and a K-9 track was unsuccessful. Two stolen vehicles were eventually found during the investigation. As the investigation continued, four boys ages 15-17 were found in Waunakee and taken into custody.
One of the teens was taken to jail, while the other three were brought to a juvenile reception center. All four boys were booked on multiple charges.
Anyone with information or video surveillance footage of either incident can call the Waunakee Police Department at<PHONE_NUMBER>.


--- permalink: "/2012/2/3/Node-Require-and-Exports" layout: post title: "Node.js, Require and Exports" ---
Back when I first started playing with node.js, there was one thing that always made me uncomfortable. Embarrassingly, I'm talking about module.exports
. I say embarrassingly because it's such a fundamental part of node.js and it's quite simple. In fact, looking back, I have no idea what my hang up was...I just remember being fuzzy on it. Assuming I'm not the only one who's had to take a second, and third, look at it before it finally started sinking in, I thought I could do a little write up.
In Node, things are only visible to other things in the same file. By things, I mean variables, functions, classes and class members. So, given a file misc.js
with the following contents:
var x = 5; var addX = function(value) { return value + x; };
Another file cannot access the x
variable or addX
function. This has nothing to do with the use of the var
keyword. Rather, the fundamental Node building block is called a module which maps directly to a file. So we could say that the above file corresponds to a module named file1
and everything within that module (or any module) is private.
Now, before we look at how to expose things out of a module, let's look at loading a module. This is where require
comes in. require
is used to load a module, which is why its return value is typically assigned to a variable:
var misc = require('./misc');
Of course, as long as our module doesn't expose anything, the above isn't very useful. To expose things we use module.exports
and export everything we want:
var x = 5; var addX = function(value) { return value + x; }; module.exports.x = x; module.exports.addX = addX;
Now we can use our loaded module:
var misc = require('./misc'); console.log("Adding %d to 10 gives us %d", misc.x, misc.addX(10));
There's another way to expose things in a module:
var User = new function(name, email) { this.name = name; this.email = email; }; module.exports = User;
The difference is subtle by important. See it? We are exporting user
directly, without any indirection. The difference between:
module.exports.User = User; //vs module.exports = User;
is all about how it's used:
var user = require('./user'); var u = new user.User(); //vs var u = new user();
It's pretty much a matter of whether your module is a container of exported values or not. You can actually mix the two within the same module, but I think that leads to a pretty ugly API.
Finally, the last thing to consider is what happens when you directly export a function:
var powerLevel = function(level) { return level > 9000 ? "it's over 9000!!!" : level; }; module.exports = powerLevel;
When you require the above file, the returned value is the actual function. This means that you can do:
require('./powerlevel')(9050);
Which is really just a condensed version of:
var powerLevel = require('./powerlevel') powerLevel(9050);
Hope that helps!


{% extends 'base.html' %}
{% load crispy_forms_tags static escape_extras %}
{% block title %}Project {{ project.pk }} : Sharing{% endblock %}
{% block scripts %}
{{ block.super }}
{% endblock %}
{% block content %}
{% include "projects/_project_header.html" with project=project tab="sharing" %}
{% crispy form %}
Remove project access?
{% csrf_token %}
Are you sure you want to remove access to {{ object.name }} from
[[ agentName]]?
Collaborator access
Name
Type
Role
{% for project_agent_role in project_agent_roles %}
{{ project_agent_role.agent_description }}
{% if project_agent_role.content_type == user_content_type %}User{% endif %}
{% if project_agent_role.content_type == team_content_type %}Team{% endif %}
{% include "projects/_project_role_select.html" with project_agent_role_id=project_agent_role.id roles=all_roles current_role=project_agent_role.role agent_type=project_agent_role.content_type agent_id=project_agent_role.agent_id %}
{% if project_agent_role.role not in roles or project_agent_role.content_type == user_content_type and project_agent_role.agent_id == request.user.id %}
{# show nothing, this is easier than trying to negate the if condition with django template's limited parsing #}
{% else %}
{% endif %}


-ddp.participant.firstName- -ddp.participant.lastName- has submitted a new participant registration. You may view this registration by going to the Study Manager, selecting the tab “Study”, then selecting “Participant list”, and filtering in the search bar with the value '-ddp.participant.firstName- -ddp.participant.lastName-'.


This small port lies just 6nm north of the border with England on the east coast. It still retains many of the features of its ancient herring fishing port past. It still has a working fishing fleet.
In recent years the harbour has been deepened and extended and now there are two new floating pontoons for visiting yachts. There is a depth of 0.9m at LW but the bottom is soft mud.
There is water and electricity on the pontoons. Toilets, showers and laundry facilities ashore at the Harbour building.
The harbour is in the centre of this busy the town but the visitors' berths offer a quiet, sheltered mooring.
Last updated April 2014.


A few days ago Mark Baker left a little comment on WSGI on his blog (for background Mark Baker is an enthusiastic REST advocate).
While he was mostly positive about WSGI, he said this in a comment:
This is the problem [with WSGI]:
def application(environ, start_response):Because it encourages bad practice with HTTP, such as those apps that behave the same way to GET and POST requests (as the examples in the article do).
I think this would have been superior:
def get(environ, start_response): def post(environ, start_response): def put(environ, start_response):
Well, the first reason this doesn't work is fairly concrete. It would actually have to look like this:
class Application: def get(self, environ, start_response): ... etc..
because you can't pass a request to a set of functions, without somehow defining what the "set" is. You could also put them in a module, or some other container object. This opens up a whole bunch of messy and dull questions about how you traverse the container to get to the request method method.
This also encodes request method dispatch into the spec, without encoding any other kinds of dispatch into the spec. The bad solution here would be to encode all kinds of dispatch into the spec. What WSGI got really right was that it has absolutely no dispatch in the specification.
At the same time implementing dispatch in WSGI is really easy. Creating a dispatcher in a style like Mark suggests is rather difficult, because you have to do something like this:
class Dispatcher: def dispatch(self, environ, start_response): return self.sub_object(environ)(environ, start_response) get = post = put = dispatch
And of course you have to enumerate all the possible request methods. This is just silly, but it's become a common design misfeature in frameworks influenced by the Java Servlet specification (e.g., BaseHTTPServer).
The reason I think this misdesign seems reasonable is because other kinds of dispatch are assumed to have already occurred, and are opaque to the specification. WSGI does not make this mistaken assumption.
The primary kind of dispatch that people do is based on the request path. I.e., if you do GET /blog/archive/2006/10, first you have to figure out what /blog/archive/2006/10 is. Here's the general way you do this in WSGI:
Note that this specific example is not the only way it might work. For instance, we might have started with:
This adds virtual hosting. Server environments that code step 1 directly into their environment often have to create special exceptions for virtual hosting. Or:
Now you can set up a wildcard DNS and get your blog app to look up the user based on that key.
If you want to pay close attention to the request method, you are quite free to do so. WSGI does not tell you how, but it does not in any way hinder you from doing so. A good example of something that pays close attention to the request method is Joe Gregorio's wsgicollection, which could very well be the terminal point for some of these examples.
Because WSGI does not include any form of dispatching it represents HTTP very accurately. HTTP does not lend special meaning to the request path. It does not say that different domains resolve to different servers. HTTP is a kind of message, and there are many ways to interpret that message. Low-level specifications overstep their bounds when they interpret those messages for you. WSGI is not an educational project, it is infrastructure, and an important feature is that it does not overstep its bounds.
I'll also note that I think WSGI represents the HTTP message very well; the parts of HTTP that it leaves out are primarily about the HTTP connection, which are best handled by the actual connected-to-the-browser server. The rest of the message is all in there if you want to use it.
"bad practice with HTTP, such as those apps that behave the same way to GET and POST requests"
Is there a real reason why this matters? No.
For one, it matters for the simplicity of a client application. If the server implements REST properly, then all the client needs to know is the URI for the resource it's dealing with and then it basically knows that it can do a GET or a POST or a DELETE or whatever on that URI and the appropriate action will be taken. If the server doesn't distinguish between GET and POST (or the others) the dispatching to different functionality has to be done via the URI, so the client then also needs to know what URIs to hit for the equivalent create/delete/update actions.
The other problem is that if the server doesn't distinguish between GET and POST, then some client somewhere is going to use a GET for an update because, hey, it seems to work. Then a cache somewhere in between might legitimately cache it. Or you get problems like with the Google Web Accelerator that would delete all the content on a site because there are "delete" buttons with links to URIs that delete a resource on a GET request and the GWA hits them all because it ought to be safe to make GET requests according to the specs.
It matters only sometimes, and in those cases people will handle it on their own. It's counterproductive to force everyone to use programming model they don't need just so that someone else will not make a certain (well known and understood) mistake. That's B&D approach which thankfuly is not in Python or WSGI style. import this will give you a couple reasons what is.
It's not really B&D: when you recieve a request, you have to keep in mind what verb was used because each verb guarantees different kinds of behaviour. For instance, it's one thing to treat GET and POST requests identically if what you're doing to process the request fits the kind of behaviour that's acceptable in response to such a request, such as, say, displaying a page, but quite another thing if they don't, such as Anders' example of an application allowing items to be deleted with GET requests.
However, as Ian outlined, such matters are a matter for a higher-level framework than WSGI and deciding them at WSGI's level would complicate the interface between it and the application or framework sitting on top of it.
It is something that matters quite a bit, but because of HTTP itself and not some misplaced desire for B&D. It's something which ought to be in the minds of any application developer because part of developing a good application is using the underlying protocol correctly. It's nothing to do with forcing a programming model and everything to do with passing the request onto another lump of code smart enough to really know what to do with it.
I want to be clear that I wasn't disagreeing with Ian at all. I think he's absolutely spot on that the dispatching on method shouldn't be done at the WSGI level. It should be done by some layer that's on top of WSGI (I use wsgicollection for that, and it rocks).
The point that I was making was just that GET and POST are not interchangeable. They are completely different operations with different semantics. Adhering to standardized semantics isn't B&D, it's just interoperability and it lets you make simpler clients and servers.
Thanks for clearing up my failed attempt at Python; I've only dabbled with it.
You're right that this was partly inspired by Servlets, but only insofar as I consider them to be a pretty good API for HTTP that I've used successfully for a number of years. You can use Servlets as you would use WSGI, by just overriding the service() method, or you can use doGet, doPost, etc.. URI based dispatch can either be handled within service(), or using any of the URI-dispatching tools the containers typically provide (e.g. web.xml). So there's certainly ample precedent for this form of API supporting the flexibility WSGI seems to require. But only doing the equivalent of service() (as WSGI currently does) places more of the burden on remaining HTTP-friendly with what's built on top. Perhaps that will work out, I don't know, but I don't see much downside to such a framework constraining the use of HTTP as I've described. But if it doesn't work out for WSGI, and you have apps which, for example, don't distingiush GET and POST, then you lose the ability to, say, support cache management at the WSGI level. Providing a Servlet-like API doesn't guarantee you that HTTP won't be abused of course, but it does reduce the likelihood that it'll be done accidentally.
Mark, not much people will wirte apps directly to the WSGI layer, but instead they'll use some framework... or at least will use some simple tool (like the 'selector' wsgi dispatch - http://lukearno.com/projects/selector/).
# Damjan


App Showcase
Indie Support Weeks is an open effort aimed at helping indie developers within the Apple Developer Community who have been impacted by the current global COVID-19 pandemic. We will be showcasing the apps created by the indie developers inorder to support them during these times of global pandemic. Download their apps and support them. We do not charge for showcasing any of the apps. We will showcase the apps only if they meet certain quality checks. Do you want your app to be reviewed by us and showcased in here? Send an email to<EMAIL_ADDRESS>App Showcase
1. Winya (iOS, and iPadOS)
Summary - Stream games from iPhone/iPad like a PRO. The UX of the app is amazing. It gets you started in seconds.
Key highlights - Stream games, Unlimited streaming, pause streaming, control video quality with precision, control audio quality with precision
2. Sourcery Pro (macOS)
Summary - Sourcery Pro is the most advanced Xcode Source extension ever made. Do you hate writing protocol mocks, adding Codable conformance,or just writing same patterns over and over again Now you no longer need to, it’s just a shortcut away, and you can automate any other repetitions in your Swift codebase too!
Key highlights - Generate Swift code, Xcode extension, Automate repetitive code, powerful editor with intelisense
3. Proxyman (iOS, iPadOS, and macOS)
Summary - Developers, rejoice. We have an excellent debug assistant to add to your toolkit. Its name is Proxyman – from Proxy + middleMan. Natively built for macOS, the app is an easy way to intercept HTTP/HTTPS requests and debug from your Mac, iOS simulator, or remote devices without disrupting your network connection.
Key highlights - Intercept network requests, network debugger
3. Core Data Lab (macOS)
Summary - Core Data Lab lets you easily view, edit, track and analyze data of SQLite based Core Data apps. Trust me, it is the best CoreData debugger tool out there.
Key highlights - Data change tracker, predicate editor, data editor, extensive field viewer with support for HTML, XML, JSON, images, binary content and more, simulator browser, relationships viewer, entity description viewer, export to CSV and JSON.


This Application demonstrates the importance of Event streams. Taking data from the server located at data center to the Network monitoring center is defacto now a days. Data analytics plays a crucial role in businesses. A stitch in time saves nine applies here.So, Taking the data from the server to web browser and showing data in terms of Charts is very important for easy comprehension.
Play system monitor uses top
command line utility of linux/unix to
send the system memory and CPU usage statistics to the web UI using event source.
top -b
produces system memory, cpu usage data continuosly. top -b
-b makes top run in batch mode and send the data that can be captured and used by other programs.
Please check top command to know more about it or do man top
to read the man page of the top command.
Now process API of scala helps to execute the system commands from the Scala code and the output stream of the data produces by the system command can be captured.
Here is the code snippet which helps us to understand executing system command from scala
import sys.process._
"cat somefile.txt".!!
The above code executes the cat command and prints the output to the scala console
Note that the top -b
continuously produces the data so we capture that stream of data in the iterator rather than consuming it at once. So, we request the iterator while executing the linux command.
import sys.process._
"top -b".lines_!.iterator
Iterator obtained from executing the process can be passed to Enumerator.enumerate(iterator)
method to get the Enumerator[String]. Once we get the Enumerator we are good to go and get the required lines containing the CPU and MEM data.
Enumerator thus obtained can be adapted using the Enumeratee
From the Final Enumerator[JsValue]
we now can turn this into event source using the following code snippet
Ok.chunked(enumerator &> EventSource()).as(EVENT_STREAM)
Now instantiate the EventSource() object passing the endpoint and in the callback function data is received in a push manner.
var source = new EventSource("@routes.Application.mem()");
source.addEventListener('message', function(e) {
//e.data is the data in the form of json from the action @routes.Application.mem()
});
The above obtained can be used to update the UI element.
Chart.js helps to draw nice charts like pie, doughnut, Bar, line etc calling the update function on the chart would change the UI with an animation and transitions look cool.


Email
History
Settings
Subscription
SignOut
Send Emails
500 out of 1000
Drag here to upload
or
choose file
Sender
Drag here to upload
or
choose file
Sender
Subject
Message
Submit


{# This form expects a "form" variable and a "form_action" variable #} {# "form" should be the form to be displayed #} {# "form_action" should be the url to post the completed form to #}


Flash and JavaScript are required for this feature.
Download the video from iTunes U or the Internet Archive.
Description: How can we recognize the number of objects in a line drawing? We consider how Guzman, Huffman, and Waltz approached this problem. We then solve an example using a method based on constraint propagation, with a limited set of junction and line labels.
Instructor: Patrick H. Winston
Lecture 7: Constraints: Int...
PATRICK WINSTON: Many of you, maybe most of you, will never have to work another search problem by hand in your natural life.
Others will want to take another run at it on the final.
I've been much criticized for this way of doing grading in the class.
But the way I look at it is that the relationship between students and instructors ought to be less adversarial than it used to be in the good old days when I was a student.
I especially remember an examination we took-- all of us took-- on Rayleigh scattering.
That was 803, I think.
And back in the old days, we had to take four physics courses, not just two.
And we had to take four math courses, not just two.
Back in the days when-- well, I was going to say men were men.
But most of us were men in those days.
I think we only had 20 women in our class.
Anyway, we had a quiz on Rayleigh scattering.
And I thought, well, this is pretty hard.
And then I got my quiz back.
26.
I thought, well, I've been found out.
I'm going to flunk out.
My father will make me go to law school.
I'll never attract anyone to marry.
Horrible things will happen.
Then the instructor announced the class average was 18.
I was two standard deviations above that.
They gave us the same exam two weeks later, and accounts vary.
Some people say that the class average went down.
Anyway, today we're going to study some stuff.
We're going to study some stuff that will make it possible for you to understand how you can do that computation in just a couple of seconds, even with the delays introduced by the redrawing.
Now this particular program-- I'm not real sure and I don't have a proof, but I think it will take more than the lifetime of the universe to find a legitimate coloring of the continental United States.
But by the end of the next class, you'll see how to do that lickety-split in just couple of seconds, even with the re-display delays.
Now we could, of course, do this in two ways.
One way is I could start off by saying, let C be a constraint satisfaction problem and just give you the result.
And anybody can do that.
That's great.
And you needed to learn some stuff that way.
But there are some things that you needed to learn, I think, a different way.
And that different way involves my telling you the story of how it all came to be.
This is a new field, pretty much, and therefore I know most of the people in it.
And I know all of the people who did the work that I'm going to tell you about today.
I'm going to tell you a little bit about the struggle for coming up with the ideas that led to one of the most powerful methods you'll learn about in the subject.
It all has to do, originally, with an attempt to make a computer capable of seeing.
And everybody said to themselves, well, let's start with seeing simple things, like children's blocks.
And so Adolfo Guzman, a graduate student of Marvin Minsky's, was charged with the summer project, which led to his Ph.D. thesis, of writing a program that could look at a line drawing and determine how many objects are in the line drawing.
So for example, there behind my outline is a line drawing.
And you believe instantly that there are two objects there, even though in some deep sense, it's ambiguous.
There are all sorts of ways that you could, through trickery, arrange something with even seven objects that look that way.
But most people would say there are two objects.
So Guzman set about the problem of figuring out how to do that.
And then his work was followed by Dave Huffman.
And his work was followed up by Dave Waltz.
And his work was followed up by Jane [? Froyter ?], who's not listed there quite yet.
And I want to tell you a little bit of story how that all happened.
So Guzman took a lot of pictures.
He went to Boston Baby, the precursor to Toys R Us, purchased a large block set on a government contract, and went about the business of taking a lot of pictures of them so he'd get a feel for the domain.
And eventually he decided that he could build a program that could determine that there are two objects here by using the lines as a quanta of evidence about which faces belong together in an object.
So he said, after studying these for a long time, that these drawings tend to have a lot of arrow-type junctions and a lot of fork-type junctions.
And when you see an arrow, it's a little bit of evidence that the objects on either side of the shaft are the same-- the face on either side of the shaft belong to the same object.
And over here, the fork-type junction suggests that pairwise, three pairs of faces seem to belong to the same object.
So with that idea, he could come back to a drawing like this and start decorating it with these so-called links, these quanta of evidence that faces belong to the same object.
And if I've done it right, you get something that looks like so.
It's a little hard to see what's going on on the drawing itself.
So let me number these.
Now I have an easier-to-deal-with picture.
There are two links between 1 and 2 and 1 and 3.
One link between 2 and 3.
One between 2 and 4.
Two here.
Two here.
And one each from all of these.
So Guzman produces this evidence for how the problem ought to be solved and then he begins to think about various ways of using the evidence.
So he could, and did, decide that one link is enough to presume that the faces belong to the same object.
And you can see that that's a little bit too liberal.
Because that says that the whole thing is just one object.
So Guzman rejected the one-link theory and went to the two-link theory.
And the two-link theory says, oh, well, let's see.
If we insist that two links should be there before we are willing to decide that it's the same object, then these three faces are pulled together into one object.
These three are pulled together into one object.
But alas, 7 doesn't share two links with anything, so it's left dangling out there.
So plainly, the two-link theory is too conservative.
So that as you would soon discover in any [INAUDIBLE] project, would lead you to a third theory, which is two lengths repeated.
So now that we've formed these super regions, we can come back and say we'll merge super regions if they're connected together by two or more links.
So nothing new happens up here.
But this super region is joined at 7 by two or more links.
So it pulls everything together like so.
So that worked fine.
Well, it didn't work fine.
There were lots of examples of situations where it didn't work-- in situations that were considered nonsensical by us humans because it seemed silly, the kind of conclusions that it reached.
So when Guzman presented this work in his Ph.D. thesis defense, it's said-- and who knows if it's true-- but it's said that Marvin Minsky thought it was great work and we should make him a professor.
It happens that Dave Huffman was also on the committee and said that it was ad hoc and the thesis should be rejected.
So we had two polar opposites of impressions there.
Dave Huffman, by the way-- you've heard that name before, I imagine.
It's the guy who invented Huffman coating as a term paper in a information theory course taught by Bob Fano.
He got an A, they say.
So Huffman didn't like it.
He thought it was a little bit too ad hoc.
It was too heuristic.
It didn't take advantage of anything we might know about physics.
And so people began to say, well, why does it work?
And when does it not work?
And that's just about the best question you can answer in a situation like this.

We'll reserve the word junction for something else.
And three-face vertexes generally project into either an arrow or a fork.
So Guzman's whole program worked on the weak backward conclusion that if you see one of those, it probably came from one of these.
So this is in the drawing.
That's in the world.
So by a process that's neither deduction or induction, but rather abduction, you see one of those guys.
And you say, well, they often come from three-face vertexes in the world, so if you see one, it probably came from a three-face vertex in the world.
That's abduction.
So once Huffman saw all that, being a mathematician, he began to think about how one might develop a different and better theory.
But we have to recognize that all this work started off with the efforts of Guzman, who was an experimentalist.
And Huffman was a mathematician.
So naturally, they approached the problem differently.
So Huffman says, I'm not going to concern myself too much with the actual problem that Guzman was trying to solve.
Rather, I'm going to work in a very simple world, which I can deal with mathematically.
So he decided that he was going to work in a world which had several characteristics.
Characteristic number one was that the world would be presented in general position.
That is to say, no screw cases.
So if you see a cube, it's going to look like this.
And it's not going to look like this.
So that's out.
And this is in.
And the idea here is that that's not general position, because if you perturb your point of view a little bit, you'll change those T junctions into forks and arrows.
So we know it had to deal with those kinds of weird kinds of cases.
So that's presumption number one.
Presumption number two is that we're going to be dealing with a world that's trihedral.
That means all vertexes out there are going to be formed from three planes.
So you're going to have the intersection of three planes.
So how many kinds of junctions can you see if the world is composed that way is the question that Huffman sent himself upon.
The next assumption was that there are going to be four kinds of lines.
See, Guzman only recognized two kinds of lines-- lines that have a length and lines that don't have a link.
And they don't have very much to do with the physical world.
So Huffman says, I want to get the constraint out of the physical world.
So I'm going to deal with four kinds of lines-- concave, convex, and boundary.
So each of those kinds of lines is going to have its own notation.
We'll call the convex lines plus, the concave lines minus, and a boundary lines are going to get an arrow on them, depending on which side of the object-- which side you would see the object if you walk along the direction of this little arrow.
STUDENT: Question.
Which is concave and which is convex?
You said something and you wrote the opposite.
PATRICK WINSTON: Yeah, sorry.
Thank you.
So concave, convex, and boundary.
Thank you.
So this down here, that's a concave line.

Oh, I don't know.
These lines you're seeing here, if there were stuff behind them instead of me, then all those would be convex lines.
Many times you see a boundary line.
For example, now you don't see both sides of that line down here at the bottom.
So that's a boundary line.
And the arrow would point in that direction, so as to keep the stuff of the object on the right as you walk along a kind of mathematical convention.
So three kinds of lines, four kinds of labels.
And there's some things left out.
That's because Huffman wanted to keep his problem simple, something he could manage by hand.
What's left out?
Cracks are left out.
Shadows are left out.
There's a presumption that there's nothing of interest here with respect to that.
So let's have a little vocabulary before I go on.
And I'll try to stick to it.
But there's the stuff out there, and that consists of vertexes and edges.
And over here, on the blackboard, we'll have junctions and lines.
And I'll try to stick to that vocabulary.
All right?
Yes, Christopher?
STUDENT: Didn't you say there were four types of lines?
PATRICK WINSTON: Yeah, there are four kinds of-- the question is, didn't I say there were four kinds of lines?
There are three kinds of lines, but since we can label a boundary line in either direction, we have four labels.
OK?
It depends on which side of the object the stuff is on.
And that will be clear, I think, as soon as I do an example.
So one, two, three assumptions.
A little bit of vocabulary.
So we have the possibility of making a complete catalog.
This is so simple.
We have the possibility of making a complete catalog of all the ways that lines can come together to form a junction with respect to these four labels.
Now at first you might say, oh my god, that will take a couple of years.
But maybe it won't take a couple of years.
And in the end, to perhaps your surprise, you discover that there are only 18 ways to arrange the labels around a junction in this world.
Everything else is excluded.
If you have something that's not in the set we're going to produce now, it can't be built with trihedral vertexes.
So I've listed up there six L's, five forks, four T's, and three arrows.
Let's see if I can figure out why there are those 18 and nothing else.
Well, if we have three vertexes coming together, that means there are eight octants, right?
And the stuff of the object may fill 1, 2, 3, 4, 5, 6, 7 or all eight octants.
Now of course, if you fill all eight octants, there's no junction.
So we don't consider that case.
If we don't fill any the octants, there's no junction.
There's no vertex.
So we don't consider that case.
But if just one of the eight octants is filled with stuff, then we can look at it from any of the seven remaining octants.
So right now, you're looking at it from one of the seven remaining octants.
And if I'm not mistaken, you're going to see a fork-style junction there, right?
And you're going to see a fork-style junction in which all of the edges are convex.
An unfortunate selection of names, because the linguists tell me that we index all of our words by the first forename.
And those have the same first forename, so they're easily confused.
So here's a fork-style junction.
And we know that one way that's legitimate for the lines to come in is with four pluses.
Now that's not the only way you can see that.
And here's another way.
There's an L-style junction, right?
And both of those are boundary lines.
And we want to draw the boundary line indicators on there so that if we walk along the arrows, the stuff of the object would be on the right.
So I suppose, to make it easier to me do my drawing, I should look at it this way.
And then I would say, well, that has to be a legitimate way of labeling a junction.
Are there any more?
Well, there's seven altogether, but many of them are the same.
There is one more that's a little different, though.
I can hold this guy up like so.
And if I'm holding at the right angle for you, you see an arrow-style junction, right?
Two boundaries, and the barb is convex.
So in this particular case, I've got that.
I've got that.
And I've got a plus there.
And that's there happen to be for the one octant filled with stuff case.
I happen to be able to reverse this, though.
And here's the seven octants filled case.
So that tells us that it's possible to have a vertex out there in a space that when reduced to a junction on the board deserves three minus labels, because all of these that you're seeing now are concave.
So another fork-style junction looks like so.
And since there's only one octant to look at from, that completes our analysis of the seven octants filled case.
Now we have a couple of other possibilities here.
We might have five octants filled with stuff.
So that means there are three octants that we can look from.
So let's suppose that these little chalk pieces are little people.
And they're looking at this junction down there, where this white object is fused with the table.
I'm fusing it with the table because I want to consider it to be one object.
We can view it from the three objects indicated by those three little chalk pieces.
And ask ourselves, well, in the event that we look at it from those three places, what do we see?
And if we look at it from the perspective of the piece of purple chalk-- I'll have to walk around and be sure-- looks like an arrow junction with two concaves and a convex.
Did I get that right?
So I'm looking at it from this perspective.
It's an arrow.
This is convex and these two are concave because I fused the paper box with the table.
Looking at it from the perspective of this blue guy-- let me rotate it so you can have a better understanding of the blue guy-- it looks like a concave line and a boundary.
So it's an L. And this one is a boundary.
And that's concave.
And by a kind of symmetry, we're also going to get that one from the other side, the third of the three octants.
Well, we're off and running.
But we still have an awful lot to go.
And we could manage to deal with it by thinking about this object once again.
But instead of this situation out here, to turn it around and look at this vertex.
Think about the junctions that it can produce.
I think I'll do that for you.
Because you really have to play with this and move it around a little bit to see how things are going to look.
So let me think about how that's going to work out.
I know that one of the possibilities is going to look like so.
I might as well not hide that from you.
It's going to be what happens when there's a little man looking up at the junction.
And this one's going to be minus.
And now we've got two more that are just like that.
Look like so.
And you say, oops.
You say, aren't those just a rotational variance of each other?
And the answer is sure.
I write them all down, because if you get a fork-style junction in space, there are three different ways it could be labeled.
Depending on which of the lines you put the minus label on.
So that takes care of that.
And then there's one more of these fork-style junctions.
And that's plus, plus, minus that derives from this case.
And there appear to be three more of these L-style junctions.
And they look like, let's see, plus, then plus.
I'm having to think this through as I go.
And then-- and that's it.
Well, what about the T's?
Well, in this world, the only way you can get a T is if some object is obscuring another object.
And if an object is obscuring a line, it can be any line at all.
So that's why the four remaining ones are easy beyond description to label.
And of course, the cross pieces of the T are all boundary lines, with the obscuring object on the right.
Now let's see.
We've taken care now of the one, three, five, and seven octants filled cases.
What about two, four, and six?
Well, it turns out you can have vertexes that are made that way too.
But they will have more than three faces.
They'll have six faces.
They'll be like what happens when an object comes together at a point, like so.
Like that.
You can play with it a little bit and see that if you have two, four, or six objects filled with stuff, there are more than three faces.
So we're going to ignore those.
So our constraint is going to be a little more severe than would be suggested by the terminology Huffman uses.
They're going to be trihedral all right, but they're also going to be three faces.
So we went to a lot of work there.
But what have we discovered?
We've discovered that in this world, this is a complete, 100% percent, nothing excluded, nothing else can be there, catalog of all possible ways the junctions can have line labels arranged around them.
There's nothing else in this world.
So that's a very powerful constraint.
So now let's see what we can do with it.
This example is usually more fun when the Red Sox are doing better, but they're not.
Yet we'll use it any way.
We're going to start with an object that looks like home plate.
And I'll ask you the question.
Can you build one of those?
I don't know.
Let's give it a shot.
We're going to assume that this object is hanging, floating in space.
So therefore, all of these lines around the boundary are boundary lines, like so.
Now that gets us off to a good-- it's just hanging in space, Christopher, all right?
You look confused.
It's just hanging in space so that all the lines around the edges are places where you see only one side has stuff on it.
So that enables us to just quickly run around the periphery and put arrow labels on all those outside lines.
Now we have a lot of arrow-style junctions on the boundary.
That's commonly the case.
So we can run over to our catalog of all possible labels, and we see that if we have an arrow with boundaries on its barbs, there's only one of those.
So I know instantly that there must be a plus on the shaft.
So we can come back here and take all these arrows here.
And label them with plus lines on their shafts.
Now a line can't change its nature along its length.
So if it's a plus line on one end, it's going to be a plus line on the other end.
All right?
So what else can we do?
Here deep inside is a fork-style junction.
It's got convex markers on both of those two lines.
So we go over to our catalog and say, what can we say about it, given that there are pluses on two of its lines?
Whoop, that means that the third one has to be a plus as well.
And now we're done.
We've labeled everything.
Except-- look at this.
What about that guy?
There's an L-style junction with pluses on both of its two lines.
Is there one of those in my catalog?
No.
Therefore, I haven't passed a necessary condition for constructability in the world that I've made.
You can't make it.
You can't construct it.
So Huffman's ideas give us a way of testing something to see if it's not possible for it to be in this world.
If it passes the test, does that mean it's possible?
No.
It's a necessary but not sufficient condition.
On this one-- blue-collar occupation-- on this one, maybe it will help if we put in another line.
For example, we could put a line like so.
You feel better about it now?
I don't know.
Let's see.
This has to be a plus for the same argument we used on several other arrows before.
That gives us an arrow-style junction here with a plus on everything.
Is there such a junction label?
No.
We lose.
It doesn't help.
You think you can make it, but you can't.
STUDENT: You could actually construct it as a 3-D object, though.
PATRICK WINSTON: He thinks you can construct it as a 3-D object.
Let me show you the next example, Christopher.
Consider this example.
Can you make that?
Your intuition is yes.
So let's label it.
Oh, I've already lost.
We just boost that up a little bit to make the situation more clear.
So already, I've got myself in a situation where I can't label that.
But you feel like you can make it.
So what's wrong?
What's wrong is-- what, Elliott?
STUDENT: You have an obscured-- or, we're presuming that we have an obscured [INAUDIBLE] alley from the upper-left corner to the [INAUDIBLE].
PATRICK WINSTON: Putting a little interpretation on what Elliott has said.
If you look at this situation back here, you get a four-faced junction there.
So you can make it.
But not with three faces.
So some of these look like you could make it.
But they can't be labeled because you need more than four faces at a junction.
And we can carry that idea back here.
You can make this OK.
But this junction, you've got two in the back and two here.
So it has four faces.
Same idea.
So that's Guzman's contribution.
That's Huffman's contribution.
Huffman was a mathematician.
But we wanted to build robots back in those days.
And neither one of these guys solved the problem of dealing with natural objects with shadows, with cracks, with more than trihedral vertexes in space, and what to do about that?
Well, that was a problem that another graduate student, David Waltz, set about to solve.
So Waltz decided that he would not be content unless he added cracks, shadows, non-trihedral vertexes.
Uh-- yeah, non-trihedral vertexes.
And light.
These considerations led Waltz to go from four labels to 50-plus.
Because he had to pack a lot of information into each of the labels he put on a line.
What kind of light was on the right?
What kind of light was on the left?
Maybe it's a crack.
Maybe it's a crack that-- all sorts of considerations.
Here we had 18 ways that lines can come together around junctions.
That went to thousands of junctions in Waltz's world.
So here's Guzman.
He writes a program that sort of works.
Down below, we have Huffman.
Huffman, who has a theory but solves the wrong problem.
So here comes Waltz, and he's trying to solve the right problem with a satisfying theory that has a generalizable principle.
So when we get all through this, we'll talk about criteria for success.
And we'll conclude that to have a really successful thing, you need a problem, to start with.
You need a method that works.
And you have to show that it works because of some principal.
So Guzman had the problem and something that worked.
Huffman had a method which worked on the wrong problem.
And it's left to Waltz to bring it all together.
So Waltz does all this work.
And now he has, instead at 18 labels, he has thousands.
Instead of four-line labels, he has more than 50.
So naturally, it becomes difficult to work these by hand.
We were able to work those Huffman examples by hand.
We started with labeling everything on the boundary and worked our way in.
There's no particular method there.
It was just easy to work out the puzzle.
But poor Waltz, he didn't have that luxury.
So he might have, in a typical scene, he might have tens or even hundreds of junctions to label and no easy way of dealing with it.
So naturally writes himself a depth-first search program.
So here is vertex, or rather junction number 1.
There are many choices for which label can be used on it.
And for each of those choices, whatever he's decided junction number 2 is has its own suite of possibilities.
And so it becomes a simple depth-first search problem, right?
So in actuality, as soon as Waltz-- he was my office mate at the time.
I can tell you this for a fact.
As soon as he wrote this program, he kept looking over at the computer-- they were big in those days.
They all had lights.
So you looked over at the computer to see if the lights were still blinking.
Because he'd start this depth-first search program up and nothing would happen.
He thought the computer had crashed.
Nothing happened.
Why did nothing happen?
Because the search base is exponential and much too big for an ordinary computer, or maybe even an ordinary universe.
So Waltz has to do something else.
He has to come up with a new method for using all these labels that he's-- after about a year and a half's worth of hard work, with lots of paper on his desk in little blocks.
After year and a half of hard work getting all these junction labels figured out, he then has to come up with a method for figuring out how to use them.
And so we don't know whether to think his biggest contribution was that label set or his method.
And probably both deserve about equal billing.
Oh, I don't know how to explain what Waltz did.
Well, one way is to do an example.
And I think I will hazard an example.
Let's see.
Let me find some space.
I think I'm reduced to going over here.
But that will be convenient, since the line labels are here.
Here's my example.
And you say, how can I give you just part of a picture?
Well, you can assume I'm looking at this through a window.
So the edge of the window form boundary lines, and they exert no constraint whatsoever on what's behind them.
So this is a legitimate drawing to have to think about.
By the way, is this ambiguous?
Or do you get a firm sense that there's a unique interpretation of all those lines?
I think there's a unique interpretation of all those lines.
What I'm going to do is I'm actually going to solve this problem using Huffman's labels but Waltz's method.
Because I can't simulate on the blackboard something with 50 line types and thousands of line junctions.
So I'm going to use Huffman's set to demonstrate Waltz's algorithm.
So Waltz's algorithm involves starting out by plopping on some junction all of the possible labels that the answer has to be drawn from.
So let me number these in the order that we're going to visit them.
Like so.
And so far, I've just put down the three fork options that are resident on that first junction.
And I have to take note of exactly what they do with the lines that come out of the junction.
So let's see.
I'll just copy them down.
One possibility is this one.
Another possibility is this one.
And another possibility is plus, plus, minus.
Oops, I've got plus, plus.
No, that's right.
So that right so far?
All I've done is copy the junction labelings from my library.
And at this point, Waltz's algorithm says there's nothing else to do but go on to junction number two.
And unfortunately, sadly, there are lots of labelings that have to be considered on junction number 2.
Six of them.
1, 2, 3, 4, 5, 6.
So one of them looks like that.
Another one looks like that.
One of them is plus here, arrow in.
Another one is plus here, arrow out.
Another one is minus here, arrow down.
And minus here, arrow up.
I think I've copied those all right.
But now, having copied those down, Waltz's algorithm looks around at the neighboring junctions and says, are any of the things that I just placed on junction two disallowed by what I've already placed on a neighboring junction?
So it looks over here in step number two.
And it sees that these three arrows require the line that joins junctions 1 and 2 to be either minus or plus.
So of the six possibilities, I can only keep the ones that are likewise content to put a plus on that line that joins the two.
So that means that the influence flowing from junction 1 eliminates that one, eliminates that one, eliminates that one, and eliminates that one.
So half of them are gone.
All the ones that try to put a boundary line on that line between 1 and 2 are disallowed.
All right?
Now likewise, we could say, well, of the remaining ones, do they restrict what I can do at junction 1?
So let's see.
Here's a minus.
And here's a plus.
So all these possibilities over here are still alive.
So now, continuing on, we have to see what we can do at junction 3.
These are arrow labels again.
So we have to copy exactly the same labels set as we had before.
And now we look down at junction 2 and say, well, what does that tell me about the three that I've just placed?
If we look up from junction 2 to see what kind of constraints it puts on here, we have this one alive and this one alive.
I guess we've eliminated four of the six.
So we have these two alive.
And they both but boundary lines-- I think I must have had this boundary line wrong, right?
No, that's right.
Oh yes, I see.
Plus.
This one goes-- hang on a second.
You let me do something wrong.
So plus is out.
And that must be one that goes-- this minus goes up.
Oh, yes.
I'm too hasty and uncertain about what I was doing.
So let's see.
This guy has a boundary going down.
And this guy has a boundary going up.
All of the others have been eliminated.
So that means that something that tries to put a concave line there is gone.
And something that tries to put a plus line there is gone.
So the influence flowing up in this direction in the third step eliminates that guy and eliminates that guy, leaving only this guy.
But now, the thing I was worried about is you have to also at this point go down to 2 and see if there's any further constraint on what can survive down there, based on what has happened over here at junction 3.
Now let's see.
This one goes up, which is compatible with a survivor.
But this one goes down, which is not compatible with a survivor.
So when I bring this down in step three, this guy is eliminated.
So now I'm down to just one interpretation for what can be going on at vertex number 2.
And one interpretation for vertex number 3.
Now let's see.
This can propagate.
So now that I've made a change on vertex number 2, I have to also see if that causes a change at vertex number 1.
So it's propagating through.
And now I can see that the only possibility here is a minus, the label that's coming down from our survivor.
So that eliminates these two.
Whew!
It's hard to do this by hand, but I've got three of the four things labeled.
And even with just three of the four labeled, I'm down to a single interpretation for all of the junctions and the lines between them.
So there's one left.
We have to deal with that fork vertex.
We better deal with it, because for all we know, this is not a legal drawing in this world.
We have five fork vertexes to place.
But you know what?
I don't have to draw much here, because I know this is forced to be a plus now.
And this is forced to be a plus now.
And there's only one fork vertex with any pluses on it at all.
So now I can come through and say, well, the only possible survivor is this one.
These are gone.
And now I have an interpretation for all of the junctions.
And I see that the winners are this one.
And this one.
And this one.
And this one.
So I've got a unique interpretation.
This line is convex.
This one is concave.
This is a boundary.
That's a boundary.
And this line is convex, and that's convex.
Now that's a lot of work.
So I better check and make sure I got it right.
You'd like to see this demonstrated to make sure I haven't made a mistake.
I'm sure of that.
Let's see.
That it?
So each of the places where a line is obscured has four possibilities, labeled E. The arrow junctions are labeled A.
The forks-- there are five of them-- at the fork junction 5.
So let's just step through here and see what happens.
Boom.
I've got it.
I did do it right.
So let's try some more.
What do you think will happen with this one?
Unique solution?
It stopped.
Bug in my program?
Unthinkable.
What's happened?
It is genuinely ambiguous.
It can be something hanging down from the ceiling.
Or it could be something that we can think of as a step going up from left to right.
Let's look at something more complicated.
You think it'll work?
Not enough constraint for us to figure that one out.
It's equally ambiguous, but a little bit larger example.
What about this one?
Yeah, but the stuff is creeping up from the lower left up to the upper right.
Yeah, bingo.
It worked.
It's unambiguous.
It's variation on the same theme we had before.
But let me, just for fun, take these two lines out.
What do you think will happen now?
Seems to be doing just fine until it hits the upper right-hand corner and discovers it can't label stuff.
So it propagates back down.
And what looked OK in the lower left is no good after all.
So these results are kind of consistent with what we humans do when we look at these kinds of things.
So it's very likely that we, in our heads, do have some constraint propagation apparatus that we use in vision.
But putting that aside, we can think about other kinds of intelligence different from human, that might use this kind of mechanism to solve problems that involve a lot of constraint in finding a solution.
So here, we saw the constraint propagation activity at work on line drawing analysis.
But next time, what we're going do is we're going to see at work in map coloring.
And who cares about map coloring?
People who do scheduling, because that turns out to be the same problem.