Over the past three months I have participate in both formal and informal learning opportunities to deepen my knowledge of User Experience. Formal learning opportunities including completing online courses for user experiences in an academic setting and developing a blog. My informal learning opportunities occurring through meetups across the area of Seattle, independent learning, reading and additional online courses.
a critical aspect of user experience is the development of a website and content to increase services, products, or engagement of users in a website. Google analytics allows website owners to track client engagement with marketing materials, product sales, videos plays, and so much more. Businesses can use google analytics data, goals, and other categories of data analysis to create website content to reach their desired results. Website goals can be achieved and measures through a variety of analytics tools such as goal setting and optimization or effective use of captivating content.
Setting Goals
Google analytics allows website owners to goals in four categories- Destination, Page views, Event, and Page/Screen- owners can set goals based on business objectives owners can then use optimization to track specific pages to measure goal effectiveness.
During Optimization, website owners can select variants, items to test, and targeting pages to test variants, and identify website functionality to optimize. The optimization goals for the User Experience Journal included duration goals, media play and session duration. The goals were selected based on previously collected data for a longitude comparison. Media content was added to the User Experience Journal as an additional method of learning for potential clients and was set as a media event. Media as a visual learning tool used to improve the overall user experience had the potential to increase session duration.
Methods: Goal Implementation, Tracking, and Funneling
Goal implementation process included identifying a goal to implement in the conversion, administrative and goal setting tools. The Event goal was set by identifying Event category as a goal, media play, and setting a category and action for Media. The engagement and session duration and engagement goals were set by identifying the goal type and the amount of time the user experience journal would engage users and adding the optimization script tag to the user experience journal page for measurement.
Three strategies for funneling users to the experience jounal included emailing a direct request to students from the formal earning setting. Posting the User experience journal online and posting a link to the user experience journal on a slack channel of users participating in an academic setting.
The implementation included changing two of the previousu videos on the index page from previously viewed videos from the formal education setting to new content about a similar subject. The two updated videos related to exploring careers in UX, becoming a user researcher and how to get hired without a portfolio. The video topics were selected based on the methods used to funnel users to the website, the direct emails and slack posting have an audience of clients in the process of completing a credential with a UX learning requirement.
Results: Goals and User experience Journal
The results of the goal setting experiment concluded with the engagement and session duration goal having the strongest rate of conversion 3.57% percent, with the event goal at a zero converson rate.
My hypothesis for the conversion rate of session duration being the strongest outcome includes the review of previous assignments and additions to the index page.
The funneling process for all the goals were held constant, however the results of the funneing process impacted the session duration goal the greatest.
The overall engagement of the user journal engagement journal improved over the three month process, the greatest increase in users occuring in the month of may with a new 25 users viewing the user experience journal causing a spike in data. This outcome is hypothesized to occur based on the direct email request to view content, the update in index page content and review of previous assignments having the strongest page views


Tutorial : Director
Objects: VDirectorGroup, VDirectorTrack, VDirectorEvent
This group is unique - you can only have one Director Group in your sequence.
The Director Group, coupled with a Director Track, gives you power over scene definition and camera views in your sequence. This is particularly useful for Cinematic or Cutscene sequences! You wouldn't need to use a Director if you were, say moving an elevator or opening a door. In this case, you will remain in control of your Player, Vehicle or Camera.
The Director Track also allows you to define Scenes in your sequence, which can be jumped to using Scene Jump Events.
How to Use:
In this Sequence, I have a Director Group and Track as well as a valid Camera Group. If you are unsure of how to create or validate a Group, click here.
Right-Click on the Track and select "Add Event".
Select the newly created Event. From the Property List window, you are able to identify which Camera you would like to Cut to when the event is triggered.
Here you can also define the name of the Scene by applying a Label to the Event. If you wanted to define a Scene without changing the camera, you would need to create a new Event and reference the same Camera Group in the last Event.


--- title: "LED Wall Washer Light, LWW-5-12P, LWW-5-18P，LWW-5-24P，LWW-5-36P, Linear Wall Washer, Architectural lighting, China LED Wall Washer Suppliers, IP65, DMX Stage Lighting, RGB High Power LED Wall Washer, LED Floodlight, LED Projector, Wall Washer Manufact" description: "LWW-5-12P, LWW-5-18P，LWW-5-24P，LWW-5-36P, LED WALL WASHER LIGHT is mainly used for decoration and highlight in building frame, garden, restaurant, Architectural lighting and stage scene etc, by offering colorful and magic environment. It can work in independent mode and DMX mode, which can generate various color changing effects, such as flashing, fading, steady, seven colour jumping synchronously etc." keywords: - LED Wall Washer Light - "LWW-5-12P" - "LWW-5-18P，LWW-5-24P，LWW-5-36P" - Linear Wall Washer - Architectural lighting - China LED Wall Washer Suppliers - IP65 - DMX Stage Lighting - RGB High Power LED Wall Washer - LED Floodlight - LED Projector - Wall Washer Manufact ---
|
LED WALL WASHER LIGHT |
|||||||||||||||||||||||||||||||||||||||||
|
LED WALL WASHER LIGHT is mainly used for decoration and highlight in building frame, garden, restaurant and architectural lighting etc, by offering colorful and magic environment. It can work in independent mode and DMX mode, which can generate various color changing effects, such as flashing, fading, steady, seven color jumping synchronously etc. DMX256 classes gray degree dimmer, DMX programmable (thousands of effects available if many lights connected together). |
|||||||||||||||||||||||||||||||||||||||||
|
MODEL NO: LWW-5-12P LWW-5-15P
A. Stucture and Specification
|
|||||||||||||||||||||||||||||||||||||||||
|
C. Function
D. Control mode |
|||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||
|
|
|||||||||||||||||||||||||||||||||||||||||


