├── dev
├── style.css
└── index.html
├── .gitignore
├── d3_handwriting.gif
├── src
├── app.coffee
├── handwritten
│ └── write.coffee
└── dev
│ └── dev.coffee
├── .gitattributes
├── example.html
├── bower.json
├── package.json
├── gulpfile.js
├── handwritten.min.js
├── graph.json
├── README.md
├── app.js
└── handwritten.dev.js
/dev/style.css:
--------------------------------------------------------------------------------
1 | svg path{
2 | fill: none;
3 | stroke-width: 3;
4 | }
5 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist
3 | .tmp
4 | .sass-cache
5 | bower_components
6 |
7 |
--------------------------------------------------------------------------------
/d3_handwriting.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxArturo/d3_handwriting/HEAD/d3_handwriting.gif
--------------------------------------------------------------------------------
/src/app.coffee:
--------------------------------------------------------------------------------
1 | Handwritten = window.Handwritten or {}
2 | window.Handwritten = Handwritten
3 |
4 | # general settings
5 | Handwritten.dev =
6 | enabled: true
7 | mountPoint: null
8 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Set the default behavior, in case people don't have core.autocrlf set.
2 | * text=auto
3 |
4 | # Explicitly declare text files you want to always be normalized and converted
5 | # to native line endings on checkout.
6 | *.md text
7 |
8 | # Declare files that will always have CRLF line endings on checkout.
9 |
10 | # Denote all files that are truly binary and should not be modified.
11 | *.png binary
12 | *.jpg binary
13 | *.gif binary
14 |
--------------------------------------------------------------------------------
/example.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | "
7 | ],
8 | "description": "Handwritten svg, with d3.js",
9 | "main": "js/handwritten.js",
10 | "moduleType": [],
11 | "keywords": [
12 | "handwritten",
13 | "d3"
14 | ],
15 | "license": "MIT",
16 | "private": true,
17 | "ignore": [
18 | "**/.*",
19 | "node_modules",
20 | "bower_components",
21 | "test",
22 | "tests"
23 | ],
24 | "dependencies": {
25 | "d3": "~3.5.6",
26 | "dat-gui": "dataarts/dat.gui#~0.5.1",
27 | "lodash": "~3.10.1"
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "js_handwriting",
3 | "version": "1.0.0",
4 | "description": "Handwritten SVG glyps, using d3.js",
5 | "main": "app.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "git+https://github.com/maxArturo/d3_handwriting.git"
12 | },
13 | "keywords": [
14 | "d3.js",
15 | "handwriting"
16 | ],
17 | "author": "Max Alcala (@maxArturoAS)",
18 | "license": "ISC",
19 | "bugs": {
20 | "url": "https://github.com/maxArturo/d3_handwriting/issues"
21 | },
22 | "homepage": "https://github.com/maxArturo/d3_handwriting#readme",
23 | "devDependencies": {
24 | "coffee": "^1.2.0",
25 | "gulp": "^3.9.0",
26 | "gulp-coffee": "^2.3.1",
27 | "gulp-concat": "^2.6.0",
28 | "gulp-if": "^2.0.0",
29 | "gulp-rename": "^1.2.2",
30 | "gulp-sourcemaps": "^1.6.0",
31 | "gulp-uglify": "^1.4.1",
32 | "gulp-util": "^3.0.6",
33 | "yargs": "^3.26.0"
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp'),
2 | argv = require('yargs').argv,
3 | coffee = require('gulp-coffee'),
4 | sourcemaps = require('gulp-sourcemaps'),
5 | concat = require('gulp-concat'),
6 | rename = require('gulp-rename'),
7 | uglify = require('gulp-uglify'),
8 | gutil = require('gulp-util'),
9 | gulpif = require('gulp-if');
10 |
11 | var prodFiles = ['src/app.coffee', 'src/handwritten/*.coffee'];
12 | var devFiles = prodFiles.concat(['src/dev/dev.coffee']);
13 |
14 | var compile = function(){
15 | gulp.src(argv.production ? prodFiles : devFiles)
16 | .pipe(sourcemaps.init())
17 | .pipe(coffee({bare: true}).on('error', gutil.log))
18 | .pipe(concat('handwritten.dev.js'))
19 | .pipe(sourcemaps.write())
20 | .pipe(gulpif(argv.production, rename('handwritten.min.js')))
21 | .pipe(gulpif(argv.production, uglify()))
22 | .pipe(gulp.dest('.'));
23 | }
24 |
25 | gulp.task('build', compile(prodFiles));
26 |
27 | gulp.task('watch', function(){
28 | gulp.watch('src/**/*.coffee', ['build'])
29 | });
30 |
31 | gulp.task('default', ['build', 'watch']);
32 |
--------------------------------------------------------------------------------
/handwritten.min.js:
--------------------------------------------------------------------------------
1 | var Handwritten;Handwritten=window.Handwritten||{},window.Handwritten=Handwritten,Handwritten.dev={enabled:!0,mountPoint:null};var hasProp={}.hasOwnProperty;Handwritten.writing=function(){var t,n,r,e,a,i,o,u,l,h,c;return e=function(t){return t.each(function(t,n){var e,a,o,l,h,c;e=d3.select(this),e.selectAll("path").remove(),h=[];for(a in t)hasProp.call(t,a)&&(c=t[a],o=u(c),h.push(function(){var t,n,a;for(a=[],t=0,n=o.length;n>t;t++)l=o[t],a.push(e.append("path").attr("d",i(l)).attr("stroke",r));return a}()));return h})},i=d3.svg.line().x(function(t){return t.x}).y(function(t){return t.y}).interpolate("basis"),o={top:20,right:20,bottom:20,left:20},c=900-o.left-o.right,a=500-o.bottom-o.top,h=5,l=100,t=0,r="#000000",e.width=function(t){return arguments.length?(c=t,e):c},e.height=function(t){return arguments.length?(a=t,e):a},e.variability=function(t){return arguments.length?(h=t,e):h},e.transform=function(t){return arguments.length?(l=t,e):l},e.baseline=function(n){return arguments.length?(t=n,e):t},e.color=function(t){return arguments.length?(r=t,e):r},u=function(t){var r,e,a,i;for(i=_.cloneDeep(t),r=0,e=i.length;e>r;r++)a=i[r],a=a.map(n);return i},n=function(n){return n.x=(n.x+Math.random()*h-h/2)*(l/100),n.y=(n.y+Math.random()*h-h/2)*(l/100)+t,n},e};
--------------------------------------------------------------------------------
/graph.json:
--------------------------------------------------------------------------------
1 | {
2 | "A": [
3 | [
4 | {
5 | "x": 65.00141906738281,
6 | "y": 179.5014190673828
7 | },
8 | {
9 | "x": 123.50141906738281,
10 | "y": 89.50141906738281
11 | },
12 | {
13 | "x": 140.5014190673828,
14 | "y": 66.00141906738281
15 | },
16 | {
17 | "x": 150.5014190673828,
18 | "y": 70.50141906738281
19 | },
20 | {
21 | "x": 177.0014190673828,
22 | "y": 115.5014190673828
23 | },
24 | {
25 | "x": 183.0014190673828,
26 | "y": 178.0014190673828
27 | }
28 | ],
29 | [
30 | {
31 | "x": 100.00283813476562,
32 | "y": 123.00283813476562
33 | },
34 | {
35 | "x": 165.00283813476562,
36 | "y": 126.00283813476562
37 | },
38 | {
39 | "x": 172.00283813476562,
40 | "y": 120.00283813476562
41 | }
42 | ]
43 | ],
44 | "B": [
45 | [
46 | {
47 | "x": 223.00283813476565,
48 | "y": 182.00283813476562
49 | },
50 | {
51 | "x": 189.00283813476562,
52 | "y": 49.00284194946289
53 | },
54 | {
55 | "x": 255.00283813476562,
56 | "y": 35.00284194946289
57 | },
58 | {
59 | "x": 327.0028381347656,
60 | "y": 72.00283813476562
61 | },
62 | {
63 | "x": 266.0028381347656,
64 | "y": 101.00283813476562
65 | },
66 | {
67 | "x": 205.00283813476562,
68 | "y": 104.00283813476562
69 | },
70 | {
71 | "x": 323.0028381347656,
72 | "y": 133.00283813476562
73 | },
74 | {
75 | "x": 304.0028381347656,
76 | "y": 182.00283813476562
77 | },
78 | {
79 | "x": 253.00283813476562,
80 | "y": 182.00283813476562
81 | },
82 | {
83 | "x": 230.00283813476562,
84 | "y": 172.00283813476562
85 | }
86 | ]
87 | ]
88 | }
89 |
--------------------------------------------------------------------------------
/src/handwritten/write.coffee:
--------------------------------------------------------------------------------
1 | Handwritten.writing = ->
2 |
3 | draw = (selection) ->
4 | selection.each( (d, i) ->
5 | element = d3.select(@)
6 | element.selectAll('path').remove()
7 |
8 | for own letter, values of d
9 | letterPaths = randomize(values)
10 | for path in letterPaths
11 | element.append('path')
12 | .attr('d', lineFunction(path))
13 | .attr('stroke', color)
14 | )
15 |
16 | lineFunction = d3.svg.line()
17 | .x((d) ->
18 | d.x
19 | ).y((d) ->
20 | d.y
21 | ).interpolate('basis')
22 |
23 | margin =(
24 | top: 20
25 | right: 20
26 | bottom: 20
27 | left: 20)
28 |
29 | width = 900 - margin.left - margin.right
30 | height = 500 - margin.bottom - margin.top
31 | variability = 5
32 | transform = 100
33 | baseline = 0
34 | color = '#000000'
35 |
36 | # accessor functions
37 | draw.width = (value) ->
38 | return width unless arguments.length
39 | width = value
40 | draw
41 |
42 | draw.height = (value) ->
43 | return height unless arguments.length
44 | height = value
45 | draw
46 |
47 | draw.variability = (value) ->
48 | return variability unless arguments.length
49 | variability = value
50 | draw
51 |
52 | draw.transform = (value) ->
53 | return transform unless arguments.length
54 | transform = value
55 | draw
56 |
57 | draw.baseline = (value) ->
58 | return baseline unless arguments.length
59 | baseline = value
60 | draw
61 |
62 | draw.color = (value) ->
63 | return color unless arguments.length
64 | color = value
65 | draw
66 |
67 | randomize = (letterPaths) ->
68 | paths = _.cloneDeep(letterPaths)
69 | for path in paths
70 | path = path.map(coerce)
71 | paths
72 |
73 | coerce = (d) ->
74 | d.x = (d.x + Math.random() * variability - variability / 2) *
75 | (transform / 100)
76 | d.y = (d.y + Math.random() * variability - variability / 2) *
77 | (transform / 100) + baseline;
78 | d
79 |
80 | # return main update function
81 | draw
82 |
--------------------------------------------------------------------------------
/src/dev/dev.coffee:
--------------------------------------------------------------------------------
1 | if Handwritten.dev.enabled
2 | d3.json('../graph.json', (error, letters) ->
3 | Handwritten.dev.mountPoint = d3.select('body').append('svg')
4 | .attr('width', Handwritten.writing().width())
5 | .attr('height', Handwritten.writing().height())
6 | .datum(letters)
7 | .on("click", Handwritten.dev.addCoordinates);
8 |
9 | Handwritten.dev.gui = new dat.GUI()
10 | Handwritten.dev.params = (->
11 | @.variability = 5
12 | @.transform = 100
13 | @.baseline = 0
14 | @.color = '#000000'
15 | @
16 | ).bind(@)
17 |
18 | Handwritten.dev.input = new Handwritten.dev.params()
19 |
20 | (->
21 | drawing = Handwritten.writing()
22 | mountPoint = Handwritten.dev.mountPoint
23 | Handwritten.dev.gui_controller = (
24 | variability: Handwritten.dev.gui.add(Handwritten.dev.input,
25 | 'variability', 0, 100).onChange(
26 | ->
27 | drawing.variability(Handwritten.dev.input.variability)
28 | drawing(mountPoint))
29 | transform: Handwritten.dev.gui.add(Handwritten.dev.input, 'transform', 0, 200).onChange(
30 | ->
31 | drawing.transform(Handwritten.dev.input.transform)
32 | drawing(mountPoint))
33 | baseline: Handwritten.dev.gui.add(Handwritten.dev.input, 'baseline', 0, 100).onChange(
34 | ->
35 | drawing.baseline(Handwritten.dev.input.baseline)
36 | drawing(mountPoint))
37 | color: Handwritten.dev.gui.add(Handwritten.dev.input, 'color').onChange(
38 | (value) ->
39 | drawing.color(Handwritten.dev.input.color)
40 | drawing(mountPoint))
41 | )
42 | )()
43 | )
44 |
45 | Handwritten.dev.addCoordinates =( ->
46 | coordinates = d3.mouse(@)
47 | if !@data.newLetter
48 | @data.newLetter = [[]]
49 |
50 | @data.newLetter[0].push(
51 | x: coordinates[0] / Handwritten.writing().transform() * 100,
52 | y: coordinates[1] / Handwritten.writing().transform() * 100
53 | )
54 | Handwritten.writing().draw(Handwritten.dev.mountPoint)
55 | )
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## D3 Handwriting type generator
2 |
3 | Have you ever noticed those [types](http://www.google.com/fonts/specimen/Rock+Salt) that make you think like they are handwritten, only to find same-letter multiples together and have the illusion completely shattered?
4 |
5 | With static types, there are simply no satisfactory replacements for a handwritten type. I find that completely upending, and to scratch that itch I've turned to D3 for a more 'proper' implementation of an actual 'handwritten' typeset - one that changes upon rendering.
6 |
7 | 
8 |
9 | D3 takes care of generating SVG lines for the glyphs, whose coordinates are randomized runtime and interpolated using [basis interpolation](https://en.wikipedia.org/wiki/B-spline) to achieve that good ol' scrawl feel. It also (almost) guarantees that every rendering will be unique - just like every scribble is.
10 |
11 |
12 | It is worthwhile to note that this is completely preposterous to use as an actual typeface, as it would require JavaScript upon any given display (say, your birthday card). However, this does lend itself to more meaningful applications, such as rendering and then transferring to static media (PDF, say) multiple times over.
13 |
14 | I am looking for a proper glyph implementation - one that can be projected and transformed. My current process (painting a glyph with my mouse on the SVG element and saving the coordinates) is not close to optimal, but it works for now. If anyone knows of a better standard way (taking a standard Unicode implementation and parsing out to a SVG:line) do let me know.
15 |
16 | ### Development
17 | After `git clone`, run `npm install` and `bower install` to add the dev dependencies. Then `gulp` will translate the CoffeeScript and watch for any changes.
18 |
19 | Without the `--production` option, a dev version of `handwritten.js` is built, which includes default ``s for the glyphs to draw on, along with dat.GUI to play with variables. There is a handy `index.html` file under the dev folder where you can experiment with your changes - serve the entire repo folder with your [favorite server](https://gist.github.com/willurd/5720255) and browse to see your changes.
20 |
21 | ### Build release
22 | Run `gulp --production` to generate an uglified, minifed version ready for release.
23 |
--------------------------------------------------------------------------------
/app.js:
--------------------------------------------------------------------------------
1 | /* global d3, $, dat */
2 | 'use strict';
3 |
4 | var margin = {
5 | top: 20,
6 | right: 20,
7 | bottom: 20,
8 | left: 20
9 | },
10 | width = 900 - margin.left - margin.right,
11 | height = 500 - margin.bottom - margin.top,
12 | lineData;
13 |
14 | var svg = d3.select('body').append('svg')
15 | .attr('width', width)
16 | .attr('height', height)
17 | .on("click", addCoordinates);
18 |
19 | // gui stuff
20 | var params = function() {
21 | this.variability = 5;
22 | this.transform = 100;
23 | this.baseline = 0;
24 | this.color = '#000000';
25 | };
26 | var input = new params();
27 | var gui = new dat.GUI({
28 | height: 5 * 32 - 1
29 | });
30 |
31 | var controller = {
32 | variability: gui.add(input, 'variability', 0, 100)
33 | .onChange(function() {
34 | update();
35 | }),
36 |
37 | transform: gui.add(input, 'transform', 0, 200)
38 | .onChange(function() {
39 | update();
40 | }),
41 | baseline: gui.add(input, 'baseline', 0, 100)
42 | .onChange(function() {
43 | update();
44 | }),
45 | color: gui.addColor(input, 'color')
46 | .onChange(function(value) {
47 | svg.selectAll('path').attr('stroke', value);
48 | }),
49 | };
50 |
51 | var lineFunction = d3.svg.line()
52 | .x(function(d) {
53 | return d.x;
54 | })
55 | .y(function(d) {
56 | return d.y;
57 | })
58 | .interpolate('basis');
59 |
60 | d3.json('graph.json', function(error, letters) {
61 | lineData = letters;
62 | update();
63 | });
64 |
65 | function update() {
66 | svg.selectAll('path').remove();
67 |
68 | //for each letter
69 | for (var letter in lineData) {
70 | if (lineData.hasOwnProperty(letter)) {
71 | var letterPaths = transform(lineData[letter]);
72 |
73 | for (var i = letterPaths.length - 1; i >= 0; i--) {
74 | svg.append('path')
75 | .attr('d', lineFunction(letterPaths[i]))
76 | .attr('stroke', input.color);
77 | }
78 | }
79 | }
80 | }
81 |
82 | function addCoordinates() {
83 | var coordinates = d3.mouse(this);
84 | if (!lineData.newLetter) {
85 | lineData.newLetter = [
86 | []
87 | ];
88 | }
89 |
90 | lineData.newLetter[0].push({
91 | x: coordinates[0] / input.transform * 100,
92 | y: coordinates[1] / input.transform * 100
93 | });
94 | update();
95 | }
96 |
97 | function transform(letterPaths) {
98 | var paths = _.cloneDeep(letterPaths);
99 | for (var i = paths.length - 1; i >= 0; i--) {
100 | paths[i].map(coerce);
101 | }
102 | return paths;
103 | }
104 |
105 | // randomizes the points
106 | function coerce(d) {
107 | d.x = (d.x + Math.random() * input.variability - input.variability / 2) *
108 | (input.transform / 100);
109 | d.y = (d.y + Math.random() * input.variability - input.variability / 2) *
110 | (input.transform / 100) + input.baseline;
111 | return d;
112 | }
113 |
--------------------------------------------------------------------------------
/handwritten.dev.js:
--------------------------------------------------------------------------------
1 | var Handwritten;
2 |
3 | Handwritten = window.Handwritten || {};
4 |
5 | window.Handwritten = Handwritten;
6 |
7 | Handwritten.dev = {
8 | enabled: true,
9 | mountPoint: null
10 | };
11 |
12 | var hasProp = {}.hasOwnProperty;
13 |
14 | Handwritten.writing = function() {
15 | var baseline, coerce, color, draw, height, lineFunction, margin, randomize, transform, variability, width;
16 | draw = function(selection) {
17 | return selection.each(function(d, i) {
18 | var element, letter, letterPaths, path, results, values;
19 | element = d3.select(this);
20 | element.selectAll('path').remove();
21 | results = [];
22 | for (letter in d) {
23 | if (!hasProp.call(d, letter)) continue;
24 | values = d[letter];
25 | letterPaths = randomize(values);
26 | results.push((function() {
27 | var j, len, results1;
28 | results1 = [];
29 | for (j = 0, len = letterPaths.length; j < len; j++) {
30 | path = letterPaths[j];
31 | results1.push(element.append('path').attr('d', lineFunction(path)).attr('stroke', color));
32 | }
33 | return results1;
34 | })());
35 | }
36 | return results;
37 | });
38 | };
39 | lineFunction = d3.svg.line().x(function(d) {
40 | return d.x;
41 | }).y(function(d) {
42 | return d.y;
43 | }).interpolate('basis');
44 | margin = {
45 | top: 20,
46 | right: 20,
47 | bottom: 20,
48 | left: 20
49 | };
50 | width = 900 - margin.left - margin.right;
51 | height = 500 - margin.bottom - margin.top;
52 | variability = 5;
53 | transform = 100;
54 | baseline = 0;
55 | color = '#000000';
56 | draw.width = function(value) {
57 | if (!arguments.length) {
58 | return width;
59 | }
60 | width = value;
61 | return draw;
62 | };
63 | draw.height = function(value) {
64 | if (!arguments.length) {
65 | return height;
66 | }
67 | height = value;
68 | return draw;
69 | };
70 | draw.variability = function(value) {
71 | if (!arguments.length) {
72 | return variability;
73 | }
74 | variability = value;
75 | return draw;
76 | };
77 | draw.transform = function(value) {
78 | if (!arguments.length) {
79 | return transform;
80 | }
81 | transform = value;
82 | return draw;
83 | };
84 | draw.baseline = function(value) {
85 | if (!arguments.length) {
86 | return baseline;
87 | }
88 | baseline = value;
89 | return draw;
90 | };
91 | draw.color = function(value) {
92 | if (!arguments.length) {
93 | return color;
94 | }
95 | color = value;
96 | return draw;
97 | };
98 | randomize = function(letterPaths) {
99 | var j, len, path, paths;
100 | paths = _.cloneDeep(letterPaths);
101 | for (j = 0, len = paths.length; j < len; j++) {
102 | path = paths[j];
103 | path = path.map(coerce);
104 | }
105 | return paths;
106 | };
107 | coerce = function(d) {
108 | d.x = (d.x + Math.random() * variability - variability / 2) * (transform / 100);
109 | d.y = (d.y + Math.random() * variability - variability / 2) * (transform / 100) + baseline;
110 | return d;
111 | };
112 | return draw;
113 | };
114 |
115 | if (Handwritten.dev.enabled) {
116 | d3.json('../graph.json', function(error, letters) {
117 | Handwritten.dev.mountPoint = d3.select('body').append('svg').attr('width', Handwritten.writing().width()).attr('height', Handwritten.writing().height()).datum(letters).on("click", Handwritten.dev.addCoordinates);
118 | Handwritten.dev.gui = new dat.GUI();
119 | Handwritten.dev.params = (function() {
120 | this.variability = 5;
121 | this.transform = 100;
122 | this.baseline = 0;
123 | this.color = '#000000';
124 | return this;
125 | }).bind(this);
126 | Handwritten.dev.input = new Handwritten.dev.params();
127 | return (function() {
128 | var drawing, mountPoint;
129 | drawing = Handwritten.writing();
130 | mountPoint = Handwritten.dev.mountPoint;
131 | return Handwritten.dev.gui_controller = {
132 | variability: Handwritten.dev.gui.add(Handwritten.dev.input, 'variability', 0, 100).onChange(function() {
133 | drawing.variability(Handwritten.dev.input.variability);
134 | return drawing(mountPoint);
135 | }),
136 | transform: Handwritten.dev.gui.add(Handwritten.dev.input, 'transform', 0, 200).onChange(function() {
137 | drawing.transform(Handwritten.dev.input.transform);
138 | return drawing(mountPoint);
139 | }),
140 | baseline: Handwritten.dev.gui.add(Handwritten.dev.input, 'baseline', 0, 100).onChange(function() {
141 | drawing.baseline(Handwritten.dev.input.baseline);
142 | return drawing(mountPoint);
143 | }),
144 | color: Handwritten.dev.gui.add(Handwritten.dev.input, 'color').onChange(function(value) {
145 | drawing.color(Handwritten.dev.input.color);
146 | return drawing(mountPoint);
147 | })
148 | };
149 | })();
150 | });
151 | Handwritten.dev.addCoordinates = (function() {
152 | var coordinates;
153 | coordinates = d3.mouse(this);
154 | if (!this.data.newLetter) {
155 | this.data.newLetter = [[]];
156 | }
157 | this.data.newLetter[0].push({
158 | x: coordinates[0] / Handwritten.writing().transform() * 100,
159 | y: coordinates[1] / Handwritten.writing().transform() * 100
160 | });
161 | return Handwritten.writing().draw(Handwritten.dev.mountPoint);
162 | });
163 | }
164 |
165 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImFwcC5jb2ZmZWUiLCJ3cml0ZS5jb2ZmZWUiLCJkZXYuY29mZmVlIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLElBQUE7O0FBQUEsV0FBQSxHQUFjLE1BQU0sQ0FBQyxXQUFQLElBQXNCOztBQUNwQyxNQUFNLENBQUMsV0FBUCxHQUFxQjs7QUFHckIsV0FBVyxDQUFDLEdBQVosR0FDRTtFQUFBLE9BQUEsRUFBUyxJQUFUO0VBQ0EsVUFBQSxFQUFZLElBRFo7OztBQ0xGLElBQUE7O0FBQUEsV0FBVyxDQUFDLE9BQVosR0FBc0IsU0FBQTtBQUVwQixNQUFBO0VBQUEsSUFBQSxHQUFPLFNBQUMsU0FBRDtXQUNMLFNBQVMsQ0FBQyxJQUFWLENBQWdCLFNBQUMsQ0FBRCxFQUFJLENBQUo7QUFDZCxVQUFBO01BQUEsT0FBQSxHQUFVLEVBQUUsQ0FBQyxNQUFILENBQVUsSUFBVjtNQUNWLE9BQU8sQ0FBQyxTQUFSLENBQWtCLE1BQWxCLENBQXlCLENBQUMsTUFBMUIsQ0FBQTtBQUVBO1dBQUEsV0FBQTs7O1FBQ0UsV0FBQSxHQUFjLFNBQUEsQ0FBVSxNQUFWOzs7QUFDZDtlQUFBLDZDQUFBOzswQkFDRSxPQUFPLENBQUMsTUFBUixDQUFlLE1BQWYsQ0FDRSxDQUFDLElBREgsQ0FDUSxHQURSLEVBQ2EsWUFBQSxDQUFhLElBQWIsQ0FEYixDQUVFLENBQUMsSUFGSCxDQUVRLFFBRlIsRUFFa0IsS0FGbEI7QUFERjs7O0FBRkY7O0lBSmMsQ0FBaEI7RUFESztFQWFQLFlBQUEsR0FBZSxFQUFFLENBQUMsR0FBRyxDQUFDLElBQVAsQ0FBQSxDQUNiLENBQUMsQ0FEWSxDQUNWLFNBQUMsQ0FBRDtXQUNELENBQUMsQ0FBQztFQURELENBRFUsQ0FHWixDQUFDLENBSFcsQ0FHVCxTQUFDLENBQUQ7V0FDRixDQUFDLENBQUM7RUFEQSxDQUhTLENBS1osQ0FBQyxXQUxXLENBS0MsT0FMRDtFQU9mLE1BQUEsR0FDRTtJQUFBLEdBQUEsRUFBSyxFQUFMO0lBQ0EsS0FBQSxF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RDtNQUNBLENBQUEsRUFBRyxXQUFZLENBQUEsQ0FBQSxDQUFaLEdBQWlCLFdBQVcsQ0FBQyxPQUFaLENBQUEsQ0FBcUIsQ0FBQyxTQUF0QixDQUFBLENBQWpCLEdBQXFELEdBRHhEO0tBREY7V0FJQSxXQUFXLENBQUMsT0FBWixDQUFBLENBQXFCLENBQUMsSUFBdEIsQ0FBMkIsV0FBVyxDQUFDLEdBQUcsQ0FBQyxVQUEzQztFQVRnQyxDQUFGLEVBNUNsQyIsImZpbGUiOiJoYW5kd3JpdHRlbi5kZXYuanMiLCJzb3VyY2VzQ29udGVudCI6WyJIYW5kd3JpdHRlbiA9IHdpbmRvdy5IYW5kd3JpdHRlbiBvciB7fVxud2luZG93LkhhbmR3cml0dGVuID0gSGFuZHdyaXR0ZW5cblxuIyBnZW5lcmFsIHNldHRpbmdzXG5IYW5kd3JpdHRlbi5kZXYgPVxuICBlbmFibGVkOiB0cnVlXG4gIG1vdW50UG9pbnQ6IG51bGxcbiIsIkhhbmR3cml0dGVuLndyaXRpbmcgPSAtPlxuXG4gIGRyYXcgPSAoc2VsZWN0aW9uKSAtPlxuICAgIHNlbGVjdGlvbi5lYWNoKCAoZCwgaSkgLT5cbiAgICAgIGVsZW1lbnQgPSBkMy5zZWxlY3QoQClcbiAgICAgIGVsZW1lbnQuc2VsZWN0QWxsKCdwYXRoJykucmVtb3ZlKClcblxuICAgICAgZm9yIG93biBsZXR0ZXIsIHZhbHVlcyBvZiBkXG4gICAgICAgIGxldHRlclBhdGhzID0gcmFuZG9taXplKHZhbHVlcylcbiAgICAgICAgZm9yIHBhdGggaW4gbGV0dGVyUGF0aHNcbiAgICAgICAgICBlbGVtZW50LmFwcGVuZCgncGF0aCcpXG4gICAgICAgICAgICAuYXR0cignZCcsIGxpbmVGdW5jdGlvbihwYXRoKSlcbiAgICAgICAgICAgIC5hdHRyKCdzdHJva2UnLCBjb2xvcilcbiAgICApXG5cbiAgbGluZUZ1bmN0aW9uID0gZDMuc3ZnLmxpbmUoKVxuICAgIC54KChkKSAtPlxuICAgICAgZC54XG4gICAgKS55KChkKSAtPlxuICAgICAgZC55XG4gICAgKS5pbnRlcnBvbGF0ZSgnYmFzaXMnKVxuXG4gIG1hcmdpbiA9KFxuICAgIHRvcDogMjBcbiAgICByaWdodDogMjBcbiAgICBib3R0b206IDIwXG4gICAgbGVmdDogMjApXG5cbiAgd2lkdGggPSA5MDAgLSBtYXJnaW4ubGVmdCAtIG1hcmdpbi5yaWdodFxuICBoZWlnaHQgPSA1MDAgLSBtYXJnaW4uYm90dG9tIC0gbWFyZ2luLnRvcFxuICB2YXJpYWJpbGl0eSA9IDVcbiAgdHJhbnNmb3JtID0gMTAwXG4gIGJhc2VsaW5lID0gMFxuICBjb2xvciA9ICcjMDAwMDAwJ1xuXG4gICMgYWNjZXNzb3IgZnVuY3Rpb25zXG4gIGRyYXcud2lkdGggPSAodmFsdWUpIC0+XG4gICAgcmV0dXJuIHdpZHRoIHVubGVzcyBhcmd1bWVudHMubGVuZ3RoXG4gICAgd2lkdGggPSB2YWx1ZVxuICAgIGRyYXdcblxuICBkcmF3LmhlaWdodCA9ICh2YWx1ZSkgLT5cbiAgICByZXR1cm4gaGVpZ2h0IHVubGVzcyBhcmd1bWVudHMubGVuZ3RoXG4gICAgaGVpZ2h0ID0gdmFsdWVcbiAgICBkcmF3XG5cbiAgZHJhdy52YXJpYWJpbGl0eSA9ICh2YWx1ZSkgLT5cbiAgICByZXR1cm4gdmFyaWFiaWxpdHkgdW5sZXNzIGFyZ3VtZW50cy5sZW5ndGhcbiAgICB2YXJpYWJpbGl0eSA9IHZhbHVlXG4gICAgZHJhd1xuXG4gIGRyYXcudHJhbnNmb3JtID0gKHZhbHVlKSAtPlxuICAgIHJldHVybiB0cmFuc2Zvcm0gdW5sZXNzIGFyZ3VtZW50cy5sZW5ndGhcbiAgICB0cmFuc2Zvcm0gPSB2YWx1ZVxuICAgIGRyYXdcblxuICBkcmF3LmJhc2VsaW5lID0gKHZhbHVlKSAtPlxuICAgIHJldHVybiBiYXNlbGluZSB1bmxlc3MgYXJndW1lbnRzLmxlbmd0aFxuICAgIGJhc2VsaW5lID0gdmFsdWVcbiAgICBkcmF3XG5cbiAgZHJhdy5jb2xvciA9ICh2YWx1ZSkgLT5cbiAgICByZXR1cm4gY29sb3IgdW5sZXNzIGFyZ3VtZW50cy5sZW5ndGhcbiAgICBjb2xvciA9IHZhbHVlXG4gICAgZHJhd1xuXG4gIHJhbmRvbWl6ZSA9IChsZXR0ZXJQYXRocykgLT5cbiAgICBwYXRocyA9IF8uY2xvbmVEZWVwKGxldHRlclBhdGhzKVxuICAgIGZvciBwYXRoIGluIHBhdGhzXG4gICAgICBwYXRoID0gcGF0aC5tYXAoY29lcmNlKVxuICAgIHBhdGhzXG5cbiAgY29lcmNlID0gKGQpIC0+XG4gICAgZC54ID0gKGQueCArIE1hdGgucmFuZG9tKCkgKiB2YXJpYWJpbGl0eSAtIHZhcmlhYmlsaXR5IC8gMikgKlxuICAgICAgKHRyYW5zZm9ybSAvIDEwMClcbiAgICBkLnkgPSAoZC55ICsgTWF0aC5yYW5kb20oKSAqIHZhcmlhYmlsaXR5IC0gdmFyaWFiaWxpdHkgLyAyKSAqXG4gICAgICAodHJhbnNmb3JtIC8gMTAwKSArIGJhc2VsaW5lO1xuICAgIGRcblxuICAjIHJldHVybiBtYWluIHVwZGF0ZSBmdW5jdGlvblxuICBkcmF3XG4iLCJpZiBIYW5kd3JpdHRlbi5kZXYuZW5hYmxlZFxuICBkMy5qc29uKCcuLi9ncmFwaC5qc29uJywgKGVycm9yLCBsZXR0ZXJzKSAtPlxuICAgIEhhbmR3cml0dGVuLmRldi5tb3VudFBvaW50ID0gZDMuc2VsZWN0KCdib2R5JykuYXBwZW5kKCdzdmcnKVxuICAgICAgLmF0dHIoJ3dpZHRoJywgSGFuZHdyaXR0ZW4ud3JpdGluZygpLndpZHRoKCkpXG4gICAgICAuYXR0cignaGVpZ2h0JywgSGFuZHdyaXR0ZW4ud3JpdGluZygpLmhlaWdodCgpKVxuICAgICAgLmRhdHVtKGxldHRlcnMpXG4gICAgICAub24oXCJjbGlja1wiLCBIYW5kd3JpdHRlbi5kZXYuYWRkQ29vcmRpbmF0ZXMpO1xuXG4gICAgSGFuZHdyaXR0ZW4uZGV2Lmd1aSA9IG5ldyBkYXQuR1VJKClcbiAgICBIYW5kd3JpdHRlbi5kZXYucGFyYW1zID0gKC0+XG4gICAgICBALnZhcmlhYmlsaXR5ID0gNVxuICAgICAgQC50cmFuc2Zvcm0gPSAxMDBcbiAgICAgIEAuYmFzZWxpbmUgPSAwXG4gICAgICBALmNvbG9yID0gJyMwMDAwMDAnXG4gICAgICBAXG4gICAgKS5iaW5kKEApXG5cbiAgICBIYW5kd3JpdHRlbi5kZXYuaW5wdXQgPSBuZXcgSGFuZHdyaXR0ZW4uZGV2LnBhcmFtcygpXG5cbiAgICAoLT5cbiAgICAgIGRyYXdpbmcgPSBIYW5kd3JpdHRlbi53cml0aW5nKClcbiAgICAgIG1vdW50UG9pbnQgPSBIYW5kd3JpdHRlbi5kZXYubW91bnRQb2ludFxuICAgICAgSGFuZHdyaXR0ZW4uZGV2Lmd1aV9jb250cm9sbGVyID0gKFxuICAgICAgICB2YXJpYWJpbGl0eTogSGFuZHdyaXR0ZW4uZGV2Lmd1aS5hZGQoSGFuZHdyaXR0ZW4uZGV2LmlucHV0LFxuICAgICAgICAgICd2YXJpYWJpbGl0eScsIDAsIDEwMCkub25DaGFuZ2UoXG4gICAgICAgICAgLT5cbiAgICAgICAgICAgIGRyYXdpbmcudmFyaWFiaWxpdHkoSGFuZHdyaXR0ZW4uZGV2LmlucHV0LnZhcmlhYmlsaXR5KVxuICAgICAgICAgICAgZHJhd2luZyhtb3VudFBvaW50KSlcbiAgICAgICAgdHJhbnNmb3JtOiBIYW5kd3JpdHRlbi5kZXYuZ3VpLmFkZChIYW5kd3JpdHRlbi5kZXYuaW5wdXQsICd0cmFuc2Zvcm0nLCAwLCAyMDApLm9uQ2hhbmdlKFxuICAgICAgICAgIC0+XG4gICAgICAgICAgICBkcmF3aW5nLnRyYW5zZm9ybShIYW5kd3JpdHRlbi5kZXYuaW5wdXQudHJhbnNmb3JtKVxuICAgICAgICAgICAgZHJhd2luZyhtb3VudFBvaW50KSlcbiAgICAgICAgYmFzZWxpbmU6IEhhbmR3cml0dGVuLmRldi5ndWkuYWRkKEhhbmR3cml0dGVuLmRldi5pbnB1dCwgJ2Jhc2VsaW5lJywgMCwgMTAwKS5vbkNoYW5nZShcbiAgICAgICAgICAtPlxuICAgICAgICAgICAgZHJhd2luZy5iYXNlbGluZShIYW5kd3JpdHRlbi5kZXYuaW5wdXQuYmFzZWxpbmUpXG4gICAgICAgICAgICBkcmF3aW5nKG1vdW50UG9pbnQpKVxuICAgICAgICBjb2xvcjogSGFuZHdyaXR0ZW4uZGV2Lmd1aS5hZGQoSGFuZHdyaXR0ZW4uZGV2LmlucHV0LCAnY29sb3InKS5vbkNoYW5nZShcbiAgICAgICAgICAodmFsdWUpIC0+XG4gICAgICAgICAgICBkcmF3aW5nLmNvbG9yKEhhbmR3cml0dGVuLmRldi5pbnB1dC5jb2xvcilcbiAgICAgICAgICAgIGRyYXdpbmcobW91bnRQb2ludCkpXG4gICAgICAgIClcbiAgICApKClcbiAgKVxuXG4gIEhhbmR3cml0dGVuLmRldi5hZGRDb29yZGluYXRlcyA9KCAtPlxuICAgIGNvb3JkaW5hdGVzID0gZDMubW91c2UoQClcbiAgICBpZiAhQGRhdGEubmV3TGV0dGVyXG4gICAgICBAZGF0YS5uZXdMZXR0ZXIgPSBbW11dXG5cbiAgICBAZGF0YS5uZXdMZXR0ZXJbMF0ucHVzaChcbiAgICAgIHg6IGNvb3JkaW5hdGVzWzBdIC8gSGFuZHdyaXR0ZW4ud3JpdGluZygpLnRyYW5zZm9ybSgpICogMTAwLFxuICAgICAgeTogY29vcmRpbmF0ZXNbMV0gLyBIYW5kd3JpdHRlbi53cml0aW5nKCkudHJhbnNmb3JtKCkgKiAxMDBcbiAgICApXG4gICAgSGFuZHdyaXR0ZW4ud3JpdGluZygpLmRyYXcoSGFuZHdyaXR0ZW4uZGV2Lm1vdW50UG9pbnQpXG4gICkiXSwic291cmNlUm9vdCI6Ii9zb3VyY2UvIn0=
166 |
--------------------------------------------------------------------------------