Goal Setting Doesn't Serve You

Is it necessary to have goals in life?

In general, it’s considered essential to have goals. They give you purpose and meaning in life. And it feels like we’re built to pursue our goals to live a more fulfilling life.

But, goals could be the very things that prevent you from getting yourself to where you want to be. 

Clock Time and Psychological Time

In The Power of Now, Eckhart Tolle talks about “clock time” and “psychological time.”

“If you set yourself a goal and work toward it, you are using clock time. You are aware of where you want to go, but you honor and give your fullest attention to the step that you are taking at this moment.

If you then become excessively focused on the goal, perhaps because you are seeking happiness, fulfillment, or a more complete sense of self in it, the Now is no longer honored. It becomes reduced to a mere stepping stone to the future, with no intrinsic value.

Clock time then turns into psychological time. Your life’s journey is no longer an adventure, just an obsessive need to arrive, to attain, to ‘make it.’

If you set a goal and give your fullest attention to the step just ahead of you, you know where you’re going, and you’re also living in the process. 

But, obsessing over your goal rather than the present makes you unable to take appropriate actions for your objective. Your ‘adventure’ turns into a mere task you have to complete.

Scott Adams, the creator of Dilbert, talks about how goal setting leads to failure in his book How to Fail at Almost Everything and Still Win Big.

“To put it bluntly, goals are for losers. That’s literally true most of the time. For example, if your goal is to lose ten pounds, you will spend every moment until you reach the goal—if you reach it at all—feeling as if you were short of your goal.

In other words, goal-oriented people exist in a state of nearly continuous failure that they hope will be temporary. That feeling wears on you. In time, it becomes heavy and uncomfortable. It might even drive you out of the game.”

It’s a familiar feeling to feel not enough for not living up to your standards. When you feel that way, you’re obsessing over your goals. 

Systems Conquer Goals

Scott, instead, introduces the concept of having a system as a replacement for a goal.

“let’s say a goal is a specific objective that you either achieve or don’t sometime in the future. A system is something you do on a regular basis that increases your odds of happiness in the long run. If you do something every day, it’s a system. If you’re waiting to achieve it someday in the future, it’s a goal… The minimum requirement of a system is that a reasonable person expects it to work more often than not. Buying lottery tickets is not a system no matter how regularly you do it.”

A system, or a habit, is still in some way a goal. Still, it is a collection of small things you do regularly. It’s less likely that you obsess over them because it’s always about doing at the moment.

But if you start treating your habits as just something you have to do every day, they are in control of you. You don’t perform at your best or get energized. They just become another thing that drains you.

You’re at Your Best When You Do What You Like

So, it’s best that you like what you do. And to do so, you want to be deliberately and fully present and recognize the joy/beauty of it.

If you can find joy in anything, you start liking it. And what you like gives you energy.

Scott uses the amount of energy as his primary metric, prioritizing things he enjoys doing.

“The way I approach the problem of multiple priorities is by focusing on just one main metric: my energy. I make choices that maximize my personal energy because that makes it easier to manage all of the other priorities.”

When you feel unmotivated or stuck, it’s easier to start by doing what you like, which gives you a boost to do other things. 

Naval also talks about how doing what you like yields the best performance.

“The less you want something, the less you’re thinking about it, the less you’re obsessing over it, the more you’re going to do it in a natural way. The more you’re going to do it for yourself. You’re going to do it in a way you’re good at, and you’re going to stick with it. The people around you will see the quality of your work is higher.”

Doing what you like in the most natural way without thinking about your goal is paradoxically the best way to get to where you want.

Luckily, in Hardwiring Happiness: The New Brain Science of Contentment, Calm, and Confidence, Dr. Hanson states that liking and wanting are not connecting in your brain.

“In your subcortex and brain stem, connected but separate circuits handle liking and wanting. This means you can like something without wanting it.”

You don’t have to want something for you to like it.

I tend to think that just doing what you like is not sufficient. But it’s true that you’re the most natural when you do what makes you happy. And that way, your performance is at its peak.

As Naval also says

No one can compete with you on being you.

What are the things do you enjoy doing in and of itself? What feels like play to you?

This saying below encapsulates the dichotomy of liking and wanting.

Liking without wanting is heaven, wanting without liking is hell.

Share

I am on Twitter. Comments, feedback, book/article recommendations, anything is welcome.

AI cameras introduced in London to monitor social distancing

The sensors were initially developed by Vivacity to track the flow of traffic, cyclists and pedestrians and monitor how roads are being used.

But when the country went into lockdown in March, Vivacity added on an extra feature to the AI scanners so it could register the distance between pedestrians. This data is shared in a monthly report with the Government.

Vivacity Labs said they have more than 1,000 sensors installed across the UK, in cities including London, Manchester, Oxford, Cambridge and Nottingham.

Chief Operating Officer at Vivacity Peter Mildon told BBC Radio Kent on Wednesday that the data is potentially “useful for informing policy decisions” regarding lockdown measures.

The data could be used to see where traffic calming measures might be necessary on UK roads (Vivacity Labs)

He stressed that the cameras are not CCTV but that they operate as a data collating device rather than a camera that stores footage.

“They are not recording any footage, they are not streaming any footage and no one is actually watching it,” he said.

The AI technology is able to differentiate between pedestrians and vehicles (Vivacity Labs)

“We’ve trained an algorithm to be able to recognise what a pedestrian looks like as opposed to a cyclist or a van or truck.”

The Chief Operating Officer of Vivacity said the manufacturers introduced a new social distancing feature for the sensors in March.

1/50

A woman jogging near City Hall, London, the day after Prime Minister Boris Johnson put the UK in lockdown

PA

2/50

An image of Queen Elizabeth II and quotes from her broadcast on Sunday to the UK and the Commonwealth in relation to the coronavirus epidemic are displayed on lights in London’s Piccadilly Circus

PA

3/50

A pedestrian walks past a billboard reading “Please believe these days will pass” on Broadway Market in east London

AFP via Getty Images

4/50

Military vehicles cross Westminster Bridge

Getty Images

5/50

Boris Johnson

Jeremy Selwyn

6/50

Sun-seekers cool off in the water and sunbathe on the riverbank at Hackney Marshes in east London

AFP via Getty Images

7/50

Ed Davey is shown on screens as he speaks via videolink during Prime Minister’s Questions in the House of Commons, London

PA

8/50

A herd of fallow deer graze on the lawns in front of a housing estate in Harold Hill in east London

AFP via Getty Images

9/50

A woman wearing a mask crosses a bridge over Camden Lock, London

PA

10/50

An empty Millenium Bridge

PA

11/50

A sign advertising a book titled “How Will We Survive On Earth?” is seen on an underground station platform

Getty Images

12/50

People push to enter the Niketown shop in Londo

AP

13/50

Jo Proudlove and daughter Eve, 9, follow the daily online “PE with Joe” Joe Wickes’ exercise class on “Fancy dress Friday

Reuters

14/50

Police in Westminster

Jeremy Selwyn

15/50

Waterloo station looking empty

PA

16/50

Getty Images

17/50

A quiet Parliament Square

Getty Images

18/50

PABest A man walks along a passageway at London’s Oxford Street Underground station the day after Prime Minister Boris Johnson put the UK in lockdown to help curb the spread of the Coronavirus

PA

19/50

Social distancing markers around the camel enclosure at ZSL London Zoo

PA

20/50

A police car patrols Greenwich Park in London

PA

21/50

The Premier League in action in front of empty stands

AP

22/50

Novikov restaurant in London with its shutters pulled down while the restaurant is closed.

23/50

A deserted Piccadilly Circus

PA

24/50

A general view is seen of a deserted Trafalgar Square

AFP via Getty Images

25/50

Getty Images

26/50

The iconic Abbey Road crossing is seen after a re-paint by a Highways Maintenance team as they take advantage of the COVID-19 coronavirus lockdown and quiet streets to refresh the markings

Getty Images

27/50

A view of 20 Fenchurch Street (the ‘Walkie Talkie’ building) in the City of London, the day after Prime Minister Boris Johnson put the UK in lockdown to help curb the spread of the coronavirus

PA

28/50

A deserted Chinatown

PA

29/50

A person looks at graffiti on a JD Wetherspoon pub in Crystal Palace, south London. Wetherspoons workers have described founder Tim Martin’s lack of support for his chain’s 40,000 employees as “absolutely outrageous”

PA

30/50

The London ExCel centre that has been turned into a makeshift NHS Hospital and critical care unit to cope with the Coronavirus pandemic

PA

31/50

The Palace Theatre, which usually shows the Harry Potter and the Cursed Child play, sits in a deserted Shaftesbury Avenue

PA

32/50

The Sondheim Theatre, which usually shows the Les Miserables musical, sits in a deserted Shaftesbury Avenue

PA

33/50

Two members of a British Army mounted regiment exercise their horses in Parliament Square

AP

34/50

Westminster Bridge is deserted

PA

35/50

A quiet Canary Wharf Underground Station

PA

36/50

An empty street and bus stop at St James’s Park

AFP via Getty Images

37/50

Whitehall

Jeremy Selwyn

38/50

A quiet Canary Wharf Underground Station

PA

39/50

A single pedestrian walks past The national Gallery

AFP via Getty Images

40/50

London Bridge Station

Jeremy Selwyn

41/50

Kings Cross and St Pancras

Jeremy Selwyn

42/50

Buckingham Palace looking empty in London,

PA

43/50

London Bridge Station

Jeremy Selwyn

44/50

Kings Cross and St Pancras

Jeremy Selwyn