This post is the second part in the customer segmentation analysis. The first post focused on k-means clustering in R
to segment customers into distinct groups based on purchasing habits. This post takes a different approach, using Pricipal Component Analysis (PCA) in R
as a tool to view customer groups. Because PCA attacks the problem from a different angle than k-means, we can get different insights. We’ll compare both the k-means results with the PCA visualization. Let’s see what happens when we apply PCA.
Table of Contents
- Why PCA?
- Where We Left Off
- Getting Ready for PCA
- Applying PCA
- Visualizing the Results
- Conclusions
- Recap
- Further Reading
Why PCA?
PCA is a dimensionality reduction algorithm: PCA takes your data and decomposes it using transformations into principal components (PC). Each PC is selected in the orthogonal direction that maximizes the linear variance of the data. In essence, PCA is nothing more than an algorithm that takes numeric data in x, y, z coordinates and changes the coordinates to x’, y’, and z’ that maximize the linear variance. A great article on the background behind PCA is Pricipal Component Analysis: Explained Visually. As the title suggests, the article has great visuals to explain the algorithm.
How does this help in customer segmentation / community detection? Unlike k-means, PCA is not a direct solution. What PCA helps with is visualizing the essence of a data set. Because PCA selects PC’s based on the maximum linear variance, we can use the first few PC’s to describe a vast majority of the data set without needing to compare and contrast every single feature. By using PC1 and PC2, we can then visualize in 2D and inspect for clusters. We can also combine the results with the k-means groups to see what k-means detected as compared to the clusters in the PCA visualization.
Before we jump into PCA, it’s a good idea to review where we left off in the previous customer segmentation post.
Where We Left Off
In the first post, we used k-means clustering to analyze the bikes data set
, a collection of excel files that contains data for bike shops (customers), bikes (products), and sales orders for the bike manufacturer, Cannondale. The bike shops and sales orders are fictional / simulated (see the orderSimulatoR post for more on this), but the bikes (products) are actual models from Cannondale’s website.
A hypothesis was formed that bike shops purchase bikes based on bike features such as unit price (high end vs affordable), primary category (Mountain vs Road), frame (aluminum vs carbon), etc. The sales orders were combined with the customer and product information and grouped to form a matrix of sales by model and customer. The kmeans()
function was run on a range of potential clusters, k, and the silhouette()
function from the cluster
package was used to determine the optimal number of clusters.
Getting Ready for PCA
Rather than run through the previous post, the sections below can be used to get everthing ready for PCA.
Getting the Data
You can access the data here if you would like to follow along. You’ll need to download the following files:
-
orders.xlsx: Contains the fictional sales orders for Cannondale.
customer.id
in the orders.xlsx file relates tobike shop.id
in the bikeshops.xlsx file, andproduct.id
in the orders.xlsx file relates tobike.id
in the bikes.xlsx file. -
bikes.xlsx: Contains information on products (e.g. bike model, primary category, secondary category, unit price, etc).
bike.id
is the primary key. -
bikeshops.xlsx: Contains information on customers (e.g. customer name and location).
bikeshop.id
is the primary key.
The script to load and configure the data into a customer trends matrix is shown below.
Reading the Data
This script will read the data. Make sure you have the excel files in a folder named “data” in your current working directory prior to running the script below.
# Read Cannondale orders data --------------------------------------------------
library(xlsx) # Used to read bikes data set
customers <- read.xlsx2("./data/bikeshops.xlsx", sheetIndex = 1,
colClasses = c("numeric", "character", "character",
"character", "character", "numeric"))
products <- read.xlsx2("./data/bikes.xlsx", sheetIndex = 1,
colClasses = c("numeric", "character", "character",
"character", "character", "numeric"))
orders <- read.xlsx2("./data/orders.xlsx", sheetIndex = 1, colIndex = 2:7,
colClasses = c("numeric", "numeric", "Date", "numeric",
"numeric", "numeric"))
Manipulating the Data
The script below combines the orders
, customers
and products
data frames into orders.extended
, which is a data frame that simulates output we would get from an SQL query of a sales orders database / ERP system. The data is then manipulated to form customerTrends
, which has the data structured such that the rows contain products and the columns contain purchase quantity (as percentage of total) by customer. The output, customerTrends
, is then used for k-means clustering.
# Combine orders, customers, and products data frames --------------------------
library(dplyr)
orders.extended <- merge(orders, customers, by.x = "customer.id", by.y="bikeshop.id")
orders.extended <- merge(orders.extended, products, by.x = "product.id", by.y = "bike.id")
orders.extended <- orders.extended %>%
mutate(price.extended = price * quantity) %>%
select(order.date, order.id, order.line, bikeshop.name, model,
quantity, price, price.extended, category1, category2, frame) %>%
arrange(order.id, order.line)
# Group by model & model features, summarize by quantity purchased -------------
library(tidyr) # For spread function
customerTrends <- orders.extended %>%
group_by(bikeshop.name, model, category1, category2, frame, price) %>%
summarise(total.qty = sum(quantity)) %>%
spread(bikeshop.name, total.qty)
customerTrends[is.na(customerTrends)] <- 0 # Remove NA's
# Convert price to binary high/low category ------------------------------------
library(Hmisc) # Needed for cut2 function
customerTrends$price <- cut2(customerTrends$price, g=2)
# Convert customer purchase quantity to percentage of total quantity -----------
customerTrends.mat <- as.matrix(customerTrends[,-(1:5)]) # Drop first five columns
customerTrends.mat <- prop.table(customerTrends.mat, margin = 2) # column-wise pct
customerTrends <- bind_cols(customerTrends[,1:5], as.data.frame(customerTrends.mat))
Here’s the first 6 rows of customerTrends
:
knitr::kable(head(customerTrends))
| model | category1 | category2 | frame | price | Albuquerque Cycles | Ann Arbor Speed | Austin Cruisers | Cincinnati Speed | Columbus Race Equipment | Dallas Cycles | Denver Bike Shop | Detroit Cycles | Indianapolis Velocipedes | Ithaca Mountain Climbers | Kansas City 29ers | Las Vegas Cycles | Los Angeles Cycles | Louisville Race Equipment | Miami Race Equipment | Minneapolis Bike Shop | Nashville Cruisers | New Orleans Velocipedes | New York Cycles | Oklahoma City Race Equipment | Philadelphia Bike Shop | Phoenix Bi-peds | Pittsburgh Mountain Machines | Portland Bi-peds | Providence Bi-peds | San Antonio Bike Shop | San Francisco Cruisers | Seattle Race Equipment | Tampa 29ers | Wichita Speed |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Bad Habit 1 | Mountain | Trail | Aluminum | [ 415, 3500) | 0.0174825 | 0.0066445 | 0.0081301 | 0.0051151 | 0.0101523 | 0.0128205 | 0.0117340 | 0.0099206 | 0.0062696 | 0.0181962 | 0.0181504 | 0.0016026 | 0.0062893 | 0.0075949 | 0.0042135 | 0.0182648 | 0.0086705 | 0.0184783 | 0.0074074 | 0.0129870 | 0.0244898 | 0.0112755 | 0.0159151 | 0.0108696 | 0.0092251 | 0.0215054 | 0.0026738 | 0.0156250 | 0.0194175 | 0.0059172 |
| Bad Habit 2 | Mountain | Trail | Aluminum | [ 415, 3500) | 0.0069930 | 0.0099668 | 0.0040650 | 0.0000000 | 0.0000000 | 0.0170940 | 0.0139070 | 0.0158730 | 0.0031348 | 0.0110759 | 0.0158456 | 0.0000000 | 0.0094340 | 0.0000000 | 0.0112360 | 0.0167428 | 0.0173410 | 0.0021739 | 0.0074074 | 0.0095238 | 0.0040816 | 0.0190275 | 0.0026525 | 0.0108696 | 0.0239852 | 0.0000000 | 0.0026738 | 0.0078125 | 0.0000000 | 0.0000000 |
| Beast of the East 1 | Mountain | Trail | Aluminum | [ 415, 3500) | 0.0104895 | 0.0149502 | 0.0081301 | 0.0000000 | 0.0000000 | 0.0042735 | 0.0182529 | 0.0119048 | 0.0094044 | 0.0213608 | 0.0181504 | 0.0016026 | 0.0251572 | 0.0000000 | 0.0140449 | 0.0167428 | 0.0086705 | 0.0086957 | 0.0172840 | 0.0242424 | 0.0000000 | 0.0126850 | 0.0053050 | 0.0108696 | 0.0092251 | 0.0053763 | 0.0000000 | 0.0156250 | 0.0097087 | 0.0000000 |
| Beast of the East 2 | Mountain | Trail | Aluminum | [ 415, 3500) | 0.0104895 | 0.0099668 | 0.0081301 | 0.0000000 | 0.0050761 | 0.0042735 | 0.0152108 | 0.0059524 | 0.0094044 | 0.0181962 | 0.0138289 | 0.0000000 | 0.0220126 | 0.0050633 | 0.0084270 | 0.0076104 | 0.0086705 | 0.0097826 | 0.0172840 | 0.0086580 | 0.0000000 | 0.0232558 | 0.0106101 | 0.0155280 | 0.0147601 | 0.0107527 | 0.0026738 | 0.0234375 | 0.0291262 | 0.0019724 |
| Beast of the East 3 | Mountain | Trail | Aluminum | [ 415, 3500) | 0.0034965 | 0.0033223 | 0.0000000 | 0.0000000 | 0.0025381 | 0.0042735 | 0.0169492 | 0.0119048 | 0.0000000 | 0.0102848 | 0.0181504 | 0.0032051 | 0.0000000 | 0.0050633 | 0.0042135 | 0.0152207 | 0.0202312 | 0.0043478 | 0.0049383 | 0.0051948 | 0.0204082 | 0.0162086 | 0.0026525 | 0.0201863 | 0.0073801 | 0.0322581 | 0.0000000 | 0.0078125 | 0.0097087 | 0.0000000 |
| CAAD Disc Ultegra | Road | Elite Road | Aluminum | [ 415, 3500) | 0.0139860 | 0.0265781 | 0.0203252 | 0.0153453 | 0.0101523 | 0.0000000 | 0.0108648 | 0.0079365 | 0.0094044 | 0.0000000 | 0.0106598 | 0.0112179 | 0.0157233 | 0.0278481 | 0.0210674 | 0.0182648 | 0.0375723 | 0.0152174 | 0.0172840 | 0.0103896 | 0.0163265 | 0.0126850 | 0.0026525 | 0.0139752 | 0.0073801 | 0.0053763 | 0.0026738 | 0.0078125 | 0.0000000 | 0.0098619 |
K-Means Clustering
We used the kmeans()
function to perform k-means clustering. The k-means post goes into great detail on how to select the right number of clusters, which I skipped for brevity. We’ll use the groups for and clusters with the PCA analysis. Five clusters was the theoretical best solution, and four clusters was the best solution upon inspection of the data.
# K-Means Clustering (used later) ----------------------------------------------
set.seed(11) # For reproducibility
km4.out <- kmeans(t(customerTrends[,-(1:5)]), centers = 4, nstart = 50)
set.seed(11) # For reproducibility
km5.out <- kmeans(t(customerTrends[,-(1:5)]), centers = 5, nstart = 50)
Applying PCA
Now, back to our main focus: PCA. Applying PCA is very simple once the data is formatted. We use the prcomp()
function available in base R
. It’s strongly recommended to scale and center the data (for some reason this is not the default). Further reading on PCA in R
can be found here.
# PCA using prcomp() -----------------------------------------------------------
pca <- prcomp(t(customerTrends[,-(1:5)]), scale. = T, center = T) # Perform PCA
Once PCA is performed, it’s a good idea to take a look at the variance explained. As stated before, the goal of PCA is to reduce the dimensions of the data. PCA does this by transforming the data into dimensions that are orthogonal to the variation. The greater the variance explained, the more information that is summarized by the PC. The prcomp()
function returns this variance by PC. You can use summary(pca)
to get the variance explained. Let’s take a look at the first nine PC’s visually.
PC1 and PC2 combined explain 44% of the variance of the data, and there’s a steep drop-off between PC2 and PC3. This means that plotting PC’s 1 and 2 will give us a reasonably good understanding of the data, and adding more PC’s beyond PC2 will result in minimal improvement. Note that it won’t always happen that there is a significant drop-off after PC2, and if more PC’s explain variance we would need to evaluate them as well.
Visualizing the Results
We’ll plot PC1 and PC2, and we’ll color the clusters initially using the k-means groups previously created. To do this, we first need to get the pca
data into a data frame that combines the customers with the PC’s. Luckily, the ggfortify
package has a function called fortify()
to do just that. Once our data is fortified, we create two data frames with the k-means groups added to the end so we can group on them. We’ll use the k-means group to color the PCA results so we can compare to k-means and gain insights.
# Manipulate data for PCA Analyis ----------------------------------------------
library(ggfortify) # For fortify()
pca.fortify <- fortify(pca) # fortify() gets pca into usable format
# Add group (short for color) column using k=4 and k=5 groups
pca4.dat <- cbind(pca.fortify, group=km4.out$cluster)
pca5.dat <- cbind(pca.fortify, group=km5.out$cluster)
Plotting the PC’s
The script below provides sample ggplot
scripts to create a general plot for PC1 and PC2. The script uses my favorite interactive plotting library, plotly
, to turn the ggplot
results into interactive plots. The scripts used for the next section follow the same general procedure, so I won’t show the code for brevity.
# Plotting PC1 and PC2 using ggplot and plotly ---------------------------------
library(ggplot2)
library(plotly)
# Script for plotting k=4
gg2 <- ggplot(pca4.dat) +
geom_point(aes(x=PC1, y=PC2, col=factor(group), text=rownames(pca4.dat)), size=2) +
labs(title = "Visualizing K-Means Clusters Against First Two Principal Components") +
scale_color_brewer(name="", palette = "Set1")
# Use plotly for inteactivity
plotly2 <- ggplotly(gg2, tooltip = c("text", "x", "y")) %>%
layout(legend = list(x=.9, y=.99))
PCA Viz: K=4 K-Means Grouping
The PCA segmentation shows some interesting results. It appears that there are five clusters as opposed to four. The k-means results would not pick this up, because we selected four clusters. Maybe your thinking that the silhouette analysis from the previous post indicated that we should pick , so this is where we went wrong. Let’s see what happens with the five cluster k-means.
PCA Viz: K=5 K-Means Grouping
Well, that’s not what we thought was going to happen! It looks like Group 2 was incorrectly classified. From the k-means post, this actually makes sense: We inspected the clusters, and Group 2 and 4 were very similar in their preferences for bikes in the low-end price range. We decided to combine these clusters by switching to clusters. Next, we’ll look at clustering based on inspection of the PCA plot.
PCA Viz: Visual Inspection Grouping
From the PCA visualization, we can see there are two bike shops that do not belong to Group 4. Based on our visual inspection, we can modify the groups (column 128) by switching Group 2 (San Antonio Bike Shop & Philadelphia Bike Shop) with the incorrectly classified Group 4 shops (Denver Bike Shop & Kansas City 29ers).
# Switch Group 2 Bike Shops with misclassified Bike Shops in Group 4 -----------
pca.final.dat <- pca5.dat
pca.final.dat[rownames(pca.final.dat) %in%
c("San Antonio Bike Shop", "Philadelphia Bike Shop"), 128] <- 4
pca.final.dat[rownames(pca.final.dat) %in%
c("Denver Bike Shop", "Kansas City 29ers"), 128] <- 2
And, let’s visualize the results.
Everything looks good, but we need to inspect the newly created Group 2’s preferences to make sure they should truly be a standalone customer segment.
Group 2 Inspection
The script below modifies the customerTrends
data frame to select only customer columns that are in the group we want to inspect. The script then takes the average of the customer’s percent of quantity purchased vs total quantity purchased (the values in the customer columns). The data frame is sorted by most frequently purchased so we can see the group’s central tendency. For Group 2, the central tendency is a preference for low-end mountain bikes.
# Inspect Group 2 Preferences --------------------------------------------------
# Select only groups in group num and perform row-wise average of bike prefs
library(dplyr)
group.num <- 2 # Set group number
group.names <- rownames(pca.final.dat[pca.final.dat$group == group.num, ])
groupTrends <- customerTrends %>%
select(model:price, match(group.names, names(.))) # Use match() to select column names
group.avg <- apply(groupTrends[6:ncol(groupTrends)], 1, mean) # Take average of values
groupTrends <- bind_cols(groupTrends, as_data_frame(group.avg)) %>%
arrange(-group.avg)
knitr::kable(head(groupTrends, 10)) # Top ten products by group avg. pct. purchased
| model | category1 | category2 | frame | price | Denver Bike Shop | Kansas City 29ers | value |
|---|---|---|---|---|---|---|---|
| Catalyst 2 | Mountain | Sport | Aluminum | [ 415, 3500) | 0.0256410 | 0.0187266 | 0.0221838 |
| Trail 5 | Mountain | Sport | Aluminum | [ 415, 3500) | 0.0204259 | 0.0216076 | 0.0210168 |
| F-Si Carbon 4 | Mountain | Cross Country Race | Carbon | [ 415, 3500) | 0.0165146 | 0.0247767 | 0.0206456 |
| Scalpel 29 4 | Mountain | Cross Country Race | Aluminum | [ 415, 3500) | 0.0186875 | 0.0210314 | 0.0198595 |
| Catalyst 4 | Mountain | Sport | Aluminum | [ 415, 3500) | 0.0199913 | 0.0184385 | 0.0192149 |
| F-Si 1 | Mountain | Cross Country Race | Aluminum | [ 415, 3500) | 0.0204259 | 0.0175742 | 0.0190000 |
| Trail 4 | Mountain | Sport | Aluminum | [ 415, 3500) | 0.0152108 | 0.0218957 | 0.0185532 |
| Trail 1 | Mountain | Sport | Aluminum | [ 415, 3500) | 0.0204259 | 0.0164218 | 0.0184238 |
| Trail 2 | Mountain | Sport | Aluminum | [ 415, 3500) | 0.0208605 | 0.0158456 | 0.0183530 |
| Beast of the East 1 | Mountain | Trail | Aluminum | [ 415, 3500) | 0.0182529 | 0.0181504 | 0.0182017 |
Group 4 Inspection
Let’s compare to Group 4. Rerun the previous script changing group.num
from 2 to 4. We can see that Group 4’s preference is similar to Group 2 in that both groups prefer low-end/affordable bikes. However, Group 4’s top purchases contain a mixture of Mountain and Road, while Group 2’s top purchases are exclusively Mountain. It appears there is a difference!
| model | category1 | category2 | frame | price | Albuquerque Cycles | Dallas Cycles | Detroit Cycles | Los Angeles Cycles | Minneapolis Bike Shop | New York Cycles | Philadelphia Bike Shop | Phoenix Bi-peds | Portland Bi-peds | Providence Bi-peds | San Antonio Bike Shop | value |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| F-Si 2 | Mountain | Cross Country Race | Aluminum | [ 415, 3500) | 0.0174825 | 0.0256410 | 0.0119048 | 0.0471698 | 0.0258752 | 0.0246914 | 0.0040816 | 0.0183228 | 0.0186335 | 0.0129151 | 0.0215054 | 0.0207476 |
| Slice Ultegra | Road | Triathalon | Carbon | [ 415, 3500) | 0.0104895 | 0.0085470 | 0.0099206 | 0.0251572 | 0.0076104 | 0.0049383 | 0.0571429 | 0.0133897 | 0.0248447 | 0.0092251 | 0.0537634 | 0.0204572 |
| CAAD12 Disc 105 | Road | Elite Road | Aluminum | [ 415, 3500) | 0.0139860 | 0.0085470 | 0.0297619 | 0.0157233 | 0.0136986 | 0.0222222 | 0.0204082 | 0.0176180 | 0.0310559 | 0.0092251 | 0.0215054 | 0.0185229 |
| Catalyst 3 | Mountain | Sport | Aluminum | [ 415, 3500) | 0.0314685 | 0.0427350 | 0.0178571 | 0.0188679 | 0.0152207 | 0.0024691 | 0.0040816 | 0.0140944 | 0.0186335 | 0.0202952 | 0.0161290 | 0.0183502 |
| F-Si Carbon 4 | Mountain | Cross Country Race | Carbon | [ 415, 3500) | 0.0104895 | 0.0128205 | 0.0238095 | 0.0188679 | 0.0152207 | 0.0271605 | 0.0448980 | 0.0183228 | 0.0139752 | 0.0129151 | 0.0000000 | 0.0180436 |
| Synapse Carbon Disc 105 | Road | Endurance Road | Carbon | [ 415, 3500) | 0.0139860 | 0.0170940 | 0.0099206 | 0.0125786 | 0.0304414 | 0.0271605 | 0.0285714 | 0.0091614 | 0.0170807 | 0.0166052 | 0.0107527 | 0.0175775 |
| CAAD8 Sora | Road | Elite Road | Aluminum | [ 415, 3500) | 0.0069930 | 0.0213675 | 0.0099206 | 0.0188679 | 0.0273973 | 0.0098765 | 0.0040816 | 0.0204369 | 0.0217391 | 0.0202952 | 0.0215054 | 0.0165892 |
| Synapse Disc 105 | Road | Endurance Road | Aluminum | [ 415, 3500) | 0.0279720 | 0.0213675 | 0.0019841 | 0.0094340 | 0.0121766 | 0.0271605 | 0.0204082 | 0.0155039 | 0.0093168 | 0.0129151 | 0.0215054 | 0.0163404 |
| CAAD12 105 | Road | Elite Road | Aluminum | [ 415, 3500) | 0.0069930 | 0.0299145 | 0.0277778 | 0.0188679 | 0.0106545 | 0.0098765 | 0.0326531 | 0.0084567 | 0.0093168 | 0.0018450 | 0.0215054 | 0.0161692 |
| Trigger Carbon 4 | Mountain | Over Mountain | Carbon | [ 415, 3500) | 0.0069930 | 0.0085470 | 0.0099206 | 0.0125786 | 0.0060883 | 0.0197531 | 0.0285714 | 0.0119803 | 0.0124224 | 0.0239852 | 0.0322581 | 0.0157362 |
Conclusion
PCA can be a valuable cross-check to k-means for customer segmentation. While k-means got us close to the true customer segments, visually evaluating the groups using PCA helped identify a different customer segment, one that the k-means solution did not pick up.
Recap
This post expanded on our customer segmentation methodology by using PCA to visually examine the clusters. We manipulated our sales order data to obtain a format that relates products to customer purchases. We used the prcomp()
function to perform PCA on our formatted data frame. We fortified the PCA output using the fortify()
function from the ggfortify
package, which enabled us to plot the PC’s by customer. We added the k-means cluster groups to the fortified data frame for visual inspection of the k-means clusters. We saw that differences can arise because k-means programatically determines the clusters while PCA allows us to visually inspect the clusters. The end result was an improvement to the customer segmentation by attacking the community detection problem from two different angles and combining the results!
Further Reading
-
Pricipal Component Analysis: Explained Visually: This article is an excellent place to start for those that are new to PCA or those that would like to understand the details.
-
Computing and Visualizing PCA in R: This is a great article that takes PCA to the next level in
R
with biplots, predictions, and the caret package.


