Le web et la sémantique
5/10/2011 08:36:00 PM
123-new-feature
, chacun un commit. L'historique ressemble à ça:@ changeset: 3:f3a6c5394605 | tag: tip | parent: 0:11575ff21a29 | user: Alice | date: Tue Jan 11 15:34:05 2011 +0100 | summary: Dummy | | o changeset: 2:c6dc5c92d631 | | branch: 123-new-feature | | user: Bob | | date: Tue Jan 11 15:15:26 2011 +0100 | | summary: Plus expressif! | | | o changeset: 1:fafdcd7dccf5 |/ branch: 123-new-feature | user: Alice | date: Tue Jan 11 15:11:40 2011 +0100 | summary: Nicer. | o changeset: 0:11575ff21a29 user: Alice date: Tue Jan 11 15:08:58 2011 +0100 summary: Initial commit.
default
. On utilise l'option --keep
pour ne pas détruire tout de suite la branche. En gros on prend le noeud 1 et ses ancetres, on fusionne, et on recolle la modification résultante sur le noeud 3.$ hg rebase --collapse --keep --source 1 --dest 3 @ changeset: 4:2bf346072a24 | tag: tip | user: Alice | date: Tue Jan 11 15:15:26 2011 +0100 | summary: Plus joli et plus expressif! | o changeset: 3:f3a6c5394605 | parent: 0:11575ff21a29 | user: Alice | date: Tue Jan 11 15:34:05 2011 +0100 | summary: Dummy | | o changeset: 2:c6dc5c92d631 | | branch: 123-new-feature | | user: Bob | | date: Tue Jan 11 15:15:26 2011 +0100 | | summary: Plus expressif! | | | o changeset: 1:fafdcd7dccf5 |/ branch: 123-new-feature | user: Alice | date: Tue Jan 11 15:11:40 2011 +0100 | summary: Nicer. | o changeset: 0:11575ff21a29 user: Alice date: Tue Jan 11 15:08:58 2011 +0100 summary: Initial commit.
$ hg strip 1 @ changeset: 2:2bf346072a24 | tag: tip | user: Alice | date: Tue Jan 11 15:15:26 2011 +0100 | summary: Plus joli et plus expressif! | o changeset: 1:f3a6c5394605 | user: Alice | date: Tue Jan 11 15:34:05 2011 +0100 | summary: Dummy | o changeset: 0:11575ff21a29 user: Alice date: Tue Jan 11 15:08:58 2011 +0100 summary: Initial commit.
123-new-feature
reste dans les autres dépôts -- en d'autres termes l'historique n'est pas lui même versionné. Bob pourrait donc faire d'autres modifications dans la branche, ce qui n'est bien sûr pas trop souhaitable...# Bob fait une modif (#3) et la commite o changeset: 5:2bf346072a24 | tag: tip | user: Alice | date: Tue Jan 11 15:15:26 2011 +0100 | summary: Plus joli et plus expressif! | o changeset: 4:f3a6c5394605 | parent: 0:11575ff21a29 | user: Alice | date: Tue Jan 11 15:34:05 2011 +0100 | summary: Dummy | | @ changeset: 3:b37a07ad9982 | | branch: 123-new-feature | | user: Alice | | date: Tue Jan 11 15:39:38 2011 +0100 | | summary: Never enough of that. | | | o changeset: 2:c6dc5c92d631 | | branch: 123-new-feature | | user: Bob | | date: Tue Jan 11 15:15:26 2011 +0100 | | summary: Plus expressif! | | | o changeset: 1:fafdcd7dccf5 |/ branch: 123-new-feature | user: Alice | date: Tue Jan 11 15:11:40 2011 +0100 | summary: Nicer. | o changeset: 0:11575ff21a29 user: Alice date: Tue Jan 11 15:08:58 2011 +0100 summary: Initial commit.
o changeset: 5:b37a07ad9982 | branch: 123-new-feature | tag: tip | user: Alice | date: Tue Jan 11 15:39:38 2011 +0100 | summary: Never enough of that. | o changeset: 4:c6dc5c92d631 | branch: 123-new-feature | user: Bob | date: Tue Jan 11 15:15:26 2011 +0100 | summary: Plus expressif! | o changeset: 3:fafdcd7dccf5 | branch: 123-new-feature | parent: 0:11575ff21a29 | user: Alice | date: Tue Jan 11 15:11:40 2011 +0100 | summary: Nicer. | | o changeset: 2:2bf346072a24 | | user: Alice | | date: Tue Jan 11 15:15:26 2011 +0100 | | summary: Plus joli et plus expressif! | | | o changeset: 1:f3a6c5394605 |/ user: Alice | date: Tue Jan 11 15:34:05 2011 +0100 | summary: Dummy | @ changeset: 0:11575ff21a29 user: Alice date: Tue Jan 11 15:08:58 2011 +0100 summary: Initial commit.
hg commit --close-branch
). On peut imaginer que les très branches sont effacées périodiquement de tous les dépôts, quand il n'y a plus de souci possible.hg update default
. Ensuite, sans changer notre position dans l'historique, on applique sur nos fichiers les modifs appliquées dans l'autre branche: hg revert -r tip --all
. Enfin, on commit ces modifications en une fois: hg ci -m "Combined."
. Voila, 1 et 2 sont devenus 3:@ changeset: 3:b29ddaf6c31c | tag: tip | parent: 0:11575ff21a29 | user: Alice | date: Tue Jan 11 15:57:58 2011 +0100 | summary: Combined. | | o changeset: 2:c0aa9c6feb0a | | branch: 123-new | | user: Alice | | date: Tue Jan 11 15:47:36 2011 +0100 | | summary: Two. | | | o changeset: 1:23e96c98b90e |/ branch: 123-new | user: Alice | date: Tue Jan 11 15:47:29 2011 +0100 | summary: One. | o changeset: 0:11575ff21a29 user: Alice date: Tue Jan 11 15:08:58 2011 +0100 summary: Initial commit.
hg strip 1
.Libellés : code
#is_ready
method that tells whether the source can produce a sample for the current instant. A source is always ready when it is in the middle of a track. And we have the #get
method which returns at most one sample, none when the current track ends, and should never be called unless the source #is_ready
.#get
, possibly followed by a sample. How do we use that cache: for an operator which already had M end of tracks and performs a #get
, we return an end of track if M<N, the sample otherwise.#is_ready
(rather, rely on the same cache). As with #get
, we need to know the number of end of tracks already obtained by the observer to tell him if the source is ready at that precise point.#get
which may be too ad-hoc. The alternative is to attach an end-of-track tag to the last sample. Looks like a meaningless choice to me.#get
because of metadata. It corresponds to a view where, end of tracks are "after" the last sample, while metadata is "before" or maybe "inside" samples. We should try to generalize this into a nice notion of event, some being interruptions, some not.#simulated_get
method from a simple #get
. This is why compilation is needed now.#is_ready
will be asked not only if a source is ready at a particular point but for how long. This enables a nice frame-based implementation of the precise sum operator described above. Of course, it goes with a #get
that takes not only a start but also a stop position.Libellés : design, liquidsoap
output(fallback([queue,playlist]))
fallback
between our two sources only switches from one to the other for new tracks. For example, if the queue
becomes available while we are in the middle of a playlist
track, we'll keep playing the playlist
track, and only switch to the queue
for the next track. In order to obtain the expected behavior this means that (when possible) unused sources are (almost) frozen in time: the queue
doesn't start playing its request until the fallback
asks it to do so. The stream of a source isn't defined in itself, but computed in interaction with the source's environment. Simply put, it's on-demand streaming.#get
for filling a frame and #is_ready
for knowing if a source has a ready track (ongoing or not).source = fallback([queue,playlist]) output_1(source) output_2(source)This means that at each cycle of the clock, the source will be asked twice to fill a frame with a segment of its stream. Of course, the source should give the same data twice: we don't want to split our stream among the two outputs, one frame each. To deal with this, we have some caching mechanisms in
#get
. In more details, we create new sources by inheriting from a base class which defines #get
as a public method wrapping the virtual private method #get_frame
which can be written without thinking about sharing at all.output( switch([ ({am},fallback([queue,am_playlist]), ({pm},fallback([queue,pm_playlist])]))))Here it looks like the queue is shared, but in fact the first occurrence can only be used in the morning (am), the second only in the afternoon (pm). While we could try to detect some of those cases, it is hopeless to catch them all. So we're bound to over-approximate sharing. This has been done, and isn't too complicated, although it does introduce some activation/deactivation methods that must be used carefully, especially when using transitions. This is okay regarding performance, but it has one nasty side effect: the approximation can have an impact on the stream!
#get
but not #is_ready
. Now, it is possible that a source fills its cache, has no new track to produce, and hence declares itself as not ready. Which might not be correct from the viewpoint of an operator that wants to access the data from the beginning of the cached frame. As a result of this weakness, I recently had to allow what should be illegal behavior in some operators that rely quite precisely on the readiness of their sources. Of course, this is a slippery slope.Libellés : design, liquidsoap
Libellés : design, english, programmation
Random
de Caml.self_init
initialise le générateur de façon très simple, à partir de l'heure et de l'identifiant du processus, données pour le moins aléatoires. Il faut donc vraiment se méfier de cela si on souhaite utiliser le module Random
à des fins cryptographiques. En pratique, le petit bout de code suivant devine assez rapidement la graine générée, en supposant connu l'identifiant du processus (ce n'est pas bien dur à deviner sinon) et en supposant approximativement connue l'heure de l'initialisation:(** Random.self_init relies on caml_sys_random_seed * which returns an int. * That integer is sec ^ usec ^ ppid<<16 ^ pid. * We try to guess the seed to reproduce the output of * the random generator. * The PID and PPID are supposed to be known, * the time in seconds and micro-seconds is supposed * to be known resp. with precision 1s and 1000ms. * With that knowledge it's really fast; * with less it'd take longer. *) let gen sec usec pid ppid = sec lxor usec lxor pid lxor (ppid lsl 16) let random _ = Random.int 100 (** Given a leaked sequence of numbers consecutively * generated by [random] _immediately after_ * [Random.self_init], call [k] with seeds that allow * to reproduce that sequence. *) let crack leak k = let t = Unix.gettimeofday () in let sec = int_of_float t in let usec = int_of_float (fst (modf t) *. 1_000_000.) in let pid = Unix.getpid () in let ppid = Unix.getppid () in (* Since we sec and usec are xored, trying sec and * sec-1 would be useless: all we'd be doing is * flipping a bit that is flipped anyway when * enumerating posssible values for usec. *) for usec = usec - 10000 to usec do let seed = gen sec usec pid ppid in Random.init seed ; if Array.init (Array.length leak) random = leak then k seed done let () = let leak,valid = Random.self_init () ; let leak = Array.init 1000 random in let valid = Array.init 5000 random in leak, valid in let k seed = let guess = Random.init seed ; ignore (Array.init (Array.length leak) random) ; Array.init (Array.length valid) random in Printf.printf "Guessed seed: %d. Validated: %b.\n" seed (guess=valid) in crack leak k ; Printf.printf "Search space exhausted.\n"
$ ocamlopt unix.cmxa crack.ml -o crack && ./crack Guessed seed: 262818353. Validated: true. Search space exhausted.
Libellés : ocaml
Libellés : internet