45/50

London Bridge Station

Jeremy Selwyn

46/50

London’s Carnaby Street empty as shops closed after a lockdown was announced in the latest bid to stop the spread of coronavirus through the UK

AP

47/50

A quiet Jubilee line westbound train carriage

PA

48/50

A single pedestrian walks past The national Gallery

AFP via Getty Images

49/50

A quiet Canary Wharf Underground Station

PA

50/50

Empty Embankment

Jeremy Selwyn

1/50

A woman jogging near City Hall, London, the day after Prime Minister Boris Johnson put the UK in lockdown

PA

2/50

An image of Queen Elizabeth II and quotes from her broadcast on Sunday to the UK and the Commonwealth in relation to the coronavirus epidemic are displayed on lights in London’s Piccadilly Circus

PA

3/50

A pedestrian walks past a billboard reading “Please believe these days will pass” on Broadway Market in east London

AFP via Getty Images

4/50

Military vehicles cross Westminster Bridge

Getty Images

5/50

Boris Johnson

Jeremy Selwyn

6/50

Sun-seekers cool off in the water and sunbathe on the riverbank at Hackney Marshes in east London

AFP via Getty Images

7/50

Ed Davey is shown on screens as he speaks via videolink during Prime Minister’s Questions in the House of Commons, London

PA

8/50

A herd of fallow deer graze on the lawns in front of a housing estate in Harold Hill in east London

AFP via Getty Images

9/50

A woman wearing a mask crosses a bridge over Camden Lock, London

PA

10/50

An empty Millenium Bridge

PA

11/50

A sign advertising a book titled “How Will We Survive On Earth?” is seen on an underground station platform

Getty Images

12/50

People push to enter the Niketown shop in Londo

AP

13/50

Jo Proudlove and daughter Eve, 9, follow the daily online “PE with Joe” Joe Wickes’ exercise class on “Fancy dress Friday

Reuters

14/50

Police in Westminster

Jeremy Selwyn

15/50

Waterloo station looking empty

PA

16/50

Getty Images

17/50

A quiet Parliament Square

Getty Images

18/50

PABest A man walks along a passageway at London’s Oxford Street Underground station the day after Prime Minister Boris Johnson put the UK in lockdown to help curb the spread of the Coronavirus

PA

19/50

Social distancing markers around the camel enclosure at ZSL London Zoo

PA

20/50

A police car patrols Greenwich Park in London

PA

21/50

The Premier League in action in front of empty stands

AP

22/50

Novikov restaurant in London with its shutters pulled down while the restaurant is closed.

23/50

A deserted Piccadilly Circus

PA

24/50

A general view is seen of a deserted Trafalgar Square

AFP via Getty Images

25/50

Getty Images

26/50

The iconic Abbey Road crossing is seen after a re-paint by a Highways Maintenance team as they take advantage of the COVID-19 coronavirus lockdown and quiet streets to refresh the markings

Getty Images

27/50

A view of 20 Fenchurch Street (the ‘Walkie Talkie’ building) in the City of London, the day after Prime Minister Boris Johnson put the UK in lockdown to help curb the spread of the coronavirus

PA

28/50

A deserted Chinatown

PA

29/50

A person looks at graffiti on a JD Wetherspoon pub in Crystal Palace, south London. Wetherspoons workers have described founder Tim Martin’s lack of support for his chain’s 40,000 employees as “absolutely outrageous”

PA

30/50

The London ExCel centre that has been turned into a makeshift NHS Hospital and critical care unit to cope with the Coronavirus pandemic

PA

31/50

The Palace Theatre, which usually shows the Harry Potter and the Cursed Child play, sits in a deserted Shaftesbury Avenue

PA

32/50

The Sondheim Theatre, which usually shows the Les Miserables musical, sits in a deserted Shaftesbury Avenue

PA

33/50

Two members of a British Army mounted regiment exercise their horses in Parliament Square

AP

34/50

Westminster Bridge is deserted

PA

35/50

A quiet Canary Wharf Underground Station

PA

36/50

An empty street and bus stop at St James’s Park

AFP via Getty Images

37/50

Whitehall

Jeremy Selwyn

38/50

A quiet Canary Wharf Underground Station

PA

39/50

A single pedestrian walks past The national Gallery

AFP via Getty Images

40/50

London Bridge Station

Jeremy Selwyn

41/50

Kings Cross and St Pancras

Jeremy Selwyn

42/50

Buckingham Palace looking empty in London,

PA

43/50

London Bridge Station

Jeremy Selwyn

44/50

Kings Cross and St Pancras

Jeremy Selwyn

45/50

London Bridge Station

Jeremy Selwyn

46/50

London’s Carnaby Street empty as shops closed after a lockdown was announced in the latest bid to stop the spread of coronavirus through the UK

AP

47/50

A quiet Jubilee line westbound train carriage

PA

48/50

A single pedestrian walks past The national Gallery

AFP via Getty Images

49/50

A quiet Canary Wharf Underground Station

PA

50/50

Empty Embankment

Jeremy Selwyn

“We developed an addition to our sensors that was not just looking at the paths pedestrians were taking, but if two pedestrians come within two metres of one another then we will count that as one, and if they don’t come within two metres of one another then we will count that as a different one,” said Mr Mildon.

“We’re creating a set of statistics on how behaviour is changing in terms of how people are staying close together or apart. And it is that data that is then useful for informing policy decisions on whether there should be a two metre rule or a one metre plus rule or whether local lockdown measures are having the impact they are envisioned to.”

Privacy concerns have been raised around the cameras, with the issue flagged during a Kent Council scrutiny committee meeting on Tuesday after Simon Jones said the scheme is “in the pipeline” for the borough, reports Kent Online.

Mr Mildon added: “Even if Kent Council wanted to use them for enforcement purposes they wouldn’t be able to

“The [cameras] enable us to provide anonymous data on how the road is being used. There are huge benefits in understanding how that space is being used and how that can be improved or how it can be made safer.

“The idea is to provide an evidence base to check that the interventions that are being put in and are having the policy benefits that the council envisioned in the first place.”

The Department for Transport told the Evening Standard that the Government, along with a number of other bodies, receives monthly data reports from Vivacity which forms part of the department’s monitoring of the impact of Covid-19.

The information supplied to the department are aggregate findings and no personal data is included in these reports, said the DfT.

A Stoic Philosopher in a Hanoi Prison: I am the captain of my soul

Takeaway Tues…FRIDAY on A Stoic Philosopher in a Hanoi Prison and The Stoic Warrior’s Triad

Apologies for the delay! We should be back on Tuesday starting next week.

We appreciate all our subscribers’ ongoing support. Please continue to share with those who might also enjoy receiving our free newsletter. Any suggested materials for our Sunday newsletter can be sent to social@butwhatfor.com. Thank you!

James B. Stockdale was a vice admiral and aviator who served for 37 years in the United States Navy, spending the majority of his time as a fighter pilot on aircraft carriers. Shot down on his third combat tour over North Vietnam, Stockdale was the senior-most navy prisoner of war in Hanoi, where he spent over seven years – four of them in solitary confinement and two in leg irons – before being released. He was awarded the Medal of Honor, along with 26 other combat decorations, and retired as an educator and author.

Preparation and experience work most of the time – but not all of the time

Stockdale had no reason to think that the day’s mission was to be anything unique.

The flight in September 1965 was part of his third combat tour of North Vietnam, serving as Wing Commander of the aircraft carrier Oriskany. Despite his misgivings about the purpose of him being in Vietnam, he was a competent and skilled career fighter pilot. Nothing suggested he shouldn’t expect to make it back home that day – let alone that decade.

But sometimes life deals you a lousy hand, and it dealt Stockdale quite an unhappy one.

While trying to aid trapped American soldiers on the ground, he was suddenly falling out of the sky and hurtling towards a small Vietnamese village. His plane was on fire, the control system shot out by North Vietnamese who had used the grounded soldiers as bait, and he didn’t have much choice beyond punching out of the plane.

After ejection, I had about 30 seconds to make my last statement in freedom before I landed in the main street of a little village right ahead. And, so help me, I whispered to myself: “Five years down there, at least. I’m leaving the world of technology and entering the world of Epictetus.”

Just like that, Stockdale’s day had gone from routine to disastrous – but why was the first thing to jump into his mind the ancient philosopher, Epictetus?

It is never too late to learn something that can be meaningful, sometimes so meaningful that it saves your life

Five years previously, Stockdale had enrolled in the International Relations graduate program at Standford University. Twenty years in the Navy had given him the background needed to be a strategic planner in the Pentagon. But something wasn’t right – his heart wasn’t in it.

He eventually landed in Stanford’s Philosophy department where he was introduced to Epictetus, amongst others. He took the study of philosophy to heart, and his decades of real-life military experience focused his attention on the “noble philosophy that has proven to be more practicable than a modern cynic would expect” – Stoicism.

His bedside table on the aircraft carrier was no longer stacked with busy work to impress his superiors, but the “Discourses, Xenophon’s Memorabilia, recollections of Socrates, and of course, The Iliad and The Odyssey.

I came to the philosophic life as a 38-year-old Navy pilot in graduate school at Stanford University. I had been in the Navy for 20 years and scarcely ever out of a cockpit… Then I cruised into Stanford’s philosophy corner one winter morning and met Philip Rhinelander, dean of humanities and sciences… Within 15 minutes, we had agreed that I would enter his two-term course in the middle. To make up for my lack of background, I would meet him for an hour a week for a private tutorial in the study of his campus home.

