]> git.pld-linux.org Git - packages/xv.git/blame - xv-libpng-1.5.patch
- added jasper patch (don't use internal functions or hacks)
[packages/xv.git] / xv-libpng-1.5.patch
CommitLineData
e015b08c
JR
1$OpenBSD: patch-xvpng_c,v 1.2 2011/08/29 18:07:44 espie Exp $
2
3Fix build with png-1.5.
4
5--- xvpng.c.orig Mon May 14 02:53:28 2007
6+++ xvpng.c Mon Aug 29 15:05:31 2011
7@@ -31,6 +31,7 @@
8
9 #ifdef HAVE_PNG
10
11+#include "zlib.h"
12 #include "png.h"
13
14 /*** Stuff for PNG Dialog box ***/
15@@ -41,7 +42,7 @@
16 #define COMPRESSION 6 /* default zlib compression level, not max
17 (Z_BEST_COMPRESSION) */
18
19-#define HAVE_tRNS (info_ptr->valid & PNG_INFO_tRNS)
20+#define HAVE_tRNS (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
21
22 #define DWIDE 86
23 #define DHIGH 104
24@@ -435,6 +436,16 @@ int WritePNG(fp, pic, ptype, w, h, rmap, gmap, bmap, n
25 {
26 png_struct *png_ptr;
27 png_info *info_ptr;
28+ struct {
29+ /* IHDR */
30+ png_uint_32 width;
31+ png_uint_32 height;
32+ int bit_depth;
33+ int color_type;
34+ int interlace_type;
35+ /* PLTE */
36+ int use_palette;
37+ } info_tmp;
38 png_color palette[256];
39 png_textp text;
40 byte r1[256], g1[256], b1[256]; /* storage for deduped palette */
41@@ -444,6 +455,7 @@ int WritePNG(fp, pic, ptype, w, h, rmap, gmap, bmap, n
42 byte *p, *png_line;
43 char software[256];
44 char *savecmnt;
45+ int num_text, max_text;
46
47 if ((png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,
48 png_xv_error, png_xv_warning)) == NULL) {
49@@ -458,7 +470,7 @@ int WritePNG(fp, pic, ptype, w, h, rmap, gmap, bmap, n
50 FatalError(software);
51 }
52
53- if (setjmp(png_ptr->jmpbuf)) {
54+ if (setjmp(png_jmpbuf(png_ptr))) {
55 png_destroy_write_struct(&png_ptr, &info_ptr);
56 return -1;
57 }
58@@ -489,8 +501,8 @@ int WritePNG(fp, pic, ptype, w, h, rmap, gmap, bmap, n
59 png_set_filter(png_ptr, 0, filter);
60 }
61
62- info_ptr->width = w;
63- info_ptr->height = h;
64+ info_tmp.width = w;
65+ info_tmp.height = h;
66 if (w <= 0 || h <= 0) {
67 SetISTR(ISTR_WARNING, "%s: image dimensions out of range (%dx%d)",
68 fbasename, w, h);
69@@ -498,7 +510,8 @@ int WritePNG(fp, pic, ptype, w, h, rmap, gmap, bmap, n
70 return -1;
71 }
72
73- info_ptr->interlace_type = interCB.val ? 1 : 0;
74+ info_tmp.interlace_type =
75+ interCB.val ? PNG_INTERLACE_ADAM7 : PNG_INTERLACE_NONE;
76
77 linesize = 0; /* quiet a compiler warning */
78
79@@ -542,40 +555,40 @@ int WritePNG(fp, pic, ptype, w, h, rmap, gmap, bmap, n
80 png_destroy_write_struct(&png_ptr, &info_ptr);
81 return -1;
82 }
83- info_ptr->color_type = PNG_COLOR_TYPE_RGB;
84- info_ptr->bit_depth = 8;
85+ info_tmp.color_type = PNG_COLOR_TYPE_RGB;
86+ info_tmp.bit_depth = 8;
87+ info_tmp.use_palette = 0;
88 } else /* ptype == PIC8 */ {
89 linesize = w;
90- info_ptr->color_type = PNG_COLOR_TYPE_PALETTE;
91+ info_tmp.color_type = PNG_COLOR_TYPE_PALETTE;
92 if (numuniqcols <= 2)
93- info_ptr->bit_depth = 1;
94+ info_tmp.bit_depth = 1;
95 else
96 if (numuniqcols <= 4)
97- info_ptr->bit_depth = 2;
98+ info_tmp.bit_depth = 2;
99 else
100 if (numuniqcols <= 16)
101- info_ptr->bit_depth = 4;
102+ info_tmp.bit_depth = 4;
103 else
104- info_ptr->bit_depth = 8;
105+ info_tmp.bit_depth = 8;
106
107 for (i = 0; i < numuniqcols; i++) {
108 palette[i].red = r1[i];
109 palette[i].green = g1[i];
110 palette[i].blue = b1[i];
111 }
112- info_ptr->num_palette = numuniqcols;
113- info_ptr->palette = palette;
114- info_ptr->valid |= PNG_INFO_PLTE;
115+ info_tmp.use_palette = 1;
116 }
117 }
118
119 else if (colorType == F_GREYSCALE || colorType == F_BWDITHER) {
120- info_ptr->color_type = PNG_COLOR_TYPE_GRAY;
121+ info_tmp.color_type = PNG_COLOR_TYPE_GRAY;
122+ info_tmp.use_palette = 0;
123 if (colorType == F_BWDITHER) {
124 /* shouldn't happen */
125 if (ptype == PIC24) FatalError("PIC24 and B/W Stipple in WritePNG()");
126
127- info_ptr->bit_depth = 1;
128+ info_tmp.bit_depth = 1;
129 if (MONO(r1[0], g1[0], b1[0]) > MONO(r1[1], g1[1], b1[1])) {
130 remap[0] = 1;
131 remap[1] = 0;
132@@ -595,7 +608,7 @@ int WritePNG(fp, pic, ptype, w, h, rmap, gmap, bmap, n
133 png_destroy_write_struct(&png_ptr, &info_ptr);
134 return -1;
135 }
136- info_ptr->bit_depth = 8;
137+ info_tmp.bit_depth = 8;
138 }
139 else /* ptype == PIC8 */ {
140 int low_precision;
141@@ -617,7 +630,7 @@ int WritePNG(fp, pic, ptype, w, h, rmap, gmap, bmap, n
142 for (; i < 256; i++)
143 remap[i]=0; /* shouldn't be necessary, but... */
144
145- info_ptr->bit_depth = 8;
146+ info_tmp.bit_depth = 8;
147
148 /* Note that this fails most of the time because of gamma */
149 /* (and that would be a bug: GRR FIXME) */
150@@ -636,7 +649,7 @@ int WritePNG(fp, pic, ptype, w, h, rmap, gmap, bmap, n
151 for (i = 0; i < numuniqcols; i++) {
152 remap[i] &= 0xf;
153 }
154- info_ptr->bit_depth = 4;
155+ info_tmp.bit_depth = 4;
156
157 /* try to adjust to 2-bit precision grayscale */
158
159@@ -652,7 +665,7 @@ int WritePNG(fp, pic, ptype, w, h, rmap, gmap, bmap, n
160 for (i = 0; i < numuniqcols; i++) {
161 remap[i] &= 3;
162 }
163- info_ptr->bit_depth = 2;
164+ info_tmp.bit_depth = 2;
165
166 /* try to adjust to 1-bit precision grayscale */
167
168@@ -668,7 +681,7 @@ int WritePNG(fp, pic, ptype, w, h, rmap, gmap, bmap, n
169 for (i = 0; i < numuniqcols; i++) {
170 remap[i] &= 1;
171 }
172- info_ptr->bit_depth = 1;
173+ info_tmp.bit_depth = 1;
174 }
175 }
176 }
177@@ -677,6 +690,20 @@ int WritePNG(fp, pic, ptype, w, h, rmap, gmap, bmap, n
178 else
179 png_error(png_ptr, "Unknown colorstyle in WritePNG");
180
181+ png_set_IHDR(png_ptr, info_ptr,
182+ info_tmp.width, info_tmp.height,
183+ info_tmp.bit_depth, info_tmp.color_type,
184+ info_tmp.interlace_type, PNG_COMPRESSION_TYPE_BASE,
185+ PNG_FILTER_TYPE_BASE);
186+ if (info_tmp.use_palette) {
187+ /*
188+ * info_ptr->num_palette = numuniqcols;
189+ * info_ptr->palette = palette;
190+ * info_ptr->valid |= PNG_INFO_PLTE;
191+ */
192+ png_set_PLTE(png_ptr, info_ptr, palette, numuniqcols);
193+ }
194+
195 if ((text = (png_textp)malloc(sizeof(png_text)))) {
196 sprintf(software, "XV %s", REVDATE);
197
198@@ -684,21 +711,29 @@ int WritePNG(fp, pic, ptype, w, h, rmap, gmap, bmap, n
199 text->key = "Software";
200 text->text = software;
201 text->text_length = strlen(text->text);
202+ text->lang = NULL;
203
204- info_ptr->max_text = 1;
205- info_ptr->num_text = 1;
206- info_ptr->text = text;
207+ /*
208+ * info_ptr->max_text = 1;
209+ * info_ptr->num_text = 1;
210+ * info_ptr->text = text;
211+ */
212+ png_set_text(png_ptr, info_ptr, text, 1);
213+ num_text = max_text = 1;
214 }
215
216 Display_Gamma = gDial.val; /* Save the current gamma for loading */
217
218 // GRR FIXME: add .Xdefaults option to omit writing gamma (size, cumulative errors when editing)--alternatively, modify save box to include "omit" checkbox
219- info_ptr->gamma = 1.0/gDial.val;
220- info_ptr->valid |= PNG_INFO_gAMA;
221+ /*
222+ * info_ptr->gamma = 1.0/gDial.val;
223+ * info_ptr->valid |= PNG_INFO_gAMA;
224+ */
225+ png_set_gAMA(png_ptr, info_ptr, 1.0/gDial.val);
226
227 png_write_info(png_ptr, info_ptr);
228
229- if (info_ptr->bit_depth < 8)
230+ if (info_tmp.bit_depth < 8)
231 png_set_packing(png_ptr);
232
233 pass=png_set_interlace_handling(png_ptr);
234@@ -711,13 +746,13 @@ int WritePNG(fp, pic, ptype, w, h, rmap, gmap, bmap, n
235 int j;
236 p = pic;
237 for (j = 0; j < h; ++j) {
238- if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY) {
239+ if (info_tmp.color_type == PNG_COLOR_TYPE_GRAY) {
240 int k;
241 for (k = 0; k < w; ++k)
242 png_line[k] = ptype==PIC24 ? MONO(p[k*3], p[k*3+1], p[k*3+2]) :
243 remap[pc2nc[p[k]]];
244 png_write_row(png_ptr, png_line);
245- } else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) {
246+ } else if (info_tmp.color_type == PNG_COLOR_TYPE_PALETTE) {
247 int k;
248 for (k = 0; k < w; ++k)
249 png_line[k] = pc2nc[p[k]];
250@@ -743,24 +778,26 @@ int WritePNG(fp, pic, ptype, w, h, rmap, gmap, bmap, n
251 strcpy(savecmnt, picComments);
252 key = savecmnt;
253 tp = text;
254- info_ptr->num_text = 0;
255
256+ png_free_data(png_ptr, info_ptr, PNG_FREE_TEXT, -1);
257+ num_text = 0;
258+
259 comment = strchr(key, ':');
260
261 do {
262 /* Allocate a larger structure for comments if necessary */
263- if (info_ptr->num_text >= info_ptr->max_text)
264+ if (num_text >= max_text)
265 {
266 if ((tp =
267- realloc(text, (info_ptr->num_text + 2)*sizeof(png_text))) == NULL)
268+ realloc(text, (num_text + 2)*sizeof(png_text))) == NULL)
269 {
270 break;
271 }
272 else
273 {
274 text = tp;
275- tp = &text[info_ptr->num_text];
276- info_ptr->max_text += 2;
277+ tp = &text[num_text];
278+ max_text += 2;
279 }
280 }
281
282@@ -810,7 +847,7 @@ int WritePNG(fp, pic, ptype, w, h, rmap, gmap, bmap, n
283 }
284
285 tp->compression = tp->text_length > 640 ? 0 : -1;
286- info_ptr->num_text++;
287+ num_text++;
288 tp++;
289 }
290 }
291@@ -834,27 +871,29 @@ int WritePNG(fp, pic, ptype, w, h, rmap, gmap, bmap, n
292 tp->text = key;
293 tp->text_length = q - key;
294 tp->compression = tp->text_length > 750 ? 0 : -1;
295- info_ptr->num_text++;
296+ num_text++;
297 key = NULL;
298 }
299 } while (key && *key);
300+ png_set_text(png_ptr, info_ptr, text, num_text);
301 }
302 else {
303- info_ptr->num_text = 0;
304+ png_free_data(png_ptr, info_ptr, PNG_FREE_TEXT, -1);
305 }
306 }
307- info_ptr->text = text;
308
309- png_convert_from_time_t(&(info_ptr->mod_time), time(NULL));
310- info_ptr->valid |= PNG_INFO_tIME;
311+ {
312+ png_time mod_time;
313
314+ png_convert_from_time_t(&mod_time, time(NULL));
315+ png_set_tIME(png_ptr, info_ptr, &mod_time);
316+ }
317+
318 png_write_end(png_ptr, info_ptr);
319 fflush(fp); /* just in case we core-dump before finishing... */
320
321 if (text) {
322 free(text);
323- /* must do this or png_destroy_write_struct() 0.97+ will free text again: */
324- info_ptr->text = (png_textp)NULL;
325 if (savecmnt)
326 {
327 free(savecmnt);
328@@ -886,6 +925,8 @@ int LoadPNG(fname, pinfo)
329 int pass;
330 int gray_to_rgb;
331 size_t commentsize;
332+ png_textp text;
333+ int num_text;
334
335 fbasename = BaseName(fname);
336
337@@ -921,7 +962,7 @@ int LoadPNG(fname, pinfo)
338 FatalError("malloc failure in LoadPNG");
339 }
340
341- if (setjmp(png_ptr->jmpbuf)) {
342+ if (setjmp(png_jmpbuf(png_ptr))) {
343 fclose(fp);
344 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
345 if (!read_anything) {
346@@ -945,8 +986,8 @@ int LoadPNG(fname, pinfo)
347 #endif
348 png_read_info(png_ptr, info_ptr);
349
350- pinfo->w = pinfo->normw = info_ptr->width;
351- pinfo->h = pinfo->normh = info_ptr->height;
352+ pinfo->w = pinfo->normw = png_get_image_width(png_ptr, info_ptr);
353+ pinfo->h = pinfo->normh = png_get_image_height(png_ptr, info_ptr);
354 if (pinfo->w <= 0 || pinfo->h <= 0) {
355 SetISTR(ISTR_WARNING, "%s: image dimensions out of range (%dx%d)",
356 fbasename, pinfo->w, pinfo->h);
357@@ -957,9 +998,9 @@ int LoadPNG(fname, pinfo)
358 pinfo->frmType = F_PNG;
359
360 sprintf(pinfo->fullInfo, "PNG, %d bit ",
361- info_ptr->bit_depth * info_ptr->channels);
362+ png_get_bit_depth(png_ptr,info_ptr) * png_get_channels(png_ptr, info_ptr));
363
364- switch(info_ptr->color_type) {
365+ switch(png_get_color_type(png_ptr, info_ptr)) {
366 case PNG_COLOR_TYPE_PALETTE:
367 strcat(pinfo->fullInfo, "palette color");
368 break;
369@@ -983,15 +1024,20 @@ int LoadPNG(fname, pinfo)
370
371 sprintf(pinfo->fullInfo + strlen(pinfo->fullInfo),
372 ", %sinterlaced. (%d bytes)",
373- info_ptr->interlace_type ? "" : "non-", filesize);
374+ png_get_interlace_type(png_ptr, info_ptr) ? "" : "non-", filesize);
375
376- sprintf(pinfo->shrtInfo, "%lux%lu PNG", info_ptr->width, info_ptr->height);
377+ sprintf(pinfo->shrtInfo, "%lux%lu PNG",
378+ png_get_image_width(png_ptr, info_ptr),
379+ png_get_image_height(png_ptr, info_ptr));
380
381- if (info_ptr->bit_depth < 8)
382+ if (png_get_bit_depth(png_ptr, info_ptr) < 8)
383 png_set_packing(png_ptr);
384
385- if (info_ptr->valid & PNG_INFO_gAMA)
386- png_set_gamma(png_ptr, Display_Gamma, info_ptr->gamma);
387+ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_gAMA)) {
388+ double gamma;
389+ png_get_gAMA(png_ptr, info_ptr, &gamma);
390+ png_set_gamma(png_ptr, Display_Gamma, gamma);
391+ }
392 /*
393 *else
394 * png_set_gamma(png_ptr, Display_Gamma, 0.45);
395@@ -1000,7 +1046,7 @@ int LoadPNG(fname, pinfo)
396 gray_to_rgb = 0; /* quiet a compiler warning */
397
398 if (have_imagebg) {
399- if (info_ptr->bit_depth == 16) {
400+ if (png_get_bit_depth(png_ptr, info_ptr) == 16) {
401 my_background.red = imagebgR;
402 my_background.green = imagebgG;
403 my_background.blue = imagebgB;
404@@ -1013,8 +1059,8 @@ int LoadPNG(fname, pinfo)
405 }
406 png_set_background(png_ptr, &my_background, PNG_BACKGROUND_GAMMA_SCREEN,
407 0, Display_Gamma);
408- if ((info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
409- (info_ptr->color_type == PNG_COLOR_TYPE_GRAY && HAVE_tRNS)) &&
410+ if ((png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_GRAY_ALPHA ||
411+ (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_GRAY && HAVE_tRNS)) &&
412 (imagebgR != imagebgG || imagebgR != imagebgB)) /* i.e., colored bg */
413 {
414 png_set_gray_to_rgb(png_ptr);
415@@ -1022,8 +1068,10 @@ int LoadPNG(fname, pinfo)
416 gray_to_rgb = 1;
417 }
418 } else {
419- if (info_ptr->valid & PNG_INFO_bKGD) {
420- png_set_background(png_ptr, &info_ptr->background,
421+ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD)) {
422+ png_color_16p background;
423+ png_get_bKGD(png_ptr, info_ptr, &background);
424+ png_set_background(png_ptr, background,
425 PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
426 } else {
427 my_background.red = my_background.green = my_background.blue =
428@@ -1033,13 +1081,13 @@ int LoadPNG(fname, pinfo)
429 }
430 }
431
432- if (info_ptr->bit_depth == 16)
433+ if (png_get_bit_depth(png_ptr, info_ptr) == 16)
434 png_set_strip_16(png_ptr);
435
436- if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY ||
437- info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
438+ if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_GRAY ||
439+ png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_GRAY_ALPHA)
440 {
441- if (info_ptr->bit_depth == 1)
442+ if (png_get_bit_depth(png_ptr, info_ptr) == 1)
443 pinfo->colType = F_BWDITHER;
444 else
445 pinfo->colType = F_GREYSCALE;
446@@ -1050,8 +1098,8 @@ int LoadPNG(fname, pinfo)
447
448 png_read_update_info(png_ptr, info_ptr);
449
450- if (info_ptr->color_type == PNG_COLOR_TYPE_RGB ||
451- info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA || gray_to_rgb)
452+ if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_RGB ||
453+ png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_RGB_ALPHA || gray_to_rgb)
454 {
455 linesize = 3 * pinfo->w;
456 if (linesize/3 < pinfo->w) { /* know pinfo->w > 0 (see above) */
457@@ -1065,16 +1113,20 @@ int LoadPNG(fname, pinfo)
458 } else {
459 linesize = pinfo->w;
460 pinfo->type = PIC8;
461- if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY ||
462- info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
463+ if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_GRAY ||
464+ png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_GRAY_ALPHA) {
465 for (i = 0; i < 256; i++)
466 pinfo->r[i] = pinfo->g[i] = pinfo->b[i] = i;
467 } else {
468+ png_colorp palette;
469+ int num_palette;
470+
471+ png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
472 pinfo->colType = F_FULLCOLOR;
473- for (i = 0; i < info_ptr->num_palette; i++) {
474- pinfo->r[i] = info_ptr->palette[i].red;
475- pinfo->g[i] = info_ptr->palette[i].green;
476- pinfo->b[i] = info_ptr->palette[i].blue;
477+ for (i = 0; i < num_palette; i++) {
478+ pinfo->r[i] = palette[i].red;
479+ pinfo->g[i] = palette[i].green;
480+ pinfo->b[i] = palette[i].blue;
481 }
482 }
483 }
484@@ -1092,7 +1144,17 @@ int LoadPNG(fname, pinfo)
485 png_error(png_ptr, "can't allocate space for PNG image");
486 }
487
488- png_start_read_image(png_ptr);
489+ /*
490+ * In png 1.5 (or at least 1.5.1beta06) calling this after calling
491+ * png_read_update_info() does nothing besides issue a misleading
492+ * warning message. The png docs are not at all clear on what an
493+ * application is *supposed* to do, so I'm not sure if this is a
494+ * problem with xv or with libpng. However, for now I'll comment
495+ * this out as according to the png source that should be harmless
496+ * and we don't want to see the warning message every time someone
497+ * opens a png.
498+ */
499+ /*png_start_read_image(png_ptr);*/
500
501 for (i = 0; i < pass; i++) {
502 byte *p = pinfo->pic;
503@@ -1106,22 +1168,24 @@ int LoadPNG(fname, pinfo)
504
505 png_read_end(png_ptr, info_ptr);
506
507- if (info_ptr->num_text > 0) {
508+ png_get_text(png_ptr, info_ptr, &text, &num_text);
509+ if (num_text > 0) {
510 commentsize = 1;
511
512- for (i = 0; i < info_ptr->num_text; i++)
513- commentsize += strlen(info_ptr->text[i].key) + 1 +
514- info_ptr->text[i].text_length + 2;
515+ for (i = 0; i < num_text; i++)
516+ commentsize += strlen(text[i].key) + 1 +
517+ text[i].text_length + 2;
518
519 if ((pinfo->comment = malloc(commentsize)) == NULL) {
520 png_warning(png_ptr,"can't allocate comment string");
521 }
522 else {
523 pinfo->comment[0] = '\0';
524- for (i = 0; i < info_ptr->num_text; i++) {
525- strcat(pinfo->comment, info_ptr->text[i].key);
526+ for (i = 0; i < num_text; i++) {
527+ strcat(pinfo->comment, text[i].key);
528 strcat(pinfo->comment, "::");
529- strcat(pinfo->comment, info_ptr->text[i].text);
530+ if (text[i].text_length != 0)
531+ strcat(pinfo->comment, text[i].text);
532 strcat(pinfo->comment, "\n");
533 }
534 }
535@@ -1143,7 +1207,7 @@ png_xv_error(png_ptr, message)
536 {
537 SetISTR(ISTR_WARNING,"%s: libpng error: %s", fbasename, message);
538
539- longjmp(png_ptr->jmpbuf, 1);
540+ longjmp(png_jmpbuf(png_ptr), 1);
541 }
542
543
This page took 0.122846 seconds and 4 git commands to generate.