|
|
|
|
Just a reminder that your access to InVision Studio starts now! We're looking forward to working with you and can't wait to hear your feedback.
Cheers,
|
|
|
|
InVision Studio is only
a few steps away.
|
Click below to agree to the terms of our privacy policy, and them download Studio (Mac OS*) for free.
When the download is complete, sign in with your InVision account credentials to get started.
|
|
GET STUDIO NOW
|
|
|
Any questions?
|
Email us at<EMAIL_ADDRESS>We're here to help.
*PC users:
Fill out this form
to get notified about the Windows beta.
|
|


Hello, {{ currentUser }}!
You are in: {{ room }}
Create a New Room
Submit
Select Room
Leave
Logout
Menu
{{ user }}
Send


You can find me on various web development websites
I have worked in these web development websites.
I will edit your website theme and put your content on it fiverr
At only $10
I will create awesome beautiful looking website fiverr
only At $10
I will create a landing page website best fiverr
Asifmir51353@gmail.com


When you want to apply CQRS the command bus is your best friend. It takes an incoming command message and routes it to the responsible command handler. The advantage of using a CommandBus instead of calling command handlers directly is that you can change your model without affecting the application logic. You can work with command versions to dispatch a newer version to a new command handler and older versions to old command handlers. Your model can support different versions at the same time which makes migrations a lot easier. Another feature of a command bus could be automatic transaction handling. And for distributed systems it is also interesting to push the command on a queue and handle it asynchronously.
When dividing your domain logic into modules or bounded contexts you need a way to inform the outside world about events that happened in your model. An EventBus is responsible for dispatching event messages to all interested listeners. If a listener is part of another system the event may need to be sent to a remote interface.
A system based on Microservices requires a lightweight
communication channel.
The two most used protocols are HTTP request-response with resource API's and lightweight messaging. The latter
is supported by prooph/service-bus out-of-the-box but HTTP API's can be integrated too.
The QueryBus is responsible for routing a query message to a so-called finder. The query indicates that the
producer expects a response.
The finder's responsibility is to fetch data from a data source using the query parameters defined in the query
message. It is up to the finder if the data is fetched synchronous or asynchronous, so the QueryBus returns
a React\Promise\Promise
to the callee.
All three bus types extend the same base class Prooph\ServiceBus\MessageBus
and therefore make use of an
event-driven message dispatch process. Take a look at the CommandBus API. It is the same for EventBus and
QueryBus except that the QueryBus returns a promise from QueryBus::dispatch
.
class CommandBus extends MessageBus
{
public function attach(string $eventName, callable $listener, int $priority = 0): ListenerHandler
public function detach(ListenerHandler $handler): void
/**
* @param mixed $command
*
* @throws CommandDispatchException
*/
public function dispatch($command): void;
}
The public API of a message bus is very simple. You can attach and detach plugins which are simple event listener aggregates and you can dispatch a message.
Internally a prooph message bus uses an event-driven process to dispatch messages. This offers a lot of flexibility without the need to define interfaces for messages. A message can be anything, even a string. prooph/service-bus doesn't care. But using some defaults will reduce the number of required plugins and increase performance.
But first let's take a look at the internals of a message dispatch process and the differences between the bus types.
This action event is triggered right after MessageBus::dispatch($message)
is invoked.
The following default priorities are integrated:
public const PRIORITY_INITIALIZE = 400000;
public const PRIORITY_DETECT_MESSAGE_NAME = 300000;
public const PRIORITY_ROUTE = 200000;
public const PRIORITY_LOCATE_HANDLER = 100000;
public const PRIORITY_INVOKE_HANDLER = 0;
At this time the action event only contains the message
. You can attach any listeners for initialization.
Before a message handler can be located, the message bus needs to know how the message is named. Their are two
possibilities to provide the information. The message can implement the
Prooph\Common\Messaging\HasMessageName
interface.
In this case the message bus picks the name directly from the message and sets it as the param message-name
in the
action event for use later. The detect-message-name
event is not triggered. If the message
does not implement the interface the detect-message-name
priority can be used to add a plugin to inject the
name using ActionEvent::setParam('message-name', $messageName)
.
If no message-name
was set by a listener, the message bus uses a fallback:
gettype($message)
in all other casesDuring the route
phase a plugin (typically a router) should provide the responsible message handler either
in the form of a ready to use callable
, an object or just a string.
The latter should be a service id that can be passed to a service locator to get an instance of the message
handler.
The message handler should be set as action event param message-handler
(for CommandBus and QueryBus) or
event-listeners
(for EventBus).
As you can see, the command and query bus work with a single message handler whereas the event bus works with multiple listeners. This is one of the most important differences. Only the event bus allows multiple message handlers per message and therefore uses a slightly different dispatch process.
After routing the message, the message bus checks if the handler was provided as a string. This is the last chance to provide an object or callable as message handler. If no plugin was able to provide one the message bus throws an exception.
With the message handler in place, it's time to invoke it with the message. callable
message handlers
are invoked by the bus. However, the invoke-handler
/ invoke-finder
events are always triggered.
At this stage all three bus types behave a bit different.
invoke-handler
event is triggered.React\Promise\Deferred
that needs to be resolved by the message handler aka finder. The query bus
triggers a invoke-finder
action event to indicate that a finder should be invoked and not a normal message
handler.event-listeners
and triggers the locate-handler
and invoke-handler
action
events for each message listener.Note: The command and query bus have a mechanism to check if the command or query was handled. If not they throw an exception. The event bus does not have such a mechanism as having no listener for an event is a valid case.
This action event is always triggered at the end of the process no matter if the process was successful or an exception was thrown. It is the ideal place to attach a monitoring plugin.
If at any time a plugin or the message bus itself throws an exception it is caught and passed as param
exception
to this action event. The normal action event chain breaks and a finalize
event is triggered
instead. Plugins can then access the exception by getting it from the action event.
A finalize
plugin can unset the exception by calling ActionEvent::setParam("exception", null)
.
When all plugins are informed about the error and no one has unset the exception the message bus
throws a Prooph\ServiceBus\Exception\MessageDispatchException to inform the outside world about the error.
Note: The query bus has another additional priority PRIORITY_PROMISE_REJECT
which is used to reject the promise
in case of an exception during the finalize event. If you want to remove the exception with a listener, you need
to add your listener with a higher priority than that.
There are two things to consider when upgrading from v5.
handle-error
event is gone. If you want to have a plugin that tracks exceptions, you need to use the
finalize
event and check for the existence of an exception. This can look like this:$commandBus->attach(
CommandBus::EVENT_FINALIZE,
function (ActionEvent $actionEvent) {
if ($ex = $actionEvent->getParam(CommandBus::EVENT_PARAM_EXCEPTION)) {
// do something
}
}
);
The event bus has a listener exception collection mode. This means that you can activate the mode and the event bus will
invoke all event listeners, catch possible exceptions and push them to an exception collection. If an exception is caught
the event bus will throw an Prooph\ServiceBus\Exception\EventListenerException
at the end which contains all caught listener exceptions.
To enable the collection mode you can attach the plugin Prooph\ServiceBus\Plugin\ListenerExceptionCollectionMode
.
Detach the plugin to deactivate the mode again.
dispatch
event replacing all other previously existing events. It is controlled by
event priorities instead. So if your previous plugin looked like this:$commandBus->attach(
CommandBus::EVENT_INVOKE_HANDLER,
function (ActionEvent $actionEvent) {
if ($ex = $actionEvent->getParam(CommandBus::EVENT_PARAM_EXCEPTION) {
// do something
}
}
);
it now has to look like this:
$commandBus->attach(
CommandBus::EVENT_DISPATCH,
function (ActionEvent $actionEvent) {
if ($ex = $actionEvent->getParam(CommandBus::EVENT_PARAM_EXCEPTION) {
// do something
}
},
CommandBus::PRIORITY_INVOKE_HANDLER
);
Instead of calling:
$commandBus
->getActionEventEmitter()
->attachListener(string $event, callable $listener, int $priority = 1): ListenerHandler;
It's more simple now:
$commandBus->attach(string $event, callable $listener, int $priority = 1): ListenerHandler;
Instead of implementing Prooph\Common\Event\ActionEventListenerAggregate
a plugin now has to
implement Prooph\ServiceBus\Plugin\Plugin
. The signature is:
public function attachToMessageBus(MessageBus $messageBus): void;
public function detachFromMessageBus(MessageBus $messageBus): void;
Instead of having this:
$finder->findQueryOne(QueryOne $query, Deferred $deferred = null): void;
you simply have this:
$finder->find(QueryOne $query, Deferred $deferred = null): void;
If you want to go back to the old behaviour, you can do the following things:
a)
class MyFinder
{
public function find(Query $query, Deferred $deferred = null): void
{
if ($query instanceof QueryOne) {
$this->findQueryOne($query, $deferred);
} elseif ($query instanceof QueryTwo) {
$this->findQueryTwo($query, $deferred);
} else {
throw new \InvalidArgumentException('Unknown query passed');
}
}
}
or b) Write a custom FinderInvokeStrategy.
Same as for FinderInvokeStrategy, the handler is only expected have a handle(Command $command): void
method.
If you need the old behaviour back, implement this in your handlers or write a custom plugin.
Same as above: There handler is only expected to have a onEvent(Event $message): void
method.