Phil Rhinelander opened my eyes. In that study, it all happened for me – my inspiration, my dedication to the philosophic life. From then on, I was out of international relations and into philosophy… On my last session, he reached high on his wall of books and brought down a copy of the Enchiridion. He said, “I think you’ll be interested in this.”

Success is never certain, but suffering is – it is best to prepare for it

But what was it about Epictetus and Stoicism that hit so close to home for Stockdale? Why did he think it more practical than other schools of thought?

Epictetus is known amongst Stoic philosophers for his blunt advice – he referred to the lecture room not only as a place of learning, but as a hospital where you leave in pain but are better prepared for the future.

One of Epictetus’s key messages is that the only thing guaranteed humans is that they will suffer. By being prepared to appropriately handle suffering, we will also be better prepared to humbly handle and appreciate any success. For a military man who had seen the brutality of war first hand for decades, you can imagine why such an acceptance of human frailty would be attractive.

But further still, Epictetus lays the source of all that suffering on the suffering individual themselves. A disciplined mind, for the Stoics, along with taking personal responsibility for your orientation towards your situation, is the key to being able to get out of bed in the morning. In this way, you have control over yourself and your suffering without letting the world dictate it for you, regardless of the circumstances.

Epictetus explained that his curriculum was not about “revenues or income, or peace or war, but about happiness and unhappiness, success and failure, slavery and freedom.” His model graduate was not a person “able to speak fluently about philosophic principles as an idle babbler, but about things that will do you good if your child dies, or your brother dies, or if you must die or be tortured. …Let others practice lawsuits, others study problems, others syllogisms; here you practice how to die, how to be enchained, how to be racked, how to be exiled.”

A man is responsible for his own “judgments, even in dreams, in drunkenness, and in melancholy madness.” Each individual brings about his own good and his own evil, his good fortune, his ill fortune, his happiness, and his wretchedness. It is unthinkable that one man’s error could cause another’s suffering; suffering, like everything else in stoicism, was all internal – remorse at destroying yourself.

Epictetus was telling his students that there can be no such thing as being the “victim” of another. You can only be a “victim” of yourself. It’s all in how you discipline your mind. Who is your master?” He who has authority over any of the things on which you have set your heart. …What is the result at which all virtue aims? Serenity. …show me a man who though sick is happy, who though in danger is happy, who though in prison is happy, and I’ll show you a Stoic.”

Your status and security in life can change in an instant, so do not define yourself by what you are

Back in September 1965, Stockdale can feel the bullets whistling past his head and into the parachute canopy above him.

Closer to the ground now he hears the shouting of villagers and can see the angry eyes, fists raised, looking up at him. His parachute catches on a tree near the main street, and but he hits the ground in relatively good shape.

That outcome wasn’t acceptable to the unhappy villagers – so a group of ten or fifteen of them gang tackled Stockdale and beat him for over three minutes. He was saved by a policeman’s whistle, but a few broken bones and badly twisted and shattered leg were harbingers of what was to be the next seven years of his life.

As I glide down toward that little town on my short parachute ride, I’m just about to learn how negligible is my control over my station in life. It’s not at all up to me. Of course, I’m going right now from being the Wing Commander, in charge of a thousand people (pilots, crewmen, maintenance men), responsible for nearly a hundred airplanes, and beneficiary of goodness knows all sorts of symbolic status and goodwill, to being an object of contempt. “Criminal,” I’ll be known as.

And more than that even, you’re going to face fragilities you never before let yourself believe could be true. [ See * at end of post, removed description of “taking the ropes” in case it is your preference to skip reading it] … that you can be made to blurt out answers, probably correct answers, to questions about anything they know you know. I’m not going to pull you through that explanation again. I’ll just call it “taking the ropes.”

No, “station in life” can be changed from that of a dignified and competent gentleman of culture to that of a panic-stricken, sobbing, self-loathing wreck, maybe a permanent wreck if you have no will, in less than an hour. So what? So after you work a lifetime to get yourself all set up, and then delude Yourself into thinking that YOU have some kind of ownership claim on Your station in life, you’re riding for a fall. You’re asking for disappointment. To avoid that, stop kidding yourself, just do the best you can on a common-sense basis to make your station in life what you want it to be, but never get hooked on it. Make sure in your heart of hearts, in your inner self, that you treat your station in life with indifference. Not with contempt, only with indifference.

Shame at not living up to your own ideals is worse than a terrible situation itself

Torture was now a part of Stockdale’s daily life – as it was for any of the prisoners of war in North Vietnam. And that started with the first introduction to the Hanoi prisoner of war camp – you were broken down and isolated. The only way out of this pain was the betrayal of ideals you previously held – giving up military secrets, aiding in propaganda by admitting wrongdoing. Your reward for giving your captors what they wanted was to be isolated further for two months “to contemplated your crimes.”

According to Stockdale, what was actually contemplated by these men was “his betrayal of himself and everything that he stood for.”

Once released into the general population, this feeling of shame caused men to recoil from other prisoners, thinking themselves uniquely fragile. However, once they realized that everyone in the camp had gone through – and said – the same things, there was a turning point. They gained strength and together the men were able to make the best of an impossibly terrible situation.

The keyword for all of us at first was fragility. Each of us, before we were ever in shouting distance of another American, was made to “take the ropes.” That was a real shock to our systems – and as with all shocks, its impact on our inner selves was a lot more impressive and lasting and important than to our limbs and torsos. These were the sessions where we were taken down to submission and made to blurt out distasteful confessions of guilt and American complicity into antique tape recorders, and then to be put in what I call “cold soak,” six or eight weeks of total isolation to “contemplate our crimes.”

What we actually contemplated was what even the most self-satisfied American saw as his betrayal of himself and everything he stood for. It was there that I learned what “Stoic harm” meant. A shoulder broken, a bone in my back broken, and a leg broken twice were peanuts by comparison. Epictetus said: “Look not for any greater harm than this: destroying the trustworthy, self-respecting, well-behaved man within you.”

When put into a regular cell block, hardly an American came out of that without responding something like this when first whispered to by a fellow prisoner next door: “You don’t want to talk to me; I am a traitor.” And because we were equally fragile, it seemed to catch on that we all replied something like this: “Listen, pal, there are no virgins in here. You should have heard the kind of statement I made. Snap out of it. We’re all in this together. What’s your name? Tell me about yourself. “To hear that was, for most new prisoners just out of initial shakedown and cold soak, a turning point in their lives.

You can always be in control of you, in any situation

Stockdale was the senior-most officer in the prison, and as such, he was in command of what was essentially an American military colony on Vietnamese soil. In this position, he was able to multiply what he had learned from Epictetus across the entire American prisoner of war population. He knew that allowing men to be isolated without a sense of purpose would result in them all breaking down – feeling shame that they did not live up to their own definition of themselves was worse than a broken body.

We are in a spot like we’ve never been in before. But we deserve to maintain our self-respect, to have the feeling we are fighting back. We can’t refuse to do every degrading thing they demand of us, but it’s up to you, boss, to pick out things we must all refuse to do, unless and until they put us through the ropes again. We deserve to sleep at night. We at least deserve to have the satisfaction that we are hewing to our leader’s orders. Give us the list: What are we to take torture for?

And Stockdale followed his own advice – he took “the ropes” fifteen times, had his shoulder broken, his back broken, and his same leg twice broken.

The only way to survive without feeling debilitating shame – shame that was worse than the torture itself – was to have control over what you did and what you said.

This was a first step in claiming what was rightfully ours. Epictetus said: “The judge will do some things to you which are thought to be terrifying; but how can he stop you from taking the punishment he threatened?”

That’s my kind of Stoicism. You have a right to make them hurt you, and they don’t like to do it. The prison commissar told my fellow prisoner Ev Alvarez when he was released: “You Americans were nothing like the French; we could count on them to be reasonable.”

An individual pursuing that which is meaningful can find a reason to face any adversity

Epictetus turned out to be right. All told, it was only a temporary setback from things that were important to me, and being cast in the role as the sovereign head of an American expatriate colony which was destined to remain autonomous, out of communication with Washington, for years on end, was very important to me. I was determined to “play well the given part.”

It matters not how strait the gate,

How charged with punishment the scroll,

I am the master of my fate,

I am the captain of my soul.

But What For? – Multidisciplinary insights for self development. Improve yourself in such a way that you might eventually improve more than you.

Share

*- [After mere minutes, in a flurry of action while being knocked down and then sat up to be bound with tourniquet-tight ropes, with care, by a professional, hands cuffed behind, jack-knifed forward, head pushed down between your ankles held secure in lugs attached to a heavy iron bar, that with the onrush of anxiety, knowing your upper-body blood circulation has been stopped, and feeling the evergrowing pain and the ever-closing-in of claustrophobia as the man standing on your back gives your head one last shove down with his heel and you start to gasp and vomit…]

Deploying Dockerized Apps with Google Cloud's MIGs

Paulo Carvalho

Photo by Mike Gieson from FreeImages

In the third part of this guide, we will walk through setting up a CICD solution for Docker containerized application such as a Ruby on Rails backend.

We want to deploy a web application consisting of one or more frontends using a client side framework such as ReactJS which connects to one (or more) backends that have been containerized with Docker. Our backend will connect to a CloudSQL instance for storage and all environment variables will be encrypted with GCP’s Key Management Service (KMS). GIT commits to a specific branch on GitHub will trigger a build and deploy of the application. A load balancer will direct traffic and serve as a proxy for HTTPS using a managed certificate.

Setup the environment proposed in part 1 of this guide or equivalent. Basic understanding of Docker and CloudBuild triggers as shown in part 2.

