I can't remember exactly when, it was either pre-Zoe heart-related diagnostic
imaging or during her pregnancy with Zoe, that it became apparent that Sarah
had gall stones.
Apparently it's not uncommon for women to develop them after pregnancy, and
it turns out that Sarah is slightly more genetically predisposed to getting
them to boot. So it wasn't terribly surprising when she started having some
pain recently. She had another ultrasound to confirm it, and went off to see
a surgeon.
Apparently they care more about the symptoms than the number of stones in
the gallbladder, and they don't bother removing the stones and keeping the
gallbladder, so she was booked in for a cholecystectomy last Thursday.
It was a pretty straightforward procedure, she was out of the operating room
in just under an hour, and awake a bit over an hour after that.
I've had a few friends need to have a cholecystectomy, and the photos on
Wikipedia have always fascinated me, particularly this one. It
seems so freaky to have a gallbladder full of that much gravel. It can't be
comfortable. We're going to be able to pick up Sarah's stones on Monday, so
it'll be interesting to see what they look like.
Sarah's recovering now. It's one of the few surgeries she's had under
general anaesthesia where she hasn't been sick afterwards, so that was a
good start. The procedure was done laparoscopically, using four incisions,
and to give themselves room to work, they inflate the body with carbon
dioxide gas, which then has to work its way out of her body over the
following days. So she's dealing with some bloating, bruising and swelling
at the moment, but not doing too badly. Apparently if you're vertical for
too long, the gas can work its way up to your diaphragm, which causes some
shoulder pain, so the trick has been to walk around a bit, then lie down for
a bit, and then rinse and repeat.
She's not allowed to lift Zoe for 3-4 weeks, which presents a few
challenges for us, but nothing insurmountable (hopefully). We converted
Zoe's crib to a toddler bed a week before the surgery, and Zoe thought that
was just the best thing ever, and has taken to it really well. I'm around
at home for breakfast and dinner, so I can take care of the lifting into
and out of the high chair for those meals, and Zoe can eat lunch at her
little table. Zoe's also pretty good about getting into and out of the car
by herself (not that Sarah can drive until she's off the painkillers) and
she's normally in daycare two days a week. She's in daycare again on Monday,
so Sarah won't have to deal with Zoe on her own until Tuesday, and we have
backup daycare arrangements we can fall back on if need be. Zoe's been very
good about Sarah not being able to pick her up, and been very gentle. It
helped with the explanation that Sarah could show her all of her "owwies".
The surgeon was saying that only 1 in 400 people need to alter their diet
after removing their gallbladder, so we're hopeful that Sarah will do just
fine without it. She'll certainly be more comfortable in the long run.
Today, I've merged my erc notifications
module inside
Emacs trunk. This way, it will be available for everybody in Emacs 24.2.
This module allows you to be notified via notifications-notify
(the Emacs implementation of the Freedesktop desktop
notifications) on
private message received on IRC, or when your nickname is mentioned on a
channel.
To enable it in Emacs > 24.1, you just have to add the following line to your configuration
file:
(add-to-list 'erc-modules 'notifications)If you want to download it and use it stand-alone for a previous Emacs version, you can fetch the latest file revision and load it before adding the previously given line.
from zeitgeist.client import ZeitgeistClient from zeitgeist.datamodel import * zeitgeist = ZeitgeistClient() def on_events_received(events): if events: song = events[0] print "Last song: %s" % song.subjects[0].uri else: print "You haven't listened to any songs." template = Event.new_for_values(subject_interpretation=Interpretation.AUDIO) zeitgeist.find_events_for_template(template, on_events_received, num_events=1) # Start a mainloop - note: the Qt mainloop also works from gi.repository import GLib GLib.MainLoop().run()
from zeitgeist.client import ZeitgeistClient from zeitgeist.datamodel import * zeitgeist = ZeitgeistClient() def on_events_received(events): for event in events: print "- %s" % event.subjects[0].uri tmpl1 = Event.new_for_values(subject_interpretation=Interpretation.AUDIO) tmpl2 = Event.new_for_values(subject_interpretation=Interpretation.VIDEO) zeitgeist.find_events_for_templates([tmpl1, tmpl2], on_events_received, num_events=5) # Start a mainloop from gi.repository import GLib GLib.MainLoop().run()
zeitgeist.find_events_for_templates( [tmpl1, tmpl2], on_events_received, num_events=5, result_type=ResultType.MostRecentSubjects, storage_state=StorageState.Available)
subj1 = Subject.new_for_values(interpretation=Interpretation.SOURCE_CODE, uri="file:///home/rainct/Development/*") subj2 = Subject.new_for_values(uri="!file:///home/rainct/Development/zeitgeist/*") tmpl1 = Event.new_for_values(interpretation=Interpretation.MODIFY_EVENT, subjects=[subj1, subj2]) templates = [tmpl1]
from zeitgeist.client import ZeitgeistClient from zeitgeist.datamodel import * zeitgeist = ZeitgeistClient() def on_events_received(events): for event in events: print '- %s' % event.subjects[0].uri def on_ids_received(event_ids): print 'A total of %d source code files were found.' % len(event_ids) print 'Fetching the first 100...' zeitgeist.get_events(event_ids[:100], on_events_received) tmpl = Event.new_for_values(subject_interpretation=Interpretation.SOURCE_CODE) zeitgeist.find_event_ids_for_templates( [tmpl], on_ids_received, num_events=10000, # you can use 0 for "all events", but do you really need to? timerange=TimeRange.from_seconds_ago(3600*24*30*3), result_type=ResultType.MostPopularSubjects) # Start a mainloop from gi.repository import GLib GLib.MainLoop().run()
from zeitgeist.client import ZeitgeistClient from zeitgeist.datamodel import * zeitgeist = ZeitgeistClient() def on_insert(time_range, events): # do awesome stuff with the events here print events def on_delete(time_range, event_ids): # a previously inserted event was deleted print event_ids templates = [Event.new_for_values(subject_uri='file:///home/user/kittens/*', subject_interpretation=Interpretation.IMAGE)] zeitgeist.install_monitor(TimeRange.always(), templates, on_insert, on_delete) # Start a mainloop from gi.repository import GLib GLib.MainLoop().run()
m = zeitgeist.install_monitor(TimeRange.always(), templates, on_insert, on_delete) zeitgeist.remove_monitor(m)
import time from zeitgeist.client import ZeitgeistClient from zeitgeist.datamodel import * zeitgeist = ZeitgeistClient() def on_related_received(uris): print 'Related URIs:' for uri in uris: print ' - %s' % uri query_templates = [Event.new_for_values( subject_interpretation=Interpretation.SOURCE_CODE, subject_uri='file:///home/rainct/Development/zeitgeist/*', subject_mimetype="text/x-vala")] result_templates = [Event.new_for_values( subject_interpretation=Interpretation.WEBSITE, subject_manifestation=Manifestation.WEB_DATA_OBJECT)] now = time.time()*1000 zeitgeist.find_related_uris_for_events( query_templates, on_related_received, time_range=TimeRange(now - 1000*3600*24*30*6, now), result_event_templates=result_templates, num_events=10) # Start a mainloop from gi.repository import GLib GLib.MainLoop().run()
from zeitgeist.client import ZeitgeistClient from zeitgeist.datamodel import * zeitgeist = ZeitgeistClient() index = zeitgeist._iface.get_extension('Index', 'index/activity') query = 'hello' # search query time_range = TimeRange.always() event_templates = [] offset = 0 num_events = 10 result_type = 100 # magic number for "relevancy" (ResultType.* also work) def on_reply(events, num_estimated_matches): print 'Got %d out of ~%d results.' % (len(events), num_estimated_matches) events = map(Event, events) for event in events: print ' - %s' % event.subjects[0].uri def on_error(exception): print 'Error from FTS:', exception index.Search(query, time_range, event_templates, offset, num_events, result_type, reply_handler=on_reply, error_handler=on_error) # Start a mainloop from gi.repository import GLib GLib.MainLoop().run()
The default boolean operator is AND. Thus the query foo bar will be interpreted as foo AND bar. To exclude a term from the result set prepend it with a minus sign - eg foo -bar. Phrase queries can be done by double quoting the string "foo is a bar". You can truncate terms by appending a *. There are a few keys you can prefix to a term or phrase to search within a specific set of metadata. They are used like key:value. The keys name and title search strictly within the text field of the event subjects. The key app searches within the application name or description that is found in the actor attribute of the events. Lastly you can use the site key to search within the domain name of the subject URIs. You can also control the results with the boolean operators AND and OR and you may use brackets, ( and ), to control the operator precedence.Modifying the log So far we ve only queried Zeitgeist for information, let s get a bit more active. You can delete events from Zeitgeist with the following query:
from zeitgeist.client import ZeitgeistClient zeitgeist = ZeitgeistClient() def on_deleted(timerange): print 'Deleted events going from %s to %s' % (timerange[0], timerange[1]) event_ids = [50] # put the IDs of the events you want to delete here zeitgeist.delete_events(event_ids, on_deleted) # Start a mainloop from gi.repository import GLib GLib.MainLoop().run()
import time from gi.repository import GLib from zeitgeist.client import ZeitgeistClient from zeitgeist.datamodel import * zeitgeist = ZeitgeistClient() def on_status_changed_callback(enabled): """ This method will be called whenever someone enables or disables the data-source. """ if enabled: print 'Data-source enabled and ready to send events!' else: print 'Data-source disabled; don\'t send event, they\'ll be ignored.' def register(): # Always use the same unique_id. Name and description can change # freely. unique_id = 'com.example.your.data.source' name = 'user visible name (may be translated)' description = 'user visible description (may be translated)' # Describe what sort of events will be inserted (optional) subject_template = Subject() subject_template.interpretation = Interpretation.PLAIN_TEXT_DOCUMENT subject_template.manifestation = Manifestation.FILE_DATA_OBJECT templates = [] for interp in (Interpretation.ACCESS_EVENT, Interpretation.LEAVE_EVENT): event_template = Event() event_template.interpretation = interp event_template.manifestation = Manifestation.USER_ACTIVITY event_template.append_subject(subject_template) templates.append(event_template) zeitgeist.register_data_source(unique_id, name, description, templates, on_status_changed_callback)
def log(title, uri, opened): subject = Subject.new_for_values( uri=uri, interpretation=Interpretation.PLAIN_TEXT_DOCUMENT, manifestation=Manifestation.FILE_DATA_OBJECT, origin=GLib.path_get_dirname(uri), mimetype='text/plain', text=title) event = Event.new_for_values( timestamp=time.time()*1000, manifestation=Manifestation.USER_ACTIVITY, actor='application://your_application_name.desktop', subjects=[subject]) if opened: event.interpretation = Interpretation.ACCESS_EVENT else: event.interpretation = Interpretation.LEAVE_EVENT def on_id_received(event_ids): print 'Logged %s (%d) with event id %d.' % (title, opened, event_ids[0]) zeitgeist.insert_events([event], on_id_received) if __name__ == '__main__': register() log('test.txt', 'file:///tmp/test.txt', opened=True) log('another_file.txt', 'file:///tmp/another_file.txt', opened=True) log('another_file.txt', 'file:///tmp/another_file.txt', opened=False) log('test.txt', 'file:///tmp/test.txt', opened=False) # Start a mainloop GLib.MainLoop().run()
from zeitgeist.mimetypes import * print get_interpretation_for_mimetype('text/plain') print get_manifestation_for_uri('file:///tmp/test.txt')
That's a seemingly simple question I started asking various people two
weeks ago. I didn't get many useful answers, but now I have experience
doing it myself, and so here's a blog post brain dump.
I have been trying to convert git-annex to use GHC's threaded runtime, for
a variety of reasons. Naively adding the -threaded option resulted in a
git-annex command that seemed to randomly freeze, but only sometimes
(and, infuriatingly, never when I straced it), and a test suite that froze
at a random point almost every time I ran it. Not a good result, and
lacking any knowledge about gotchas with using the threaded runtime, I was
at a loss for a long time (most of DebConf) about how to fix it.
I now know of at least three classes of problems that enabling the threaded
runtime can turn up in programs that have been developed using the
non-threaded runtime.
accessing a MVar after forkprocess can hang
MissingH has some code similar to this, which works ok with the
non-threaded runtime:
forkProcess $ do
debugM "about to run some command"
executeFile ...
In the above example, debugM accesses a MVar. Doing that after
forkProcess can result in a MVar deadlock, as it tries to access a MVar
value, that is, apparently, not accessible to the forked process.
(Bug report with test case)
So, using System.Cmd.Utils from MissingH is asking for trouble.
I switched all my code to the newer and, apparently, threaded runtime
safe System.Process.
forkProcess is a massively bad idea
Even when not accessing a MVar after forkProcess, it's very unsafe to
use. It's easy to miss the warning attached to forkProcess, when the code
seems to work. But with the threaded runtime, I've found that most
any call to forkProcess will sometimes succeed, and sometimes freeze
the whole program. This might only happen around 1 time in 1000.
Then you'll find this warning and do a lot of head-scratching about what
it really means:
forkProcess comes with a giant warning: since any other running threads are not copied into the child process, it's easy to go wrong: e.g. by accessing some shared resource that was held by another thread in the parent.The hangs I saw could be due to laziness issues deferring code to run after the
forkProcess that you'd expect to have run before it ... or
who knows what else.
It's not clear to me that it's possible to use forkProcess safely in
Haskell code. I think it's notable that System.Process runs the whole
fork/exec in C code instead.
unsafe FFI calls block
According to most of the documentation you'll find in eg, the Haskell wiki,
Real World Haskell, etc, the only difference between the safe and
unsafe imports in the FFI is that unsafe is faster, and shouldn't be
used for C code that calls back into Haskell code.
But the documentation is out of date. Actually, if you're using the FFI,
and the foreign function can block, you need to use safe. When using
unsafe, a blocking foreign function can block all threads of the program.
In my case, I was using kqueue to wait for changes to files, and this
indeed blocked my whole program when linked with -threaded. Marking it
safe fixed this.
The details are well described in this paper:
http://community.haskell.org/~simonmar/papers/conc-ffi.pdf
Somewhat surprisingly, this blocking only happens when using the threaded
runtime. If you're using the non-threaded runtime with unsafe blocking
FFI functions, your other pseudo-threads won't be blocked. This is because
the non-threaded runtime has an SIGALARM timer that interrupts (most)
blocking system calls. This leads to other troubles of its own (like
needing to restart interrupted FFI functions, or blocking the other
pseudo-threads from running if the C code ignores SIGALARM), but that's
offtopic for this post.
summary
Converting a large Haskell code base from the default, non-threaded runtime
to the threaded runtime can be quite tricky. None of the problems are the
sort of thing that Haskell helps to manage either. I will be developing new
programs using the threaded runtime from the beginning from now on.
By the way, don't take this post to say that threading in Haskell sucks.
I've really been enjoying writing threaded Haskell code. The control
Haskell gives over isolation of state to threads, and the excellent and
wide-ranging suite of thread communications data types (MVar, Chan,
QSemN, TMVar, SampleVar, etc) have made developing a complex threaded
program something I feel comfortable doing for the first time, in any
language.
It s been released. Use this with NIST::NVD 1.00.00 and you will be able to perform immediate look-ups of CVE and CWE data given a CPE URN. For instance:
cjac@foxtrot:/usr/src/git/f5/NIST-NVD-Store-SQLite3$ perl Makefile.PL ; make ; make test ; cjac@foxtrot:/usr/src/git/f5/NIST-NVD-Store-SQLite3$ perl -MNIST::NVD::Query -MData::Dumper -e '
$q = NIST::NVD::Query->new(store => q SQLite3 ,database => q t/data/nvdcve-2.0.db );
$cve_list = $q->cve_for_cpe( cpe => q cpe:/a:microsoft:ie:7.0.5730.11 );
print Data::Dumper::Dumper cve_list => $cve_list, first_cvss => $q->cve( cve_id => $cve_list->[0] )-> q vuln:cvss
'
$VAR1 =
'cve_list' => [
'CVE-2002-2435',
'CVE-2010-5071'
],
'first_cvss' =>
'cvss:base_metrics' =>
'cvss:confidentiality-impact' => 'PARTIAL',
'cvss:score' => '4.3',
'cvss:authentication' => 'NONE',
'cvss:access-vector' => 'NETWORK',
'cvss:source' => 'http://nvd.nist.gov',
'cvss:generated-on-datetime' => '2011-12-08T06:47:00.000-05:00',
'cvss:availability-impact' => 'NONE',
'cvss:integrity-impact' => 'NONE',
'cvss:access-complexity' => 'MEDIUM'
;
https://metacpan.org/release/CJCOLLIER/NIST-NVD-Store-SQLite3-1.00.00
In my effort to automate most of the stuff needed to release, I am working on a SOAP to OCaml converter. Richard W.M. Jones has kindly allowed me to take-over its project "ocsoap". The project is now located here and I am working on making it compatible with FusionForge SOAP.
My first step was to make it compatible with OASIS and ocamlbuild. The project is Makefile based and needs some extra care to make it ocamlbuild based.
The oasis-fication itself was a piece of cake. Just describe the dependencies of the project and make some extra choice like compiling the camlp5 extension to a .cma rather than a .cmo. You can see the
_oasis and myocamlbuild.ml results, compared to the initial Makefile.
The _oasis is simple:
OASISFormat: 0.3
Name: ocsoap
Version: 0.7.1
Synopsis: SOAP converter to OCaml code
Authors: Richard W.M. Jones, Sylvain Le Gall
License: LGPL-2.1 with OCaml linking exception
Plugins: DevFiles (0.3), META (0.3),
StdFiles (0.3)
BuildTools: ocamlbuild,
cduce
BuildDepends: dynlink,
pxp-lex-utf8,
pxp-engine,
netclient,
cduce,
extlib,
calendar,
pcre
Library ocsoap
Path: src
Modules: OCSoap
Library pa_ocsoapclientstubs
Path: src
Modules: Pa_ocsoapclientstubs
BuildTools: camlp5o
BuildDepends: camlp5
FindlibParent: ocsoap
FindlibName: syntax
CompiledObject: byte
Executable wsdl_validate
Path: src
MainIs: wsdl_validate.ml
Executable wsdltointf
Path: src
MainIs: wsdltointf.ml
Executable adwords_test1
Path: examples/adwords
BuildDepends: ocsoap
MainIs: test1.ml
Build$: flag(tests)
Install: false
BuildTools: camlp5o
BuildDepends: ocsoap.syntax
Executable adwords_test2
Path: examples/adwords
BuildDepends: ocsoap
MainIs: test2.ml
Build$: flag(tests)
Install: false
BuildTools: camlp5o
BuildDepends: ocsoap.syntax
Executable adwords_examples
Path: examples/adwords
BuildDepends: ocsoap
MainIs: example.ml
Build$: flag(tests)
Install: false
BuildTools: camlp5o
BuildDepends: ocsoap.syntax
Document "api-ocsoap"
Title: API reference of OCSoap
Type: ocamlbuild (0.3)
BuildTools+: ocamldoc
XOCamlbuildLibraries: ocsoap
XOCamlbuildPath: src/
Most of it was generated using oasis quickstart, that helps you to write _oasis. This part was not tricky and mostly a translation of what the previous Makefile was explaining, in its language.
Now comes the tricky part, translating Makefile rules into ocamlbuild rules. This part is more tricky because the general principle behind Makefile and ocamlbuild are not exactly the same.
Let's start with a simple rule: compiling a CDuce .cd file into a .cdo.
Here is the Makefile rule:
%.cdo: %.cd
$(CDUCE) --compile $<
In the oasis-fication, we have added an extra complexity, because we move the source to src, which needs extra flags.
Here is the ocamlbuild rule:
rule "cduce: %.cd -> %.cdo"
~prod:"%.cdo"
~dep:"%.cd"
begin
fun env build ->
Cmd(S[cduce;
T(tags_of_pathname (env "%.cd")++"cduce"++"compile");
A"--compile";
A"-I"; P(Filename.dirname (env "%.cd"));
P (env "%.cd")])
end
;;
It is a little bit more complex, lets explain it.
The function rule create a rule with a name and a function that execute it. The labels ~prod and ~dep are the right and left parts of %.cdo: %.cd of the Makefile. When we call env "%cd", it replaces the % by the matching part of ~prod and ~dep.
Next we return a Rule.action. The rule in this case is a command Cmd. This rules use a sequence S, which are the command line itself. The sequence is made of smaller pieces that can be a placeholder for tag content (T + what will trigger it), atom (A, typically command line option), and filename (P).
For a file src/foo.ml, the command generated will
cduce $(TAG) --compile -I src src/foo.mlwhere
$(TAG) will be replaced by the content of flag ["file:src/foo.ml"; "cduce"; "compile"] content. But also by the content of flag ["cduce"; "compile"] content, the flag just need to be subset. For example if you want to add --verbose to the command line, just add flag ["cduce"; "compile"] (S[A"--verbose"]);; somewhere in myocamlbuild.ml.
Next rules, we need to compile %.cdo to %.cmo. It is trickier because in this case, we want to have %.cmi eventually built before. It is not require to build it before, if there is no %.mli file.
Here is the code to do that:
let cduce_mkstubs includes =
Quote (S([cduce;
S(List.map
(fun fn -> S[A"-I"; P fn])
includes);
A"--mlstub"]));;
(* cduce < 0.3.9: cdo2ml -static *)
let cduce_compile_args env =
[
A"-c"; A"-package"; A"cduce";
A"-pp"; cduce_mkstubs [Filename.dirname (env "%.cmi")];
A"-I"; P(Filename.dirname (env "%.cmi"));
A"-impl"; P(env "%.cdo")
]
;;
let cduce_prepare_compile env build =
List.iter
(function
Outcome.Bad _ ->
(* Fail but it just means that the .cmi will be generated
* during compilation.
*)
()
Outcome.Good _ ->
())
(build [[env "%.cmi"]])
;;
rule "cduce: %.cdo -> %.cmo"
~prod:"%.cmo"
~dep:"%.cdo"
begin
fun env build ->
cduce_prepare_compile env build;
Cmd(S(
[ocamlfind; ocamlc;
T(tags_of_pathname (env "%.cdo")
++"cduce"++"ocamlc"++"compile"++"byte")]
@ (cduce_compile_args env)))
end
;;
The difference with the former rules, is that we call cduce_prepare_compile which in turns call (build [[env "%.cmi"]]). The call to build will ask ocamlbuild to compile src/foo.cmi, but we don't care about the result, i.e. in case of Outcome.Bad exn we don't fail. This way we don't stop the build process that will continue and produce a .cmo and .cmi just out of the .cdo. The .cdo itself is compiled as a .ml file with ocamlfind ocamlc except that we apply cduce --mlstub as a preprocessor A"-pp"; Quote(S[cduce; ..; A"--mlstub"]).
The last rule that I will comment is the one that transform a .intf into a .ml. This rule is particular because it is totally different than the pieces of code of the original Makefile.
Here are the couple of rules that was needed to translate .intf:
examples/adwords/%Service.cmx: examples/adwords/%Service.intf
ocamlfind ocamlopt $(OCAMLOPTFLAGS) -c \
-pp "camlp5o ./pa_ocsoapclientstubs.cmo -impl" -c -impl $<
.depend: $(wildcard *.mli) $(wildcard *.ml) \
$(wildcard examples/adwords/*.mli) $(wildcard examples/adwords/*.ml)
$(OCAMLDEP) $^ > .depend
for f in examples/adwords/*.intf; do \
$(OCAMLDEP) \
-pp "camlp5o ./pa_ocsoapclientstubs.cmo pr_o.cmo -impl" $$f \
>> .depend; \
done
Here is the ocamlbuild rule:
rule "ocsoap: %.intf -> %.ml"
~prod:"%.ml"
~deps:(if !ocsoap_dev then
["%.intf"; !pa_ocsoapclientstubs]
else
["%.intf"])
begin
fun env build ->
Cmd(S[Px !camlp5o; P !pa_ocsoapclientstubs; P "pr_o.cmo"; A"-impl";
P(env "%.intf"); A"-o"; P(env "%.ml")])
end
;;
Here we decided to translate directly the .intf into a .ml file. The good thing about ocamlbuild is that it has a powerfull dynamicy dependencies scheme. So here you will generate the .ml file, which in turns will generate a .ml.depends and then will be compiled the standard way. In the makefile, you need to compute the .depends file using a different process that will do everything before the compilation even starts (in fact, before the inclusion of the .depends). We also use the trick to use an OCaml printer (pr_o.cmo) with camlp5o, that will directly output the standard .ml file.
Don't hesitate to post comment if you have question about OASIS and ocamlbuild
Enjoy.
Repetition: Repetition of the same crash could lead to multiple reports on the same buggy behavior. For this, apport, if senses that you have already filed a bug, it provides you with the option to further ignore all crashes for that particular type.Following image should explain it better.
My initial thought regarding defaults was to make apport a default opt out tool for the entire archive and only file reports for packages where the developer has manually enabled to opt-in for apport reports. But that'd have been very slow in terms of adoption, hence, for now, instead, the version in experimental does it the other way around. It will file bug reports for all packages. If you need to opt out, you will have to add the above expalined control field. That's it for this post. Please provide feedback once you spend some time with apport.PS: Please take conscious steps when filing bug reports with apport. I think it is a great tool. It just needs great users. :-)
mysqldump and mysql. These two tools have one
severe discrepancy, which I would like to comment here because I think
it is an excellent example of what not to do when designing tools to be
used together.Save
mysqldump(1) is a
database backup tool, that takes a MySQL database and prints the
necessary SQL statements to restore it to a new server. It has one interesting option:
--default-character-set=charset_name Use charset_name as the default character set. See Section 10.5, Character Set Configuration . If no character set is specified, mysqldump uses utf8.As you can see, it is quite modern in its default choice: if you do not specify which encoding you want to encode your database content into, it uses UTF-8. This way, it can save any database content, whatever characters it may contain. A more sensible choice may have been to use the
LC_CTYPE environment variable.
Restore
mysql(1) is the command-line MySQL client, which can is used to restore such dumps. It has a similar option:
--default-character-set=charset_name Use charset_name as the default character set for the client and connection. A common issue that can occur when the operating system uses utf8 or another multi-byte character set is that output from the mysql client is formatted incorrectly, due to the fact that the MySQL client uses the latin1 character set by default. You can usually fix such issues by using this option to force the client to use the system character set instead.As you can see, this utility is still has an antique design: if you do not specify a character set, it assumes you are giving it data encoded in latin-1. Discrepancy You can see the obvious discrepancy here:
mysqldump encodes your database backups in UTF-8 by
default, and mysql restores them
as if they were encoded in latin-1. This way, when you have to restore
your databases, if you thought you could do it without wondering,
congratulations: voil , you have just fucked your databases
up! And as an additional present, chances are high that this mistake is
discreet enoughto be detected only after a while, when modifications
have been done to the restored database and the original backups have
been deleted.
So, if you are dealing with MySQL databases, remember that you
must take care of the encoding of your backups, because MySQL
utilities will not by itself, or rather it will do just what should not
be done. And if you are designing similar tools, please think,
and if you want an example of what not to do, here is one!
It feels like I'm sitting in a roller-coaster wagon. There's probably
too much change going on for me to assimilate naturally. In
particular:
I just wrapped up (well, mostly) one of the toughest Uni semestres. I had
to deal with lots of very time consuming assignments, and then the usual
round of final exams. Even if this semester I got the best marks in my
journey (or shall we say Via Crucis) through University, I still
managed to fail one exam, for the Advanced Networks subject, which is
quite annoying, given I got high marks (even the highest in one case) in
other subjects I really don't master at all. In any case, this is the end
of the pain. The only thing that's left is just one exam and a project
based on GNU/Linux technologies which will basically mean formatting for
prettyness the sysadmin docs we've been collecting at the office during
the last few years. This effort will be nothing to what I've been doing
during the past 18 months, so I'm really relieved to have it past me
already.
Getting rid of studies comes just two weeks before a big change in my
professional career. Friday was my last day at the
Institut Tecnol gic d'Inform tica, after
five and a half fantastic years working with awesome people in a very
friendly atmosphere. I've learned a great deal, and taking this decision
wasn't easy at all. I leave lots of good friends behind, people I really
love, and tomorrow will be difficult to not have them around me. I wish my
ITI ex-workmates the best of luck in these difficult times for everyone in
Spain and specially in the Valencian Country with the massive cuts going
on. I feel the timing for this jump couldn't be better.
Tomorrow, when I get ready to go for work, I won't be leaving home at
all, instead I will just sit where I am right now, at home, and log into some
corporate IRC server. Tomorrow I'll be joining
Collabora, and I'm a mix
of excited, curious and happy about this incredible opportunity. Thanks to
Sjoerd for nags, I might not be
writing this if it wasn't for you!
When I was first approached about this, I thought Collabora was a small
company. But as I looked more into it, I discovered that's not longer the
case, there's many more people than I imagined working there (here!), and
was delighted to see I knew many of them, and many other are well known
members of the major Free Sofware communities. I'll be joining the
sysadmin team to work closely with
Jo Shields. See you tomorrow,
folks. :)
This opportunity to work from home is godsend, given the third bit of
change that'll be happening soon: sometime in late September, Maria and I
should join the ranks of first-time parents, following the baby boom wave
surrounding us. While you can imagine we're really happy about this, we're
also freaking out because this is going to happen in just two months
and a half, and weeks go by really fast lately. So yeah, being able to be at
home with this really small baby will be a big bonus for the incredible
experience we're about to enjoy. We've been both busy with other stuff,
but during the summer we should be focusing on preparing the baby's
arrival. There's a whole lot to do!
Expect my Debian and other Free Software activities to get a hit, of
course. :) If I am normally sleep-deprived, this is going to be the next
level.
Thanks for your work. Your workshop was very interesting and didactic: a relevant discussion between Claire and me for the future of Creatools has emerged from the difficulties you encountered to package creatools. I will try, before the end of the month, to fully package creatools. And for sure, I will contact the debian-med mailing list.Integration of VistA into Debian I had the good chance to directly address some issues of Claudio Zaugg the speaker in the talk Implementing open source Health Information Systems in Low- and Middle Income Countries a practical review directly before mine. It turned out that by using Debian packaged software might help simplifying the issues they had in supporting health care workers in Low- and Middle Income Countries.
On the desktop, I usually rely on Privoxy to strip out ads, tracking resources and other privacy-invading elements. So I was looking for an equivalent solution on Android. Firefox 10 With the current version of Firefox for Android, you can simply install the Adblock Plus extension and it will filter most undesirable elements from webpages. Unfortunately, that extension is not yet available for the latest Firefox Beta, so I had to find another solution. Android Adblock It turns out that there is an Open Source proxy similar to Privoxy (though much more limited in functionality) available for Android: Adblock (also available on the F-Droid Free Software market). However, its default configuration really doesn't block much and so you'll probably want to import a new blocklist as soon as you install it. I used a combination of the Easylist and EasyPrivacy blocklists. Configuring Fennec to use a proxy Unlike its desktop cousin, Firefox for Android (also called Fennec) doesn't expose proxy settings in the user interface. Instead, you have to open the about:config page and configure the following settings manually: Once you're done, test your connection by going into the AdBlock application and turning the proxy off. Then switch back to Firefox and go to a new website. You should get an error message telling you that the proxy is blocking connections. That means it's successfully using your proxy to talk to other websites and not connecting to them directly. (It might also be possible to set this up in the default Android browser or in the Chrome for Android Beta, but I haven't been able to find how. Feel free to leave a comment if you know how it's done.) Bonus tips While you're at it, I highly recommend you turn on the Do Not Track feature in Firefox. Some large sites (like Twitter) have recently committed to turning off individual tracking on web requests which contain this new privacy header. Also, if you want to help move the mobile web away from a WebKit monoculture (remember how bad the Internet Explorer 6 monoculture was for the web?), then please consider joining the Mobile Testdrivers team and help us make Firefox rock on Android!
network.proxy.http = localhost
network.proxy.http_port = 8080
network.proxy.ssl = localhost
network.proxy.ssl_port = 8080
network.proxy.type = 1
Sitting in the airport during a layover on my way back from DebConf is one of
the few times of year that time and motivation come together and routinely
lead me to blog.
Each year's DebConf has been special in its own way. This year at
DebConf 12, in addition to the usual
routine of catching up with all my far-away Debian friends, and of
making new Debian friends in a country I've never been before, I got a
special treat: my first opportunity to experience the practice of
medicine in a foreign country.
Last Saturday after arriving in Managua, I discovered that the very pretty
paving stones making up the hotel walkway were also very slippery when wet,
and the thin rubber strips that had been helpfully put in place to make them
less slippery did not measurably succeed in doing so. So as it was raining
that afternoon (as it does nearly every afternoon this time of year in
Nicaragua), I slipped, and made the critical error of not falling.
Instead, I stopped my slide - as it happens, by using the big toe of my
left foot as if it were a roller skate brake.
I don't recommend this, particularly if, as in my case, you already had it on
your todo list to consult a podiatrist after DebConf regarding an ongoing
feeling of weakness in precisely that part of precisely that foot.
So while everything seemed fine the next day, Monday I woke up early
with excruciating pain in my foot which, having forgotten about the
incident two days prior, seemed to come from nowhere. After favoring
the foot for another day and trying to keep the pain at bay using just
OTC drugs, by Tuesday my foot was quite swollen and a source of concern. So
I visited the clinic on the university campus, where the doctor diagnosed me
with a dropped arch plus cellulitis due to bacteria entering through some
invisible cut.
Conclusion: university campus clinics are equally useless the world over.
But at least in addition to pointlessly prescribing antibiotics, the doctor
also prescribed some anti-inflammatory drugs to help bring the swelling
down.
Nevertheless, my questionable mobility kept both me and Patty from attending
the day trip on Wednesday, which was a real shame as I had been keen to
climb a volcano that day with
my fellow Debian Developers (which in the end didn't happen for anyone, but
that's a story for someone else's blog). Instead I took it easy for the
day at the hotel, together with a few others who had opted not to attend
the day trip, catching up on email and other work and hoping matters would
improve. But by the end of the day the swelling was as bad as ever, if not
worse, and I had no idea what was going on. Was it broken? Was something
dislocated? And so I decided that the following day I would go to the
hospital.
The nearest hospital, as given in the DebConf local information page, is
the
Hospital Militar.
It's a strange sort of thing as an American who remembers the 1980s to be
seeking medical care from a facility operated by the Nicaraguan military; but
accompanied by Fitoria, my native escort from the local
team I had nothing to worry about; and besides, as a frequent international
traveler I long ago learned the secret truth that people are people
everywhere, no matter what flag they were born under. The highlight of the
hospital visit was definitely when a member of the hospital staff, in full
military uniform, shooed me towards a chair instead of standing to talk to
her because "every patient has the right to sit, no matter what country
they're in".
After six x-rays and a doctor's consult, the conclusion was that it's
probably not a broken bone and that it will probably clear up in just a
couple of days with an even-better anti-inflammatory prescription and
taking care of it by not walking on it. And indeed, my foot was already
feeling better by Friday and aside from a little tenderness is now just
about 100%.
There are plenty of other entries on Planet Debian
talking about the conference itself, and I don't think I have much to add to
what's already been said there. But as for Nicaragua, I can conclude that it
must be one of the best countries in the world to break your foot in - between
the help of the hotel staff, the top-notch medical professionals, and above
all the support of the DebConf local team (with a very big thank you again to
Fitoria!), this is one brand of socialized medicine I can appreciate.
Not sure if that will work as I expect, but here as my runs in the
city of Managua, combined in one single map, thanks to OpenRunner:
<script src="http://www.openrunner.com/orservice/inorser-script.php?key=mykey&ser=S03&id=1802807&w=500&h=350&hp=128&k=5&m=0&pa=0&c=0&ts=1342329989" type="text/javascript"></script>
As already written, even though it seems, I didn't spend my time
running at Debconf12.
Or eating cheese...
Or (tentatively) hiking volcanoes...
Or helping people to kill each other with socks...
Or drinking beers...
Not *only* all of these (some of them at the same time, though hiking
a volcano while eating cheese and drinking beers is not particularly
easy)....but also some Debian work.
So, I uploaded a backport of samba to squeeze backports and our
squeeze users should now have the same samba version than wheezy ones.
I also stopped several cronjobs on i18n.debian.net and moved some
material there as links have been (or should be) moved to the brand
new i18n.debian.org (and its alias l10n.debian.org).
I did a major cleanup in tasksel, committed
several fixes, proposed others for review (mostly to Joey Hess). All
this in preparation for a soon-to-come upload, probably after D-I
beta1 which has been prepared by Cyril Brulebois while he was.....not
attending Debconf12..
I also followed the integration of Sorina Sandu's work on netcfg for
link detection and network ESSID choice in Debian Installer. Sorina is
doing well in her GSOC work, because she's clearly someone with great
capabilities who we will, I hope, be able to keep contributing to
Debian. We can also thank the mentoring work of Gaudenz Steinlin to
guide Sorina through D-I's arcanes.
I also went through the current status of debconf translation
completeness in testing for the 7 languages that target 100% (Czech,
German, Spanish, French, Portuguese, Russian, Swedish). Here, the
point is mostly taking care that fixes are either:
Not few times I ve come upon the situation where I m working over a Subversion working copy locally and I wanted to commit bits of what I ve already baked and ready to go. Odds are that there s only one file not belonging to such changeset but mostly there are many files scattered around.
This situation, I learned, can be managed with a lot more flexibility and fun.svn changelist is a nice tool for such situation. svn changelist allows you to create a list of files I want to do something with meaning that you can use the changelist on your usual svn operations, read commit, remove, etc.
Let s suppose you start with a project myapp, then you start creating three files A, B and C.
dragon% touch A B C
dragon% ls -lh
total 0
-rw-r--r-- 1 rudy rudy 0 Jul 13 20:16 A
-rw-r--r-- 1 rudy rudy 0 Jul 13 20:16 B
-rw-r--r-- 1 rudy rudy 0 Jul 13 20:16 C
dragon% svn add A B C
A A
A B
A C
dragon% svn ci "first commit of A, B and C" .
Adding A
Adding B
Adding C
Transmitting file data ...
Committed revision 1.
Now we want to edit A and add few pieces of text. Then edit B also.
dragon% echo "This file looks empty, so let's put some text inside it" > A
dragon%
dragon% echo "I'm afraid this one also is empty. Just in case" >> B
Now, I need to work on this C file and that implies touching B also. I don t want to commit the changes I ve already made since I haven t made up my mind about them.
dragon% echo "C is a nice name for a source file, but this one doesn't look like one does it?" > C
dragon% echo "I'm going to add few lines to B too" >> B
dragon% svn st
M A
M B
M C
So, let s suppose I m ready to hit the key and commit the 2nd revision. But I m not done on A, so I want to commit just B and C the way they are now. Here svn changelist enters the arena.
I can create a changelist for the two files and do several tasks related to them. Let s see.
dragon% svn changelist mylist B C
Path 'B' is now a member of changelist 'mylist'.
Path 'C' is now a member of changelist 'mylist'.
Now I have a changelist named mylist that I can do operations with. For instance,
dragon% svn st
M A
--- Changelist 'mylist':
M B
M C
dragon% svn diff --changelist mylist
Index: B
===================================================================
--- B (revision 1)
+++ B (working copy)
@@ -0,0 +1,2 @@
+I'm afraid this one also is empty. Just in case
+I'm going to add few lines to B too
Index: C
===================================================================
--- C (revision 1)
+++ C (working copy)
@@ -0,0 +1 @@
+C is a nice name for a source file, but this one doesn't look like one does it?
Now let s commit the list.
dragon% svn ci -m "Comitting files from the mylist changelist" --changelist mylist
Sending B
Sending C
Transmitting file data ..
Committed revision 2.
dragon% svn st
M A
Now that I ve committed the files, the changelist mylist vanishes from our working copy. I cannot do any new operations with it.
Few things you have to consider when using svn changelist.changelist s are created in a one-time list, that means you cannot add another file to an existing list. If I type svn changelist mylist A it will define the changelist mylist to have just one member, A. It will not add A to the existing member files, B and C.
Now, you are free to remove any file from an existing changelist using svn changelist mylist --remove B, for our previous example. That will make the changelist shrink to just have one element, C. You can also have as many changelists as you want, and member files can be associated to each one of them. Use case for that could be a diff over specific files.
For this test project it almost makes no difference using this feature, but when you have lots of file sitting modified on your working copy, this feature will keep your hair on it s place, and maybe save the day. svn changelist is available since Subversion 1.5.
Next.