MGLSymbolStyleAnnotation
@interface MGLSymbolStyleAnnotation : MGLStyleAnnotation
An MGLSymbolStyleAnnotation
is a type of style layer annotation that renders both an icon
and text label at a specified coordinate.
To display a symbol style annotation on a map, use one of the initializers below to create a symbol
style annotation object. Then, use -[MGLSymbolAnnotationController add:]
to add the annotation
to a symbol style annotation controller.
If rendering an icon, first add an image to the map style’s sprite using
the -[MGLStyle setImage:forName:]
method within the Mapbox Maps SDK for iOS.
Example
func mapView(_ mapView: MGLMapView, didFinishLoading style: MGLStyle) {
let attraction = UIImage(named: "attraction")
if let styleImage = attraction {
self.mapView.style?.setImage(styleImage, forName: "attraction")
}
let symbolAnnotationController = MGLSymbolAnnotationController(mapView: self.mapView)
let symbol = MGLSymbolStyleAnnotation(coordinate: CLLocationCoordinate2DMake(59, 18));
symbol.iconImageName = "attraction"
symbol.text = "This is a cool place!"
symbol.textFontSize = 16
symbolAnnotationController.add(symbol)
}
-
Returns a new symbol style annotation anchored at a specified coordinate.
Declaration
Objective-C
- (nonnull instancetype)initWithCoordinate:(id)coordinate;
Swift
init(coordinate: Any!)
Parameters
coordinate
The coordinate at which the symbol style annotation’s anchor should be placed.
Return Value
An initialized symbol style annotation anchored at the specified coordinate.
-
Returns a new symbol style annotation anchored at a specified coordinate with a defined text color.
Declaration
Objective-C
- (nonnull instancetype)initWithCoordinate:(id)coordinate text:(nonnull NSString *)text color:(nonnull UIColor *)color;
Swift
init(coordinate: Any!, text: String, color: UIColor)
Parameters
coordinate
The coordinate at which the symbol style annotation’s anchor should be placed.
color
Return Value
An initialized symbol style annotation anchored at the specified coordinate with a text field and a defined text color.
-
Returns a new symbol style annotation anchored at a specified coordinate with a defined icon image.
To add an image to the map style’s sprite, use the
-[MGLStyle setImage:forName:]
method within the Mapbox Maps SDK for iOS.Declaration
Objective-C
- (nonnull instancetype)initWithCoordinate:(id)coordinate iconImageName:(nonnull NSString *)iconImageName;
Swift
init(coordinate: Any!, iconImageName: String)
Parameters
coordinate
The coordinate at which the symbol style annotation’s anchor should be placed.
iconImageName
The name of the image within the
MGLMapStyle
‘s sprite to use for rendering the icon image of the symbol style annotation.Return Value
An initialized symbol style annotation anchored at the specified coordinate with a defined icon image.
-
The name of the image within an
MGLMapStyle
‘s sprite to use for rendering the icon image of the symbol style annotation. Not set by default.To add an image to the map style’s sprite, use the
-[MGLStyle setImage:forName:]
method within the Mapbox Maps SDK for iOS.This property corresponds to the
icon-image
property in the style Mapbox Style Specification.Declaration
Objective-C
@property (readwrite, strong, nonatomic) NSString *_Nonnull iconImageName;
Swift
var iconImageName: String { get set }
-
The color to render the icon image of the symbol style annotation. Requires
iconImageName
. Defaults to black.This property corresponds to the
icon-color
property in the style Mapbox Style Specification.Declaration
Objective-C
@property (readwrite, strong, nonatomic) UIColor *_Nonnull iconColor;
Swift
var iconColor: UIColor { get set }
-
The placement of the symbol style annotation’s icon image relative to its anchor, as specified by
MGLIconAnchor
. RequiresiconImageName
. Defaults tocenter
.This property corresponds to the
icon-anchor
property in the style Mapbox Style Specification.Declaration
Objective-C
@property (assign, readwrite, nonatomic) int iconAnchor;
Swift
var iconAnchor: Int32 { get set }
-
The offset distance of the symbol style annotation’s icon image from its anchor. Positive values indicate right and down, while negative values indicate left and up.
Each component is multiplied by the value of
iconSize
to obtain the final offset in screen points. When combined withiconRotation
, the offset will be as if the rotated direction was up. RequiresiconImageName
. Defaults to aCGVector
struct set to 0 points rightward and 0 points downward.This property corresponds to the
icon-offset
property in the style Mapbox Style Specification.Declaration
Objective-C
@property (assign, readwrite, nonatomic) CGVector iconOffset;
Swift
var iconOffset: CGVector { get set }
-
The opacity of the symbol style annotation’s icon image. Requires
iconImageName
. Defaults to1
.This property corresponds to the
icon-opacity
property in the style Mapbox Style Specification.Declaration
Objective-C
@property (assign, readwrite, nonatomic) CGFloat iconOpacity;
Swift
var iconOpacity: CGFloat { get set }
-
The counterclockwise rotation angle of the symbol style annotation’s icon image, measured in degrees. Requires
iconImageName
. Defaults to0
.This property corresponds to the
icon-rotate
property in the style Mapbox Style Specification.Declaration
Objective-C
@property (assign, readwrite, nonatomic) CGFloat iconRotation;
Swift
var iconRotation: CGFloat { get set }
-
The value of which to multiply the size of the original symbol style annotation icon size, measured in screen points.
The new size of the image will be the original size multiplied by the
iconScale
value.1
is the original size;3
triples the size of the image. RequiresiconImageName
. Defaults to1
.This property corresponds to the
icon-size
property in the style Mapbox Style Specification.Declaration
Objective-C
@property (assign, readwrite, nonatomic) CGFloat iconScale;
Swift
var iconScale: CGFloat { get set }
-
An optional value representing the size of the halo or
outline
around a symbol annotation’s icon image, measured in screen points. RequiresiconImageName
. Defaults to0
.This property corresponds to the
icon-halo-width
property in the style Mapbox Style Specification.Declaration
Objective-C
@property (assign, readwrite, nonatomic) CGFloat iconHaloWidth;
Swift
var iconHaloWidth: CGFloat { get set }
-
An optional value representing the fade out size of the halo or
outline
around a symbol annotation’s icon image, measured in screen points. RequiresiconImageName
. Defaults to0
.This property corresponds to the
icon-halo-blur
property in the style Mapbox Style Specification.Declaration
Objective-C
@property (assign, readwrite, nonatomic) CGFloat iconHaloBlur;
Swift
var iconHaloBlur: CGFloat { get set }
-
An optional value representing the color of the halo or
outline
around a symbol annotation’s icon image. RequiresiconImageName
. Defaults to a clear color.This property corresponds to the
icon-halo-blur
property in the style Mapbox Style Specification.Declaration
Objective-C
@property (readwrite, strong, nonatomic) UIColor *_Nonnull iconHaloColor;
Swift
var iconHaloColor: UIColor { get set }
-
An optional array of font face names used to display the text of the symbol style annotation. Requires
text
.Defaults to an array containing the strings
Open Sans Regular
andArial Unicode MS Regular
. Fonts installed on the device’s system are not used. You can register a custom font with your style when designing styles in Mapbox Studio.This property corresponds to the
text-font
property in the style Mapbox Style Specification.Declaration
Objective-C
@property (readwrite, strong, nonatomic) NSArray<NSString *> *_Nonnull fontNames;
Swift
var fontNames: [String] { get set }
-
The text to display for a symbol style annotation. Defaults to
""
.This property corresponds to the
text-field
property in the style Mapbox Style Specification.Declaration
Objective-C
@property (readwrite, strong, nonatomic) NSString *_Nonnull text;
Swift
var text: String { get set }
-
The color of the text used by the symbol style annotation. Requires
text
. Defaults to black.This property corresponds to the
text-color
property in the style Mapbox Style Specification.Declaration
Objective-C
@property (readwrite, strong, nonatomic) UIColor *_Nonnull textColor;
Swift
var textColor: UIColor { get set }
-
The font size of the text used by the symbol style annotation, measured in screen points. Requires
text
. Defaults to16
.This property corresponds to the
text-size
property in the style Mapbox Style Specification.Declaration
Objective-C
@property (assign, readwrite, nonatomic) CGFloat textFontSize;
Swift
var textFontSize: CGFloat { get set }
-
The opacity of the text used by the symbol style annotation, represented as a range of values between
0
and1
. Requirestext
. Defaults to1
.This property corresponds to the
text-opacity
property in the style Mapbox Style Specification.Declaration
Objective-C
@property (assign, readwrite, nonatomic) CGFloat textOpacity;
Swift
var textOpacity: CGFloat { get set }
-
The type of text transformation that should be used by the text of the symbol style annotation, as specified by
MGLTextTransform
. Requirestext
. Defaults tonone
.This property corresponds to the
text-transform
property in the style Mapbox Style Specification.Declaration
Objective-C
@property (assign, readwrite, nonatomic) int textTransform;
Swift
var textTransform: Int32 { get set }
-
The text justification or
alignment
of the symbol style annotation’s text, as specified byMGLTextJustification
. Requirestext
. Defaults tocenter
.This property corresponds to the
text-justify
property in the style Mapbox Style Specification.Declaration
Objective-C
@property (assign, readwrite, nonatomic) int textJustification;
Swift
var textJustification: Int32 { get set }
-
The placement of the symbol style annotation’s text relative to its anchor, as specified by
MGLTextAnchor
. Requirestext
. Defaults tocenter
.This property corresponds to the
text-anchor
property in the style Mapbox Style Specification.Declaration
Objective-C
@property (assign, readwrite, nonatomic) int textAnchor;
Swift
var textAnchor: Int32 { get set }
-
The tracking amount of the symbol style annotation’s text, measured in ems. Requires
text
. Defaults to0
.This property corresponds to the
text-letter-spacing
property in the style Mapbox Style Specification.Declaration
Objective-C
@property (assign, readwrite, nonatomic) CGFloat textLetterSpacing;
Swift
var textLetterSpacing: CGFloat { get set }
-
The counterclockwise rotation angle of the symbol style annotation’s text, measured in degrees. Requires
text
. Defaults to0
.This property corresponds to the
text-rotate
property in the style Mapbox Style Specification.Declaration
Objective-C
@property (assign, readwrite, nonatomic) CGFloat textRotation;
Swift
var textRotation: CGFloat { get set }
-
The distance that the text of the symbol style annotation is moved from its original placement.
Positive values indicate right and down, while negative values indicate left and up. Requires
text
. Defaults to aCGVector
struct set to 0 points rightward and 0 points downward.This property corresponds to the
text-translate
property in the style Mapbox Style Specification.Declaration
Objective-C
@property (assign, readwrite, nonatomic) CGVector textTranslation;
Swift
var textTranslation: CGVector { get set }
-
The offset distance of the text belonging to a symbol style annotation from its anchor, measured in ems.
Positive values indicate right and down, while negative values indicate left and up. Requires
text
. Defaults to aCGVector
struct set to 0 points rightward and 0 points downward. Disabled bytextRadialOffset
. This property corresponds to thetext-offset
property in the style Mapbox Style Specification.Declaration
Objective-C
@property (assign, readwrite, nonatomic) CGVector textOffset;
Swift
var textOffset: CGVector { get set }
-
The radial offset of the text belonging to a symbol style annotation in the direction of the symbol’s anchor, measured in ems. Requires
text
. Defaults to0
. Disabled bytextOffset
.This property corresponds to the
text-offset
property in the style Mapbox Style Specification.Declaration
Objective-C
@property (assign, readwrite, nonatomic) CGFloat textRadialOffset;
Swift
var textRadialOffset: CGFloat { get set }
-
An optional value representing the fade out size of the halo or
outline
around a symbol style annotation’s text, measured in screen points. Requirestext
. Defaults to0
.This property corresponds to the
text-halo-blur
property in the style Mapbox Style Specification.Declaration
Objective-C
@property (assign, readwrite, nonatomic) CGFloat textHaloBlur;
Swift
var textHaloBlur: CGFloat { get set }
-
An optional value representing the color of the halo or
outline
around a symbol style annotation’s text. Requirestext
. Defaults to a clear color.This property corresponds to the
text-halo-blur
property in the style Mapbox Style Specification.Declaration
Objective-C
@property (readwrite, strong, nonatomic) UIColor *_Nonnull textHaloColor;
Swift
var textHaloColor: UIColor { get set }
-
An optional value representing the size of the halo or
outline
around a symbol style annotation’s text, measured in screen points. Requirestext
. Defaults to0
.This property corresponds to the
text-halo-width
property in the style Mapbox Style Specification.Declaration
Objective-C
@property (assign, readwrite, nonatomic) CGFloat textHaloWidth;
Swift
var textHaloWidth: CGFloat { get set }
-
The maximum line width before text wraps to a new line, measured in ems. Requires
text
. Defaults to10
.This property corresponds to the
text-max-width
property in the style Mapbox Style Specification.Declaration
Objective-C
@property (assign, readwrite, nonatomic) CGFloat maximumTextWidth;
Swift
var maximumTextWidth: CGFloat { get set }
-
An optional value representing the ascending order at which symbol style annotations should be placed.
Features with a higher sort key will appear above features with a lower sort key when they overlap. Features with a lower sort key will have priority over other features when doing placement.
This property corresponds to the
symbol-sort-key
property in the style Mapbox Style Specification.Declaration
Objective-C
@property (assign, readwrite, nonatomic) NSInteger symbolSortKey;
Swift
var symbolSortKey: Int { get set }