Below, we have a Dockerfile (placed in the root of the repository) that creates docker images containing our application’s source code. Note that this is a multi-stage build with 2 distinct end images. We will use 1 image for testing and the other for deployment since each case has different dependencies (this may not be true for your application).

Note: We define an ENTRYPOINT for our production image which performs a database migration prior to starting our web server. This is one of many ways to perform migrations and strategies for rolling back need to be considered when choosing how to migrate.

#############################
# STAGE 1: Installer build #
#############################

Docker Compose is a useful tool for running multiple containers and allowing them to interface with each other. We use this capability to run our integration tests (in the example below we only connect to a DB but options are limitless).

The Compose below spins up a MySQL database container called db with a default database my-db and no root password (please don’t do this with a user facing DB!). It then creates a second container called app running a test version of our application. Note the ./scripts/wait-for-mysql.sh (shown after the docker-compose file) preceding the test command. This is required (as discussed here) in order to ensure that the database is ready to accept connections prior to connecting to it.

version: '3.4'

The wait-for-mysql.sh script is shown below and is based on the Compose documentation script.

#!/bin/sh

Note: For more information on CloudBuild see part 2 of the guide.

The deployment pipeline described in this part of the guide will require two build files. One to create and deploy a production grade image and the other to create a test image and run tests on it. The latter is shown in this step.

We create a file named cloudbuild-tests.yml(you can rename it as desired) as shown below. The build it describes consists of two steps:

  1. Build the Docker image using Kaniko. We use Kaniko in order to cache the Docker build steps which speeds up future runs of the build. The image is automatically pushed to the specified destination when build is complete along with all cache artifacts.
  2. We run a docker-compose which is responsible for running our tests. The exit code from our docker-compose is used to indicate if tests passed or failed.
steps:

Whenever a developer pushes to a branch we want our tests to automatically run. To this end, we create a trigger such as the one below (for more information on creating a trigger see part 2):

The trigger above will run whenever there is a push to any branch except staging or production. We will have a separate script (or multiple separate scripts) that will run for those branches.

The CloudBuild script below consists of 5 steps:

  1. We build the production image and push it to our container registry.
  2. We decrypt our secrets.
  3. We create a new instance template using our previously built image and decrypted secrets. Note: This manner of secret management may not be appropriate for your organization. Adjust accordingly.
  4. If your organization does deploys often, you may need to ensure that the cluster is stable (the last update has already been applied) before attempting to perform a new update. Else, the new update will fail. This step waits for the cluster to be stable.
  5. We update our managed instance group with our new instance template. Note the --max-unavailable flag. This is recommended if you have a small clusters (less servers than number of availability zones in your region) in order to not have disruptions during the update.

Note: We increased the timeout (from the default 10 minutes) to accommodate the time required to build our image if cache has expired. Adjust accordingly for your application.

steps:

We want to configure a trigger to automatically deploy our application to the staging environment whenever code is merged into the staging branch. The trigger is shown below:

Note: A similar trigger can be created for production. However, I would recommend placing production on a separate project entirely (The $PROJECT_ID in our scripts will handle that as long as the trigger is created on the separate project as well). With separate projects better separation between staging and production is possible. It will also simplify the permission management for developers that have access to either system.

At this point, we have all the infrastructure setup (part 1) and are able to deploy frontend code automatically to our Cloud Storage bucket(s) (part 2). Now we are also able to perform testing and deployment of our backends.

JuliaMono – a monospaced font for scientific and technical computing

JuliaMono is a monospaced typeface designed for programming in the Julia Programming Language and in other text editing environments that require a wide range of specialist and technical Unicode characters. It was intended as a fun experiment to be presented at the 2020 JuliaCon conference in Lisbon, Portugal (which of course didn’t physically happen in Lisbon, but online).

The original temporary website used JuliaMono everywhere, so let’s try to make the rest of this page do the same.

To download and install JuliaMono, see the instructions here.

Editing code in Juno.

And in VS Code.

screenshot of VS code editor

And in Vim:

screenshot of VIM editor

And in Emacs:

screenshot of emacs editor

using Zygote: @adjoint
function ignore(f)
  try return f()
        catch e; return 0; end
end
@adjoint function ignore(f)
  try Zygote._pullback(__context__, f)
  catch e
    0, ȳ -> nothing
  end
end

There are different weights of JuliaMono, so you can control the amount of contrast you have in your highlighted code: JuliaMono-Light, JuliaMono-Regular, JuliaMono-Medium, JuliaMono-Bold, JuliaMono-ExtraBold, and JuliaMono-Black. [3]

(There are also versions of two of the fonts with “Latin” in the name: these are stripped down versions supporting just the basic MacRoman/Windows1252 “Latin” character sets, intended for use as place-holders, of interest mainly if you want to have more control over font loading times in web browser-based applications.)

In the hands of a virtuoso (such as Dr Zygmunt Szpak, the author of the following Julia code fragment[4]), the range of available Unicode characters can be quite expressive:

function T(𝛉::AbstractArray,
           𝒞::Tuple{AbstractArray,
           Vararg{AbstractArray}},
           𝒟::Tuple{AbstractArray, Vararg{AbstractArray}})
    ⊗ = kron
    l = length(𝛉)
    𝐈ₗ = SMatrix{l,l}(1.0I)
    𝐈ₘ = SMatrix{1,1}(1.0I)
    𝐓 = @SMatrix zeros(l,l)
    N = length(𝒟[1])
    ℳ, ℳʹ = 𝒟
    Λ₁, Λ₂ = 𝒞
    𝚲ₙ = @MMatrix zeros(4,4)
    𝐞₁ = @SMatrix [1.0; 0.0; 0.0]
    𝐞₂ = @SMatrix [0.0; 1.0; 0.0]
    for n = 1:N
        index = SVector(1,2)
        𝚲ₙ[1:2,1:2] .=  Λ₁[n][index,index]
        𝚲ₙ[3:4,3:4] .=  Λ₂[n][index,index]
        𝐦    = hom(ℳ[n])
        𝐦ʹ   = hom(ℳʹ[n])
        𝐔ₙ   = (𝐦 ⊗ 𝐦ʹ)
        ∂ₓ𝐮ₙ = [(𝐞₁ ⊗ 𝐦ʹ) (𝐞₂ ⊗ 𝐦ʹ) (𝐦 ⊗ 𝐞₁) (𝐦 ⊗ 𝐞₂)]
        𝐁ₙ   = ∂ₓ𝐮ₙ * 𝚲ₙ * ∂ₓ𝐮ₙ'
        𝚺ₙ   = 𝛉' * 𝐁ₙ * 𝛉
        𝚺ₙ⁻¹ = inv(𝚺ₙ)
        𝐓₁   = @SMatrix zeros(Float64,l,l)
        for k = 1:l
            𝐞ₖ = 𝐈ₗ[:,k]
            ∂𝐞ₖ𝚺ₙ = (𝐈ₘ ⊗ 𝐞ₖ') * 𝐁ₙ * (𝐈ₘ ⊗ 𝛉) + (𝐈ₘ ⊗ 𝛉') * 𝐁ₙ * (𝐈ₘ ⊗ 𝐞ₖ)
            # Accumulating the result in 𝐓₁ allocates memory,
            # even though the two terms in the
            # summation are both SArrays.
            𝐓₁ = 𝐓₁ + 𝐔ₙ * 𝚺ₙ⁻¹ * (∂𝐞ₖ𝚺ₙ) * 𝚺ₙ⁻¹ * 𝐔ₙ' * 𝛉 * 𝐞ₖ'
        end
        𝐓 = 𝐓 + 𝐓₁
    end
    𝐓
end

Here are some samples of various languages[5] :

Ancient Greek Ἄδμηθ’, ὁρᾷς γὰρ τἀμὰ πράγμαθ’ ὡς ἔχει, λέξαι θέλω σοι πρὶν θανεῖν ἃ βούλομαι.
Bulgarian Я, пазачът Вальо уж бди, а скришом хапва кюфтенца зад щайгите.
Catalan «Dóna amor que seràs feliç!». Això, il·lús company geniüt, ja és un lluït rètol blavís d’onze kWh.
Czech Zvlášť zákeřný učeň s ďolíčky běží podél zóny úlů
Danish Quizdeltagerne spiste jordbær med fløde, mens cirkusklovnen Walther spillede på xylofon.
English Sphinx of black quartz, judge my vow.
Estonian Põdur Zagrebi tšellomängija-följetonist Ciqo külmetas kehvas garaažis
Finnish Charles Darwin jammaili Åken hevixylofonilla Qatarin yöpub Zeligissä.
French Voix ambiguë d’un cœur qui au zéphyr préfère les jattes de kiwi.
German Victor jagt zwölf Boxkämpfer quer über den großen Sylter Deich.
Greek Ταχίστη αλώπηξ βαφής ψημένη γη, δρασκελίζει υπέρ νωθρού κυνός.
Guarani Hĩlandiagua kuñanguéra oho peteĩ saʼyju ypaʼũme Gavõme omboʼe hag̃ua ingyleñeʼẽ mitãnguérare neʼẽndyʼỹ.
Hungarian Jó foxim és don Quijote húszwattos lámpánál ülve egy pár bűvös cipőt készít.
IPA [ɢʷɯʔ.nas.doːŋ.kʰlja] [ŋan.ȵʑi̯wo.ɕi̯uĕn.ɣwa]
Icelandic Kæmi ný öxi hér, ykist þjófum nú bæði víl og ádrepa.
Irish Ċuaiġ bé ṁórṡáċ le dlúṫspád fíorḟinn trí hata mo ḋea-ṗorcáin ḃig.
Latvian Muļķa hipiji mēģina brīvi nogaršot celofāna žņaudzējčūsku.
Lithuanian Įlinkdama fechtuotojo špaga sublykčiojusi pragręžė apvalų arbūzą.
Macedonian Ѕидарски пејзаж: шугав билмез со чудење џвака ќофте и кељ на туѓ цех.
Norwegian Jeg begynte å fortære en sandwich mens jeg kjørte taxi på vei til quiz
Polish Pchnąć w tę łódź jeża lub ośm skrzyń fig.
Portuguese Luís argüia à Júlia que «brações, fé, chá, óxido, pôr, zângão» eram palavras do português.
Romanian Înjurând pițigăiat, zoofobul comandă vexat whisky și tequila.
Russian Широкая электрификация южных губерний даст мощный толчок подъёму сельского хозяйства.
Scottish Mus d’fhàg Cèit-Ùna ròp Ì le ob.
Serbian Ајшо, лепото и чежњо, за љубав срца мога дођи у Хаџиће на кафу.
Spanish Benjamín pidió una bebida de kiwi y fresa; Noé, sin vergüenza, la más champaña del menú.
Swedish Flygande bäckasiner söka hwila på mjuka tuvor.
Turkish Pijamalı hasta yağız şoföre çabucak güvendi.
Ukrainian Чуєш їх, доцю, га? Кумедна ж ти, прощайся без ґольфів!

