1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
(** Computing information from articles. *)
open Types;;
open Filter_types;;
module XR = Xtmpl.Rewrite
module Xml = Xtmpl.Xml
let is_archived_doc stog =
match Types.get_def stog.stog_defs ("","archived-docs") with
| Some (_,[XR.D cdata]) ->
let types = Stog_base.Misc.split_string cdata.Xtmpl.Types.text [',' ; ';'] in
let types = List.map Stog_base.Misc.strip_string types in
(fun doc_id -> let doc = Types.doc stog doc_id in List.mem doc.doc_type types)
| _ ->
(fun _ -> true)
;;
let compute_map f_words f_update stog =
let f doc_id doc map =
let on_word map w =
let set =
try Types.Str_map.find w map
with Not_found -> Types.Doc_set.empty
in
let set = Types.Doc_set.add doc_id set in
Types.Str_map.add w set map
in
List.fold_left on_word map (f_words doc)
in
f_update stog
(Tmap.fold f stog.stog_docs Types.Str_map.empty)
;;
let compute_topic_map stog =
compute_map
(fun a -> a.doc_topics)
(fun stog map -> { stog with stog_docs_by_topic = map })
stog
;;
let compute_keyword_map stog =
compute_map
(fun a -> a.doc_keywords)
(fun stog map -> { stog with stog_docs_by_kw = map })
stog
;;
let compute_graph_with_dates stog =
let is_archived = is_archived_doc stog in
let pred (doc_id, _) = is_archived doc_id in
let docs = Types.doc_list ~by_date:true stog in
let docs = List.filter pred docs in
let g = Types.Graph.create () in
let rec iter g = function
[] | [_] -> g
| (doc_id, _) :: (next_id, next) :: q ->
let g = Types.Graph.add g (doc_id, next_id, Types.Date) in
iter g ((next_id, next) :: q)
in
{ stog with stog_graph = iter g docs }
;;
let next_by_date f_next stog art_id =
let next = f_next stog.stog_graph art_id in
let next = List.filter (function (_,Types.Date) -> true | _ -> false) next in
match next with
[] -> None
| (id,_) :: _ -> Some id
let succ_by_date = next_by_date Types.Graph.succ;;
let pred_by_date = next_by_date Types.Graph.pred;;
let add_words_in_graph stog f edge_data =
let get_last table word =
try Some(Types.Str_map.find word table)
with Not_found -> None
in
let roots = Types.Graph.pred_roots stog.stog_graph in
let add_for_node g table id =
let words = f id in
let g =
List.fold_left
(fun g word ->
match get_last table word with
None -> g
| Some id0 ->
Types.Graph.add g (id0, id, (edge_data word))
)
g
words
in
let table =
List.fold_left
(fun t word ->
Types.Str_map.add word id t)
table words
in
(g, table)
in
let rec f (g, table) id =
let (g, table) = add_for_node g table id in
let succs = Types.Graph.succ g id in
let succs = List.filter
(fun (_,data) -> data = Date) succs
in
let succs = Stog_base.Misc.list_remove_doubles
(List.map fst succs)
in
List.fold_left f (g, table) succs
in
let (g, _) = List.fold_left f
(stog.stog_graph, Types.Str_map.empty)
roots
in
{ stog with stog_graph = g }
;;
let add_topics_in_graph stog =
add_words_in_graph stog
(fun id ->
let doc = Types.doc stog id in
doc.doc_topics
)
;;
let add_keywords_in_graph stog =
add_words_in_graph stog
(fun id ->
let doc = Types.doc stog id in
doc.doc_keywords
)
;;
let add_refs_in_graph stog = stog
;;
let compute_archives stog =
let pred = is_archived_doc stog in
let f_mon doc_id m mmap =
let set =
try Types.Int_map.find m mmap
with Not_found -> Types.Doc_set.empty
in
let set = Types.Doc_set.add doc_id set in
let set = Types.Doc_set.filter pred set in
match Types.Doc_set.is_empty set with
true -> mmap
| false -> Types.Int_map.add m set mmap
in
let f_art doc_id doc ymap =
match doc.doc_date with
None -> ymap
| Some dt ->
let ((year, month, _), _) = Date.to_date_time dt in
let mmap =
try Types.Int_map.find year ymap
with Not_found -> Types.Int_map.empty
in
let mmap = f_mon doc_id month mmap in
Types.Int_map.add year mmap ymap
in
let arch = Tmap.fold f_art
stog.stog_docs Types.Int_map.empty
in
{ stog with stog_archives = arch }
;;
let color_of_text s =
let len = String.length s in
let r = ref 0 in
for i = 0 to len - 1 do
r := !r + Char.code s.[i]
done;
let g = ref 0 in
for i = 0 to len - 1 do
g := !g + (abs (lnot (Char.code s.[i])))
done;
let b = ref 0 in
for i = 0 to len - 1 do
b := !b + ((Char.code s.[i]) lsl 2)
done;
let (br, bg, bb) =
if len <= 2 then
(true, true, true)
else
((Char.code s.[0]) land 5 > 0,
(Char.code s.[1]) land 5 > 0,
(Char.code s.[2]) land 5 > 0)
in
((if br then 20 + !r mod 180 else 0),
(if bg then 20 + !g mod 180 else 0),
(if bb then 20 + !b mod 180 else 0))
;;
let dot_of_graph f_href stog =
let g =
Types.Graph.fold_succ
stog.stog_graph
(fun id succs g ->
List.fold_left
(fun g (id2, edge) ->
match edge with
Date -> g
| d -> Types.Graph.add g (id, id2, d)
)
g succs
)
(Types.Graph.create ())
in
let f_edge = function
Date -> assert false
| Topic word | Keyword word ->
let (r,g,b) = color_of_text word in
let col = Printf.sprintf "#%02x%02x%02x" r g b in
(word, ["fontcolor", col ; "color", col])
| Ref ->
("", ["style", "dashed"])
in
let f_node id =
let doc = Types.doc stog id in
let col =
match doc.doc_topics with
[] -> "black"
| w :: _ ->
let (r,g,b) = color_of_text w in
Printf.sprintf "#%02x%02x%02x" r g b
in
let href = f_href doc in
(Printf.sprintf "id%d" (Tmap.int id),
doc.doc_title,
["shape", "rect"; "color", col; "fontcolor", col;
"href", Url.to_string href])
in
Types.Graph.dot_of_graph ~f_edge ~f_node g
;;
let compute stog =
let stog = compute_keyword_map stog in
let stog = compute_topic_map stog in
let stog = compute_graph_with_dates stog in
let stog = add_topics_in_graph stog (fun w -> Types.Topic w) in
let stog = add_keywords_in_graph stog (fun w -> Types.Keyword w) in
let stog = add_refs_in_graph stog in
let stog = compute_archives stog in
stog
;;
let rec doc_verifies doc = function
| Or (f1, f2) -> (doc_verifies doc f1) || (doc_verifies doc f2)
| And (f1, f2) -> (doc_verifies doc f1) && (doc_verifies doc f2)
| Not f -> not (doc_verifies doc f)
| Pred (("","set"), name) -> List.mem name doc.doc_sets
| Pred (("","keyword"), name) -> List.mem name doc.doc_keywords
| Pred (("","topic"), name) -> List.mem name doc.doc_topics
| Pred (("","type"), v) -> doc.doc_type = v
| Pred (name, v) ->
match Types.get_def doc.doc_defs name with
None -> v = ""
| Some (_, body) ->
let s = XR.to_string body in
v = s
;;
let remove_not_published stog =
let pred =
match stog.stog_publish_only with
None -> (fun _ -> true)
| Some f -> (fun doc -> doc_verifies doc f)
in
let (docs, removed) = Tmap.fold
(fun id doc (acc, removed) ->
if pred doc then
(acc, removed)
else
(Tmap.remove acc id, doc.doc_path :: removed)
)
stog.stog_docs
(stog.stog_docs, [])
in
let stog = Tmap.fold
(fun doc_id doc stog ->
Types.add_path stog doc.doc_path doc_id)
docs { stog with stog_docs_by_path = Types.Path_trie.empty }
in
{ stog with
stog_docs = docs ;
}
;;