oxbar
—
configurable X11 status bar for OpenBSD
oxbar |
[ -H ]
[-F config-file ]
[-x xloc ]
[-y yloc ]
[-w width ]
[-h height ]
[-f font ]
[-m margins ]
[-p paddings ]
[-s spacing ]
[-c header-style ]
[-t time-format ]
[-W widgets ]
[-S key=value ]
[theme ] |
TABLE OF CONTENTS
oxbar
is a X11 status bar for
OpenBSD showing various system stats. It has a
configurable display and works out-of-the-box on most modern window managers
in an intuitive fashion.
oxbar
supports
FreeType font rendering and styling, true transparency & alpha blending on
all UI components (including the root window), and a simple configuration
format that can concisely support multiple themes.
Overview of Configuring
oxbar
All configurable properties in
oxbar
can be
set via the command line or a configuration file. The default configuration
file is
$HOME/.oxbar.conf but that can be
overridden with the
-F
config-file command line option. When using a
configuration file, the file can be reread at runtime by sending a
SIGHUP signal to
oxbar
.
Setting configurable properties is always of the form
property=value, either from the command line
or configuration file. Many properties have intuitive shortcuts on the command
line. See the section
CONFIGURATION for a list of
all configurable properties.
oxbar
supports the following command line
flags:
-H
- Print brief help information regarding the supported command line
flags.
-F
config-file
- Load config-file instead of the default
configuration file
$HOME/.oxbar.conf.
-x
xloc
- Sets the x coordinate, in pixels, of the upper-left corner of the window.
Corresponding configurable property:
window.x.
-y
yloc
- Sets the y coordinate, in pixels, of the upper-left corner of the window.
If set to -1, the window will be aligned to the bottom of the display.
Corresponding configurable property:
window.y.
-w
width
- Sets the width, in pixels, of the window. If set to -1, the window will
span the full width of the X display.
Corresponding configurable property:
window.w.
-h
height
- Sets the height, in pixels, of the window. If set to -1, the window's
height will be derived from the font description used and any
margins/paddings specified.
Corresponding configurable property:
window.h.
-f
font
- A string specifying the font, and its styling, used throughout the display
of
oxbar
. This supports a very flexible
format as it's parsed by
pango_font_description_from_string(3). See
the section SPECIFYING
FONTS below for details on the format and samples.
Corresponding configurable property:
font.desc.
-m
margins
- Sets the margins, in pixels, surrounding each widget shown in
oxbar
. The margins are the same for
every widget. The margins can be specified for the
top, right,
bottom, and left
regions around a widget, in that order, by providing a quoted string with
four unsigned integers. E.g. -m
“10 20 10 20” would set the top and bottom margins to 10
pixels, and the right and left margins to 20 pixels. Providing a single
number, such as -m
10, will set all components to 10 pixels.
This follows CSS style conventions.
Corresponding configurable property:
gui.margin.
-p
paddings
- Sets the paddings, in pixels, within each widget shown in
oxbar
. The paddings are the same for
every widget, and can be specified using the same format as the
-m
margins option (above).
Corresponding configurable property:
gui.padding.
-s
spacing
- Sets the spacing, in pixels, between each widget in the display.
Corresponding configurable property:
gui.spacing.
-c
header-style
oxbar
can show colored
“headers” above/below each widget, within the padding region
of each widget. These help quickly find/identify widgets visually. The
color can be specified per-widget. This option instructs if/where to
render such headers. It accepts the following string options:
- none
- Do not render any header bars.
- above
- Render header bars in the top padding
region of each widget (they will be as wide as the
top padding of each widget).
- below
- Render header bars in the bottom padding
region of each widget.
Corresponding configurable property:
gui.header_style.
-t
time-format
- Sets the format used by the time widget when
rendering the date/time. This is any string accepted by
strftime(3).
Corresponding configurable property:
time.format.
-W
widgets
- A string specifying the list of widgets to be rendered by
oxbar
and where they should appear. See
the section SPECIFYING
WIDGETS below on the format of this string.
Corresponding configurable property:
widgets.
-S
“property=value”
- Set any configurable property to
value in
oxbar
. This is a generic way to set any
aspect of oxbar
at the command line.
Note that all such options could also be set in the
oxbar
configuration file. This option
is useful for testing changes/tweaks to
oxbar
. See the section
CONFIGURATION below for
a list of all such properties that can be set.
As an example, the flag -S
“window.x = 100” would set the x location (in pixels) of the
upper-left corner of the display to x.
This would be equivalent to either -x
100 at the command line, or a line like
window.x = 100 in the configuration
file.
- theme
- An optional theme name to load from the configuration file. If a theme is
specified and no configuration file is found (either specified via
-F
config-file or using the default
$HOME/.oxbar.conf)
oxbar
will report an error and exit.
When specified, any lines in the configuration file after a line like
[theme]
, and before any other theme
definition, will be loaded, along with any lines before the first theme
definition (considered global options). See the
FILES section for full
details.
HOME
- The user's home directory, which
oxbar
will use to construct the name of the default configuration file to load
($HOME/.oxbar.conf) if no
-F
config-file command line parameter is
set.
oxbar
can optionally use a configuration
file, whose format is described here. When using a configuration file, the
file can be re-loaded and processed at runtime by sending a
SIGHUP signal to
oxbar
.
By default
oxbar
will attempt to use
$HOME/.oxbar.conf by using the
$HOME
environment variable. If that
variable is not set,
getpwuid(3) is used to try
and determine the caller's home directory as a replacement for
$HOME
. If both of those fail, no default
configuration file is loaded.
To load a different configuration file on startup, use the
-F
config-file command line flag.
The bulk of the configuration file contains lines like
Most properties have a prefix (or “namespace”) that denote the
scope of the property. As an example, a line like
would set the location of the main window's top-left corner to
x (in pixels). And a block like
window.bgcolor = "ff0000"
time.bgcolor = "00ff00"
would set the window's primary background color to red, but the background color
for time widget to green (these are using 32-bit hex color codes, see the
section
SPECIFYING
COLORS for details).
The configuration file is parsed with
fparseln(3),
and thus supports rich spacing and comments. Specifically,
- Blank lines are ignored
- Spacing within lines is liberal. All of the following are permitted and
equivalent:
window.x=100
window.x = 100
window.x = 100
- Lines can be continued with a \ ending a line, such as:
- Anything after a # is considered a comment.
# this is a comment
# so is this
window.x = 100 # set offset to 100 (this is a comment)
Themes provide a way to support multiple configurations of
oxbar
in a single file and load each
optionally at the command line. This is useful if you run multiple instances
of
oxbar
, say one configuration for the top
of your display showing some widgets, and another configuration at the bottom
of your display showing a different set of widgets.
Themes are a subset of a configuration file. They begin with a line like:
All lines after that are considered part of a theme named
theme-name until either the end of the file or a
new theme is defined.
To run
oxbar
and use a theme, simply provide
the
theme-name as the last parameter on the
command line, like this:
$ oxbar [options] theme-name
The following example configuration file is used below to illustrate the usage
of themes.
# global configuration (always loaded for any or no themes)
font.desc = "DejaVu Sans Mono 20px" # font used everywhere
font.fgcolor = "93a1a1" # a light gray
window.x = 0 # align to left of display
window.w = -1 # align to bottom of display
window.h = -1 # derive height
# start the "top" theme
[top]
widgets = "< nprocs cpulong | memory > net"
window.y = 0 # show at top of display
# start the "bottom" theme
[bottom]
widgets = "< volume | time > battery"
window.y = -1 # show at bottom of display
Given the above configuration file, two themes are defined:
top and
bottom. The
lines that occur before any theme definition are considered global, and are
always loaded for any, or no, theme. This is handy if some things (such as
font) apply to all themes.
Using the above, the following two commands would launch two instances of
oxbar
, using their respective theme
definitions.
$ oxbar [options] top &
$ oxbar [options] bottom &
The result is one instance (“top”) running at the top of the
display with the 4 widgets (nprocs, cpulong, memory, and net) and another
instance (“bottom”) running at the bottom of the display with 3
widgets (volume, time, and battery).
This is a complete list of all configurable properties supported by
oxbar
. They can be set:
- At the command line with
-S
property=value, where
property is one of the properties listed
below and value is the value you which to set
it to, or
- In the configuration file with a line like
property=value. See the section
FILES for more details on that
format.
Many of the configurable properties have common suffixes, and knowing what they
mean can help to understand their use. These suffixes are:
- fgcolor
- A foreground color, typically for text.
- bgcolor
- A background color, for the whole window or individual widgets.
- hdcolor
- A header color, typically denoting the header of each widget (the
horizontal bars optionally shown above or below each widget). These
properties allow you to color each widget's bar separately.
- pgcolor
- The color of a progress indicator, typically a progress bar (like those
used for the battery and volume widgets).
What follows is the list of all configurable properties in
oxbar
.
These control core font used throughout the display and what the default color
of all text is.
- font.desc
- Set's the font and styles to be used throughout the display. See the
section SPECIFYING
FONTS for full details.
Default value: “DejaVu sans mono 16px”
- font.fgcolor
- Set's the default foreground color for all text in the display. Note the
foreground color of each widget can be overridden (see other options
below).
Default value: “#93a1a1”
These control with window placement, dimensions, color, and window-manager name.
- window.x
- The x coordinate, in pixels, of the upper-left corner of the display.
Default value: “0”
- window.y
- The y coordinate, in pixels, of the upper-left corner of the display. If
set to -1, the window will be aligned to the bottom of the display.
Default value: “0”
- window.w
- The width, in pixels, of the display. If set to -1, the window will span
the full width of the X display.
Default value: “-1”
- window.h
- The height, in pixels, of the display. If set to -1, derive the height
from the font described and any margins/paddings specified.
Default value: “-1”
- window.wname
- The name of the window created as identified by the X11 display.
Default value: “
oxbar
”
- window.bgcolor
- The background color of the main display. To achieve a transparent
display, use alpha blending here by explicitly setting an alpha component
in the value. See the section
SPECIFYING COLORS
for how to do that.
Default value: “0a0a0a”
The “GUI” of
oxbar
is just an
orchestrator of widgets, in that it only controls where/how they are rendered.
These properties are specific to that, spanning all widgets and the display.
- widgets
- The list of widgets to be rendered, and where. See the section
SPECIFYING WIDGETS
for full details.
Default value: “nprocs cpu memory net > battery wifi bright volume
time”
- gui.margin
- The margins, in pixels, surrounding each widget. The margins can be
specified for the top,
right, bottom,
and left regions around a widget, in that
order, by providing a quoted string with four unsigned integers. E.g.
-m
“10 20 10 20” would
set the top and bottom margins to 10 pixels, and the right and left
margins to 20 pixels. Providing a single number, such as
-m
10
will set all components to 10 pixels. This follows CSS style conventions.
Default value: “2”
- gui.padding
- The paddings, in pixels, within each widget. The value follows the same
format as the gui.margins property above.
Default value: “5”
- gui.header_style
oxbar
can show colored
“headers” above/below each widget, within the padding region
of each widget. These help quickly find/identify widgets visually. The
color can be specified per-widget. This option instructs if/where to
render such headers. It accepts the following string options:
- none
- Do not render any header bars.
- above
- Render header bars in the top padding
region of each widget (they will be as wide as the
top padding of each widget).
- below
- Render header bars in the bottom padding
region of each widget.
Default value: “below”
- gui.widget_bgcolor
- The background color for every widget. Useful if you want each widget to
have the same background color separate from the main window's background
color. If unset (or set to “”) then the value is unused.
Default value: “”
- gui.spacing
- The spacing, in pixels, between each widget in the display.
Default value: “20”
These properties configure the battery widget, showing charging & capacity
status.
- battery.hdcolor
- The header color for this widget.
Default value: “b58900”
- battery.bgcolor
- The background color for this widget.
Default value: unset (fallback to
gui.widget_bgcolor if set, or
window.bgcolor otherwise).
- battery.fgcolor
- The foreground color for this widget.
Default value: unset (fallback to font.fgcolor
).
- battery.fgcolor_unplugged
- Color of the leading text when unplugged. Useful to highlight when on
battery.
Default value: “dc322f”
- battery.chart_width
- Width (in pixels) of the progress bar.
Default value: “7”
- battery.chart_bgcolor
- Background color of the progress bar chart.
Default value: “dc322f”
- battery.chart_pgcolor
- Progress color of the progress bar chart.
Default value: “859900”
These properties configure the bright widget, showing the x display brightness
level as determined by querying
Xrandr(3).
- bright.hdcolor
- The header color for this widget.
Default value: “8900b5”
- bright.bgcolor
- The background color for this widget.
Default value: unset (fallback to
gui.widget_bgcolor if set, or
window.bgcolor otherwise).
- bright.fgcolor
- The foreground color for this widget.
Default value: unset (fallback to font.fgcolor
).
- bright.chart_width
- Width (in pixels) of the progress bar.
Default value: “7”
- bright.chart_bgcolor
- Background color of the progress bar chart.
Default value: “dc322f”
- bright.chart_pgcolor
- Progress color of the progress bar chart.
Default value: “859900”
These properties configure the CPU widgets (which includes the
cpu,
cpulong, and
cpushort widgets), showing a breakdown of CPU
usage by core.
- cpus.hdcolor
- The header color for this widget.
Default value: “6c71c4”
- cpus.bgcolor
- The background color for this widget.
Default value: unset (fallback to
gui.widget_bgcolor if set, or
window.bgcolor otherwise).
- cpus.fgcolor
- The foreground color for this widget.
Default value: unset (fallback to font.fgcolor
).
- cpus.chart_bgcolor
- Background color of the chart.
Default values: “333333”
- cpus.chart_color_system
- Color of the system component of the charts.
Default value: “ff0000”
- cpus.chart_color_interrupt
- Color of the interrupt component of the charts.
Default value: “ffff00”
- cpus.chart_color_user
- Color of the user component of the charts.
Default value: “3333ff”
- cpus.chart_color_nice
- Color of the nice component of the charts.
Default value: “ff00ff”
- cpus.chart_color_spin
- Color of the spin component of the charts.
Default value: “00ffff”
- cpus.chart_color_idle
- Color of the idle component of the charts.
Default value: “859900”
These properties configure the memory widget, showing a breakdown of memory
usage.
- memory.hdcolor
- The header color for this widget.
Default value: “d33682”
- memory.bgcolor
- The background color for this widget.
Default value: unset (fallback to
gui.widget_bgcolor if set, or
window.bgcolor otherwise).
- memory.fgcolor
- The foreground color for this widget.
Default value: unset (fallback to font.fgcolor
).
- memory.chart_bgcolor
- Background color of the chart.
Default values: “333333”
- memory.chart_color_free
- Color of the free memory component of the chart and text.
Default value: “859900”
- memory.chart_color_total
- Color of the total memory component of the chart and text.
Default value: “bbbb00”
- memory.chart_color_active
- Color of the active memory component of the chart and text.
Default value: “dc322f”
These properties configure the nprocs widget, showing the number of processes.
- nprocs.hdcolor
- The header color for this widget.
Default value: “dc322f”
- nprocs.bgcolor
- The background color for this widget.
Default value: unset (fallback to
gui.widget_bgcolor if set, or
window.bgcolor otherwise).
- nprocs.fgcolor
- The foreground color for this widget.
Default value: unset (fallback to font.fgcolor
).
These properties configure the network widget, showing the bytes in/out on the
egress interface.
- net.hdcolor
- The header color for this widget.
Default value: “268bd2”
- net.bgcolor
- The background color for this widget.
Default value: unset (fallback to
gui.widget_bgcolor if set, or
window.bgcolor otherwise).
- net.fgcolor
- The foreground color for this widget.
Default value: unset (fallback to font.fgcolor
).
- net.inbound_chart_color_bgcolor
- Background color of the inbound traffic chart.
Default value: “859900”
- net.inbound_chart_color_pgcolor
- Progress color of the inbound traffic chart.
Default value: “157ad2”
- net.inbound_text_fgcolor
- Text color of the inbound traffic number.
Default value: “157ad2”
- net.outbound_chart_color_bgcolor
- Background color of the outbound traffic chart.
Default value: “859900”
- net.outbound_chart_color_pgcolor
- Progress color of the outbound traffic chart.
Default value: “dc322f”
- net.outbound_text_fgcolor
- Text color of the outbound traffic number.
Default value: “dc322f”
These properties configure the time widget, showing the date/time.
- time.hdcolor
- The header color for this widget.
Default value: “859900”
- time.bgcolor
- The background color for this widget.
Default value: unset (fallback to
gui.widget_bgcolor if set, or
window.bgcolor otherwise).
- time.fgcolor
- The foreground color for this widget.
Default value: unset (fallback to font.fgcolor
).
- time.format
- The format to use when displaying the date/time. Any string by
strftime(3) is supported.
Default value: “%a %b %d %Y %I:%M:%S %p”
These properties configure the volume widget, showing the current volume levels.
- volume.hdcolor
- The header color for this widget.
Default value: “cb4b16”
- volume.bgcolor
- The background color for this widget.
Default value: unset (fallback to
gui.widget_bgcolor if set, or
window.bgcolor otherwise).
- volume.fgcolor
- The foreground color for this widget.
Default value: unset (fallback to font.fgcolor
).
- volume.chart_width
- Width (in pixels) of the progress bar.
Default value: “7”
- volume.chart_bgcolor
- Background color of the progress bar chart.
Default value: “dc322f”
- volume.chart_pgcolor
- Progress color of the progress bar chart.
Default value: “859900”
These properties configure the wifi widget, showing the signal strength of an
egress wifi interface.
- wifi.hdcolor
- The header color for this widget.
Default value: “ff0000”
- wifi.bgcolor
- The background color for this widget.
Default value: unset (fallback to
gui.widget_bgcolor if set, or
window.bgcolor otherwise).
- wifi.fgcolor
- The foreground color for this widget.
Default value: unset (fallback to font.fgcolor
).
The font used by
oxbar
, and styling for it,
is described and set using the
font.desc property
which is a string such as “helvetica 12px”. Its value is passed
directly to Pango through the
pango_font_description_from_string(3) API, and
will thus accept any value that API accepts (which is quite expressive). All
text rendered in
oxbar
will be done using
the font loaded from that description.
See the documentation of that API for full details. In summary, the format of
the string is a space separated list of the form
FONT-FAMILY [STYLE | VARIANT | WEIGHT]* SIZE
where
FONT-FAMILY is the name of the font family
desired, optionally followed by some number of style/variant/weight modifiers
(like
italic,
bold,
heavy,
light, etc).
The
SIZE is then specified, which can be pixels,
such as “16px”, or points, such as “16pt”. If no
suffix is specified, points are assumed.
Some examples:
- “fixed 16px”
- Specifies the default fixed-width (monospaced) font for the system, at 16
pixels in height.
- “Helvetica italic 16px”
- Specifies the italic variant of the Helvetica font, sized at 16 pixels in
height.
- “DejaVu Sans Mono bold 20px”
- Uses the monospaced and bold variant combination of the DejaVu font
(requires package to be installed), sized at 20 pixels in height.
All colors in the configuration of
oxbar
are
ultimately resolved to 32-bit color pairs of red, green, blue, and alpha
values. All colors are specified as either 3 or 6 character hex codes without
transparency, or 4 or 8 character hex codes with transparency.
Some examples are:
- f00
- Solid red, completely opaque
- f008
- Red, about half opaque / half transparent
- ff0000
- Also solid red (same as f00)
- ff000088
- Red, about half opaque / half transparent
The strings specifying these can optionally include a leading # symbol, though
in the configuration file that must be escaped to prevent that character being
interpreted as the start of a comment.
oxbar
supports true transparency / alpha
blending on the main window by specifying a transparent color to the
window.bgcolor property, such as
window.bgcolor=5558. For this support to work,
however, your window manager must support true transparency and may need a
compositing manager running for the transparency to function. On the base
install of
OpenBSD this is
xcompmgr(1), though
compton(1) from ports is often easier to setup
and configure.
The configurable property used to control which widgets are shown, and where, is
widgets, and this section describes how to
configure that property.
The property is simply a string containing a list of space-separated widget
names (such as “time”, “memory”, etc), and some
special characters that control the alignment of those widgets within the
display. A setting such as
widgets = "time volume battery"
would show the time, volume, and then battery widgets, in that order. They would
also be shown left-aligned (growing from the left-most side of the window) as
that's the default display alignment. The next subsection describes how to
alter that.
Note that the widgets property can also be set on the command line using the
-W
flag. The above example could be
specified on the command line with simply:
oxbar -W "time volume battery"
The following characters in the
widgets value
string can alter the alignment of subsequent widgets specified:
- <
- All subsequent widgets are left-aligned,
growing from the left-most edge of the display. This is the default
alignment and thus not strictly required.
- >
- All subsequent widgets are right-aligned,
growing from the right-most edge of the display.
- |
- All subsequent widgets are centered, so that
the list of widgets appears in the exact center of the display.
As an example, the following setting
widgets = "nprocs cpu memory net | time > battery volume"
would show the nprocs, cpu, memory, and net widgets on the left, a centered time
widget, and then the battery and volume widgets on the right.
This is the list of all available widgets.
- battery
- This widget shows the battery status. It starts with the string
"BAT" if running on battery or "AC" if plugged-in. It
then shows a progress bar indicating the battery charge percentage and a
corresponding text value for that percentage.
Corresponding configurable properties:
battery.*.
- bright
- This widget shows the brightness of the current X display, as a
percentage, determined by querying Xrandr(3).
Corresponding configurable properties:
bright.*.
- cpu
- This widget shows an overview, with charts, of CPU utilization. For each
CPU it shows a historical histogram (spanning the last 60 seconds)
breaking down the usage of that CPU (for user, system, idle, etc time),
followed by the latest percentage idle time.
Corresponding configurable properties:
cpus.*.
- cpulong
- Similar to the cpu widget above, only after each chart all CPU state
percentages are printed, not just idle (so system, interrupt, user, nice,
spin, and idle, in that order).
Corresponding configurable properties:
cpus.*.
- cpushort
- This widget is a very brief, text-only display of CPU utilization. For
each CPU, the percentage time non-idle is printed. That is all.
Corresponding configurable properties:
cpus.*.
- memory
- This widget shows a breakdown of memory usage over time. It includes a
historical histogram (spanning the last 60 seconds) showing a breakdown of
the active, total, and free memory utilization, followed by text restating
the latest sampled values for each (as raw memory values, not
percentages).
Corresponding configurable properties:
memory.*.
- net
- This widget shows a very brief overview of the network utilization on the
egress interface. It shows two historical
charts plotting the number of bytes inbound/outbound on that interface,
for the past 60 seconds, followed by a textual representation of the
latest sample of that activity.
Corresponding configurable properties:
net.*.
- nprocs
- This widget simply shows the number of processes. That is all. Useful if
you work on something that uses fork(2) a lot
and you frequently fork-bomb yourself.
Corresponding configurable properties:
nprocs.*.
- time
- This widget shows the current date/time.
Corresponding configurable properties:
time.*.
- volume
- This widget shows the current volume. It includes a progress bar
indicating the percentage of the current volume setting followed by a
textual representation of that percentage.
Corresponding configurable properties:
volume.*.
- wifi
- This widget shows the signal strength of the egress wifi interface. It
simply renders the signal strength as a percentage.
Corresponding configurable properties:
wifi.*.
compton(1),
xcompmgr(1),
fparseln(3),
getpwuid(3),
strftime(3)
In addition, the following libraries are heavily utilized by
oxbar
:
- https://xcb.freedesktop.org
- XCB is a MIT licensed X11 client library used by
oxbar
to connect to an X11 display,
render the window, and handle events.
- https://www.pango.org
- Pango is a LGPL licensed text layout and font rendering engine used by
oxbar
to load, render, and style fonts.
Pango supports most modern fonts and font features.
- https://cairographics.org
- Cairo is a LGPL licensed vector graphics rendering library used by
oxbar
for all graphics rendering.
oxbar
is written natively on
OpenBSD. It adheres to a strict C89 standard on the
base
clang(1) compiler, and builds/runs cleanly
with “-std=c89 -Wall -Wextra -Werror”. Additionally, the
make(1) targets
scan-build
and
cppcheck
run those tools, respectively, and
should remain error/warning-free.
style(9) is mostly followed, but there's still work
there to be done.
If interested in contributing, see the following link for tips on navigating the
code base and getting started adding stats, widgets, etc. Care has been taken
to make adding new stats and widgets easy.
The github repo is the place to submit bugs/changes/threats, and is located at:
https://github.com/ryanflannery/oxbar
oxbar
started as xstatbar, first written in
2006 as a status-bar that would work reasonably well for
OpenBSD. It was written on a Friday and Saturday
evening and had many, many bugs/shortcomings/etc. It was further hacked over a
few years to support a handful of new features and widgets, but the term
“hacked” there undervalues the level of code shit-hattery done
to “Make-It-Work!”. I have personally received much derision
because of that, and
oxbar
is an attempt to
eliminate that.
Shaming works 'yo.
oxbar
is written and maintained by
Ryan Flannery
<
<EMAIL_ADDRESS>or
https://ryanflannery.net.


