asciinema / asciicast2gif Goto Github PK
View Code? Open in Web Editor NEWGenerate GIF animations from asciicasts (asciinema recordings)
License: MIT License
Generate GIF animations from asciicasts (asciinema recordings)
License: MIT License
PhantomJS's page.render
method support second argument, an options object where it's possible to specify quality:
page.render(imagePath, { quality: 100 });
For PNG quality means compression, and with 100
it generates PNG files the fastest, with least/no compression.
This may speed up PNG generation, as it doesn't compress, but at the same time it may slow it down, as bigger PNG files need to be saved to disk, and disk I/O is slow. Needs benchmarking.
Perhaps one of these could be used instead:
https://github.com/GoogleChrome/puppeteer
https://github.com/joelgriffith/browserless
When I try to install asciicast2gif locally (though a convoluted way to build a system package), the following occurs:
~ > asciicast2gif https://asciinema.org/a/118274.json demo.gif (workstation|✔)
==> Loading https://asciinema.org/a/118274.json...
==> Spawning PhantomJS renderer...
/usr/lib/node_modules/asciicast2gif/main.js:696
return new Zo(a,Qe)}function ap(a){try{var b=a[0];return b.h?b.h(a):b.call(null,a)}catch(c){if(c instanceof Object)throw b=c,Uo(a[6]),b;throw c;}}function bp(a,b,c){c=Vo(c,$o(function(c){a[2]=c;a[1]=b;return ap(a)}));return r(c)?(a[2]=Ob(c),a[1]=b,bj):null}function cp(a,b){a=a[6];null!=b&&a.Dc(null,b,$o(function(){return function(){return null}}(a)));Uo(a);return a}
^
TypeError [ERR_INVALID_ARG_TYPE]: The "file" argument must be of type string. Received type object
at normalizeSpawnArguments (child_process.js:397:11)
at spawn (child_process.js:522:38)
at Function.exports.exec (/usr/lib/node_modules/asciicast2gif/node_modules/phantomjs-prebuilt/lib/phantomjs.js:72:10)
at Le (/usr/lib/node_modules/asciicast2gif/main.js:262:219)
at Ke (/usr/lib/node_modules/asciicast2gif/main.js:261:410)
at Je (/usr/lib/node_modules/asciicast2gif/main.js:261:320)
at Ie (/usr/lib/node_modules/asciicast2gif/main.js:261:238)
at Me (/usr/lib/node_modules/asciicast2gif/main.js:266:230)
at tp (/usr/lib/node_modules/asciicast2gif/main.js:704:224)
at /usr/lib/node_modules/asciicast2gif/main.js:710:373
When I tried building PhantomJS locally, the build failed.
It does work fine via Docker.
Take a look at this GIF, it goes on FOR MINUTES and it's only 32 kb:
https://github.com/tianon/gosleep/blob/master/example.gif
I'm curious why we can't we have this minimality with asciicast2gif
? My 30 second recording is 964 kilobytes.
Is there a way to minimalize this? I don't care about antialiasing and all those fancy stuff making the image larger.
Inspecting main.cljs, I think that I need to provide an options object to the http client object.
(defn- http-get [url ch]
(let [proto (-> url (str/split #":") first)
gunzip (.createGunzip zlib)
client (nodejs/require proto)]
(.get client url (fn [res]
[...]
I should be able to generically attach the rejectUnauthorized parameter within an options object with a default value of true. I can't figure out the syntax to accomplish this.
Any hints on the best way to proceed?
-s
or --speed
arg can be added and passed to node script.
This "─ " character is used by tmux to separate panes. When I convert this using asciicast2gif, I lose this character, and it appears as empty/space.
I have a demo where a tree is rendered with unicode, the tree is not visible in the generated gif.
WARNING: I could be completely wrong here and my javascript is not good so I haven't checked.
The 'idle_time_limit' function of asciinema rec is not working when I use asciicast2gif from the resulting json file. I just went through and retimed my recording manually to work around the problem.
Running
$ docker run --memory $(( 1024 * 1024 * 1024 )) --volume /var/tmp/demo:/data --cpus 1 asciinema/asciicast2gif demo.json demo.gif
==> Loading demo.json...
==> Spawning PhantomJS renderer...
==> Generating frame screenshots...
==> Combining screenshots into GIF file...
gifsicle:<stdin>: empty file
Killed
/app/main.js:697
return new yp(a,Oe)}function Ap(a){try{var b=a[0];return b.h?b.h(a):b.call(null,a)}catch(c){if(c instanceof Object)throw b=c,tp(a[6]),b;throw c;}}function Bp(a,b,c){c=up(c,zp(function(c){a[2]=c;a[1]=b;return Ap(a)}));return t(c)?(a[2]=Gb(c),a[1]=b,ej):null}function Cp(a,b){var c=a[6];null!=b&&c.Jc(0,b,zp(function(){return function(){return null}}(c)));tp(c);return c}
Error: Command failed: convert -loop 0 -delay 3 /tmp/tmp.RFGokXCDrf/0.png -delay 196 /tmp/tmp.RFGokXCDrf/1.png [...] -delay 100 /tmp/tmp.RFGokXCDrf/2218.png -layers Optimize gif:- | gifsicle -k 32 -O2 -Okeep-empty -o demo.gif -
gifsicle:<stdin>: empty file
Killed
at checkExecSyncError (child_process.js:472:13)
at Object.execSync (child_process.js:512:13)
at /app/main.js:711:275
at Function.b (/app/main.js:707:233)
at Ap (/app/main.js:697:64)
at /app/main.js:697:209
at /app/main.js:691:10
at Immediate.kp (/app/main.js:687:320)
at runCallback (timers.js:672:20)
at tryOnImmediate (timers.js:645:5)
The same works with a shorter recording.
Following the Docker example in the readme I get this "no space left" error, when my disk has > 200GB remaining:
[ ~/Downloads ] docker run --rm -v $PWD:/data asciinema/asciicast2gif -t solarized-dark 134369.json demo.gif
==> Loading 134369.json...
==> Spawning PhantomJS renderer...
==> Generating frame screenshots...
==> Combining screenshots into GIF file...
convert: unable to write pixel cache `/tmp/magick-26AFqOawtyXtYw': No space left on device @ error/cache.c/WritePixelCachePixels/5492.
==> Done.
The asciicast itself is 35 seconds long. Here is the content of my JSON file, for reference.
Right now it's -k 32 -O2 -Okeep-empty
. This should be exported as GIFSICLE_OPTS
inside a2gif.sh
when it's not set. main.cljs
should be modified to use this env var.
I generated a GIF using the command docker run --rm -v $PWD:/data asciinema/asciicast2gif -s 2 -t solarized-dark recording.json recording.gif
The GIF does not match the colours recorded from asciinema rec
. The original can be found here.
Is this due to an 8 bit colour limitation? Either way, my shell prompt has green in it, whereas the SUCCESS messages are grey.
Conversion has failed. Deployed asciicast2gif from docker:
# docker run --rm -v $PWD:/data asciinema/asciicast2gif -t solarized-dark ibbdis.json ibbdis.gif
==> Loading ibbdis.json...
==> Spawning PhantomJS renderer...
==> Generating frame screenshots...
==> Combining screenshots into GIF file...
gifsicle:<stdin>: empty file
Killed
/app/main.js:2284
cljs.core.async.impl.ioc_helpers.run_state_machine_wrapped=function(a){try{return cljs.core.async.impl.ioc_helpers.run_state_machine(a)}catch(b){throw b instanceof Object&&cljs.core.async.impl.ioc_helpers.aget_object(a,cljs.core.async.impl.ioc_helpers.USER_START_IDX).cljs$core$async$impl$protocols$Channel$close_BANG_$arity$1(null),b;}};
^
Error: Command failed: convert -loop 0 -delay 10 /tmp/tmp.p4NraOi9Sf/0.png -delay 60 /tmp/tmp.p4NraOi9Sf/1.png -delay 6 /tmp/tmp.p4NraOi9Sf/2.png -delay 13 /tmp/tmp.p4NraOi9Sf/3.png -delay 26 /tmp/tmp.p4NraOi9Sf/4.png -delay 9 /tmp/tmp.p4NraOi9Sf/5.png -delay 10 /tmp/tmp.p4NraOi9Sf/6.png -delay 6 /tmp/tmp.p4NraOi9Sf/7.png -delay 59 /tmp/tmp.p4NraOi9Sf/8.png -delay 76 /tmp/tmp.p4NraOi9Sf/9.png -delay 13 /tmp/tmp.p4NraOi9Sf/10.png -delay 10 /tmp/tmp.p4NraOi9Sf/11.png -delay 13 /tmp/tmp.p4NraOi9Sf/12.png -delay 6 /tmp/tmp.p4NraOi9Sf/13.png -delay 23 /tmp/tmp.p4NraOi9Sf/14.png -delay 19 /tmp/tmp.p4NraOi9Sf/15.png -delay 16 /tmp/tmp.p4NraOi9Sf/16.png -delay 6 /tmp/tmp.p4NraOi9Sf/17.png -delay 73 /tmp/tmp.p4NraOi9Sf/18.png -delay 33 /tmp/tmp.p4NraOi9Sf/19.png -delay 9 /tmp/tmp.p4NraOi9Sf/20.png -delay 23 /tmp/tmp.p4NraOi9Sf/21.png -delay 16 /tmp/tmp.p4NraOi9Sf/22.png -delay 13 /tmp/tmp.p4NraOi9Sf/23.png -delay 23 /tmp/tmp.p4NraOi9Sf/24.png -delay 26 /tmp/tmp.p4NraOi9Sf/25.png -delay 6 /tmp/tmp.p4NraOi9Sf/26.png -delay 6 /tmp/tmp.p4NraOi9Sf/27.png -delay 16 /tmp/tmp.p4NraOi9Sf/28.png -delay 16 /tmp/tmp.p4NraOi9Sf/29.png -delay 33 /tmp/tmp.p4NraOi9Sf/30.png -delay 30 /tmp/tmp.p4NraOi9Sf/31.png -delay 19 /tmp/tmp.p4NraOi9Sf/32.png -delay 50 /tmp/tmp.p4NraOi9Sf/33.png -delay 46 /tmp/tmp.p4NraOi9Sf/34.png -delay 50 /tmp/tmp.p4NraOi9Sf/35.png -delay 46 /tmp/tmp.p4NraOi9Sf/36.png -delay 66 /tmp/tmp.p4NraOi9Sf/37.png -delay 53 /tmp/tmp.p4NraOi9Sf/38.png -delay 53 /tmp/tmp.p4NraOi9Sf/39.png -delay 59 /tmp/tmp.p4NraOi9Sf/40.png -delay 50 /tmp/tmp.p4NraOi9Sf/41.png -delay 36 /tmp/tmp.p4NraOi9Sf/42.png -delay 19 /tmp/tmp.p4NraOi9Sf/43.png -delay 53 /tmp/tmp.p4NraOi9Sf/44.png -delay 40 /tmp/tmp.p4NraOi9Sf/45.png -delay 16 /tmp/tmp.p4NraOi9Sf/46.png -delay 19 /tmp/tmp.p4NraOi9Sf/47.png -delay 36 /tmp/tmp.p4NraOi9Sf/48.png -delay 33 /tmp/tmp.p4NraOi9Sf/49.png -delay 46 /tmp/tmp.p4NraOi9Sf/50.png -delay 13 /tmp/tmp.p4NraOi9Sf/51.png -delay 13 /tmp/tmp.p4NraOi9Sf/52.png -delay 53 /tmp/tmp.p4NraOi9Sf/53.png -delay 6 /tmp/tmp.p4NraOi9Sf/54.png -delay 80 /tmp/tmp.p4NraOi9Sf/55.png -delay 150 /tmp/tmp.p4NraOi9Sf/56.png -delay 193 /tmp/tmp.p4NraOi9Sf/57.png -delay 106 /tmp/tmp.p4NraOi9Sf/58.png -delay 43 /tmp/tmp.p4NraOi9Sf/59.png -delay 319 /tmp/tmp.p4NraOi9Sf/60.png -delay 3 /tmp/tmp.p4NraOi9Sf/61.png -delay 3 /tmp/tmp.p4NraOi9Sf/62.png -delay 96 /tmp/tmp.p4NraOi9Sf/63.png -delay 193 /tmp/tmp.p4NraOi9Sf/64.png -delay 276 /tmp/tmp.p4NraOi9Sf/65.png -delay 86 /tmp/tmp.p4NraOi9Sf/66.png -delay 66 /tmp/tmp.p4NraOi9Sf/67.png -delay 63 /tmp/tmp.p4NraOi9Sf/68.png -delay 63 /tmp/tmp.p4NraOi9Sf/69.png -delay 60 /tmp/tmp.p4NraOi9Sf/70.png -delay 76 /tmp/tmp.p4NraOi9Sf/71.png -delay 60 /tmp/tmp.p4NraOi9Sf/72.png -delay 66 /tmp/tmp.p4NraOi9Sf/73.png -delay 60 /tmp/tmp.p4NraOi9Sf/74.png -delay 60 /tmp/tmp.p4NraOi9Sf/75.png -delay 3 /tmp/tmp.p4NraOi9Sf/76.png -delay 126 /tmp/tmp.p4NraOi9Sf/77.png -delay 110 /tmp/tmp.p4NraOi9Sf/78.png -delay 200 /tmp/tmp.p4NraOi9Sf/79.png -delay 146 /tmp/tmp.p4NraOi9Sf/80.png -delay 193 /tmp/tmp.p4NraOi9Sf/81.png -delay 1556 /tmp/tmp.p4NraOi9Sf/82.png -delay 63 /tmp/tmp.p4NraOi9Sf/83.png -delay 123 /tmp/tmp.p4NraOi9Sf/84.png -delay 3 /tmp/tmp.p4NraOi9Sf/85.png -delay 93 /tmp/tmp.p4NraOi9Sf/86.png -delay 96 /tmp/tmp.p4NraOi9Sf/87.png -delay 93 /tmp/tmp.p4NraOi9Sf/88.png -delay 133 /tmp/tmp.p4NraOi9Sf/89.png -delay 5030 /tmp/tmp.p4NraOi9Sf/90.png -delay 3 /tmp/tmp.p4NraOi9Sf/91.png -delay 223 /tmp/tmp.p4NraOi9Sf/92.png -delay 293 /tmp/tmp.p4NraOi9Sf/93.png -delay 223 /tmp/tmp.p4NraOi9Sf/94.png -delay 3 /tmp/tmp.p4NraOi9Sf/95.png -delay 3 /tmp/tmp.p4NraOi9Sf/96.png -delay 3 /tmp/tmp.p4NraOi9Sf/97.png -delay 140 /tmp/tmp.p4NraOi9Sf/98.png -delay 156 /tmp/tmp.p4NraOi9Sf/99.png -delay 836 /tmp/tmp.p4NraOi9Sf/100.png -delay 216 /tmp/tmp.p4NraOi9Sf/101.png -delay 3 /tmp/tmp.p4NraOi9Sf/102.png -delay 3 /tmp/tmp.p4NraOi9Sf/103.png -delay 230 /tmp/tmp.p4NraOi9Sf/104.png -delay 213 /tmp/tmp.p4NraOi9Sf/105.png -delay 106 /tmp/tmp.p4NraOi9Sf/106.png -delay 96 /tmp/tmp.p4NraOi9Sf/107.png -delay 73 /tmp/tmp.p4NraOi9Sf/108.png -delay 4796 /tmp/tmp.p4NraOi9Sf/109.png -delay 233 /tmp/tmp.p4NraOi9Sf/110.png -delay 436 /tmp/tmp.p4NraOi9Sf/111.png -delay 26526 /tmp/tmp.p4NraOi9Sf/112.png -delay 69 /tmp/tmp.p4NraOi9Sf/113.png -delay 60 /tmp/tmp.p4NraOi9Sf/114.png -delay 63 /tmp/tmp.p4NraOi9Sf/115.png -delay 66 /tmp/tmp.p4NraOi9Sf/116.png -delay 63 /tmp/tmp.p4NraOi9Sf/117.png -delay 3 /tmp/tmp.p4NraOi9Sf/118.png -delay 133 /tmp/tmp.p4NraOi9Sf/119.png -delay 96 /tmp/tmp.p4NraOi9Sf/120.png -delay 73 /tmp/tmp.p4NraOi9Sf/121.png -delay 73 /tmp/tmp.p4NraOi9Sf/122.png -delay 216 /tmp/tmp.p4NraOi9Sf/123.png -delay 63 /tmp/tmp.p4NraOi9Sf/124.png -delay 126 /tmp/tmp.p4NraOi9Sf/125.png -delay 3 /tmp/tmp.p4NraOi9Sf/126.png -delay 3 /tmp/tmp.p4NraOi9Sf/127.png -delay 3 /tmp/tmp.p4NraOi9Sf/128.png -delay 3 /tmp/tmp.p4NraOi9Sf/129.png -delay 3 /tmp/tmp.p4NraOi9Sf/130.png -delay 3 /tmp/tmp.p4NraOi9Sf/131.png -delay 233 /tmp/tmp.p4NraOi9Sf/132.png -delay 230 /tmp/tmp.p4NraOi9Sf/133.png -delay 3 /tmp/tmp.p4NraOi9Sf/134.png -delay 3 /tmp/tmp.p4NraOi9Sf/135.png -delay 3 /tmp/tmp.p4NraOi9Sf/136.png -delay 3 /tmp/tmp.p4NraOi9Sf/137.png -delay 69 /tmp/tmp.p4NraOi9Sf/138.png -delay 3 /tmp/tmp.p4NraOi9Sf/139.png -delay 63 /tmp/tmp.p4NraOi9Sf/140.png -delay 200 /tmp/tmp.p4NraOi9Sf/141.png -delay 3 /tmp/tmp.p4NraOi9Sf/142.png -delay 3 /tmp/tmp.p4NraOi9Sf/143.png -delay 73 /tmp/tmp.p4NraOi9Sf/144.png -delay 216 /tmp/tmp.p4NraOi9Sf/145.png -delay 73 /tmp/tmp.p4NraOi9Sf/146.png -delay 156 /tmp/tmp.p4NraOi9Sf/147.png -delay 3046 /tmp/tmp.p4NraOi9Sf/148.png -delay 3 /tmp/tmp.p4NraOi9Sf/149.png -delay 123 /tmp/tmp.p4NraOi9Sf/150.png -delay 76 /tmp/tmp.p4NraOi9Sf/151.png -delay 73 /tmp/tmp.p4NraOi9Sf/152.png -delay 246 /tmp/tmp.p4NraOi9Sf/153.png -delay 800 /tmp/tmp.p4NraOi9Sf/154.png -delay 79 /tmp/tmp.p4NraOi9Sf/155.png -delay 80 /tmp/tmp.p4NraOi9Sf/156.png -delay 3 /tmp/tmp.p4NraOi9Sf/157.png -delay 100 /tmp/tmp.p4NraOi9Sf/158.png -layers Optimize gif:- | gifsicle -k 32 -O2 -Okeep-empty -o ibbdis.gif -
gifsicle:<stdin>: empty file
Killed
at checkExecSyncError (child_process.js:481:13)
at Object.execSync (child_process.js:521:13)
at Object.asciinema.gif.main.shell (/app/main.js:5245:143)
at Object.asciinema.gif.main.gen_gif (/app/main.js:5252:371)
at /app/main.js:5261:136
at d (/app/main.js:5255:185)
at b (/app/main.js:5256:17)
at Object.cljs.core.async.impl.ioc_helpers.run_state_machine (/app/main.js:2283:287)
at Object.cljs.core.async.impl.ioc_helpers.run_state_machine_wrapped (/app/main.js:2284:116)
at /app/main.js:2285:321
#
Hi,
I recently started using asciicast2gif and have successfully used it a number of times. I use the Docker image
However, while processing a somewhat long demo, the results were less than optimal and the screen output looks wrong
Here is the command:
docker run --rm -v $PWD:/data asciinema/asciicast2gif demo.cast.1 demo.cast.1.gif ==> Loading demo.cast.1...
==> Spawning PhantomJS renderer...
==> Generating frame screenshots...
==> Combining 607 screenshots into GIF file...
gifsicle: warning: huge GIF, conserving memory (processing may take a while)
==> Done.
What it looks like via asciinema - asciinema_play.png
What the generated gif looks like - asciicast2gif.jpg
I haven't run into this problem in shorter casts. Any ideas? Thanks.
Hi all around! I love asciinema and this script is just great!
I created an asciinema recording in my terminal. the terminal uses the font Meslo for powerline. Recording works nicely, playing it works nicely. The gif can be created using this tool, but unfortunately with the gif, a non-monospaced font is used instead of Meslo (Looks like default sans serif). As you can image this looks quite messy in a terminal.
I did not understand which part of the process picks the font when creating the gif-image. Where do I have to change the font to a monospaced one?
Cheers,
Sandra
Right now we assemble initial GIF file with ImageMagicks's convert
and the pass it through gifsicle
. convert
is doing palette reduction and dithering separately for each frame. Assembling GIF directly in gifsicle may give use better quality (and maybe even smaller file size).
Unfortunately gifsicle can't directly read PNG files so we probably still need to use convert
to convert PNG files into single-image GIF files before invoking gifsicle
.
Using docker image is a nice option, but it would be even better to be able to install it via brew or npm (since it's already a npm package).
Thank you for a great tool!
asciicast2gif
fails to generate .gif files
$ ./asciicast2gif asciicast.json image.gif
==> Loading asciicast-133781.json...
==> Spawning PhantomJS renderer...
==> Generating frame screenshots...
==> Couldn't get geometry of requested DOM element
/home/xtonousou/.scripts/others/asciicast2gif/main.js:568
return new Km(a,wf)}function Mm(a){try{var b=a[0];return b.h?b.h(a):b.call(null,a)}catch(e){if(e instanceof Object)throw b=e,a[6].Qc(),b;throw e;}}function Nm(a,b,e){e=Gm(e,Lm(function(e){a[2]=e;a[1]=b;return Mm(a)}));return k(e)?(a[2]=pc(e),a[1]=b,ck):null}function Om(a,b,e){b=b.ld(0,e,Lm(function(b){a[2]=b;a[1]=3;return Mm(a)}));return k(b)?(a[2]=pc(b),a[1]=3,ck):null}function Pm(a,b){var e=a[6];null!=b&&e.ld(0,b,Lm(function(){return function(){return null}}(e)));e.Qc();return e}
^
Error: program exited with code 1
at ChildProcess.<anonymous> (/home/xtonousou/.scripts/others/asciicast2gif/main.js:1028:100)
at emitTwo (events.js:125:13)
at ChildProcess.emit (events.js:213:7)
at Process.ChildProcess._handle.onexit (internal/child_process.js:200:12)
The .json file is the one mentioned here
$ uname -a
Linux hyperi0n 4.12.6-1-ARCH #1 SMP PREEMPT Sat Aug 12 09:16:22 CEST 2017 x86_64 GNU/Linux
I may be overly hopeful for a 6 minutes of cast to a gif, but this is what I'm getting
docker run --rm -v $PWD:/data asciinema/asciicast2gif -s 1.0 -t solarized-dark demo.cast demo.gif
==> Loading demo.cast...
==> Spawning PhantomJS renderer...
==> Generating frame screenshots...
<--- Last few GCs --->
104433 ms: Mark-sweep 1372.0 (1434.0) -> 1372.0 (1434.0) MB, 678.8 / 0.0 ms [allocation failure] [GC in old space requested].
105111 ms: Mark-sweep 1372.0 (1434.0) -> 1373.0 (1404.0) MB, 677.6 / 0.0 ms [last resort gc].
105784 ms: Mark-sweep 1373.0 (1404.0) -> 1374.0 (1404.0) MB, 673.1 / 0.0 ms [last resort gc].
<--- JS stacktrace --->
==== JS stack trace =========================================
Security context: 0x9f9db0cf781 <JS Object>
1: Dm [/app/main.js:~626] [pc=0x34f3123b23b6] (this=0x6c6287c409 <JS Global Object>,a=0x24fd68bcc6b9 <a sl with map 0x9ecc840fbf9>,b=59)
2: Em [/app/main.js:~627] [pc=0x34f3123cb54f] (this=0x6c6287c409 <JS Global Object>,a=0x24fd68bcc6b9 <a sl with map 0x9ecc840fbf9>,b=59)
3: /* anonymous */ [/app/main.js:325] [pc=0x34f31258f74e] (this=0x6c6287c409 <JS Global Object>)
4: Qf [/app...
FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory
1: node::Abort() [node]
2: 0x7d007c [node]
3: v8::Utils::ReportApiFailure(char const*, char const*) [node]
4: v8::internal::V8::FatalProcessOutOfMemory(char const*, bool) [node]
5: v8::internal::Factory::NewFillerObject(int, bool, v8::internal::AllocationSpace) [node]
6: v8::internal::Runtime_AllocateInTargetSpace(int, v8::internal::Object**, v8::internal::Isolate*) [node]
7: 0x34f3120079a7
/app/asciicast2gif: line 118: 16 Aborted (core dumped) node $NODE_OPTS "${asciicast2gif_dir}/main.js" "${1}" "${2}" "${tmp_dir}" $theme $speed $scale
http-get
function should be explicitly setting Accept: application/json
header.
Once this is done, we can make asciinema web app respond properly with JSON when requesting https://asciinema.org/a/<recording-id>
(without .json
ext). This would make generating GIFs from already uploaded recordings even easier.
I have a test gif I am trying to convert to a gif and keep getting this syntax error:
[]$ > ./asciicast2gif https://asciinema.org/a/0KXjcaOGZjHdR9b9Q7pJAFQ7P ~/Desktop/test.gif
==> Loading https://asciinema.org/a/0KXjcaOGZjHdR9b9Q7pJAFQ7P...
/Users/DJM/Misc/asciicast2gif/main.js:568
return new Km(a,wf)}function Mm(a){try{var b=a[0];return b.h?b.h(a):b.call(null,a)}catch(e){if(e instanceof Object)throw b=e,a[6].Qc(),b;throw e;}}function Nm(a,b,e){e=Gm(e,Lm(function(e){a[2]=e;a[1]=b;return Mm(a)}));return k(e)?(a[2]=pc(e),a[1]=b,ck):null}function Om(a,b,e){b=b.ld(0,e,Lm(function(b){a[2]=b;a[1]=3;return Mm(a)}));return k(b)?(a[2]=pc(b),a[1]=3,ck):null}function Pm(a,b){var e=a[6];null!=b&&e.ld(0,b,Lm(function(){return function(){return null}}(e)));e.Qc();return e}
^
SyntaxError: Unexpected token < in JSON at position 0
at JSON.parse (<anonymous>)
at Ts (/Users/DJM/Misc/asciicast2gif/main.js:1026:410)
at Function.g [as h] (/Users/DJM/Misc/asciicast2gif/main.js:288:239)
at /Users/DJM/Misc/asciicast2gif/main.js:572:157
at Function.e [as c] (/Users/DJM/Misc/asciicast2gif/main.js:310:90)
Any idea what is causing this?
it seem that asciicast2gif
does not respect the custom number of columns required and fallbacks to 80 or similar value when tmux was involved.
I mention that the the same recording behavers normal when played using asciinema, this behaviour being seen only when converting to gif. Use of -c param seems to have no effect.
Both files can be found at https://github.com/pycontribs/rmux/tree/master/docs
The command used to build the gif was asciicast2gif -S 2 -w 160 movie.cast movie.gif
and while the total number of columns of the gif is 160 you can see around the half of the animation that when tmux split window starts it is cropped to ~100 columns.
If you try to play the same recording, it will display correctly.
giflossy does "lossy" gif compression, it's worth testing how big the file size decrease would be for terminal recordings.
I tried converting a recording to a GIF.
docker run --rm -v $PWD:/data asciinema/asciicast2gif https://asciinema.org/a/193932.json 193932.gif
The original on the website looks fine:
But as you can see, the GIF is not:
In a possibly related issue, the thumbnail on the website is fine, but not in the embed.
a2gif can mean anything2gif.
My original (and obvious) idea for the name of this tool was asciicast2gif. However there's already pettarin/asciicast2gif (it does the same thing but takes a different approach).
Regardless of what gifsicle settings I put (even --lossy=0
), I get a darker box around updated text that I don't see in any of the demo GIFs on the README.
I think I'm fine with releasing it under MIT. Not sure if similar concerns as for player's GPL vs EPL are valid here. Thoughts?
When running lein cljsbuild once main
I get the following error. Using the Docker image is failing too because of #21 😢
Compiling ClojureScript...
Compiling "main.js" from ["src"]...
Compiling "main.js" failed.
clojure.lang.ExceptionInfo: failed compiling file:/home/raskolnikov/soft/asciicast2gif/src/asciinema/gif/main.cljs {:file #object[java.io.File 0x3d41449a "/home/raskolnikov/soft/asciicast2gif/src/asciinema/gif/main.cljs"]}
at clojure.core$ex_info.invokeStatic(core.clj:4617)
at clojure.core$ex_info.invoke(core.clj:4617)
at cljs.compiler$compile_file$fn__3884.invoke(compiler.cljc:1471)
at cljs.compiler$compile_file.invokeStatic(compiler.cljc:1436)
at cljs.compiler$compile_file.invoke(compiler.cljc:1412)
at cljs.closure$compile_file.invokeStatic(closure.clj:497)
at cljs.closure$compile_file.invoke(closure.clj:488)
at cljs.closure$eval5698$fn__5699.invoke(closure.clj:566)
at cljs.closure$eval5634$fn__5635$G__5623__5642.invoke(closure.clj:450)
at cljs.closure$compile_sources$iter__5834__5838$fn__5839.invoke(closure.clj:914)
at clojure.lang.LazySeq.sval(LazySeq.java:40)
at clojure.lang.LazySeq.seq(LazySeq.java:49)
at clojure.lang.Cons.next(Cons.java:39)
at clojure.lang.RT.next(RT.java:688)
at clojure.core$next__4341.invokeStatic(core.clj:64)
at clojure.core$dorun.invokeStatic(core.clj:3033)
at clojure.core$doall.invokeStatic(core.clj:3039)
at clojure.core$doall.invoke(core.clj:3039)
at cljs.closure$compile_sources.invokeStatic(closure.clj:908)
at cljs.closure$compile_sources.invoke(closure.clj:897)
at cljs.closure$build.invokeStatic(closure.clj:2307)
at cljs.closure$build.invoke(closure.clj:2236)
at cljs.build.api$build.invokeStatic(api.clj:202)
at cljs.build.api$build.invoke(api.clj:189)
at cljs.build.api$build.invokeStatic(api.clj:192)
at cljs.build.api$build.invoke(api.clj:189)
at cljsbuild.compiler$compile_cljs$fn__6943.invoke(compiler.clj:66)
at cljsbuild.compiler$compile_cljs.invokeStatic(compiler.clj:65)
at cljsbuild.compiler$compile_cljs.invoke(compiler.clj:54)
at cljsbuild.compiler$run_compiler.invokeStatic(compiler.clj:165)
at cljsbuild.compiler$run_compiler.invoke(compiler.clj:126)
at user$eval7047$iter__7083__7087$fn__7088$fn__7106.invoke(form-init545893261685407571.clj:1)
at user$eval7047$iter__7083__7087$fn__7088.invoke(form-init545893261685407571.clj:1)
at clojure.lang.LazySeq.sval(LazySeq.java:40)
at clojure.lang.LazySeq.seq(LazySeq.java:49)
at clojure.lang.RT.seq(RT.java:521)
at clojure.core$seq__4357.invokeStatic(core.clj:137)
at clojure.core$dorun.invokeStatic(core.clj:3024)
at clojure.core$doall.invokeStatic(core.clj:3039)
at clojure.core$doall.invoke(core.clj:3039)
at user$eval7047.invokeStatic(form-init545893261685407571.clj:1)
at user$eval7047.invoke(form-init545893261685407571.clj:1)
at clojure.lang.Compiler.eval(Compiler.java:6927)
at clojure.lang.Compiler.eval(Compiler.java:6917)
at clojure.lang.Compiler.load(Compiler.java:7379)
at clojure.lang.Compiler.loadFile(Compiler.java:7317)
at clojure.main$load_script.invokeStatic(main.clj:275)
at clojure.main$init_opt.invokeStatic(main.clj:277)
at clojure.main$init_opt.invoke(main.clj:277)
at clojure.main$initialize.invokeStatic(main.clj:308)
at clojure.main$null_opt.invokeStatic(main.clj:342)
at clojure.main$null_opt.invoke(main.clj:339)
at clojure.main$main.invokeStatic(main.clj:421)
at clojure.main$main.doInvoke(main.clj:384)
at clojure.lang.RestFn.invoke(RestFn.java:421)
at clojure.lang.Var.invoke(Var.java:383)
at clojure.lang.AFn.applyToHelper(AFn.java:156)
at clojure.lang.Var.applyTo(Var.java:700)
at clojure.main.main(main.java:37)
Caused by: clojure.lang.ExceptionInfo: No such namespace: asciinema.player.source, could not locate asciinema/player/source.cljs, asciinema/player/source.cljc, or Closure namespace "asciinema.player.source" in file /home/raskolnikov/soft/asciicast2gif/src/asciinema/gif/main.cljs {:tag :cljs/analysis-error}
at clojure.core$ex_info.invokeStatic(core.clj:4617)
at clojure.core$ex_info.invoke(core.clj:4617)
at cljs.analyzer$error.invokeStatic(analyzer.cljc:657)
at cljs.analyzer$error.invoke(analyzer.cljc:653)
at cljs.analyzer$error.invokeStatic(analyzer.cljc:655)
at cljs.analyzer$error.invoke(analyzer.cljc:653)
at cljs.analyzer$analyze_deps.invokeStatic(analyzer.cljc:1975)
at cljs.analyzer$analyze_deps.invoke(analyzer.cljc:1951)
at cljs.analyzer$ns_side_effects.invokeStatic(analyzer.cljc:3238)
at cljs.analyzer$ns_side_effects.invoke(analyzer.cljc:3233)
at cljs.analyzer$analyze_STAR_$fn__2767.invoke(analyzer.cljc:3328)
at clojure.lang.PersistentVector.reduce(PersistentVector.java:341)
at clojure.core$reduce.invokeStatic(core.clj:6544)
at clojure.core$reduce.invoke(core.clj:6527)
at cljs.analyzer$analyze_STAR_.invokeStatic(analyzer.cljc:3328)
at cljs.analyzer$analyze_STAR_.invoke(analyzer.cljc:3318)
at cljs.analyzer$analyze.invokeStatic(analyzer.cljc:3352)
at cljs.analyzer$analyze.invoke(analyzer.cljc:3335)
at cljs.compiler$emit_source.invokeStatic(compiler.cljc:1307)
at cljs.compiler$emit_source.invoke(compiler.cljc:1287)
at cljs.compiler$compile_file_STAR_$fn__3861.invoke(compiler.cljc:1381)
at cljs.compiler$with_core_cljs.invokeStatic(compiler.cljc:1206)
at cljs.compiler$with_core_cljs.invoke(compiler.cljc:1195)
at cljs.compiler$compile_file_STAR_.invokeStatic(compiler.cljc:1370)
at cljs.compiler$compile_file_STAR_.invoke(compiler.cljc:1363)
at cljs.compiler$compile_file$fn__3884.invoke(compiler.cljc:1459)
... 56 more
Subprocess failed
Hey hey. Trying to build this project. Having an error from lein. On Debian/testing.
$ lein -v
Leiningen 2.8.1 on Java 1.8.0_144 Java HotSpot(TM) 64-Bit Server VM
$ pwd
/home/mfowlewebs/src/asciicast2gif
$ lein cljsbuild once main
Compiling ClojureScript...
Compiling ["main.js"] from ["src"]...
Compiling ["main.js"] failed.
clojure.lang.ExceptionInfo: failed compiling file:/home/rektide/projects/archive/asciicast2gif/src/asciinema/gif/main.cljs {:file #object[java.io.File 0x32ea16b7 "/home/rektide/projects/archive/asciicast2gif/src/asciinema/gif/main.cljs"]}
at clojure.core$ex_info.invokeStatic(core.clj:4739)
at clojure.core$ex_info.invoke(core.clj:4739)
at cljs.compiler$compile_file$fn__3702.invoke(compiler.cljc:1562)
at cljs.compiler$compile_file.invokeStatic(compiler.cljc:1522)
at cljs.compiler$compile_file.invoke(compiler.cljc:1498)
at cljs.closure$compile_file.invokeStatic(closure.clj:573)
at cljs.closure$compile_file.invoke(closure.clj:564)
at cljs.closure$fn__5124.invokeStatic(closure.clj:653)
at cljs.closure$fn__5124.invoke(closure.clj:647)
at cljs.closure$fn__5052$G__5045__5059.invoke(closure.clj:521)
at cljs.closure$compile_sources$iter__5250__5254$fn__5255.invoke(closure.clj:1011)
at clojure.lang.LazySeq.sval(LazySeq.java:40)
at clojure.lang.LazySeq.seq(LazySeq.java:49)
at clojure.lang.Cons.next(Cons.java:39)
at clojure.lang.RT.next(RT.java:706)
at clojure.core$next__5108.invokeStatic(core.clj:64)
at clojure.core$dorun.invokeStatic(core.clj:3134)
at clojure.core$doall.invokeStatic(core.clj:3140)
at clojure.core$doall.invoke(core.clj:3140)
at cljs.closure$compile_sources.invokeStatic(closure.clj:1007)
at cljs.closure$compile_sources.invoke(closure.clj:996)
at cljs.closure$build.invokeStatic(closure.clj:2817)
at cljs.closure$build.invoke(closure.clj:2718)
at cljs.build.api$build.invokeStatic(api.clj:208)
at cljs.build.api$build.invoke(api.clj:189)
at cljs.build.api$build.invokeStatic(api.clj:195)
at cljs.build.api$build.invoke(api.clj:189)
at cljsbuild.compiler$compile_cljs$fn__718.invoke(compiler.clj:61)
at cljsbuild.compiler$compile_cljs.invokeStatic(compiler.clj:60)
at cljsbuild.compiler$compile_cljs.invoke(compiler.clj:48)
at cljsbuild.compiler$run_compiler.invokeStatic(compiler.clj:168)
at cljsbuild.compiler$run_compiler.invoke(compiler.clj:129)
at user$eval847$iter__895__899$fn__900$fn__926.invoke(form-init8977336585284452904.clj:1)
at user$eval847$iter__895__899$fn__900.invoke(form-init8977336585284452904.clj:1)
at clojure.lang.LazySeq.sval(LazySeq.java:40)
at clojure.lang.LazySeq.seq(LazySeq.java:49)
at clojure.lang.RT.seq(RT.java:528)
at clojure.core$seq__5124.invokeStatic(core.clj:137)
at clojure.core$dorun.invokeStatic(core.clj:3125)
at clojure.core$doall.invokeStatic(core.clj:3140)
at clojure.core$doall.invoke(core.clj:3140)
at user$eval847.invokeStatic(form-init8977336585284452904.clj:1)
at user$eval847.invoke(form-init8977336585284452904.clj:1)
at clojure.lang.Compiler.eval(Compiler.java:7062)
at clojure.lang.Compiler.eval(Compiler.java:7052)
at clojure.lang.Compiler.load(Compiler.java:7514)
at clojure.lang.Compiler.loadFile(Compiler.java:7452)
at clojure.main$load_script.invokeStatic(main.clj:278)
at clojure.main$init_opt.invokeStatic(main.clj:280)
at clojure.main$init_opt.invoke(main.clj:280)
at clojure.main$initialize.invokeStatic(main.clj:311)
at clojure.main$null_opt.invokeStatic(main.clj:345)
at clojure.main$null_opt.invoke(main.clj:342)
at clojure.main$main.invokeStatic(main.clj:424)
at clojure.main$main.doInvoke(main.clj:387)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.lang.Var.applyTo(Var.java:702)
at clojure.main.main(main.java:37)
Caused by: clojure.lang.ExceptionInfo: No such namespace: asciinema.player.asciicast, could not locate asciinema/player/asciicast.cljs, asciinema/player/asciicast.cljc, or JavaScript source providing "asciinema.player.asciicast" in file /home/rektide/projects/archive/asciicast2gif/src/asciinema/gif/main.cljs {:tag :cljs/analysis-error}
at clojure.core$ex_info.invokeStatic(core.clj:4739)
at clojure.core$ex_info.invoke(core.clj:4739)
at cljs.analyzer$error.invokeStatic(analyzer.cljc:697)
at cljs.analyzer$error.invoke(analyzer.cljc:693)
at cljs.analyzer$error.invokeStatic(analyzer.cljc:695)
at cljs.analyzer$error.invoke(analyzer.cljc:693)
at cljs.analyzer$analyze_deps.invokeStatic(analyzer.cljc:2129)
at cljs.analyzer$analyze_deps.invoke(analyzer.cljc:2103)
at cljs.analyzer$ns_side_effects.invokeStatic(analyzer.cljc:3476)
at cljs.analyzer$ns_side_effects.invoke(analyzer.cljc:3471)
at cljs.analyzer$analyze_STAR_$fn__2510.invoke(analyzer.cljc:3596)
at clojure.lang.PersistentVector.reduce(PersistentVector.java:341)
at clojure.core$reduce.invokeStatic(core.clj:6747)
at clojure.core$reduce.invoke(core.clj:6730)
at cljs.analyzer$analyze_STAR_.invokeStatic(analyzer.cljc:3596)
at cljs.analyzer$analyze_STAR_.invoke(analyzer.cljc:3586)
at cljs.analyzer$analyze.invokeStatic(analyzer.cljc:3616)
at cljs.analyzer$analyze.invoke(analyzer.cljc:3598)
at cljs.compiler$emit_source.invokeStatic(compiler.cljc:1386)
at cljs.compiler$emit_source.invoke(compiler.cljc:1365)
at cljs.compiler$compile_file_STAR_$fn__3672.invoke(compiler.cljc:1467)
at cljs.compiler$with_core_cljs.invokeStatic(compiler.cljc:1285)
at cljs.compiler$with_core_cljs.invoke(compiler.cljc:1274)
at cljs.compiler$compile_file_STAR_.invokeStatic(compiler.cljc:1451)
at cljs.compiler$compile_file_STAR_.invoke(compiler.cljc:1444)
at cljs.compiler$compile_file$fn__3702.invoke(compiler.cljc:1547)
... 55 more
Subprocess failed
Their meaning, possible values and defaults.
I run this command:
i run this in alias :
asciicast2gif='docker run --rm -v $PWD:/data asciinema/asciicast2gif'
then i ran the following command:
asciicast2gif demosprint.cast demosprint.gif
==> Loading demosprint.cast...
==> Spawning PhantomJS renderer...
==> Generating frame screenshots...
==> Combining 1131 screenshots into GIF file...
And now is seem to be stuck there forever. A long normaly should this take ?
thx
I use docker image run this command,output:
ra@17zy:~/Downloads/video$ sudo asciicast2gif https://asciinema.org/a/118274.json demo.gif
==> Loading https://asciinema.org/a/118274.json...
==> Spawning PhantomJS renderer...
==> Generating frame screenshots...
==> Couldn't get geometry of requested DOM element
/usr/local/lib/node_modules/asciicast2gif/main.js:696
return new Zo(a,Qe)}function ap(a){try{var b=a[0];return b.h?b.h(a):b.call(null,a)}catch(c){if(c instanceof Object)throw b=c,Uo(a[6]),b;throw c;}}function bp(a,b,c){c=Vo(c,$o(function(c){a[2]=c;a[1]=b;return ap(a)}));return r(c)?(a[2]=Ob(c),a[1]=b,bj):null}function cp(a,b){a=a[6];null!=b&&a.Dc(null,b,$o(function(){return function(){return null}}(a)));Uo(a);return a}
^
Error: program exited with code 1
at ChildProcess.<anonymous> (/usr/local/lib/node_modules/asciicast2gif/main.js:704:399)
at emitTwo (events.js:126:13)
at ChildProcess.emit (events.js:214:7)
at Process.ChildProcess._handle.onexit (internal/child_process.js:198:12)
node: v8.10.0
npm: 3.5.2
system: Linux 17zy 4.15.0-29-generic #31-Ubuntu x86_64 x86_64 GNU/Linux
docker: Docker version 17.06.2-ce, build a04f55b
docker-image: asciinema/asciicast2gif latest 54698cc15d97
The output from procecssing is too noisy now. We can leave some basic informational/progress messages.
Everything over that should be either removed or only displayed when DEBUG=1
env var is set.
I have bit longer cast (here), that I tried to convert, but I wanted to limit the height of resulting GIF so I used the -h
parameter. Unfortunately the resulted GIF trims the part that overflow the limited window.
I would expect that the tool will imitate terminal window behaviour where when the prompt reaches bottom of the window, it will start "push out" the oldest entries up and from the window view box.
Is there some way to make this happen?
Just wanted to say this is awesome and brilliant!! I'm so glad to have found it! <3
a2gif
shell script should first check whether node
, phantomjs
, convert
and gifsicle
are in $PATH
and exit with error if that's not the case.
While this tool doesn't use constant frame-rate (delay for each frame is specified individually), it's worth investigating if skipping over frames with very small delay can decrease file size without degrading animation smoothness in noticeable way.
We can experiment with 30 fps clamp. asciinema-player has asciinema.player.frames/at-hz
function which quantizes frame times so they sit on multiples of 1/30s, and can be used on frames
before passing them to renderer (gen-image-frames
).
I built from source, and tried running from both a remote asciinema url as well as a downloaded json file. The script fully completes with no errors, but when the gif is generated, I can't open it.
[09:12AM] asciicast2gif (master)$ asciicast2gif ~/Desktop/147415.json ~/Desktop/demo.gif
==> Loading /Users/jeremywoertink/Desktop/147415.json...
==> Spawning PhantomJS renderer...
==> Generating frame screenshots...
==> Combining screenshots into GIF file...
==> Done.
npm 4.6.1
lein Leiningen 2.8.1 on Java 1.8.0_144 Java HotSpot(TM) 64-Bit Server VM
macOS 10.13.1
Hi, I'm trying to run asciicast2gif
against a recording I just posted online, but I'm getting the following output:
==> Loading https://asciinema.org/a/AsPWpL1qCvInbNAAVBfbDfRhy...
only asciicast v1 and v2 formats can be opened
==> Done.
Running locally it doesn't work, as well:
==> Loading /tmp/tmpi1soul1l-ascii.cast...
==> Spawning PhantomJS renderer...
==> Generating frame screenshots...
==> Couldn't get geometry of requested DOM element
/usr/local/lib/node/lib/node_modules/asciicast2gif/main.js:696
[ ... ]
Any pointers? Thanks!
Similar to https://github.com/marionebl/svg-term-cli --window
flag
asciicast2gif is producing gifs that cannot be opened.
I tried with both the standalone version and the docker container.
Any clue how I can troubleshoot this?
I was able to produce a minimal working test case with this asciicast.
This test case simply redirects some garbage from /dev/random
into a text file and outputs the octal dump via od
(to avoid potentially introducing Unicode bugs). Afterwards, it prints some echo
statements.
I then converted this to a gif with the command:
asciicast2gif -w 80 -h 25 https://asciinema.org/a/st5CY0WipJ1S85VkUNjK2HdXb.json cast.gif
The GIF that is then produced by asciicast2gif
however, seems to break once the row-limit of 25 is exceeded, and bugs out. It fails to include the echo
statements because it seems to get stuck and drop frames. This kind of bug was discovered when I was trying to make my own personal cast:
I am running this on Ubuntu 16.04, and the dependency of ImageMagick is satisfied. Of giflossy/gifsicle, I am using gifsicle, which I compiled from source from its GitHub repository.
My guess is that I'm doing something wrong, most likely something with my dependencies, but I'm not sure where to start looking.
I downloaded the file and found a regular curly brace at position 0.
[ ~ ] docker run --rm -v $PWD:/data asciinema/asciicast2gif https://asciinema.org/a/bqBwff05mI7Cl9bz7EqLPMKF8.json demo.gif [ master ]
==> Loading https://asciinema.org/a/bqBwff05mI7Cl9bz7EqLPMKF8.json...
/app/main.js:2284
cljs.core.async.impl.ioc_helpers.run_state_machine_wrapped=function(a){try{return cljs.core.async.impl.ioc_helpers.run_state_machine(a)}catch(b){throw b instanceof Object&&cljs.core.async.impl.ioc_helpers.aget_object(a,cljs.core.async.impl.ioc_helpers.USER_START_IDX).cljs$core$async$impl$protocols$Channel$close_BANG_$arity$1(null),b;}};
^
SyntaxError: Unexpected token in JSON at position 0
at parse (native)
at asciinema.gif.main.parse_json (/app/main.js:5235:406)
at Function.e [as cljs$core$IFn$_invoke$arity$1] (/app/main.js:931:362)
at /app/main.js:2620:464
at Function.f [as cljs$core$IFn$_invoke$arity$2] (/app/main.js:1065:400)
at Function.g [as cljs$core$IFn$_invoke$arity$2] (/app/main.js:2276:3)
at cljs.core.async.impl.channels.ManyToManyChannel.cljs$core$async$impl$protocols$WritePort$put_BANG_$arity$3 (/app/main.js:2257:80)
at Object.cljs.core.async.impl.protocols.put_BANG_ (/app/main.js:2171:146)
at Function.cljs.core.async.put_BANG_.cljs$core$IFn$_invoke$arity$2 (/app/main.js:2359:176)
at IncomingMessage.<anonymous> (/app/main.js:5238:483)
[ ~ ] docker -v
Docker version 17.06.1-ce, build 874a7374f3
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.