Sex ratios The sex ratio of male to female dragonflies varies both temporally and spatially. Adult dragonflies have a high male-biased ratio at breeding habitats. The male-bias ratio has contributed partially to the females using different habitats to avoid male harassment. As seen in Hine's emerald dragonfly (Somatochlora hineana), male populations use wetland habitats, while females use dry meadows and marginal breeding habitats, only migrating to the wetlands to lay their eggs or to find mating partners. Unwanted mating is energetically costly for females because it affects the amount of time that they are able to spend foraging.
# cat /etc/php/7.3/fpm/pool.d/example.com.conf [example.com] user = example.com group = example.com listen = /run/php/php7.3-example.com.sock listen.owner = www-data listen.group = www-data pm = dynamic pm.max_children = 5 pm.start_servers = 2 pm.min_spare_servers = 1 pm.max_spare_servers = 3Here is the upstream documentation for fpm configuration [5]. Then for the Apache configuration for the site in question you could have something like the following:
ProxyPassMatch "^/(.*\.php(/.*)?)$" "unix:/run/php/php7.3-example.com.sock fcgi://localhost/usr/share/wordpress/"The fcgi://localhost part is just part of the way of specifying a Unix domain socket. From the Apache Wiki it appears that the method for configuring the TCP connections is more obvious [6]. I chose Unix domain sockets because it allows putting the domain name in the socket address. Matching domains for the web server to port numbers is something that s likely to be error prone while matching based on domain names is easier to check and also easier to put in Apache configuration macros. There was some additional hassle with getting Apache to read the files created by PHP processes (the options include running PHP scripts with the www-data group, having SETGID directories for storing files, and having world-readable files). But this got things basically working. Nginx My Google searches for running multiple PHP sites under different UIDs didn t turn up any good hits. It was only after I found the DigitalOcean page on doing this with Nginx [7] that I knew what to search for to find the way of doing it in Apache.
Paul-F lix Armand-Delille (3 July 1874 in Fourchambault, Ni vre 4 September 1963) was a physician, bacteriologist, professor, and member of the French Academy of Medicine who accidentally brought about the collapse of rabbit populations throughout much of Europe and beyond in the 1950s by infecting them with myxomatosis.
Charles Franklin Kettering (August 29, 1876 November 25, 1958) sometimes known as Charles "Boss" Kettering[1] was an American inventor, engineer, businessman, and the holder of 186 patents.[2] He was a founder of Delco, and was head of research at General Motors from 1920 to 1947. Among his most widely used automotive developments were the electrical starting motor[3] and leaded gasoline.[4][5] In association with the DuPont Chemical Company, he was also responsible for the invention of Freon refrigerant for refrigeration and air conditioning systems. At DuPont he also was responsible for the development of Duco lacquers and enamels, the first practical colored paints for mass-produced automobiles. While working with the Dayton-Wright Company he developed the "Bug" aerial torpedo, considered the world's first aerial missile.[6] He led the advancement of practical, lightweight two-stroke diesel engines, revolutionizing the locomotive and heavy equipment industries. In 1927, he founded the Kettering Foundation, a non-partisan research foundation. He was featured on the cover of Time magazine on January 9, 1933.
John Charles Cutler (June 29, 1915 February 8, 2003) was a senior surgeon, and the acting chief of the venereal disease program in the United States Public Health Service. After his death, his involvement in several controversial and unethical medical studies of syphilis was revealed, including the Guatemala and the Tuskegee syphilis experiments.
Ivy Ledbetter Lee (July 16, 1877 November 9, 1934) was an American publicity expert and a founder of modern public relations. Lee is best known for his public relations work with the Rockefeller family. His first major client was the Pennsylvania Railroad, followed by numerous major railroads such as the New York Central, the Baltimore and Ohio, and the Harriman lines such as the Union Pacific. He established the Association of Railroad Executives, which included providing public relations services to the industry. Lee advised major industrial corporations, including steel, automobile, tobacco, meat packing, and rubber, as well as public utilities, banks, and even foreign governments. Lee pioneered the use of internal magazines to maintain employee morale, as well as management newsletters, stockholder reports, and news releases to the media. He did a great deal of pro bono work, which he knew was important to his own public image, and during World War I, he became the publicity director for the American Red Cross.[1]
Publisher: | The New Press |
Copyright: | 2019 |
ISBN: | 1-62097-437-1 |
Format: | Kindle |
Pages: | 247 |
What many black women were angry about was how I located myself in what I'd written. I said, blithely as a matter of observable fact, that I am unattractive. Because I am unattractive, the argument went, I have a particular kind of experience of beauty, race, racism, and interacting with what we might call the white gaze. I thought nothing of it at the time I was writing it, which is unusual. I can usually pinpoint what I have said, written, or done that will piss people off and which people will be pissed off. I missed this one entirely.What follows is one of the best essays on the social construction of beauty I've ever read. It barely pauses at the typical discussion of unrealistic beauty standards as a feminist issue, instead diving directly into beauty as whiteness, distinguishing between beauty standards that change with generations and the more lasting rules that instead police the bounds between white and not white. McMillan Cottom then goes on to explain how beauty is a form of capital, a poor and problematic one but nonetheless one of the few forms of capital women have access to, and therefore why black women have fought to be included in beauty despite all of the problems with judging people by beauty standards. And the essay deepens from there into a trenchant critique of both capitalism and white feminism that is both precise and illuminating.
When I say that I am unattractive or ugly, I am not internalizing the dominant culture's assessment of me. I am naming what has been done to me. And signaling who did it. I am glad that doing so unsettles folks, including the many white women who wrote to me with impassioned cases for how beautiful I am. They offered me neoliberal self-help nonsense that borders on the religious. They need me to believe beauty is both achievable and individual, because the alternative makes them vulnerable.I could go on. Every essay in this book deserves similar attention. I want to quote from all of them. These essays are about racism, feminism, capitalism, and economics, all at the same time. They're about power, and how it functions in society, and what it does to people. There is an essay about Obama that contains the most concise explanation for his appeal to white voters that I've read. There is a fascinating essay about the difference between ethnic black and black-black in U.S. culture. There is so much more.
We do not share much in the U.S. culture of individualism except our delusions about meritocracy. God help my people, but I can talk to hundreds of black folks who have been systematically separated from their money, citizenship, and personhood and hear at least eighty stories about how no one is to blame but themselves. That is not about black people being black but about people being American. That is what we do. If my work is about anything it is about making plain precisely how prestige, money, and power structure our so-called democratic institutions so that most of us will always fail.I, like many other people in my profession, was always more comfortable with the technical and scientific classes in college. I liked math and equations and rules, dreaded essay courses, and struggled to engage with the mandatory humanities courses. Something that I'm still learning, two decades later, is the extent to which this was because the humanities are harder work than the sciences and I wasn't yet up to the challenge of learning them properly. The problems are messier and more fluid. The context required is broader. It's harder to be clear and precise. And disciplines like sociology deal with our everyday lived experience, which means that we all think we're entitled to an opinion. Books like this, which can offer me a hand up and a grounding in the intellectual rigor while simultaneously being engaging and easy to read, are a treasure. They help me fill in the gaps in my education and help me recognize and appreciate the depth of thought in disciplines that don't come as naturally to me. This book was homework, but the good kind, the kind that exposes gaps in my understanding, introduces topics I hadn't considered, and makes the time fly until I come up for air, awed and thinking hard. Highly recommended. Rating: 9 out of 10
:
'
,
.
/
, etc.-
=
[
]
\
, etc.)(1) Like when a West-Berliner in a round of 15 East Germans arrogantly talks about the time when the wall came down and tells the story that he could not go shopping between Thursdays and Sundays because the East Germans bought too many products in the supermarkets while this event marked an unimaginable rift in the biographies of 17 million East Germans, 15 of whom are sitting right in front of him. Thirty years after 1989, many of us are finally starting to question this publicly ( links in German language).
(2) Women experience it similary regularly, see Men Explain Things to me, a book by Rebecca Solnit.
(3) By the way, rather than having "recruited the wrong person" conflict may intrinsically arise as part of certain work relationships, simply due to the inter-dependencies of roles or workers, like in a delivery chain.
Sealioning (also spelled sea-lioning and sea lioning) is a type of trolling or harassment which consists of pursuing people with persistent requests for evidence or repeated questions, while maintaining a pretense of civility and sincerity.[1][2][3][4] It may take the form of "incessant, bad-faith invitations to engage in debate".[5]
Tone policing (also tone trolling, tone argument, and tone fallacy) is an ad hominem (personal attack) and antidebate tactic based on criticizing a person for expressing emotion. Tone policing detracts from the validity of a statement by attacking the tone in which it was presented rather than the message itself.
"A brawler who tattoos a message onto his knuckles does not throw every punch with the weight of First Amendment protection behind him," the brief stated. "Conduct like this does not constitute speech, nor should it. A deliberate attempt to cause physical injury to someone does not come close to the expression which the First Amendment is designed to protect."
It s no secret that times are changing. It used to be that men were men, jokes were jokes, and all facts came from one white guy in a suit who you trusted because he looked like your dad. Now I know I could get in a lot of trouble for just saying this, but I don t care because someone has to tell the truth: These days, you can t say anything racist at all without being called a racist.
Russia's neighbor has developed a plan for countering misinformation. Can it be exported to the rest of the world?
So, I wrote my BIFF Response but Marvin wrote me another angry email. Actually, he wrote 6 more this week, so what s up with that? Why didn t he stop after my first email?
The BIFF Response Method will teach you how to respond to angry emails, texts, or social media posts while maintaining your dignity and personal power.
Series: | Kangaroo #1 |
Publisher: | Thomas Dunne |
Copyright: | June 2016 |
ISBN: | 1-250-08179-3 |
Format: | Kindle |
Pages: | 312 |
True
and a hash of the definition of what
True
is can both be treated the same by Annah's compiler.True
and False
. Continue this until
I've built up enough Annah code to write some almost useful programs.
Annah can't do any IO on its own (though it can model IO similarly to how
Haskell does), so for programs to be actually useful, there needs to be
Scuttlebutt client support. The way typing works in Annah, a program's type
can be expressed as a Scuttlebutt link. So a Scuttlebutt client that wants
to run Annah programs of a particular type can pick out programs that link
to that type, and will know what type of data the program consumes and
produces.
Here are a few ideas of what could be built, with fairly simple client-side
support for different types of Annah programs...
Dashboard
, and display its output like a Scuttlebutt
message, in a dashboard window. The dashboard message gets updated
whenever other Scuttlebutt messages come in. The Annah program picks out
the messages it's interested in, and generates the dashboard message.
So, send a message updating your boat's position, and everyone sees it
update on the map. Send a message with updated weather forecasts as
they're received, and everyone can see the storm developing.
Send another message updating a waypoint to avoid the storm,
and steady as you go...
The coders, meanwhile, probably tweak their dashboard's code every day.
As they add git-ssb repos, they make the dashboard display an
overview of their bugs. They get CI systems hooked in and feeding
messages to Scuttlebutt, and make the dashboard go green or red. They
make the dashboard A-B test itself to pick the right shade of red.
And so on...
The dashboard program is stored in Scuttlebutt so everyone is on the same
page, and the most recent version of it posted by a team member gets
used. (Just have the old version of the program notice when there's a
newer version, and run that one..)
(Also could be used in disaster response scenarios, where the data
and visualization tools get built up on the fly in response to local needs,
and are shared peer-to-peer in areas without internet.)Filtered Message
. It can leave a message unchanged, or filter it out,
or perhaps minimize its display. I publish the Annah program on my feed,
and tell my Scuttlebutt client to filter all messages through it before
displaying them to me.
I published the program in my Scuttlebutt feed, and so my friends
can use it too. They can build other filtering functions for other
stuff (such an an excess of orange in photos), and integrate my
frog filter into their filter program by simply composing the two.
If I like their filter, I can switch my client to using it. Or not.
Filtering is thus subjective, like Scuttlebutt, and the subjectivity is
expressed by picking the filter you want to use, or developing a
better one.Edit
which gets posted to the user's feed. Rendering the
page is just a matter of finding the Edit
messages for it from
people who are allowed to edit it, and combining them.
Anyone can fork a wiki page by posting an Edit
to their feed. And can
then post a smart link to their fork of the page.
And anyone can merge other forks into their wiki page (this posts a
control message that makes the Annah program implementing the wiki accept
those forks' Edit
messages). Or grant other users permission to edit
the wiki page (another control message). Or grant other users
permissions to grant other users permissions.
There are lots of different ways you might want your wiki to work.
No one wiki implementation, but lots of Annah programs. Others
can interact with your wiki using the program you picked, or fork it and
even switch the program used. Subjectivity again.Game
,
and generates a tab with a list of available games.
The players of a particular game all experience the same game interface,
because the code for it is part of their shared Scuttlebutt message pool,
and the code to use gets agreed on at the start of a game.
To play a game, the Scuttlebutt client runs the Annah program, which
generates a description of the current contents of the game board.
So, for chess, use Annah to define a ChessMove
data type,
and the Annah program takes the feeds of the two players, looks
for messages containing a ChessMove
, and builds up a description
of the chess board.
As well as the pieces on the game board, the game board description
includes Annah functions that get called when the user moves a
game piece. That generates a new ChessMove
which gets recorded
in the user's Scuttlebutt feed.
This could support a wide variety of board games. If you don't mind the
possibility that your opponent might cheat by peeking at the random seed,
even games involving things like random card shuffles and dice rolls
could be built. Also there can be games like Core Wars where the gamers
themselves write Annah programs to run inside the game.
Variants of games can be developed by modifying and reusing game
programs. For example, timed chess is just the chess program
with an added check on move time, and time clock display.Series: | Species Imperative #3 |
Publisher: | DAW |
Copyright: | 2006 |
ISBN: | 0-7564-0345-6 |
Format: | Hardcover |
Pages: | 543 |
In Canada "consent means the voluntary agreement of the complainant to engage in sexual activity" without abuse or exploitation of "trust, power or authority", coercion or threats.[7] Consent can also be revoked at any moment.[8] There are 3 pillars often included in the description of sexual consent, or "the way we let others know what we're up for, be it a good-night kiss or the moments leading up to sex." They are:Saying "I've decided I won't do laundry anymore" when the other partner is tired, or busy doing things. Is different than saying "I've decided I won't do laundry anymore" when the other partner has a chance to say "why? tell me more" and take part in negotiation. Resources: Relationships Debian is the Universal Operating System. Debian is made and maintained by people. The long term health of debian is a consequence of the long term health of the relationship between Debian contributors. Debian doesn't need to be technically perfect, it needs to be socially healthy. Technical problems can be fixed by a healty community.
- Knowing exactly what and how much I'm agreeing to
- Expressing my intent to participate
- Deciding freely and voluntarily to participate[20]
"Spoons" are a visual representation used as a unit of measure used to quantify how much energy a person has throughout a given day. Each activity requires a given number of spoons, which will only be replaced as the person "recharges" through rest. A person who runs out of spoons has no choice but to rest until their spoons are replenished.
My software ate(inspired by a 1934 poem by William Carlos Williams) Don't be afraid to fail Don't be afraid to fail or drop the ball. I think that anything that has a label attached of "if you don't do it, nobody will", shouldn't fall on anybody's shoulders and should be shared no matter what. Shared or dropped. Share the responsibility for a healthy relationship Don't expect that the more experienced mates will take care of everything. In a project with active people counted by the thousand, it's unlikely that harassment isn't happening. Is anyone writing anti-harassment? Do we have stats? Is having an email address and a CoC giving us a false sense of security?
the files
that where in
your home directory and which
you were probably
needing
for work Forgive me
it was so quick to write
without tests
and it worked so well for me
When you get involved in a new community, such as Debian, find out early where, if that happens, you can find support, understanding, and help to make it stop. If you cannot find any, or if the only thing you can find is people who say "it never happens here", consider whether you really want to be in that community.(from http://www.enricozini.org/blog/2016/debian/you-ll-thank-me-later/)
There are some nice people in the world. I mean nice people, the sort I couldn t describe myself as. People who are friends with everyone, who are somehow never involved in any argument, who seem content to spend their time drawing pictures of bumblebees on flowers that make everyone happy. Those people are great to have around. You want to hold onto them as much as you can. But people only have so much tolerance for jerkiness, and really nice people often have less tolerance than the rest of us. The trouble with not ejecting a jerk whether their shenanigans are deliberate or incidental is that you allow the average jerkiness of the community to rise slightly. The higher it goes, the more likely it is that those really nice people will come around less often, or stop coming around at all. That, in turn, makes the average jerkiness rise even more, which teaches the original jerk that their behavior is acceptable and makes your community more appealing to other jerks. Meanwhile, more people at the nice end of the scale are drifting away.(from https://eev.ee/blog/2016/07/22/on-a-technicality/) Give people freedom If someone tries something in Debian, try to acknowledge and accept their work. You can give feedback on what they are doing, and try not to stand in their way, unless what they are doing is actually hurting you. In that case, try to collaborate, so that you all can get what you need. It's ok if you don't like everything that they are doing. I personally don't care if people tell me I'm good when I do something, I perceive it a bit like "good boy" or "good dog". I rather prefer if people show an interest, say "that looks useful" or "how does it work?" or "what do you need to deploy this?" Acknowledge that I've done something. I don't care if it's especially liked, give me the freedom to keep doing it. Don't give me rewards, give me space and dignity. Rather than feeding my ego, feed by freedom, and feed my possibility to create.
plotOBOS()
which charts a moving average (from one of several available variants) along with shaded standard deviation bands. That post has a bit more background on the why/how and motivation, but as a teaser here is the resulting chart of the SP500 index (with ticker ^GSCP):
polygon()
from base R) no longer cooperated with the beefed-up functionality of plot.xts()
. Luckily, Ross Bennett incorporated that same functionality into a new function addPolygon
--- which even credits this same post of mine.
With that, the updated code becomes
## plotOBOS -- displaying overbough/oversold as eg in Bespoke's plots
##
## Copyright (C) 2010 - 2017 Dirk Eddelbuettel
##
## This is free software: you can redistribute it and/or modify it
## under the terms of the GNU General Public License as published by
## the Free Software Foundation, either version 2 of the License, or
## (at your option) any later version.
suppressMessages(library(quantmod)) # for getSymbols(), brings in xts too
suppressMessages(library(TTR)) # for various moving averages
plotOBOS <- function(symbol, n=50, type=c("sma", "ema", "zlema"),
years=1, blue=TRUE, current=TRUE, title=symbol,
ticks=TRUE, axes=TRUE)
today <- Sys.Date()
if (class(symbol) == "character")
X <- getSymbols(symbol, from=format(today-365*years-2*n), auto.assign=FALSE)
x <- X[,6] # use Adjusted
else if (inherits(symbol, "zoo"))
x <- X <- as.xts(symbol)
current <- FALSE # don't expand the supplied data
n <- min(nrow(x)/3, 50) # as we may not have 50 days
sub <- ""
if (current)
xx <- getQuote(symbol)
xt <- xts(xx$Last, order.by=as.Date(xx$ Trade Time ))
colnames(xt) <- paste(symbol, "Adjusted", sep=".")
x <- rbind(x, xt)
sub <- paste("Last price: ", xx$Last, " at ",
format(as.POSIXct(xx$ Trade Time ), "%H:%M"), sep="")
type <- match.arg(type)
xd <- switch(type, # compute xd as the central location via selected MA smoother
sma = SMA(x,n),
ema = EMA(x,n),
zlema = ZLEMA(x,n))
xv <- runSD(x, n) # compute xv as the rolling volatility
strt <- paste(format(today-365*years), "::", sep="")
x <- x[strt] # subset plotting range using xts' nice functionality
xd <- xd[strt]
xv <- xv[strt]
xyd <- xy.coords(.index(xd),xd[,1]) # xy coordinates for direct plot commands
xyv <- xy.coords(.index(xv),xv[,1])
n <- length(xyd$x)
xx <- xyd$x[c(1,1:n,n:1)] # for polygon(): from first point to last and back
if (blue)
blues5 <- c("#EFF3FF", "#BDD7E7", "#6BAED6", "#3182BD", "#08519C") # cf brewer.pal(5, "Blues")
fairlylight <<- rgb(189/255, 215/255, 231/255, alpha=0.625) # aka blues5[2]
verylight <<- rgb(239/255, 243/255, 255/255, alpha=0.625) # aka blues5[1]
dark <<- rgb(8/255, 81/255, 156/255, alpha=0.625) # aka blues5[5]
## buglet in xts 0.10-0 requires the <<- here
else
fairlylight <<- rgb(204/255, 204/255, 204/255, alpha=0.5) # two suitable grays, alpha-blending at 50%
verylight <<- rgb(242/255, 242/255, 242/255, alpha=0.5)
dark <<- 'black'
plot(x, ylim=range(range(x, xd+2*xv, xd-2*xv, na.rm=TRUE)), main=title, sub=sub,
major.ticks=ticks, minor.ticks=ticks, axes=axes) # basic xts plot setup
addPolygon(xts(cbind(xyd$y+xyv$y, xyd$y+2*xyv$y), order.by=index(x)), on=1, col=fairlylight) # upper
addPolygon(xts(cbind(xyd$y-xyv$y, xyd$y+1*xyv$y), order.by=index(x)), on=1, col=verylight) # center
addPolygon(xts(cbind(xyd$y-xyv$y, xyd$y-2*xyv$y), order.by=index(x)), on=1, col=fairlylight) # lower
lines(xd, lwd=2, col=fairlylight) # central smooted location
lines(x, lwd=3, col=dark) # actual price, thicker
addPolygon
. To illustrate, we call plotOBOS("SPY", years=2)
with an updated plot of the ETF representing the SP500 over the last two years:
This post by Dirk Eddelbuettel originated on his Thinking inside the box blog. Please report excessive re-aggregation in third-party for-profit settings.
Creating a viable free open source alternative to Magma, Maple, Mathematica and Matlab.All the Ma -software packages are commercial, and expensive. On the other hand they often have very good algorithms implemented. The Sage developers invested lots of time, energy, and brain power to develop excellent algorithm in an open source project for the mathematical researcher, but this investment wasn t honored in academic life. To quote from the presentation:
Issues with software dev in academiaI can fully agree to this. Both from my own experience as well as from those around me. The presentation slides are full of other examples, from the developers of NumPy, Jupyter, as well as statements by Stephen Wolfram from Mathematica about this issue. A textbook how to not setup academia. My assumption was that this hits only on non-tenured staff, the academic precariat. It is shocking to see that even William Stein with a tenure position is leaving academics. It seems the times are not readyThe origins of SageMath, p.31
- Hard money for software development is virtually nonexistent: I can t think of anyone I know who got tenured based on his or her software.
- Researchers on soft money are systematically discriminated against in favor of tenure-track and tenured faculty.
- Researchers are increasingly evaluated solely on bibliometric counts rather than an informed assessment of their overall portfolio of papers, code, software, industry engagement, or student supervision.
Every great open source math library is built on the ashes of someone s academic career.
The origins of SageMath, p.32
~/.mutt/aliases
, a flat text file consisting of mutt
alias
commands~/.mutt/aliases
, Debian s LDAP database, and Canonical s LDAP database,
so that I can search by name with Ctrl-t in mutt
when composing a new messagemutt
such that I can continue using the same query interfacemutt
, and whatever query glue was necessary to get mutt
to understand vCards.
There are lots of different alternatives here, and if anything the problem
was an embarrassment of choice. In the end I just decided to go for things
that looked roughly the right shape for me and tried not to spend too much
time in analysis paralysis.
CardDAV server
I went with Xandikos for the
server, largely because I know Jelmer and have generally had pretty good
experiences with their software, but also because using Git for history of
the backend storage seems like something my future self will thank me for.
It isn t packaged in stretch, but it s in Debian unstable, so I installed it
from there.
Rather than the standalone mode suggested on the web page, I decided to set
it up in what felt like a more robust way using WSGI. I installed uwsgi
,
uwsgi-plugin-python3
, and libapache2-mod-proxy-uwsgi
, and created the
following file in /etc/uwsgi/apps-available/xandikos.ini
which I then
symlinked into /etc/uwsgi/apps-enabled/xandikos.ini
:
[uwsgi]
socket = 127.0.0.1:8801
uid = xandikos
gid = xandikos
umask = 022
master = true
cheaper = 2
processes = 4
plugin = python3
module = xandikos.wsgi:app
env = XANDIKOSPATH=/srv/xandikos/collections
xandikos
user and group first (adduser --system --group --no-create-home
--disabled-login xandikos
). I created /srv/xandikos
owned by
xandikos:xandikos
and mode 0700, and I recommend setting a
umask as shown above since uwsgi s default
umask is 000 (!). You should also run sudo -u xandikos xandikos -d
/srv/xandikos/collections --autocreate
and then Ctrl-c it after a short
time (I think it would be nicer if there were a way to ask the WSGI wrapper
to do this).
For Apache setup, I kept it reasonably simple: I ran a2enmod proxy_uwsgi
,
used htpasswd
to create /etc/apache2/xandikos.passwd
with a username and
password for myself, added a virtual host in
/etc/apache2/sites-available/xandikos.conf
, and enabled it with a2ensite
xandikos
:
<VirtualHost *:443>
ServerName xandikos.example.org
ServerAdmin me@example.org
ErrorLog /var/log/apache2/xandikos-error.log
TransferLog /var/log/apache2/xandikos-access.log
<Location />
ProxyPass "uwsgi://127.0.0.1:8801/"
AuthType Basic
AuthName "Xandikos"
AuthBasicProvider file
AuthUserFile "/etc/apache2/xandikos.passwd"
Require valid-user
</Location>
</VirtualHost>
service apache2 reload
, set the new virtual host up with Let s
Encrypt, reloaded again, and off we go.
Android integration
I installed DAVdroid from the Play Store: it
cost a few pounds, but I was OK with that since it s GPLv3 and I m happy to
help fund free software. I created two accounts, one for my existing Google
Contacts database (and in fact calendaring as well, although I don t intend
to switch over to self-hosting that just yet), and one for the new Xandikos
instance. The Google
setup was a bit fiddly
because I have two-step verification turned on so I had to create an
app-specific password. The Xandikos setup was straightforward: base URL,
username, password, and done.
Since I didn t completely trust the new setup yet, I followed what seemed
like the most robust option from the DAVdroid contacts syncing
documentation,
and used the stock contacts app to export my Google Contacts account to a
.vcf
file and then import that into the appropriate DAVdroid account
(which showed up automatically). This seemed straightforward and everything
got pushed to Xandikos. There are some weird delays in syncing contacts
that I don t entirely understand, but it all seems to get there in the end.
mutt integration
First off I needed to sync the contacts. (In fact I happen to run mutt
on
the same system where I run Xandikos at the moment, but I don t want to rely
on that, and going through the CardDAV server means that I don t have to
poke holes for myself using filesystem permissions.) I used
vdirsyncer for this. In
~/.vdirsyncer/config
:
[general]
status_path = "~/.vdirsyncer/status/"
[pair contacts]
a = "contacts_local"
b = "contacts_remote"
collections = ["from a", "from b"]
[storage contacts_local]
type = "filesystem"
path = "~/.contacts/"
fileext = ".vcf"
[storage contacts_remote]
type = "carddav"
url = "<Xandikos base URL>"
username = "<my username>"
password = "<my password>"
vdirsyncer discover
and vdirsyncer sync
then synced everything
into ~/.contacts/
. I added an hourly crontab
entry to run vdirsyncer
-v WARNING sync
.
Next, I needed a command-line address book tool based on this.
khard looked about right and is in
stretch, so I installed that. In ~/.config/khard/khard.conf
(this is
mostly just the example configuration, but I preferred to sort by first name
since not all my contacts have neat first/last names):
[addressbooks]
[[contacts]]
path = ~/.contacts/<UUID of my contacts collection>/
[general]
debug = no
default_action = list
editor = vim
merge_editor = vimdiff
[contact table]
# display names by first or last name: first_name / last_name
display = first_name
# group by address book: yes / no
group_by_addressbook = no
# reverse table ordering: yes / no
reverse = no
# append nicknames to name column: yes / no
show_nicknames = no
# show uid table column: yes / no
show_uids = yes
# sort by first or last name: first_name / last_name
sort = first_name
[vcard]
# extend contacts with your own private objects
# these objects are stored with a leading "X-" before the object name in the vcard files
# every object label may only contain letters, digits and the - character
# example:
# private_objects = Jabber, Skype, Twitter
private_objects = Jabber, Skype, Twitter
# preferred vcard version: 3.0 / 4.0
preferred_version = 3.0
# Look into source vcf files to speed up search queries: yes / no
search_in_source_files = no
# skip unparsable vcard files: yes / no
skip_unparsable = no
khard list
shows all my contacts. So far so good. Apparently there
are some awkward vCard compatibility
issues with creating or modifying
contacts from the khard
end. I ve tried adding one address from
~/.mutt/aliases
using khard
and it seems to at least minimally work for
me, but I haven t explored this very much yet.
I had to install python3-vobject 0.9.4.1-1 from experimental to fix
eventable/vobject#39
saving certain vCard files.
Finally, mutt
integration. I already had set query_command="lbdbq '%s'"
in ~/.muttrc
, and I wanted to keep that in place since I still wanted to
use LDAP querying as well. I had to write a very small amount of code for
this (perhaps I should contribute this to lbdb
upstream?), in
~/.lbdb/modules/m_khard
:
#! /bin/sh
m_khard_query ()
khard email --parsable --remove-first-line --search-in-source-files "$1"
~/.lbdb/rc
now reads as follows (you probably won t want the LDAP
stuff, but I ve included it here for completeness):
MODULES_PATH="$MODULES_PATH $HOME/.lbdb/modules"
METHODS='m_muttalias m_khard m_ldap'
LDAP_NICKS='debian canonical'
~/.mutt/aliases
into the new system. This
is only about 30 contacts so shouldn t take too long.
Overall this feels like a big improvement! It wasn t a trivial amount of
setup for just me, but it means I have both better usability for myself and
more independence from proprietary services, and I think I can add extra
users with much less effort if I need to.
Postscript
A day later and I ve consolidated all my accounts from Google Contacts and
~/.mutt/aliases
into the new system, with the exception of one group that
I had defined as a mutt
alias and need to work out what to do with. This
all went smoothly.
I ve filed the new lbdb
module as
#866178, and the python3-vobject
bug as
#866181.
When invoking this function, be careful not to interpolate arguments into the string run by the shell, such as Exec::shell(format!("sort ", filename)). Such code is prone to errors and, if filename comes from an untrusted source, to shell injection attacks. Instead, use Exec::cmd("sort").arg(filename).Though I'm not directly taking input from untrusted source, its still possible that the string I got back from git log command might contain some oddly formatted string with characters of different encoding which could possibly break the Exec::shell , as I'm not sanitizing the shell command. When we use Exec::cmd and pass argument using .args chaining, the library takes care of creating safe command line. So I went in and modified the function to use Exec::cmd instead of Exec::shell. Below is updated function.
fn copyright_fromgit(repo: &str) -> Result<Vec<String>>
let tempdir = TempDir::new_in(".", "debcargo")?;
Exec::cmd("git")
.args(&["clone", "--bare", repo, tempdir.path().to_str().unwrap()])
.stdout(subprocess::NullFile)
.stderr(subprocess::NullFile)
.popen()?;
let author_process =
Exec::shell(OsStr::new("git log --format=\"%an <%ae>\"")).cwd(tempdir.path())
Exec::shell(OsStr::new("sort -u"))
.capture()?;
let authors = author_process.stdout_str().trim().to_string();
let authors: Vec<&str> = authors.split('\n').collect();
let mut notices: Vec<String> = Vec::new();
for author in &authors
let author_string = format!("--author= ", author);
let first =
Exec::cmd("/usr/bin/git")
.args(&["log", "--format=%ad",
"--date=format:%Y",
"--reverse",
&author_string])
.cwd(tempdir.path()) Exec::shell(OsStr::new("head -n1"))
.capture()?;
let latest =
Exec::cmd("/usr/bin/git")
.args(&["log", "--format=%ad", "--date=format:%Y", &author_string])
.cwd(tempdir.path()) Exec::shell("head -n1")
.capture()?;
let start = i32::from_str(first.stdout_str().trim())?;
let end = i32::from_str(latest.stdout_str().trim())?;
let cnotice = match start.cmp(&end)
Ordering::Equal => format!(" , ", start, author),
_ => format!(" - , ", start, end, author),
;
notices.push(cnotice);
Ok(notices)
Next.