One of the goals of JuliaMono is to include most of the characters that a typical programmer would reasonably expect to find. (Except for all those emojis – they are best handled by the operating system.) Here’s a thousand or so chosen at random:

Unicode sampler

In JuliaMono, every character is the same width, because this is a monospaced typeface. Usually, typefaces with a lot of Unicode mathematical symbols are not monospaced, because they’re intended for use in prose and ( LaTeX ) applications, rather than in programming code.

From a design perspective, forcing every character into the same size box is a problem. It’s like fitting every human being of whatever shape or size into identical airplane seats – some characters are bound to look uncomfortable. There’s never quite enough room for a nice-looking “m” or “w”.

UnicodePlots.jl uses various Unicode characters to plot figures directly in a terminal window. [6]

UnicodePlots in action

ImageInTerminal.jl is similarly awesome, conjuring images from Unicode characters:

ImageInTerminal

JuliaMono is quite greedy[7], and contains a lot of Unicode glyphs.

silly barchart

(Of course, size isn’t everything – quality can beat quantity, and other fonts will offer different experiences[8]).

It’s also a good idea to support box-drawing characters and DataFrames.jl output (terminal permitting):

julia> df = DataFrame(A=samples, B=glyphs)
df = 10×2 DataFrame
│ Row │ A              │ B                   │
│     │ String         │ String              │
├─────┼────────────────┼─────────────────────┤
│ 1   │ sample 1       │ ▁▂▁▁▂▄▅▁▄▁▁▅▆▂▇▅▂▇  │
│ 2   │ sample 2       │ ▁▂▄▁▁▃▁▆▂▆▃▁▂▃▂▇▄   │
│ 3   │ sample 3       │ ▁▆▇▁▃▇▇▆▅▅▄▇▇▅▅▇▄▂  │
│ 4   │ sample 4       │ ▅▁▄▁▆▃▁▃▇▂▂▇▅▇▃▆▃▁  │
│ 5   │ sample 5       │ ▆▂▁▂▇▆▃▅▅▄▆▇▄▇▆▁▇   │
│ 6   │ sample 6       │ ▁▁▇▂▂▇▃▅▂▂▆▂▄▄▁▄▂▇▆ │
│ 7   │ sample 7       │ ▂▃▂▁▁▇▁▂▆▂▁▇▁▄▃▂▁▄  │
│ 8   │ sample 8       │ ▄▄▁▂▄▁▅▁▅▁▂▂▇▂▁▃▄▄  │
│ 9   │ sample 9       │ ▁▁▁▂▁▆▃▄▄▁▂▂▃▂▁▅▁▆▃ │
│ 10  │ sample 10      │ ▁▇▄▂▅▃▇▁▇▇▆▄▇▅▄▂▄▅▄ │

(Can you spot the little used and sadly mathematically-unsupported “times” character?)

If you want to know whether you can use a Unicode character as an identifier in your Julia code, use the undocumented function Base.isidentifier(). So, for example, if you have the urge to use a dingbat (one of the classic Herman Zapf dingbat designs), you could look for something suitable in the output of this:

julia> for n in 0x2700:0x27bf
                        Base.isidentifier(string(Char(n))) && print(Char(n))
           end
✀✁✂✃✄✅✆✇✈✉✊✋✌✍✎✏✐✑✒✓✔✕✖✗✘✙✚✛✜✝✞✟✠✡✢✣✤✥✦✧✨✩✪✫✬✭✮✯✰✱✲✳✴✵✶✷✸✹✺
✻✼✽✾✿❀❁❂❃❄❅❆❇❈❉❊❋❌❍❎❏❐❑❒❓❔❕❖❗❘❙❚❛❜❝❞❟❠❡❢❣❤❥❦❧➔➕➖➗➘➙➚➛➜➝➞➟➠➡
➢➣➤➥➦➧➨➩➪➫➬➭➮➯➰➱➲➳➴➵➶➷➸➹➺➻➼➽➾➿

julia> ❤(s) = println("I ❤ $(s)")
❤ (generic function with 1 method)

julia> ❤("Julia")
I ❤ Julia

JuliaMono is an OpenType typeface. OpenType technology provides powerful text positioning, pattern matching, and glyph substitution features, which are essential for languages such as Arabic and Urdu. In English, OpenType features are often seen when letter pairs such as fi in certain fonts are replaced by a single glyph such as . These ligatures have been used ever since printing with moveable type was invented, replacing the occasional awkward character combination with a better-looking alternative.

To be honest, I’m not a big fan of their use in coding fonts (and I’m not the only one[9]). I like to see exactly what I’ve typed, rather than what the font has decided to replace it with. But, there are a few places in Julia where suitable Unicode alternatives are not accepted by the language, and where I feel that the ASCII-art confections currently used can be gently enhanced by the judicious use of alternate glyphs. There are also a few places where some subtle tweaks can enhance the readability of the language without introducing ambiguity.

In JuliaMono, the following substitutions are applied when the contextual alternates feature is active:

typed

displayed

-> ->
=> =>
|> |>
<| <|
:: ::

You can see these in action in the following code fragment:[10]

julialang = true # (!= 0)
(x, y) -> (x + y)
f(p::Int) = p * p
@inbounds if f in (Base.:+, Base.:-)
    if any(x -> x <: AbstractArray{<:Number})
         nouns = Dict(
            Base.:+ => "addition",
            Base.:- => "subtraction",
        )
    end
end
df2 = df |>
    @groupby(_.a) |>
    @map({a = key(_), b = mean(_.b)}) |>
    DataFrame # <|

OpenType fonts also offer you the ability to choose different designs for certain characters. These are stored as a ‘stylistic set’.

All the options are stored in the font, and are often referred to by their internal four letter code (not the best user-oriented design, really). For example, the contextual alternates listed above are collectively stored in the calt feature.

Sometimes, an application will show the options more visually in a Typography panel[11], usually tucked away somewhere on a Font chooser dialog.

Here’s a list of the stylistic sets currently available in JuliaMono.

feature code

off

on

description

zero 0 0

slashed zero

ss01 g g

alternate g

ss02 @ @

alternate @

ss03 j j

alternate j

ss04 0 0

alternate 0

ss05 * *

lighter asterisk

ss06 a a

simple a

ss07 ` `

smaller grave

ss08 -> ->

distinct ligatures

ss09 f f

alternate f

ss10 r r

alternate r

All this fancy technology is under the control of the application and the operating system you’re using. Ideally, they will provide an easy way for you to switch the various OpenType features on and off.

Browser-based editors such as Juno and VS Code support many OpenType features in their editor windows, but not in the terminal/console windows. They provide a settings area where you can type CSS or JSON selectors to control the appearance of features, and you’ll have to know the feature codes. Some features are opt in, others are opt out; this too can vary from application to application.

Terminal/console applications also vary a lot; on MacOS the Terminal and iTerm applications try to offer controls for OpenType features, with varying degrees of success. On Linux, some terminal applications such as Kitty offer quite good support, but others such as Alacritty offer little or none, as yet. [12]

If the application allows, you should be able to switch the calt contextual ligatures off, particularly since quite a few people won’t like any of them in their code. For the following listing, I switch the calt set off using CSS (see here), and then enable some of the alternative stylistic sets: compare characters such as the 0, g, a, j, and @ with the previous listing:

julialang = true # (!= 0)
(x, y) -> (x + y)
f(p::Int) = p * p
@inbounds if f in (Base.:+, Base.:-)
    if any(x -> x <: AbstractArray{<:Number})
         nouns = Dict(
            Base.:+ => "addition",
            Base.:- => "subtraction",
        )
    end
end
df2 = df |>
    @groupby(_.a) |>
    @map({a = key(_), b = mean(_.b)}) |>
    DataFrame # <|

(I originally liked the idea of a more circular @ sign, but in practice it doesn’t work at small point sizes, as the details disappear. But I’ve kept it anyway.)

There are a few areas of the Unicode system that have been officially kept empty and are thus available to store characters that are not part of the standard. These are called the Private Use Areas, and there are three: ue000 to uf8ff, UF0000 to UFFFFD, and U100000 to U+10FFFD.