By registering to our course using this form, you agree to our Terms and Conditions.
We have been working very hard to create the new version of our course. It comes with a lot of new features. Check it out now!


Please fill in this form to create an account.
By creating an account you agree to our Terms & Privacy.
| OS | |
|---|---|
| Language | |
| LIFF SDK Version | |
| LINE Version | |
| isInClient | |
| isLoggedIn | |
Available LIFF methods vary depending on the browser you use to open the LIFF app.
Please refer to the API reference page for more information.
You have not assigned any value for LIFF ID.
If you are running the app using Node.js, please set the LIFF ID as an environment variable in your Heroku account follwing the below steps:
- Go to `Dashboard` in your Heroku account.
- Click on the app you just created.
- Click on `Settings` and toggle `Reveal Config Vars`.
- Set `MY_LIFF_ID` as the key and the LIFF ID as the value.
- Your app should be up and running. Enter the URL of your app in a web browser.
If you are using any other platform, please add your LIFF ID in the index.html
file.
For more information about how to add your LIFF ID, see Initializing the LIFF app.
Something went wrong with LIFF initialization.
LIFF initialization can fail if a user clicks "Cancel" on the "Grant permission" screen, or if an error occurs in the process of liff.init()
.
Unable to receive the LIFF ID as an environment variable.


