The Duck Teaches Learn to debug from the masters. Local to production- kill ...ShaiAlmog1
The document outlines an agenda for a workshop on debugging techniques. The workshop covers installing tools, flow and breakpoints debugging, watching variables, Kubernetes debugging, and developer observability. Key techniques discussed include tracepoints, memory debugging, exception breakpoints, object marking, and logs, snapshots, and metrics for observability. The goal is to teach practical debugging skills that can be applied at scale in production environments like Kubernetes.
The Duck Teaches Learn to debug from the masters. Local to production- kill ...ShaiAlmog1
The document outlines an agenda for a workshop on debugging techniques. The workshop covers installing tools, flow and breakpoints debugging, watching variables, Kubernetes debugging, and developer observability. Key techniques discussed include tracepoints, memory debugging, exception breakpoints, object marking, and logs, snapshots, and metrics for observability. The goal is to teach practical debugging skills that can be applied at scale in production environments like Kubernetes.
The document describes code for implementing the server-side functionality of a WhatsApp clone. It includes classes for representing users, messages, and server connections. The Server class initializes user and message data from files, handles login/signup, and establishes a websocket connection for real-time messaging. It can send and receive messages when connected, or queue messages when offline.
The document describes code for implementing the server-side functionality of a WhatsApp clone. It includes classes for representing users, messages, and server connections. The Server class initializes user and message data from files, handles login/signup, and establishes a websocket connection for real-time messaging. It can send and receive messages when connected, or queue messages when offline.
5. s.content.addAll(title, rt, next);
return s;
}
public static SignupForm createName() {
SignupForm s = new SignupForm("Name", "Terms",
getCurrentForm());
Label title = new Label("What's Your Name?", "SignupSubHeader");
TextComponent first = new TextComponent().
label("First Name").columns(12);
TextComponent last = new TextComponent().
label("Last Name").columns(12);
TextModeLayout layout = new TextModeLayout(1, 2);
Container textContainer = new Container(layout, "PaddedContainer");
textContainer.add(layout.createConstraint().
widthPercentage(50), first);
textContainer.add(layout.createConstraint().
widthPercentage(50), last);
last.getField().setDoneListener(e -> createBirthday().show());
s.content.addAll(title, textContainer,
s.createNextButton(e -> createBirthday().show()));
return s;
}
SignupForm
Lets go right into the createName method.
TextComponent is a text input component that combines the label and TextField into one component and automatically adapts it to the platform
6. s.content.addAll(title, rt, next);
return s;
}
public static SignupForm createName() {
SignupForm s = new SignupForm("Name", "Terms",
getCurrentForm());
Label title = new Label("What's Your Name?", "SignupSubHeader");
TextComponent first = new TextComponent().
label("First Name").columns(12);
TextComponent last = new TextComponent().
label("Last Name").columns(12);
TextModeLayout layout = new TextModeLayout(1, 2);
Container textContainer = new Container(layout, "PaddedContainer");
textContainer.add(layout.createConstraint().
widthPercentage(50), first);
textContainer.add(layout.createConstraint().
widthPercentage(50), last);
last.getField().setDoneListener(e -> createBirthday().show());
s.content.addAll(title, textContainer,
s.createNextButton(e -> createBirthday().show()));
return s;
}
SignupForm
TextModeLayout is a layout manager designed for TextComponent it uses TableLayout on Android & BoxLayout on iOS.
This will act like adding to a TableLayout when running in Android thus placing the components side by side.
On iOS is would ignore the percentage value and stack the components vertically using a BoxLayout on the Y axis.
The TextModeLayout isn't really a layout as much as it is a delegate. When running in the Android mode (which we refer to as the "on top" mode) the layout is almost an
exact synonym of TableLayout and in fact delegates to an underlying table layout. In fact there is a public final TableLayout instance within the layout that you "can" refer
to directly...
There is one small difference between the TextModeLayout and the underlying TableLayout and that's our choice to default to align entries to TOP with this mode. It's
important for error handling which I didn't use here.
When working in the non-android environment we use a BoxLayout on the Y axis as the basis. There is one thing we do here that's different from a default box layout and
that's grouping. Grouping allows the labels to align by setting them to the same width, internally it just invokes Component.setSameWidth(). Since text components hide
the labels there is a special group method there that can be used. However, this is implicit with the TextModeLayout which is pretty cool.
7. s.content.addAll(title, rt, next);
return s;
}
public static SignupForm createName() {
SignupForm s = new SignupForm("Name", "Terms",
getCurrentForm());
Label title = new Label("What's Your Name?", "SignupSubHeader");
TextComponent first = new TextComponent().
label("First Name").columns(12);
TextComponent last = new TextComponent().
label("Last Name").columns(12);
TextModeLayout layout = new TextModeLayout(1, 2);
Container textContainer = new Container(layout, "PaddedContainer");
textContainer.add(layout.createConstraint().
widthPercentage(50), first);
textContainer.add(layout.createConstraint().
widthPercentage(50), last);
last.getField().setDoneListener(e -> createBirthday().show());
s.content.addAll(title, textContainer,
s.createNextButton(e -> createBirthday().show()));
return s;
}
SignupForm
This listens to the done button in the virtual keyboard and automatically treats it as a click on next button
8. FloatingHint {
font-family: "native:MainRegular";
font-size: 2mm;
padding: 2mm 2mm 0.5mm 2mm;
margin: 0px;
color: black;
}
theme.css
For this form I need to add one change to the CSS. This is the text that appears on top of the Android field when we have input there.
It's a really small label that uses regular font for visibility instead of light.
With that we finished the name form and it should "just work”...
10. last.getField().setDoneListener(e -> createBirthday().show());
s.content.addAll(title, textContainer,
s.createNextButton(e -> createBirthday().show()));
return s;
}
public static SignupForm createBirthday() {
SignupForm s = new SignupForm("Birthday",
"Name",
getCurrentForm());
Label title = new Label("What's Your Birthday?", "SignupSubHeader");
Picker datePicker = new Picker();
datePicker.setType(PICKER_TYPE_DATE);
int twentyYears = 60000 * 60 * 24 * 365 * 20;
datePicker.setDate(new Date(System.currentTimeMillis() -
twentyYears));
s.content.addAll(title, datePicker,
s.createNextButton(e -> createGender().show()));
return s;
}
private static RadioButton createGenderButton(ButtonGroup bg,
String label, String icon) {
Style unselectedIconStyle = UIManager.getInstance().
SignupForm
The flip side is that the code is super simple.
11. last.getField().setDoneListener(e -> createBirthday().show());
s.content.addAll(title, textContainer,
s.createNextButton(e -> createBirthday().show()));
return s;
}
public static SignupForm createBirthday() {
SignupForm s = new SignupForm("Birthday",
"Name",
getCurrentForm());
Label title = new Label("What's Your Birthday?", "SignupSubHeader");
Picker datePicker = new Picker();
datePicker.setType(PICKER_TYPE_DATE);
int twentyYears = 60000 * 60 * 24 * 365 * 20;
datePicker.setDate(new Date(System.currentTimeMillis() -
twentyYears));
s.content.addAll(title, datePicker,
s.createNextButton(e -> createGender().show()));
return s;
}
private static RadioButton createGenderButton(ButtonGroup bg,
String label, String icon) {
Style unselectedIconStyle = UIManager.getInstance().
SignupForm
We set the picker type to date
12. last.getField().setDoneListener(e -> createBirthday().show());
s.content.addAll(title, textContainer,
s.createNextButton(e -> createBirthday().show()));
return s;
}
public static SignupForm createBirthday() {
SignupForm s = new SignupForm("Birthday",
"Name",
getCurrentForm());
Label title = new Label("What's Your Birthday?", "SignupSubHeader");
Picker datePicker = new Picker();
datePicker.setType(PICKER_TYPE_DATE);
int twentyYears = 60000 * 60 * 24 * 365 * 20;
datePicker.setDate(new Date(System.currentTimeMillis() -
twentyYears));
s.content.addAll(title, datePicker,
s.createNextButton(e -> createGender().show()));
return s;
}
private static RadioButton createGenderButton(ButtonGroup bg,
String label, String icon) {
Style unselectedIconStyle = UIManager.getInstance().
SignupForm
Twenty years ago is a good place to start for an age picker by default so that’s what I did. That's trivial and includes no changes to the CSS.
14. datePicker.setDate(new Date(System.currentTimeMillis() -
twentyYears));
s.content.addAll(title, datePicker,
s.createNextButton(e -> createGender().show()));
return s;
}
private static RadioButton createGenderButton(ButtonGroup bg,
String label, String icon) {
Style unselectedIconStyle = UIManager.getInstance().
getComponentStyle("GenderIcons");
Style selectedIconStyle = UIManager.getInstance().
getComponentSelectedStyle("GenderIcons");
FontImage unIcon =
FontImage.create(icon, unselectedIconStyle);
FontImage selIcon =
FontImage.create(icon, selectedIconStyle);
RadioButton rb = RadioButton.createToggle(label, unIcon, bg);
rb.setTextPosition(BOTTOM);
rb.setRolloverIcon(selIcon);
rb.setPressedIcon(selIcon);
rb.setUIID("GenderToggle");
return rb;
}
public static SignupForm createGender() {
SignupForm
Before we can go into it I created a small helper method to make the two gender buttons. Toggle buttons in Codename One can be radio buttons. That means that we
can pick only one of them, when we click on female the male entry is deselected
15. datePicker.setDate(new Date(System.currentTimeMillis() -
twentyYears));
s.content.addAll(title, datePicker,
s.createNextButton(e -> createGender().show()));
return s;
}
private static RadioButton createGenderButton(ButtonGroup bg,
String label, String icon) {
Style unselectedIconStyle = UIManager.getInstance().
getComponentStyle("GenderIcons");
Style selectedIconStyle = UIManager.getInstance().
getComponentSelectedStyle("GenderIcons");
FontImage unIcon =
FontImage.create(icon, unselectedIconStyle);
FontImage selIcon =
FontImage.create(icon, selectedIconStyle);
RadioButton rb = RadioButton.createToggle(label, unIcon, bg);
rb.setTextPosition(BOTTOM);
rb.setRolloverIcon(selIcon);
rb.setPressedIcon(selIcon);
rb.setUIID("GenderToggle");
return rb;
}
public static SignupForm createGender() {
SignupForm
We create the font icon based on a separate UIID because we want it to be much bigger than the text on the button. So we can't just use setMaterialIcon.
16. datePicker.setDate(new Date(System.currentTimeMillis() -
twentyYears));
s.content.addAll(title, datePicker,
s.createNextButton(e -> createGender().show()));
return s;
}
private static RadioButton createGenderButton(ButtonGroup bg,
String label, String icon) {
Style unselectedIconStyle = UIManager.getInstance().
getComponentStyle("GenderIcons");
Style selectedIconStyle = UIManager.getInstance().
getComponentSelectedStyle("GenderIcons");
FontImage unIcon =
FontImage.create(icon, unselectedIconStyle);
FontImage selIcon =
FontImage.create(icon, selectedIconStyle);
RadioButton rb = RadioButton.createToggle(label, unIcon, bg);
rb.setTextPosition(BOTTOM);
rb.setRolloverIcon(selIcon);
rb.setPressedIcon(selIcon);
rb.setUIID("GenderToggle");
return rb;
}
public static SignupForm createGender() {
SignupForm
Here we create the radio button and set the text positioning. A radio button belongs to a group & only one member of the group can be selected
17. rb.setTextPosition(BOTTOM);
rb.setRolloverIcon(selIcon);
rb.setPressedIcon(selIcon);
rb.setUIID("GenderToggle");
return rb;
}
public static SignupForm createGender() {
SignupForm s = new SignupForm("Gender",
"Birthday",
getCurrentForm());
Label title = new Label("What's Your Gender?", "SignupSubHeader");
ButtonGroup bg = new ButtonGroup();
RadioButton female = createGenderButton(bg, "Female", "ue800");
RadioButton male = createGenderButton(bg, "Male", "ue801");
Container buttons = GridLayout.encloseIn(2, female, male);
buttons.setUIID("PaddedContainer");
s.content.addAll(title, buttons,
s.createNextButton(e -> createNumber().show()));
return s;
}
SignupForm
That's mostly simple boilerplate code. The Form code is even simpler.
18. rb.setTextPosition(BOTTOM);
rb.setRolloverIcon(selIcon);
rb.setPressedIcon(selIcon);
rb.setUIID("GenderToggle");
return rb;
}
public static SignupForm createGender() {
SignupForm s = new SignupForm("Gender",
"Birthday",
getCurrentForm());
Label title = new Label("What's Your Gender?", "SignupSubHeader");
ButtonGroup bg = new ButtonGroup();
RadioButton female = createGenderButton(bg, "Female", "ue800");
RadioButton male = createGenderButton(bg, "Male", "ue801");
Container buttons = GridLayout.encloseIn(2, female, male);
buttons.setUIID("PaddedContainer");
s.content.addAll(title, buttons,
s.createNextButton(e -> createNumber().show()));
return s;
}
SignupForm
We use ButtonGroup to tie two or more radio buttons together. Only one of the radio buttons in a group can be selected
19. rb.setTextPosition(BOTTOM);
rb.setRolloverIcon(selIcon);
rb.setPressedIcon(selIcon);
rb.setUIID("GenderToggle");
return rb;
}
public static SignupForm createGender() {
SignupForm s = new SignupForm("Gender",
"Birthday",
getCurrentForm());
Label title = new Label("What's Your Gender?", "SignupSubHeader");
ButtonGroup bg = new ButtonGroup();
RadioButton female = createGenderButton(bg, "Female", "ue800");
RadioButton male = createGenderButton(bg, "Male", "ue801");
Container buttons = GridLayout.encloseIn(2, female, male);
buttons.setUIID("PaddedContainer");
s.content.addAll(title, buttons,
s.createNextButton(e -> createNumber().show()));
return s;
}
SignupForm
GridLayout gives both buttons the exact same size
20. GenderIcons {
cn1-derive: IconFont;
color: #587EBE;
}
GenderIcons.selected, GenderIcons.pressed {
color: white;
}
GenderToggle {
text-align: center;
border-radius: 3mm;
padding: 4mm;
background: white;
margin: 2mm;
border-color: #cccccc;
border-width: 1px;
}
GenderToggle.selected, GenderToggle.pressed {
background: #587EBE;
border-color: #cccccc;
border-width: 1px;
}
theme.css
The last piece for this form is the CSS for the UIID's we defined.
The gender icon uses the same icon settings as the logo with a different color
21. GenderIcons {
cn1-derive: IconFont;
color: #587EBE;
}
GenderIcons.selected, GenderIcons.pressed {
color: white;
}
GenderToggle {
text-align: center;
border-radius: 3mm;
padding: 4mm;
background: white;
margin: 2mm;
border-color: #cccccc;
border-width: 1px;
}
GenderToggle.selected, GenderToggle.pressed {
background: #587EBE;
border-color: #cccccc;
border-width: 1px;
}
theme.css
We have a special case for the selected/pressed versions of the UIID to make the icon white
22. GenderIcons {
cn1-derive: IconFont;
color: #587EBE;
}
GenderIcons.selected, GenderIcons.pressed {
color: white;
}
GenderToggle {
text-align: center;
border-radius: 3mm;
padding: 4mm;
background: white;
margin: 2mm;
border-color: #cccccc;
border-width: 1px;
}
GenderToggle.selected, GenderToggle.pressed {
background: #587EBE;
border-color: #cccccc;
border-width: 1px;
}
theme.css
The GenderToggle UIID uses a round rect border with a gray line surrounding it
Once we did all of that we can run the app and we would be halfway through the wizard!