Each typeface can do its own thing in these areas. In JuliaMono, for example, if you look around ue800 you’ll find a few familiar shapes:

julia> foreach(println, 'ue800':'ue802')




The obvious drawback to using characters in a Private Use Area is that you have to have installed the font wherever you want to see them rendered correctly, unless they’ve been converted to outlines or bitmaps. If the font isn’t installed (eg on github), you have no idea what glyph – if any – will be displayed.

You can define these to be available at the Julia REPL. For example, say you want the Julia circles to be available in the terminal when you type julialogo in a Julia session with the JuliaMono font active. Run this:

using REPL
REPL.REPLCompletions.latex_symbols["julialogo"] = "ue800"

Now you can insert the logo in strings by typing julialogo:

julia> println("Welcome to ")
Welcome to 

It’s usually possible to type Unicode values directly into text. This is a useful skill to have when you’re not using the Julia REPL… On MacOS you hold the Option (⌥) key down while typing the four hex digits (make sure you’re using the Unicode Hex Input keyboard). On Windows I think you type the four hex digits followed by ALT then X. On Linux it might be ctrlshiftu followed by the hex digits.

You can find the font files at https://github.com/cormullion/juliamono.

For Arch Linux, there is also a package in the AUR.

Mac

To install and activate a font, launch Font Book from your Applications folder, and drag the font files into the middle pane labelled Font. If you’re using a different font manager, you already know what to do. 🙂

Homebrew

On the latest version of Homebrew, you can install the fonts with:

$ brew tap homebrew/cask-fonts
$ brew cask install font-juliamono

Windows

To install and activate a font on Windows, go to Computer |> Local Disk (C:) |> Windows |> Fonts. Locate the expanded .zip file folder, and drag the font files from there into the Fonts folder.

Linux – using Font Manager

Install Font Manager:

sudo apt install font-manager

Then double-click on the font files and click Install on each one.

Linux – on the command line

Locate your font folder. Might be one of:

~/.fonts
/usr/share/fonts/truetype/newfonts/
~/.local/fonts/
~/.local/share/fonts/

and copy the files there. You might want to (or have to) regenerate the font cache:

$ fc-cache -f -v

And verify installation:

$ fc-list | grep "JuliaMono"

The typeface was introduced at the 2020 Julia Programming Language conference, JuliaCon, in Lisbon, Portugal, and it was (going to be) my contribution to the festivities. It was an experiment to see whether a font could be designed with a specific programming language in mind.

  • it has all the glyphs used in the Unicode Input chapter of the Julia documentation (except for the emojis)

  • the glyphs were designed with the Julia programming language in mind

  • the font contains special features such as contextual alternates, stylistic sets, and “ligatures” to complement Julia syntax

You can visit this mirror of the Julia blog. It hasn’t been updated for a while (it was useful during the development of Franklin.jl), but all the code examples use JuliaMono.

You can browse through this local copy of an old Julia manual. The default Roboto-Mono font has been replaced with JuliaMono-Regular.

As an example of using JuliaMono with Documenter.jl-generated documents, see the documentation for Luxor.jl.

That’s not a question! But I know what you mean. Choice of work environment (editor, font, colour scheme, background music, preferred beverage, etc.) is very much a personal thing, and over the hours, days, and weeks that you work with your particular setup, you’ll grow accustomed to it, and unfamiliar work environments will look unappealing or even ugly. You’d probably need to try any alternatives for a while before you get more accustomed to them. Fortunately, you don’t have to use Comic Code, the Kakoune editor, the music of Autechre, Durian tea, or anything else that’s new and unfamiliar; just stick to your current favourites!

Find the relevant CSS file, and add a link to the WOFF2 stored on the server. For example:

@font-face {
        font-family: JuliaMono-Regular;
        src: url("https://cdn.jsdelivr.net/gh/cormullion/juliamono/webfonts/JuliaMono-Regular.woff2");
}

This accesses the current version the Regular font using the jsDelivr CDN (Content Delivery Network).

You may prefer to serve the WOFF/2 fonts from your own server. One problem you might encounter is related to Cross-origin resource sharing, which on some browsers prevents one web page from downloading fonts from another.

VS-Code

In VS-Code you’ll find the font settings somewhere in the labyrinthine (but thankfully searchable) Settings department.

VS Code settings

To control the display of contextual and stylistic alternates, click on the Edit Settings in JSON, and look for editor.fontLigatures:

VS Code settings

This uses the feature codes (listed here). These should all be switched on or off in a single line.

For example, if you want all the alternate stylistic sets, use:

"editor.fontLigatures": "'zero', 'ss01', 'ss02', 'ss03', 'ss04',
    'ss05', 'ss06',  'ss07', 'ss08', 'ss09', 'ss10'",

Or if you just don’t like the contextual alternates, prefer the slashed zero, a simpler g, and a lighter asterisk, use this:

"editor.fontLigatures": "'calt' off, 'zero', 'ss01', 'ss05'",

Atom/Juno

In the Atom/Juno stylesheet, you can specify the font with the required CSS selectors:

font-family: "JuliaMono";

which defaults to the Regular weight, or

font-family: "JuliaMono-Medium";

You can switch off the contextual alternates (such as -> and =>) with:

font-variant-ligatures: no-contextual;

Or on (if it’s not enabled by default) with:

font-variant-ligatures: contextual;

Select any stylistic sets in a single line. For example:

font-feature-settings: "zero", "ss02";

enables the slashed zero (0) and the simpler “g”.

In Atom/Juno, you’d put these in the stylesheet, perhaps like this:

atom-text-editor {
    font-variant-ligatures: no-contextual;
        font-feature-settings: "ss01", "ss02", "ss03",
            "ss04", "ss05", "ss06";
}

‘Can I use this font in a notebook? And how do I do it?’

It’s a good question. Some browsers these days are reluctant to give even you access to things on your own local disk, “for security reasons”. But a local copy of the font may be available and accessible on your particular set-up.

If not, you could try using web fonts, as above. For example, if there’s a Jupyter CSS file here:

~/.jupyter/custom/custom.css

you could add definitions like this:

@font-face {
        font-family: JuliaMono-Regular;
        src: url("https://cdn.jsdelivr.net/gh/cormullion/juliamono/webfonts/JuliaMono-Regular.woff2");
}

.rendered_html table{
    font-size: 16px !important;
}

div.input_area {
    background: #def !important;
    font-size: 16px !important;
}

.CodeMirror {
    font-size: 16px !important;
    font-family: "JuliaMono-Regular" !important;
    font-feature-settings: "zero", "ss01";
    font-variant-ligatures: contextual;
}

which downloads the font once and is then available to applications.

screenshot of jupyter editor

Another great question. Are you sure you want a monospaced font on your plot? If you do, it should be easy enough to ask for the font when you plot. But it’s never as simple as you want it to be, as is usual in the world of fonts.

I know very little about plotting in Julia, but some investigations suggest that:

  • pyplot() works well, mostly

  • some backends do their own thing with fonts. For example, I couldn’t persuade the GR backend to use JuliaMono at all.

Here’s some code that uses JuliaMono for a plot. The plot shows the frequency of occurrence of every Unicode character used in the Julia git repository, and uses the characters as plot markers. I went through every text file and totalled all the characters – there are 956044 letter “e”s, and so on. I’m using pyplot(); the freqs DataFrame holds the characters and the counts. I’ve created a few font objects using Plots.font(), which makes it easier to use different text styles in the plot() function. I haven’t yet worked out how to use the different weights of a font family.

using Plots, Plots.PlotMeasures
pyplot()
theme(:dark)

juliamonofont8 = Plots.font(family="JuliaMono", 8,
    halign=:center, colorant"white")
juliamonofont12 = Plots.font(family="JuliaMono", 12,
    halign=:center, colorant"white")
juliamonofont80 = Plots.font(family="JuliaMono", 80,
    halign=:center, colorant"grey30")

annotation = "counting character frequenciesnin Julia source files "

p = plot(1:100,
    freqs[1:100, 2],
    fontfamily         = "JuliaMono",
    margin             = 20mm,
    yaxis              = :log10,
    annotation         = [
        (50, 1000, Plots.text(annotation, juliamonofont12)),
        (80, 1_000_000, Plots.text("", juliamonofont80))
        ],
    linewidth          = 0.25,
    series_annotations = Plots.text.(freqs[1:100, 1], Ref(juliamonofont8)),
    xlabel             = "← more frequent | less frequent → ",
    ylabel             = "occurrences (log scale) ",
    labelfontsize      = 6,
    titlefontsize      = 14,
    formatter          = :plain,
    size               = (800, 500),
        title              = "Top 100 charactersnin the Julia github repo ",
    legend             = false,
    )

display(p)

frequency counts

The top 9 characters – “etanirsol” – are a good match for the typical English frequency count e.g. “etarionsh”. It’s to be expected that parentheses make a very good showing, here.

Although over 3600 unique characters occur in the Julia documentation, about 3000 of them appear just once. All of them, except the emojis which aren’t in JuliaMono, could be plotted, but the long tail isn’t very interesting visually.

For plotting emoji characters, you’ll have to dive into the internals of the plots system…

Notice that the y-axis labels are in DejaVu Sans, provided with matplotlib. That’s because the :log10 scaling code does its own ( LaTeX )-y business, ignoring the current font. However, at least I was able to insert the Julia logo successfully, since it’s part of the JuliaMono font.

In a ( LaTeX ) document, you should be able to define and use local fonts.