{% autoescape true %}
{{ cssHTML|safe }} {{ metaHTML|safe }} {{ scriptsHTML|safe }} {{ navigationHTML|safe }}Returns a randomly chosen Bitcoin address from a SIL, LBL, LRL or LSL where the corresponding value represents the proportional chance of that address being chosen. The hash of a specified block is used as a random number generator.
| Name | Required | Type | Description |
|---|---|---|---|
| format | yes | string | Format of the results, should be “json” |
| metric | yes | string | Distribution source: "SIL", "LBL", "LRL" or "LSL" |
| address | yes | string | A Bitcoin address |
| regBlock | no | integer | A block height for the registration address, if omitted the latest blockheight is used. |
| block | yes | integer | A block height for the random number generator |
| XPUB | yes, except for SIL | string | An extended public key (BIP32) |
| Name | Type | Description |
|---|---|---|
| success | integer | 1 = success, 0 = fail |
| winnerAddress | string | the randomly chosen Bitcoin address |
| winnerIndex | integer | the index of the randomly chosen Bitcoin address |
| intHash | integer | Blockhash converted to integer |
| random | float | the intHash in reverse, with "0." added in front so it is a number between 0 and 1. |
| target | float | Total received amount multiplied by the random number |
| distribution | array | Distribution data that was used, format: [[address, value, cumulative value], ...] |
| error | string | error message in case something went wrong |
{ "winner": { "intHash":<PHONE_NUMBER>98925203423153928968980716850743356911342468975, "random": 0.5798642431196533, "target": 2127717.9021201828, "distribution": [ ["1Robbk6PuJst6ot6ay2DcVugv8nxfJh5y", 1248000, 1248000], ["1SansacmMr38bdzGkzruDVajEsZuiZHx9", 685000, 1933000], ["1AryaZJnXcMxJua4CpKaNUNRxbu7tmZSf1", 753338, 2686338], ["1Branzwx1RceFrHsjSQK1sHzyeRB7BMoWT", 458000, 3144338], ["1Jon1mTMWTwv4bYZy8ZaCHEvjGGXUmMD1X", 255000, 3399338], ["1Jon2kyK579Wh1rvPzQvrQkJ64xzAFb2fn", 270000, 3669338]], "winnerIndex": 2, "winnerAddress": "1AryaZJnXcMxJua4CpKaNUNRxbu7tmZSf1" }, "success": 1 }