Robert Moss put together an excellent package to help negotiate the various font issues that you might encounter when using Unicode and ( LaTeX ):

A custom Julia language style for the LaTeX listings package, and Unicode support for the JuliaMono font in a lstlisting environment..

An earlier approach that worked for me is as follows:

In your ( LaTeX ) source file, define the font, using the local pathname:

newfontfamily JuliaMono {JuliaMono-Regular.otf}[
    Path      = /Users/me/Library/Fonts/,
    Extension = .otf
    ]
newfontface JuliaMonoMedium{JuliaMono-Regular}
setmonofont{JuliaMonoMedium}[
        Contextuals=Alternate
]

Then you can use something like minted to format the code.

screenshot of latex

(I used the lualatex engine.)

It depends if you mean the web fonts or the ‘desktop’ fonts. Web fonts come in two flavours, .WOFF and .WOFF2, where the 2 indicates a more recent and slightly more compact format. JuliaMono-Regular.woff is 674KB, JuliaMono-Regular.woff2 is 619KB – the size of a PNG image, perhaps.

The .TTF versions are getting on for 1.8MB each.

For comparison, the Themes folder of .CSS files for the Julia manual (and for every manual built with Documenter.jl since v0.21) is about 700KB. So in that light the WOFF2 fonts aren’t that bad. Of course, the two Google fonts downloaded by every Julia document (Lato and Roboto) are tiny, at 14KB and 11KB, with 221 glyphs in each.

So, if you’re building a website, or designing for mobile applications, the size of the WOFF2 file(s) will be an important factor to weigh against the advantages of having predictable character sets. Note that you can specify font subsets in the CSS using the unicode-range feature, which defines a restricted set of characters which you know are going to be used, so that users don’t download any that they won’t need.

You could consider using the ‘-Latin’ variants to obviate the initial loading time.

You’re right, of course, there are many coding fonts, all perfectly adequate for the task of programming in Julia and most other languages. Comparing two different fonts is a matter of how important small similarities and differences are. Perhaps with one font you’ll see the occasional empty box or odd replacement rather than the character you were hoping for. Or perhaps sometimes you won’t like a particular glyph.

More likely, though, the overall ‘feel’ of a new and unfamiliar font – too narrow, too wide, too dense, too light, too quirky, too dull, too consistent, too variable – is a matter of personal taste, immune to objective measurement. The design goals of JuliaMono – readable, easy to use, unquirky, simple – mean that the shapes aren’t compressed or condensed. It’s not fashionably thin. It might feel quite “airy” because of the generously-spaced shapes. The punctuation is quite solid, which might not be to your taste; it’s much more important in code than in ordinary prose, and my eyesight is probably poorer than yours!

Most people probably can’t tell the difference between Helvetica and Arial, and certainly aren’t going to be bothered about minor differences between JuliaMono and other coding fonts. But that’s fine. Just stick to your current favourites!

In the world of typographical software, one programming language is currently ubiquitous (hint: one of the leading programmers in the typography realm is Just van Rossum, one of the van Rossum brothers) and it’s not Julia.

The typeface isn’t a Julia package. It might be, soon! But although Julia wasn’t used to build the typeface, I did use Julia quite a lot while designing it; sometimes to generate glyphs, there being plenty of symmetrical designs that lend themselves to programmatic construction with a simple graphics program (e.g. Luxor.jl). And also for producing glyph lists, charts, test output, and build scripts. And the various graphics you see here and in the specimen PDF were also made with Julia. So in that sense at least the font is a bit Julian.

And how will JuliaMono contribute? It’s often in the nature of an experiment that the outcome is uncertain until it’s been carried out.

The first β release, version 0.001, was released on July 27, 2020.

The most recent β release, version 0.020, was released in October 2020. Always download the latest version if you want the typeface to perform as well as it can.

Unicode (and Julia) allows you to combine characters. In the REPL, you can type a character and then modify it by adding a mark or diacritic. For example:

evec

displays as

e⃗

and the arrow mark is displayed above the character. These combining marks are listed in the Unicode Input section of the Julia documentation. It’s sometimes possible to add more than one:

evecdot

which JuliaMono renders like this:

e⃗̇

But this doesn’t work in all text environments, such as the terminals in Atom/Juno, VS Code, or Jupyter:

screenshots terminal emulators

For Atom/Juno and VSCode, it’s due to limitations in the JavaScript terminal emulator they use (xterm.js) – there may be improvements in the future. Other terminal applications choose not to implement all OpenType features – they’re worried about the loss of performance, for example.

If it does work for you, this is fun:

juliotaddotdota

giving:

julϊ̇a

Yes.

Yes.

Font management in Linux may require you to become familiar with the fontconfig program. And it may be necessary to provide an additional configuration file (in /etc/fonts/local.conf for example), that contains instructions like the following:

<alias>
    <family>monospace</family>
    <prefer>
                    <family>JuliaMono</family>
                </prefer>
</alias>

With some older terminal software the ligatures may cause problems (not that all terminals display ligatures properly, some are just confused by fonts that have them).

The font works well on a good quality display, but will struggle to maintain quality when displayed on low-resolution displays.

On Windows, the shapes of letters are distorted in order to place the important features of letters on pixels, rather than ‘between’ pixels (which could make features disappear). On high-resolution displays, as found on Apple devices, it isn’t necesary to distort letter shapes in this way. The distortion is controlled by a process called ‘hinting’. On Windows displays, you may find that there is unevenness and variations in thickness and alignments, particularly at smaller sizes. This is due to the hinting generating distorted shapes to target pixels.

JuliaMono is an OTF/TTF-flavoured font that contains hinting instructions, so it might look reasonably good on lower-resolution screens.

Hinted fonts are larger as a consequence.

nerdfonts can add about four thousand extra glyphs to a font. It does this by creating a new font that combines an existing font’s glyphs with a bunch of new ones, using a FontForge Python script. This is quite cool, in a way.

JuliaMono concentrates on the Unicode standard glyphs, as used for Julia code, whereas Nerdfonts adds many non-standard glyphs such as product and brand logos, trade names, icons for dozens of file extensions, programming languages, commercial applications, and a fair number of not-so-relevant characters. It’s aimed at a much wider audience. Nerdfonts doesn’t overlap much with JuliaMono.

The nerdfonts project is a bit of a hack – glyphs are pushed into areas that are outside the Private Use Area, and there’s some unnecessary duplication of icons and other Unicode characters. And, if you do build a nerdfont version of JuliaMono, it will be quite large.

Perhaps the companies could contribute money to the Julia project in exchange for having their logos stored in the font…

Good to know!

One day perhaps.

[1]   “licence” Although not MIT-licensed like Julia, JuliaMono is licensed using the SIL Open Font licence, which allows the fonts to be used, studied, modified, freely redistributed, and even sold, without affecting anything they’re bundled with.
[2]   “Windows” For more information about if and how it works on Windows, read this, but I currently don’t know enough about Windows font technology and how it differs from MacOS and Unix. Early reports said that the font didn’t look good on Windows. This was because the format was CFF/PostScript OTF, which isn’t hinted on Windows. A switch to TTF/TrueType OTF, which is hinted, was considered an improvement.
[3]   “masters” In fact there are only three masters (Light, Regular, and Black), and three instances (Medium, Bold, and ExtraBold), which are interpolated between them.
[4]   “maths in code” spotted here
[5]   “languages” Apologies for errors – I don’t speak most of these languages.
[6]   “terminals and line spacing” Terminal applications usually provide the option to vary the line spacing. For perfectly smooth Unicode plots, you can adjust this until the shaded glyphs are in tune. But for coding purposes you might want the line spacing increased (or decreased) from the default, depending on the trade-off between reading speed, font size, and how many lines of code you can cram in.
[8]   “better fonts…” Operator Mono and Fira are excellent typefaces… Try them! Also try IBM Plex Mono, Iosevka, Recursive, and Victor Mono, to name a few of my favourites. Like programming languages, every typeface has its strengths and weaknesses. Perhaps keep JuliaMono for font fallback purposes… 😉
[9]   “not the only one” Matthew Butterick says “hell no” to them. He also uses the phrase “well-intentioned amateur ligaturists” which isn’t a label I want to have. But more seriously, he says: “my main concern is typography that faces other human beings. So if you’re preparing your code for others to read — whether on screen or on paper — skip the ligatures.”
[10]   “alternate glyphs” Note that the substitute glyphs occupy the same width as the source glyphs they’re replacing. While you could in theory use one of the thousands of Unicode arrows, such as →, as a replacement for the ‘stabby lambda’ (->), these are the width of a single character, and so you’d be changing the width of your string/line whenever you made the substitution.
[11]   “Typography panel” These vary widely in their abilities and functions: the MacOS Terminal app’s Typography panel is comprehensive but I’m not convinced that all the buttons are wired up yet…
[12]   “terminals again” Writers of terminal apps usually have their own ideas about how fonts and type should be managed and displayed. I haven’t yet found one that did everything that I wanted it to and nothing I didn’t expect it to. In the world of fonts, nothing is 100% correct, which can be frustrating. You can track some of the issues and discussions on github and elsewhere: here’s a VS Code issue; here are the Alacritty terminal developers working on it; here is the iTerm documentation talking about performance.

Thanks to: Thibaut Lienart for his Franklin.jl website builder; to Jérémie Knüsel who provided invaluable suggestions and advice; to Dr Zygmunt Szpak for his cool maths code; to Simeon Schaub for the issues and PRs, and to others in the Julia community for help and suggestions.

Continuous Integration for Serverless React Application in GCP with Cloud Build

Paulo Carvalho

Saturn V Engine Nozzles by Good Free Photos

In the second part of this guide, we will walk through setting up a CICD solution for client-side Javascript applications such as ReactJS that are deployed serverless in a GCP cloud storage bucket.

We want to deploy a web application consisting of one or more frontends using a client side framework such as ReactJS which connects to one (or more) backends that have been containerized with Docker. Our backend will connect to a CloudSQL instance for storage and all environment variables will be encrypted with GCP’s Key Management Service (KMS). GIT commits to a specific branch on GitHub will trigger a build and deploy of the application. A load balancer will direct traffic and serve as a proxy for HTTPS using a managed certificate.

Setup the environment proposed in part 1 of this guide or equivalent.

Below, we have a Dockerfile (placed in the root of the repository) that creates a docker image containing our application’s source code and installs all required NPM packages. The five steps below correspond to the numbered sections of the Dockerfile.

  1. The creation of the image starts with the FROM keyword that specifies an official Node image as a base.
  2. Create and navigate into the /usr/src/app directory.
  3. Setup the path where Node should look for packages.
  4. COPY from our code source (Github repo or local) the package.json and yarn.lock specifying what NPM packages need to be installed and install them.
  5. COPY the remainder of our source code.

Note: Although we could have copied the entirety of our source code at once, we copy only the files that define the modules to install first so as to enable caching. That way, changing the source code does not require reinstalling all packages.

We will build our application using GCP’s CloudBuild. This service makes use of a YAML file that specifies the build behavior. The file can be named anything (since we will be using custom triggers as opposed to the integration via the Github App) but we will call it cloudbuild.yaml for consistency and place it inside a /deploy directory.

Below, you can observe the newly created deploy/cloudbuild.yaml file containing some comments at the top (lines starting with a #) and the first two steps. A build consists of 1 or more steps which define operations that should be executed by Google’s build VM.

The gcr.io/cloud-builders/docker specifies the container image of a cloud builder which serves as the base upon which the given step’s commands will be executed. More information on Cloud Builders can be found here.

The id is an arbitrarily named unique identifier for this step. We will use it for flow control in the following steps through the waitFor command.

The args specify the commands that will be run. A command string is constructed by concatenating each of the “-” lines in the provided order. In this case, we are running “docker build […] .” applying two tags to the image and setting the previous cache to speed up build.

The second build step pushes the newly built image to a Container Registry for later access.

We run the tests on our previously built Docker image. Note: We will go over how to run integration tests between multiple services in a future part of the guide.

The two build steps below decrypt the secrets (optional) and then builds the ReactJS application.

To execute the first step you will have to have a keyring and key created in the project as detailed in GCP’s instructions. The kms decrypt command takes in a ciphertext-file, which is a client side encrypted file containing all secrets, and generates a secrets.dec file in the workspace that can be used by later steps.

The build step runs the previously built Docker image containing our application’s code and executes a yarn build. It receives all decrypted values from the previous step (optional).

Important: Since we are not deploying the Docker image, we mount a volume called “final-build-files” to which we copy our build files to make them available to later build steps.

Below is a sample command for client side encrypting your secrets.

A sample secrets.dec file is shown below. Note that the secrets file needs to be in a format compatible with Docker’s env-file command.

In these final 3 build steps we will copy over the static files, prepare a backup of our previous files and invalidate the CDN cache to start serving our new assets.

The first step copies over the files in the volume used by the previous step (note that the volume name in the two steps need to match for data to be preserved and available) to our Cloud Storage Bucket.

The aforementioned step alone is sufficient to deploy our application. However, there are some concerns that are partly addressed by the two following points (modifications may be required to fit into the specifics of your application or organizational requirements):

  1. Since we are creating a GitOps inspired CICD, rolling back an upgrade should ideally be made by creating a revert pull request. However, depending on your uptime requirements, you may want to be capable of rolling back even if GitHub is not available. The second step addresses this requirement by keeping a backup of the index.html file (the only significant file that is not hash named and, therefore, is overwritten when deploying). So a revert would be possible by going into the bucket and replacing the current index.html with one of the previous versions.
  2. If you have your CDN caching activated (which is appropriate in most cases) the index path of your application will have been cached and even if the index.html file is replaced some clients may only receive the update at cache expiration time. For this reason, we invalidate the / path of our app. However, depending on the most common entrypoint of your application (Example: Clients may access your app via an ad that brings them via the path /my-effective-ad) you may need to invalidate more paths. I recommend reading GCP’s invalidation overview for some limitations on using them.

By now, we have a complete cloudbuild.yaml file that species our build steps. However, we have not specified when our file should run. One way to accomplish this is via triggers. Triggers associate an action in Github (such as a push to a repository) with the execution of a Cloud Build script.

  1. Navigate to Cloud Build’s triggers page and select connect repository.

2. Select GitHub (mirrored) and click continue.

3. Select the repository where your code is hosted and click connect repository.

4. Select Add trigger on the following page.

5. Give the trigger an appropriate name. Determine pushes to which branch(es) should start a build (via the regex expression where ^ means start of and $ end of) and provide the cloudbuild.yaml file directory. The _URL substitution variable is used in our cloudbuild file. Click Create trigger to complete the process.

At this point, we have all the infrastructure setup (part 1) and are (now) able to deploy code automatically to our Cloud Storage bucket(s). In the next part of our series, we will go over deploying to our backend services running on our managed instance group.

Part 3 of the guide can be found here.

CICD for Zendesk App

Paulo Carvalho

A simple continuous deployment (CICD) pipeline for your private Zendesk applications.

Photo by panumas nikhomkhai from Pexels

Zendesk allows creating of custom applications using Zendesk’s App Framework (ZAF) that can be used to enhance the base capabilities of the Zendesk environment. See their app scaffold here. Two different ways to deploy their application are provided: Upload a zip of the application manually or run a sequence of update commands on the developer’s machine.

However, what if we want to have our app automatically deployed whenever we push (or merge) to a specific branch? A third option is presented here: A Github Actions based automatic deployment!

Have a ZAF compatible application developed and uploaded into Zendesk. More information can be found here and here.

We create a file .github/workflows/deploy.yml which will define our deployment workflow.

Below, is the first portion of the file. There are a few points worth noting here:

  1. The name attribute defines the name that appears on GitHub whenever our action runs.

If the repository containing this code were to be pushed to Github, a workflow would be started that would checkout our repository and then terminate.

name: CIon:
push:
branches:
- my-branch
jobs:
build_and_deploy_my_app:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
...

Here, we install some packages that we will need in order to build and deploy our application. This includes: NodeJS (Yarn, NPM), Ruby and the Zendesk App Tools (ZAT).

...
- name: Use Node.js 12.x
uses: actions/setup-node@v1
with:
node-version: 12.x
- name: Set up Ruby 2.6
uses: actions/setup-ruby@v1
with:
ruby-version: 2.6.x
- name: Install ZAT Toolchain
run: |
gem install zendesk_apps_tools
...

It is common for applications to require configuration. This is usually done through environment variables. In the case of a Zendesk App, this may include having a configurable .zat file. To accomplish this we create a src/zat.template file as shown below:

{
"zat_latest": "3.2.3",
"zat_update_check": "2019-09-01",
"subdomain": ZENDESK_SUBDOMAIN,
"username": ZENDESK_USERNAME,
"password": ZENDESK_TOKEN,
"app_id": ZENDESK_APPID
}

In order for our template file to be updated with the correct value for each of its placeholders (ZENDESK_APPID, etc) and generate the desired .zat file (more on the purpose of the .zat file can be found here), we need to add a step in our Webpack bundler that replaces each placeholder with the correct values that should be available as environment variables.

To accomplish the replacement, we update the CopyWebpackPlugin as shown below:

new CopyWebpackPlugin([
{ from: 'src/manifest.json', to: '../', flatten: true },
{ from: 'src/images/*', to: '.', flatten: true },
{
from: 'src/zat.template',
to: '../.zat',
toType: 'file',
transform: content => {
return content.toString()
.replace(
/ZENDESK_SUBDOMAIN/,
JSON.stringify(process.env.ZENDESK_SUBDOMAIN),
).replace(
/ZENDESK_USERNAME/,
JSON.stringify(process.env.ZENDESK_USERNAME),
).replace(
/ZENDESK_TOKEN/,
JSON.stringify(process.env.ZENDESK_TOKEN)
).replace(
/ZENDESK_APPID/,
process.env.ZENDESK_APPID);
},
},
]),

By now, we have the necessary packages installed and an application that can use environment variables for configuration.

Below, we perform the build step and then deploy it to Zendesk. The build step is accomplished by simply running yarn install followed by yarn build . Output files from this step will be placed inside the /dist folder.

Finally, we deploy our application by running the zat update command from within the /dist folder.

...      - name: Build app
working-directory: ./
env:
ZENDESK_SUBDOMAIN: ${{ secrets.ZENDESK_USERNAME }}
ZENDESK_USERNAME: ${{ secrets.ZENDESK_USERNAME }}
ZENDESK_TOKEN: ${{ secrets.ZENDESK_TOKEN }}
ZENDESK_APPID: ${{ secrets.ZENDESK_APPID }}
run: |
yarn install
yarn build
- name: Deploy app
working-directory: ./dist
run: |
zat update

We have gone over how to setup a simple automatic deployment pipeline for your Zendesk applications. Several improvements can still be made including:

  1. The build is slow due to the installation of required packages. The zendesk_app_tools gem is particularly slow to install (approximately 7 minutes). A better way may be to create a custom action or builder image that has these packages preinstalled.