Undergraduates
Undergraduates who wish to participate in research programs, please refer to
this page.
Aug. 2023
One paper has been accepted in CIKM 2023.
Jul. 2023
Two papers have been accepted in ICCV 2023 (One oral presentation).
Apr. 2023
Three papers and 10 workshop papers have been accepted in ICML 2023.
Feb. 2023
One paper and one workshop paper have been accepted in ICLR 2023.
Feb. 2023
One paper has been accepted in ICASSP 2023.
Nov. 2022
Two papers and one workshop paper have been accepted in AAAI 2023.
Oct. 2022
Jinhyeok and Dain won the best paper award at CIKM2022 Data Challenge (EvalRS)!
Sep. 2022
A paper has been accepted in TNNLS.
Sep. 2022
Three papers have been accepted in NeurIPS 2022.
Jul. 2022
Two papers and one workshop paper have been accepted in ECCV 2022.
Jun. 2022
One workshop paper has been accepted in ICML 2022.
May. 2022
One paper has been accepted in ICML 2022.
Apr. 2022
One paper has been accepted in ISIT 2022.
Jan. 2022
One paper has been accepted in ICASSP 2022.
Jan. 2022
Two papers have been accepted in ICLR 2022.
Jan. 2022
Two papers have been accepted in AISTATS 2022.
Jan. 2022
Sungsoo Ahn and Namhoon Lee have joined MLLab as new faculty members!
Sep. 2021
A paper on crowdsourcing has been accepted in ACM SIGMETRICS 2022.
Sep. 2021
A paper on federated learning has been accepted in NeurIPS 2021.


Rent Sheet
Save & Continue
Reset
Cancel
Recreation Event
Number of Events
Select the number of events
Single
Multiple
Rate
3%
5%
Final Reconciliation
Add Another Event
Event Name
Estimated Gross Revenue
Estimated Prize
Final Gross Revenue
Final Prize
Event Name
Estimated Gross Revenue
Estimated Prize
Final Gross Revenue
Final Prize
Add Another Event
Total Estimated Gross Revenue
$3,000.00
Total Estimated Prize Value
$300.00
Total Final Gross Revenue
$0.00
Total Final Prize Value
$0.00
Final Rent
Calculated Rent
$277.55
Previous Payment
$178.80
Total Rent Due
$98.70
Generate Bill
View Formula
0.5 x (5000 - 2500) = 125
Rate x (Estimated Gross Revenue - Estimated Prize) = Estimated Rent


This page display search results, use page next, previous to navigate and sort dropdown to try different order
Search
meaningful description {{item.content.resource.meaningful_description}}
additional text {{item.content.resource.additional_text}}
categorization {{item.content.resource.categorization}}
standards


THE DEVELOPMENT OF A STAND MODEL ' FOR DOUGLAS FIR by
an 36
Ry M°’ NEWNHAM
B. Sc., University of Wales, 1956 M. F., University of British Columbia, 1958
A THESIS SUBMITTED IN PARTIAL FULFILMENT OF THE REQUIREMENTS FOR THE DEGREE OF
DOCTOR OF PHILOSOPHY
in the Department of FORESTRY
We accept this thesis as conforming to the
oe e . o ° e e e . e « e
THE UNIVERSITY OF BRITISH COLUMBIA October, 1964
Reproduced with permission of the copyright owner. Further reproduction prohibited without permission.


Internships at Altoro Mutual provide a hands-on introduction to our work culture and an opportunity to explore career choices in both traditional and non-traditional banking environments.
Last summer we had several college interns representing colleges and universities across the country. In addition, we offer part-time positions for students during the school year.
All students, regardless of major, are encouraged to apply. To submit your applicaiton, simply select "Summer Internships" or "Part-time Students" from our current job openings list.


Introducing Istio: An open community project to help connect, manage, monitor and secure microservices everywhere. https://t.co/HYnrdEQ3s0
— Istio (@IstioMesh) 24 mai 2017
A big day for #Istio contributors and community! Istio is now version 1.0 and production-ready. Details on the blog - https://t.co/ueB1lfuMNZ
— Istio (@IstioMesh) 31 juillet 2018
"Writing reliable, loosely coupled, production-grade applications based on micro-services"


Swiss information Technology Company Eurotech Global Sports AG (EGS) is in the business of organization and operational management of IT-Systems and services especially for major sports and entertainment events. EGS provides a wide range of information technology and consulting services to support any type of event, large or small. If you need us to assist you in defining a global IT Infrastructure for your event or you require a specific service such as an accreditation or volunteer management solution for your event, we can deliver. Eurotech is able to provide you with the right solution, at the right time. We specialize in:
|
1
|
Technology Solution Management
|
|
2
|
Event IT Consulting
|
The EGS team can work with your existing technology team to assist n developing proven, production-ready solutions that meet your strict time and budget requirements while providing support and accountability. We can develop and aid in the implementation of operational plans to support the technology delivery throughout the life cycle.
|
3
|
Event Management Systems
|
|
4
|
Network and Infrastructure Management
|
Eurotech Global Sports AG has been successfully involved in the delivery of the IT Solution for the 2014 FIFA World Cup Brazil™,
the 2010 FIFA World Cup South Africa™, the 2006 FIFA World Cup Germany™ and the 2002 FIFA World Cup Korea / Japan™.
At each fo these events, FIFA contracted EGS as the global systems integrator responsible for overseeing the delivery of the IT Solution for these events.
The EGS team was responsible for many key areas including the definition of the overall systems and network architecture.
They created the integration and operations plans that were supported by the full IT Solution team.
They coordinated all IT Related activities for sponsors, partners, vendors and suppliers.
EGS staff led all integration, deployment and operations activities as they related to the successful delivery of the IT Solution.
This all culminated in the successful delivery of IT services to one of the most complex sporting events ever, and successful
delivery was achieved under unique and challenging circumstances.
In addition to the FIFA World Cup™ events, the EGS team has fulfilled consulting and operational and IT delivery roles
in other large and small scale sporting events throughout the world, including IAAF Athletics World Championships, Olympic Games,
US Figure Skating, UCI cycling events and various bid committees.


Warden:
Ah, I understand -- no doubt another adventure calls you...
Thank you for all you've done here.
If you'd like to lend a hand again, we'd be very grateful.
Good luck on your journeys!