├── contributions └── .gitkeep ├── web ├── templates │ ├── robots.txt │ ├── 404.html │ ├── 500.html │ ├── index.html │ ├── search.html │ ├── components │ │ └── uml_list.html │ └── base.html ├── index.yaml ├── static │ ├── img │ │ ├── logo.png │ │ ├── favicon.ico │ │ ├── top_image.png │ │ ├── github_octocat.png │ │ ├── icon_state.svg │ │ ├── icon_component.svg │ │ ├── icon_sequence.svg │ │ ├── icon_activity.svg │ │ ├── icon_usecase.svg │ │ └── icon_class.svg │ ├── js │ │ └── main.js │ └── css │ │ └── main.css ├── app.yaml ├── Makefile ├── .gcloudignore ├── main.go ├── handler.go └── uml.go ├── renderer ├── Dockerfile ├── app.yaml └── Makefile ├── scraping ├── package.json ├── scraping.js ├── package-lock.json └── results │ └── 20180125_01.txt ├── indexer ├── queue.yaml ├── app.go ├── app.yaml ├── middleware.go ├── indexer_test.go ├── Makefile ├── syntax_checker.go ├── renderer.go ├── handler.go └── indexer.go ├── docs ├── architecture.png └── architexture.puml ├── syntaxchecker ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── app.yaml ├── Dockerfile ├── Makefile ├── build.gradle ├── gradlew.bat ├── src │ └── main │ │ └── kotlin │ │ └── com │ │ └── yfuruyama │ │ └── syntaxchecker │ │ └── Main.kt └── gradlew ├── .gitignore ├── util └── gen_app_yaml.go └── README.md /contributions/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /web/templates/robots.txt: -------------------------------------------------------------------------------- 1 | Allow: / 2 | -------------------------------------------------------------------------------- /web/index.yaml: -------------------------------------------------------------------------------- 1 | indexes: 2 | # AUTOGENERATED 3 | -------------------------------------------------------------------------------- /renderer/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM plantuml/plantuml-server:jetty 2 | -------------------------------------------------------------------------------- /scraping/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "chromy": "latest" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /indexer/queue.yaml: -------------------------------------------------------------------------------- 1 | queue: 2 | - name: index-create-queue 3 | target: indexer 4 | rate: 10/s 5 | -------------------------------------------------------------------------------- /docs/architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yfuruyama/real-world-plantuml/HEAD/docs/architecture.png -------------------------------------------------------------------------------- /web/static/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yfuruyama/real-world-plantuml/HEAD/web/static/img/logo.png -------------------------------------------------------------------------------- /web/static/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yfuruyama/real-world-plantuml/HEAD/web/static/img/favicon.ico -------------------------------------------------------------------------------- /web/static/img/top_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yfuruyama/real-world-plantuml/HEAD/web/static/img/top_image.png -------------------------------------------------------------------------------- /web/templates/404.html: -------------------------------------------------------------------------------- 1 | {{define "content"}} 2 |
3 | Oops! Page Not Found. 4 |
5 | {{end}} 6 | -------------------------------------------------------------------------------- /web/static/img/github_octocat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yfuruyama/real-world-plantuml/HEAD/web/static/img/github_octocat.png -------------------------------------------------------------------------------- /web/templates/500.html: -------------------------------------------------------------------------------- 1 | {{define "content"}} 2 |
3 | Oops! Server error happened. Please try again later. 4 |
5 | {{end}} 6 | -------------------------------------------------------------------------------- /syntaxchecker/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yfuruyama/real-world-plantuml/HEAD/syntaxchecker/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /renderer/app.yaml: -------------------------------------------------------------------------------- 1 | runtime: custom 2 | env: flex 3 | service: renderer 4 | network: 5 | forwarded_ports: 6 | - 80:8080 7 | manual_scaling: 8 | instances: 1 9 | -------------------------------------------------------------------------------- /syntaxchecker/app.yaml: -------------------------------------------------------------------------------- 1 | runtime: custom 2 | env: flex 3 | service: syntaxchecker 4 | network: 5 | forwarded_ports: 6 | - 80:8080 7 | manual_scaling: 8 | instances: 1 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | app.dist.yaml 3 | web/vendor 4 | 5 | scraping/node_modules 6 | 7 | # syntaxchecker 8 | syntaxchecker/build 9 | .gradle 10 | .idea 11 | !gradle-wrapper.jar 12 | -------------------------------------------------------------------------------- /renderer/Makefile: -------------------------------------------------------------------------------- 1 | PORT=8086 2 | CONTAINER_PORT=8080 3 | 4 | all: build 5 | 6 | build: 7 | docker build -t plantuml-renderer . 8 | 9 | run: 10 | docker run -p $(PORT):$(CONTAINER_PORT) plantuml-renderer 11 | -------------------------------------------------------------------------------- /syntaxchecker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:8-jdk 2 | WORKDIR /app 3 | COPY . /app/ 4 | 5 | RUN apt update && apt install -y graphviz fonts-wqy-zenhei 6 | 7 | EXPOSE 8080 8 | 9 | RUN ./gradlew build 10 | 11 | CMD ./gradlew run 12 | -------------------------------------------------------------------------------- /syntaxchecker/Makefile: -------------------------------------------------------------------------------- 1 | PORT=8087 2 | 3 | .PHONY: build 4 | all: build 5 | 6 | build: 7 | docker build -t syntaxchecker . 8 | 9 | run: 10 | docker run -p $(PORT):8080 syntaxchecker 11 | 12 | deploy: 13 | gcloud --project=$(PROJECT) app deploy 14 | -------------------------------------------------------------------------------- /web/templates/index.html: -------------------------------------------------------------------------------- 1 | {{define "content"}} 2 | 3 | {{template "uml_list" .}} 4 | 5 | {{ if .NextCursor }} 6 | 7 | {{ end }} 8 | 9 | {{ end }} 10 | -------------------------------------------------------------------------------- /syntaxchecker/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sun Dec 31 01:33:26 JST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.14-bin.zip 7 | -------------------------------------------------------------------------------- /web/templates/search.html: -------------------------------------------------------------------------------- 1 | {{define "content"}} 2 | 3 | {{if .Umls}} 4 | {{template "uml_list" .}} 5 | 6 | {{if .NextCursor}} 7 | 8 | {{end}} 9 | {{else}} 10 |
11 | No results found. 12 |
13 | {{end}} 14 | 15 | {{end}} 16 | -------------------------------------------------------------------------------- /web/app.yaml: -------------------------------------------------------------------------------- 1 | runtime: go111 2 | instance_class: F1 3 | service: default 4 | inbound_services: 5 | - warmup 6 | automatic_scaling: 7 | max_instances: 1 8 | env_variables: 9 | GA_TRACKING_ID: UA-25397287-3 10 | 11 | handlers: 12 | - url: /static 13 | static_dir: static 14 | - url: /robots.txt 15 | static_files: templates/robots.txt 16 | upload: templates/robots.txt 17 | - url: /.* 18 | script: auto 19 | -------------------------------------------------------------------------------- /indexer/app.go: -------------------------------------------------------------------------------- 1 | package indexer 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/go-chi/chi" 7 | ) 8 | 9 | func init() { 10 | router := chi.NewRouter() 11 | 12 | router.Route("/indexes", func(r chi.Router) { 13 | r.Use(AuthTaskqueue) 14 | r.Post("/", HandleIndexCreate) 15 | }) 16 | router.Post("/_ah/push-handlers/gcs_notification", HandleGcsNotification) 17 | 18 | http.Handle("/", router) 19 | } 20 | -------------------------------------------------------------------------------- /indexer/app.yaml: -------------------------------------------------------------------------------- 1 | runtime: go 2 | api_version: go1 3 | instance_class: B1 4 | service: indexer 5 | manual_scaling: 6 | instances: 1 7 | env_variables: 8 | GITHUB_API_TOKEN: {{.GITHUB_API_TOKEN}} 9 | RENDERER_BASE_URL: {{.RENDERER_BASE_URL}} 10 | SYNTAX_CHECKER_BASE_URL: {{.SYNTAX_CHECKER_BASE_URL}} 11 | 12 | handlers: 13 | - url: /_ah/push-handlers/* 14 | script: _go_app 15 | login: admin 16 | 17 | - url: /.* 18 | script: _go_app 19 | login: admin 20 | -------------------------------------------------------------------------------- /indexer/middleware.go: -------------------------------------------------------------------------------- 1 | package indexer 2 | 3 | import ( 4 | "net/http" 5 | 6 | "google.golang.org/appengine" 7 | "google.golang.org/appengine/log" 8 | ) 9 | 10 | func AuthTaskqueue(next http.Handler) http.Handler { 11 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 12 | ctx := appengine.NewContext(r) 13 | if r.Header.Get("X-AppEngine-QueueName") == "" { 14 | log.Warningf(ctx, "Request is not from TaskQueue") 15 | w.WriteHeader(http.StatusForbidden) 16 | return 17 | } 18 | next.ServeHTTP(w, r) 19 | }) 20 | } 21 | -------------------------------------------------------------------------------- /web/Makefile: -------------------------------------------------------------------------------- 1 | PORT=8080 2 | API_PORT=8081 3 | ADMIN_PORT=8082 4 | DATASTORE_PORT=8083 5 | 6 | all: 7 | test 8 | 9 | test: 10 | echo "TBD" 11 | 12 | run-datastore: 13 | gcloud beta emulators datastore start --host-port=localhost:$(DATASTORE_PORT) 14 | 15 | run: 16 | dev_appserver.py --datastore_emulator_port=$(DATASTORE_PORT) --logs_path=/tmp/log_web.db --search_indexes_path=/tmp/search.db --clear_search_indexes=false --port=$(PORT) --api_port=$(API_PORT) --admin_port=$(ADMIN_PORT) app.yaml 17 | 18 | deploy: 19 | gcloud --project=$(PROJECT) app deploy app.yaml --version=$(VERSION) 20 | -------------------------------------------------------------------------------- /web/.gcloudignore: -------------------------------------------------------------------------------- 1 | # This file specifies files that are *not* uploaded to Google Cloud Platform 2 | # using gcloud. It follows the same syntax as .gitignore, with the addition of 3 | # "#!include" directives (which insert the entries of the given .gitignore-style 4 | # file at that point). 5 | # 6 | # For more information, run: 7 | # $ gcloud topic gcloudignore 8 | # 9 | .gcloudignore 10 | # If you would like to upload your .git directory, .gitignore file or files 11 | # from your .gitignore file, remove the corresponding line 12 | # below: 13 | .git 14 | .gitignore 15 | 16 | # Binaries for programs and plugins 17 | *.exe 18 | *.exe~ 19 | *.dll 20 | *.so 21 | *.dylib 22 | # Test binary, build with `go test -c` 23 | *.test 24 | # Output of the go coverage tool, specifically when used with LiteIDE 25 | *.out -------------------------------------------------------------------------------- /web/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "net/http" 5 | "os" 6 | 7 | "github.com/go-chi/chi" 8 | 9 | "google.golang.org/appengine" 10 | ) 11 | 12 | func main() { 13 | gaTrackingId := os.Getenv("GA_TRACKING_ID") 14 | handler := NewHandler(gaTrackingId) 15 | 16 | router := chi.NewRouter() 17 | router.Get("/_ah/warmup", handler.ToHandlerFunc(handler.Warmup)) 18 | router.Get("/", handler.ToHandlerFunc(handler.GetIndex)) 19 | router.Get("/search", handler.ToHandlerFunc(handler.GetSearch)) 20 | router.Get("/umls/{umlID:\\d+}", handler.ToHandlerFunc(handler.GetUml)) 21 | router.NotFound(handler.ToHandlerFunc(handler.NotFound)) 22 | 23 | // for debugging 24 | if appengine.IsDevAppServer() { 25 | router.Get("/debug/dummy_uml", handler.ToHandlerFunc(handler.DebugRegisterDummyUml)) 26 | } 27 | 28 | http.Handle("/", router) 29 | 30 | appengine.Main() 31 | } 32 | -------------------------------------------------------------------------------- /util/gen_app_yaml.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "log" 6 | "os" 7 | "strings" 8 | "text/template" 9 | ) 10 | 11 | func main() { 12 | var inPath string 13 | var outPath string 14 | 15 | flag.StringVar(&inPath, "in", "", "Path to source app.yaml") 16 | flag.StringVar(&outPath, "out", "", "Path to target app.yaml") 17 | flag.Parse() 18 | 19 | if inPath == "" || outPath == "" { 20 | flag.Usage() 21 | os.Exit(1) 22 | } 23 | 24 | tmpl, err := template.ParseFiles(inPath) 25 | if err != nil { 26 | log.Fatal(err) 27 | } 28 | 29 | out, err := os.Create(outPath) 30 | if err != nil { 31 | log.Fatal(err) 32 | } 33 | defer out.Close() 34 | 35 | env := make(map[string]string) 36 | for _, e := range os.Environ() { 37 | pair := strings.Split(e, "=") 38 | env[pair[0]] = pair[1] 39 | } 40 | 41 | err = tmpl.Execute(out, env) 42 | if err != nil { 43 | log.Fatal(err) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | real-world-plantuml 2 | === 3 | 4 | Source code of https://real-world-plantuml.com/ 5 | 6 | ## Architecture 7 | 8 | architecture 9 | 10 | ## For development 11 | 12 | ### web 13 | 14 | Run server 15 | 16 | ``` 17 | make run GA_TRACKING_ID=${GA_TRACKING_ID} 18 | ``` 19 | 20 | Register dummy UML: access to `/debug/dummy_uml` in your browser 21 | 22 | ### indexer 23 | 24 | Run server 25 | 26 | ``` 27 | make run GITHUB_API_TOKEN=${GITHUB_API_TOKEN} GCS_BUCKET=${GCS_BUCKET} 28 | ``` 29 | 30 | ### renderer 31 | 32 | Run server 33 | 34 | ``` 35 | make run 36 | ``` 37 | 38 | ### scraping 39 | 40 | Launch Chrome with remote debugging enabled 41 | 42 | ``` 43 | /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --remote-debugging-port=9222 44 | ``` 45 | 46 | Run scraping script 47 | 48 | ``` 49 | cd scraping 50 | npm install 51 | node scraping.js > results/YYYYMMDD_01.txt 52 | ``` 53 | -------------------------------------------------------------------------------- /docs/architexture.puml: -------------------------------------------------------------------------------- 1 | @startuml 2 | cloud { 3 | [GitHub] as github 4 | } 5 | 6 | package "Local Machine" { 7 | [nodejs] as scrape 8 | } 9 | 10 | package "GCP" { 11 | database "Cloud Datastore" as datastore { 12 | [entity] 13 | } 14 | 15 | database "Cloud Storage" as gcs { 16 | [bucket] 17 | } 18 | 19 | node "App Engine" { 20 | frame "Standard" { 21 | [indexer] 22 | [web] 23 | } 24 | frame "Flexible" { 25 | [syntax_checker] 26 | [renderer] 27 | } 28 | database "TaskQueue" as taskqueue { 29 | [index-create-queue] as queue 30 | } 31 | [Search API] as searchapi 32 | } 33 | } 34 | 35 | actor User as user 36 | 37 | scrape --> github : 1. scraping 38 | scrape -r-> bucket : 2. put GitHub urls 39 | bucket -d-> indexer : 3. notification 40 | indexer -l-> queue : 4. put task 41 | queue -r-> indexer : 5. execute task 42 | indexer --> syntax_checker : 6. syntax check 43 | indexer --> renderer : 7. rendering 44 | indexer -u-> entity : 8. put 45 | web -u-> entity : 9. get 46 | web -d-> searchapi : 10. search 47 | web -r-> user : 11. show web page 48 | 49 | @enduml 50 | -------------------------------------------------------------------------------- /syntaxchecker/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.1.0-dev-1159' 3 | ext.plantuml_version = '1.2017.20' 4 | ext.repo = 'https://repo.gradle.org/gradle/repo' 5 | 6 | repositories { 7 | maven { url = repo} 8 | } 9 | dependencies { 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | } 12 | } 13 | 14 | apply plugin: 'kotlin' 15 | apply plugin: 'application' 16 | 17 | mainClassName = 'com.yfuruyama.syntaxchecker.MainKt' 18 | 19 | jar { 20 | baseName = 'com.yfuruyama.syntaxchecker' 21 | version = '0.1.0' 22 | } 23 | 24 | repositories { 25 | maven { url = repo} 26 | } 27 | 28 | dependencies { 29 | compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" 30 | compile "org.glassfish.jersey.containers:jersey-container-jetty-http:2.23.1" 31 | compile "org.glassfish.jersey.media:jersey-media-json-jackson:2.23.1" 32 | compile "com.fasterxml.jackson.module:jackson-module-kotlin:2.5.5-2" 33 | compile "net.sourceforge.plantuml:plantuml:$plantuml_version" 34 | 35 | testCompile 'org.spockframework:spock-core:1.0-groovy-2.4' 36 | testCompile "org.jetbrains.spek:spek:1.0.25" 37 | } 38 | 39 | task wrapper(type: Wrapper) { 40 | gradleVersion = '2.14' 41 | } -------------------------------------------------------------------------------- /indexer/indexer_test.go: -------------------------------------------------------------------------------- 1 | package indexer 2 | 3 | import ( 4 | "testing" 5 | 6 | "google.golang.org/appengine/aetest" 7 | ) 8 | 9 | func TestFindSources(t *testing.T) { 10 | ctx, done, err := aetest.NewContext() 11 | if err != nil { 12 | t.Fatal(err) 13 | } 14 | defer done() 15 | 16 | var tests = []struct { 17 | text string 18 | expected []string 19 | }{ 20 | { 21 | ` 22 | @startuml 23 | alice -> bob 24 | @enduml 25 | 26 | @startuml 27 | bob -> alice 28 | @enduml 29 | `, []string{"@startuml\nalice -> bob\n@enduml", "@startuml\nbob -> alice\n@enduml"}}, 30 | { 31 | ` 32 | @startuml 33 | alice -> bob 34 | @enduml 35 | @enduml 36 | @startuml 37 | `, []string{"@startuml\nalice -> bob\n@enduml"}}, 38 | { 39 | ` 40 | @enduml 41 | @startuml 42 | alice -> bob 43 | @enduml 44 | @startuml 45 | `, []string{"@startuml\nalice -> bob\n@enduml"}}, 46 | } 47 | 48 | for _, test := range tests { 49 | got := findSources(ctx, test.text) 50 | if !isSameSources(got, test.expected) { 51 | t.Errorf("not expected sources: got=%#v, expected=%#v", got, test.expected) 52 | } 53 | } 54 | } 55 | 56 | func isSameSources(got []string, expected []string) bool { 57 | if len(got) != len(expected) { 58 | return false 59 | } 60 | for i := 0; i < len(got); i++ { 61 | if got[i] != expected[i] { 62 | return false 63 | } 64 | } 65 | return true 66 | } 67 | -------------------------------------------------------------------------------- /indexer/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: test 2 | 3 | PORT=8083 4 | API_PORT=8084 5 | ADMIN_PORT=8085 6 | RENDERER_BASE_URL=http://localhost:8086 7 | SYNTAX_CHECKER_BASE_URL=http://localhost:8087 8 | 9 | # Must be set 10 | GITHUB_API_TOKEN=xxx 11 | GCS_BUCKET=xxx 12 | 13 | all: 14 | test 15 | 16 | test: 17 | go test -v ./... 18 | 19 | run: 20 | GITHUB_API_TOKEN=$(GITHUB_API_TOKEN) RENDERER_BASE_URL=$(RENDERER_BASE_URL) SYNTAX_CHECKER_BASE_URL=$(SYNTAX_CHECKER_BASE_URL) go run ../util/gen_app_yaml.go --in app.yaml --out app.dist.yaml 21 | dev_appserver.py --port=$(PORT) --api_port=$(API_PORT) --admin_port=$(ADMIN_PORT) --logs_path=/tmp/log_indexer.db --storage_path=/tmp/storage.db --search_indexes_path=/tmp/search.db --clear_search_indexes=false --default_gcs_bucket_name=$(GCS_BUCKET) app.dist.yaml 22 | 23 | notify: 24 | curl -X POST http://localhost:$(PORT)/_ah/push-handlers/gcs_notification --data '{"message": {"attributes":{"objectId":"$(OBJECT_ID)", "eventType":"OBJECT_FINALIZE"}, "messageId":"xxx"}, "subscription" :"xxx"}' 25 | 26 | deploy: 27 | GITHUB_API_TOKEN=$(GITHUB_API_TOKEN) RENDERER_BASE_URL=$(RENDERER_BASE_URL) SYNTAX_CHECKER_BASE_URL=$(SYNTAX_CHECKER_BASE_URL) go run ../util/gen_app_yaml.go --in app.yaml --out app.dist.yaml 28 | gcloud --project=$(PROJECT) app deploy app.dist.yaml --version=$(VERSION) 29 | 30 | deploy_queue: 31 | gcloud --project=$(PROJECT) app deploy queue.yaml 32 | -------------------------------------------------------------------------------- /scraping/scraping.js: -------------------------------------------------------------------------------- 1 | const Chromy = require('chromy') 2 | 3 | let chromy = new Chromy({ 4 | visible: true, 5 | launchBrowser: false, 6 | }); 7 | 8 | async function scrape(searchWord) { 9 | var page = 1; 10 | 11 | while (true) { 12 | let url = 'https://github.com/search?type=Code&q=' + encodeURIComponent(searchWord) + '&p=' + page; 13 | console.error('scrape url:' + url); 14 | await chromy.goto(url); 15 | 16 | let repos = await chromy.evaluate(() => { 17 | return Array.prototype.map.call(document.getElementsByClassName('code-list-item'), function(e) { return e.getElementsByTagName('a')[2].href; }); 18 | }); 19 | repos.forEach(function(r) { 20 | console.log(r); 21 | }); 22 | 23 | let hasNext = await chromy.evaluate(() => { 24 | if (document.getElementsByClassName('next_page').length == 0) { 25 | return false; 26 | } 27 | return document.getElementsByClassName('next_page disabled').length == 0 ? true : false; 28 | }); 29 | if (!hasNext) { 30 | console.error('no more page'); 31 | break; 32 | } 33 | 34 | page++; 35 | 36 | // sleep 37 | await new Promise(resolve => { 38 | setTimeout(() => { 39 | resolve(); 40 | }, 10000); 41 | }); 42 | } 43 | } 44 | 45 | const searchWords = [ 46 | 'startuml enduml size:>100 license:mit language:Text', 47 | 'startuml enduml size:>100 license:mit language:Markdown', 48 | 'startuml enduml size:>100 license:mit extension:puml', 49 | 'startuml enduml size:>100 license:mit extension:uml', 50 | 'startuml enduml size:>100 license:mit extension:plantuml', 51 | ]; 52 | 53 | (async function() { 54 | for (const word of searchWords) { 55 | await scrape(word); 56 | } 57 | })(); 58 | 59 | chromy.close(); 60 | -------------------------------------------------------------------------------- /web/static/img/icon_state.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Group 2 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /web/templates/components/uml_list.html: -------------------------------------------------------------------------------- 1 | {{define "uml_list"}} 2 | 3 |
4 | {{range .Umls}} 5 |
6 |
7 |
8 | {{ .Svg | safehtml }} 9 |
10 | 29 |
30 |
{{ .DiagramType.ToHumanString | toUpperCase }} DIAGRAM
31 |
{{ .ID }}
32 |
33 | {{end}} 34 |
35 | 36 | {{end}} 37 | -------------------------------------------------------------------------------- /indexer/syntax_checker.go: -------------------------------------------------------------------------------- 1 | package indexer 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "net/http" 7 | "regexp" 8 | "strings" 9 | 10 | "google.golang.org/appengine/log" 11 | "google.golang.org/appengine/urlfetch" 12 | ) 13 | 14 | type SyntaxCheckRequest struct { 15 | Source string `json:"source"` 16 | } 17 | 18 | type SyntaxCheckResult struct { 19 | Valid bool `json:"valid"` 20 | DiagramType string `json:"diagramType"` 21 | Description string `json:"description"` 22 | } 23 | 24 | func (r *SyntaxCheckResult) HasValidDiagram() bool { 25 | re := regexp.MustCompile(`^\(([0-9]+) .+\)$`) 26 | matched := re.FindStringSubmatch(r.Description) 27 | if len(matched) != 2 { 28 | // regard unexpected description as valid 29 | return true 30 | } 31 | if matched[1] == "0" { 32 | return false 33 | } 34 | return true 35 | } 36 | 37 | type SyntaxChecker struct { 38 | BaseUrl string 39 | ctx context.Context 40 | } 41 | 42 | func NewSyntaxChecker(ctx context.Context, baseUrl string) *SyntaxChecker { 43 | return &SyntaxChecker{ 44 | BaseUrl: baseUrl, 45 | ctx: ctx, 46 | } 47 | } 48 | 49 | func (s *SyntaxChecker) CheckSyntax(source string) (*SyntaxCheckResult, error) { 50 | checkReq := &SyntaxCheckRequest{source} 51 | reqBody, err := json.Marshal(checkReq) 52 | if err != nil { 53 | return nil, err 54 | } 55 | 56 | log.Infof(s.ctx, "request body: %s", string(reqBody)) 57 | 58 | req, err := http.NewRequest("POST", s.BaseUrl+"/check_syntax", strings.NewReader(string(reqBody))) 59 | if err != nil { 60 | return nil, err 61 | } 62 | req.Header.Add("Content-Type", "application/json") 63 | 64 | client := urlfetch.Client(s.ctx) 65 | resp, err := client.Do(req) 66 | if err != nil { 67 | log.Criticalf(s.ctx, "failed to request to syntax checker: err=%s", err) 68 | return nil, err 69 | } 70 | defer resp.Body.Close() 71 | 72 | var result SyntaxCheckResult 73 | if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { 74 | return nil, err 75 | } 76 | 77 | return &result, nil 78 | } 79 | -------------------------------------------------------------------------------- /web/static/img/icon_component.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Combined Shape 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /web/static/js/main.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function() { 2 | var isUmlPage = location.pathname.match(/\/umls\/(\d+)/); 3 | var umlIdInPath = isUmlPage ? isUmlPage[1] : null; 4 | var allUmlIds = $('.uml').map(function(){ 5 | return this.dataset.umlId 6 | }).get(); 7 | 8 | // setup source copy 9 | var clipboard = new Clipboard('.uml__modal__body__source__header__copy'); 10 | clipboard.on('success', function(e) { 11 | var orig = e.trigger.innerText; 12 | e.trigger.innerText = "COPIED!"; 13 | setTimeout(function() { 14 | e.trigger.innerText = orig; 15 | }, 1000); 16 | }); 17 | 18 | // setup modal 19 | $('.uml').each(function(i, elem) { 20 | var umlId = elem.dataset.umlId; 21 | var autoopen = (umlIdInPath && umlIdInPath == umlId) ? true : false; 22 | $('#uml__modal__' + umlId).popup({ 23 | autoopen: autoopen, 24 | opacity: 0.7, 25 | onopen: function() { 26 | var originalPath = location.pathname + location.search; 27 | history.replaceState(originalPath, null, '/umls/' + umlId); 28 | }, 29 | onclose: function() { 30 | var originalPath = history.state; 31 | history.replaceState(null, null, originalPath); 32 | }, 33 | }); 34 | }); 35 | 36 | // workaround for https://github.com/yfuruyama/real-world-plantuml/issues/2 37 | $('.popup_wrapper').each(function(i, elem) { 38 | elem.style.display = ''; 39 | }); 40 | 41 | // keyboard shortcut 42 | document.onkeydown = function(e) { 43 | if (e.key === 'ArrowLeft' || e.key === 'ArrowRight') { 44 | var isUmlPage = location.pathname.match(/\/umls\/(\d+)/); 45 | if (!isUmlPage || isUmlPage.length < 2) { 46 | return; 47 | } 48 | var umlId = isUmlPage[1]; 49 | 50 | var idx = allUmlIds.indexOf(umlId); 51 | if (idx !== -1) { 52 | // hide current 53 | $('#uml__modal__' + umlId).popup('hide'); 54 | 55 | // show previous 56 | if (e.key === 'ArrowLeft' && idx > 0) { 57 | $('#uml__modal__' + allUmlIds[idx - 1]).popup('show'); 58 | } 59 | 60 | // show next 61 | if (e.key === 'ArrowRight' && allUmlIds.length > idx + 1) { 62 | $('#uml__modal__' + allUmlIds[idx + 1]).popup('show'); 63 | } 64 | } 65 | } 66 | }; 67 | }); 68 | -------------------------------------------------------------------------------- /indexer/renderer.go: -------------------------------------------------------------------------------- 1 | package indexer 2 | 3 | import ( 4 | "context" 5 | "io/ioutil" 6 | "net/http" 7 | "net/url" 8 | "strings" 9 | 10 | "google.golang.org/appengine/log" 11 | "google.golang.org/appengine/urlfetch" 12 | ) 13 | 14 | type Renderer struct { 15 | BaseUrl string 16 | ctx context.Context 17 | } 18 | 19 | func NewRenderer(ctx context.Context, baseUrl string) *Renderer { 20 | return &Renderer{ 21 | BaseUrl: baseUrl, 22 | ctx: ctx, 23 | } 24 | } 25 | 26 | func (r *Renderer) RenderSvg(source string) (string, error) { 27 | umlId, err := r.getUmlId(source) 28 | if err != nil { 29 | return "", err 30 | } 31 | 32 | svgBytes, err := r.doRequest("/svg/" + umlId) 33 | if err != nil { 34 | return "", err 35 | } 36 | return string(svgBytes), err 37 | } 38 | 39 | func (r *Renderer) RenderPng(source string) ([]byte, error) { 40 | umlId, err := r.getUmlId(source) 41 | if err != nil { 42 | return nil, err 43 | } 44 | 45 | return r.doRequest("/png/" + umlId) 46 | } 47 | 48 | func (r *Renderer) RenderAscii(source string) (string, error) { 49 | umlId, err := r.getUmlId(source) 50 | if err != nil { 51 | return "", err 52 | } 53 | 54 | asciiBytes, err := r.doRequest("/txt/" + umlId) 55 | if err != nil { 56 | return "", err 57 | } 58 | return string(asciiBytes), err 59 | } 60 | 61 | func (r *Renderer) getUmlId(source string) (string, error) { 62 | values := url.Values{} 63 | values.Add("text", source) 64 | req, _ := http.NewRequest("POST", r.BaseUrl+"/form", strings.NewReader(values.Encode())) 65 | req.Header.Add("Content-Type", "application/x-www-form-urlencoded") 66 | 67 | client := urlfetch.Client(r.ctx) 68 | client.CheckRedirect = func(req *http.Request, via []*http.Request) error { 69 | // no follow redirect 70 | return http.ErrUseLastResponse 71 | } 72 | resp, err := client.Do(req) 73 | if err != nil { 74 | log.Criticalf(r.ctx, "Failed to request to renderer /form: %s", err) 75 | return "", err 76 | } 77 | defer resp.Body.Close() 78 | 79 | locationUrl, err := resp.Location() 80 | if err != nil { 81 | log.Criticalf(r.ctx, "Failed to get location header: %s", err) 82 | return "", err 83 | } 84 | umlId := strings.TrimPrefix(locationUrl.Path, "/uml/") 85 | 86 | return umlId, nil 87 | } 88 | 89 | func (r *Renderer) doRequest(path string) ([]byte, error) { 90 | req, _ := http.NewRequest("GET", r.BaseUrl+path, nil) 91 | 92 | client := urlfetch.Client(r.ctx) 93 | resp, err := client.Do(req) 94 | if err != nil { 95 | log.Criticalf(r.ctx, "Failed to request to %s: err=%s", path, err) 96 | return nil, err 97 | } 98 | defer resp.Body.Close() 99 | 100 | return ioutil.ReadAll(resp.Body) 101 | } 102 | -------------------------------------------------------------------------------- /syntaxchecker/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /web/static/img/icon_sequence.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Group 2 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /syntaxchecker/src/main/kotlin/com/yfuruyama/syntaxchecker/Main.kt: -------------------------------------------------------------------------------- 1 | package com.yfuruyama.syntaxchecker 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties 4 | import com.fasterxml.jackson.databind.ObjectMapper 5 | import com.fasterxml.jackson.databind.SerializationFeature 6 | import com.fasterxml.jackson.module.kotlin.KotlinModule 7 | import net.sourceforge.plantuml.syntax.SyntaxChecker 8 | import org.glassfish.jersey.jackson.JacksonFeature 9 | import org.glassfish.jersey.jetty.JettyHttpContainerFactory 10 | import org.glassfish.jersey.server.ResourceConfig 11 | import java.util.logging.Logger 12 | import javax.ws.rs.* 13 | import javax.ws.rs.core.MediaType 14 | import javax.ws.rs.core.UriBuilder 15 | import javax.ws.rs.ext.ContextResolver 16 | import javax.ws.rs.ext.Provider 17 | 18 | fun main(args: Array) { 19 | val port = 8080 20 | println("Starts server: port=%d".format(port)) 21 | 22 | val baseUri = UriBuilder.fromUri("http://localhost/").port(port).build() 23 | val config = ResourceConfig() 24 | .register(JacksonFeature::class.java) 25 | .register(ObjectMapperProvider::class.java) 26 | .register(CheckSyntaxResource()) 27 | 28 | val server = JettyHttpContainerFactory.createServer(baseUri, config) 29 | try { 30 | server.join() 31 | } finally { 32 | server.destroy() 33 | } 34 | } 35 | 36 | @Provider 37 | class ObjectMapperProvider : ContextResolver { 38 | val objectMapper = ObjectMapper() 39 | .enable(SerializationFeature.INDENT_OUTPUT) 40 | .registerModule(KotlinModule()) 41 | 42 | override fun getContext(type: Class<*>?): ObjectMapper? = objectMapper 43 | } 44 | 45 | @JsonIgnoreProperties(ignoreUnknown = true) 46 | data class CheckSyntaxRequest(val source: String?) 47 | 48 | data class CheckSyntaxResponse(val valid: Boolean, val diagramType: String, val description: String) 49 | 50 | @Path("check_syntax") 51 | class CheckSyntaxResource { 52 | var logger = Logger.getLogger(CheckSyntaxResource::class.java.name) 53 | 54 | @POST 55 | @Produces(MediaType.APPLICATION_JSON) 56 | @Consumes(MediaType.APPLICATION_JSON) 57 | fun checkSyntax(req: CheckSyntaxRequest): CheckSyntaxResponse { 58 | if (req.source == null) { 59 | throw BadRequestException("`source` not specified") 60 | } 61 | 62 | logger.info("Get source %s".format(req.source)) 63 | val result = SyntaxChecker.checkSyntax(req.source) 64 | 65 | if (result.isError || result.umlDiagramType == null) { 66 | logger.info("Invalid syntax: errors=%s".format(result.errors.joinToString(","))) 67 | return CheckSyntaxResponse(false, "", "") 68 | } else { 69 | logger.info("Valid syntax: diagramType=%s, description=%s".format(result.umlDiagramType, result.description)) 70 | return CheckSyntaxResponse(true, result.umlDiagramType.name, result.description) 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /web/static/img/icon_activity.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Group 8 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /web/static/img/icon_usecase.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Group 4 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /web/static/img/icon_class.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Group 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /syntaxchecker/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /web/templates/base.html: -------------------------------------------------------------------------------- 1 | {{define "base"}} 2 | 3 | 4 | Real World PlantUML 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 | 37 | 38 | 39 |
40 |
41 |
42 | Real World PlantUML 43 |
44 |
45 | 48 |
49 |
50 |
51 | 52 |
53 |
54 | 104 | 105 |
106 |
107 | {{template "content" .}} 108 |
109 |
110 | 111 |
112 |
113 | 114 |
115 | 121 | 122 |
123 | 124 | 125 | {{end}} 126 | -------------------------------------------------------------------------------- /indexer/handler.go: -------------------------------------------------------------------------------- 1 | package indexer 2 | 3 | import ( 4 | "bufio" 5 | "encoding/base64" 6 | "encoding/json" 7 | "fmt" 8 | "net/http" 9 | "os" 10 | "regexp" 11 | "time" 12 | 13 | "cloud.google.com/go/storage" 14 | "google.golang.org/appengine" 15 | "google.golang.org/appengine/file" 16 | "google.golang.org/appengine/log" 17 | "google.golang.org/appengine/taskqueue" 18 | "google.golang.org/appengine/urlfetch" 19 | ) 20 | 21 | type IndexCreateRequestBody struct { 22 | Url string `json:"url"` 23 | } 24 | 25 | type GitHubContentResponse struct { 26 | Path string `json:"path"` 27 | Sha string `json:"sha"` 28 | Content string `json:"content"` 29 | } 30 | 31 | type PubSubSubscription struct { 32 | Message PubSubMessage `json:message` 33 | Subscription string `json:subscription` 34 | } 35 | 36 | type PubSubMessage struct { 37 | Attributes map[string]string `json:attributes` 38 | MessageId string `json:messageId` 39 | } 40 | 41 | func HandleIndexCreate(w http.ResponseWriter, r *http.Request) { 42 | ctx := appengine.NewContext(r) 43 | 44 | decoder := json.NewDecoder(r.Body) 45 | var body IndexCreateRequestBody 46 | if err := decoder.Decode(&body); err != nil { 47 | log.Warningf(ctx, "%s", err) 48 | w.WriteHeader(http.StatusBadRequest) 49 | return 50 | } 51 | 52 | log.Infof(ctx, "url: %s", body.Url) 53 | 54 | re := regexp.MustCompile(`^https://github.com/([^/]+)/([^/]+)/blob/([^/]+)/(.+)$`) 55 | matched := re.FindStringSubmatch(body.Url) 56 | if len(matched) != 5 { 57 | log.Warningf(ctx, "invalid github url") 58 | w.WriteHeader(http.StatusOK) 59 | return 60 | } 61 | 62 | owner := matched[1] 63 | repo := matched[2] 64 | hash := matched[3] 65 | path := matched[4] 66 | 67 | apiUrl := fmt.Sprintf("https://api.github.com/repos/%s/%s/contents/%s?ref=%s", owner, repo, path, hash) 68 | 69 | token := os.Getenv("GITHUB_API_TOKEN") 70 | req, _ := http.NewRequest("GET", apiUrl, nil) 71 | req.Header.Add("Authorization", fmt.Sprintf("token %s", token)) 72 | 73 | client := urlfetch.Client(ctx) 74 | resp, err := client.Do(req) 75 | if err != nil { 76 | log.Criticalf(ctx, "Failed to request to GitHub: err=%s", err) 77 | w.WriteHeader(http.StatusInternalServerError) 78 | return 79 | } 80 | defer resp.Body.Close() 81 | 82 | decoder = json.NewDecoder(resp.Body) 83 | var ghcResp GitHubContentResponse 84 | if err := decoder.Decode(&ghcResp); err != nil { 85 | log.Criticalf(ctx, "Failed to parse response: %s", err) 86 | w.WriteHeader(http.StatusInternalServerError) 87 | return 88 | } 89 | 90 | log.Infof(ctx, "Get content response: %#v", ghcResp) 91 | contentBytes, err := base64.StdEncoding.DecodeString(ghcResp.Content) 92 | if err != nil { 93 | log.Criticalf(ctx, "Failed to parse GitHub content: err=%s", err) 94 | w.WriteHeader(http.StatusInternalServerError) 95 | return 96 | } 97 | content := string(contentBytes) 98 | 99 | rendererBaseUrl := os.Getenv("RENDERER_BASE_URL") 100 | renderer := NewRenderer(ctx, rendererBaseUrl) 101 | 102 | syntaxCheckerBaseUrl := os.Getenv("SYNTAX_CHECKER_BASE_URL") 103 | syntaxChecker := NewSyntaxChecker(ctx, syntaxCheckerBaseUrl) 104 | 105 | indexer := NewIndexer(renderer, syntaxChecker) 106 | err = indexer.CreateIndexes(ctx, content, body.Url) 107 | if err != nil { 108 | log.Criticalf(ctx, "%s", err) 109 | w.WriteHeader(http.StatusInternalServerError) 110 | return 111 | } 112 | 113 | w.WriteHeader(http.StatusOK) 114 | fmt.Fprintf(w, "ok") 115 | } 116 | 117 | func HandleGcsNotification(w http.ResponseWriter, r *http.Request) { 118 | ctx := appengine.NewContext(r) 119 | 120 | decoder := json.NewDecoder(r.Body) 121 | var sub PubSubSubscription 122 | if err := decoder.Decode(&sub); err != nil { 123 | log.Warningf(ctx, "%s", err) 124 | w.WriteHeader(http.StatusBadRequest) 125 | return 126 | } 127 | 128 | log.Infof(ctx, "Received: %#v", sub) 129 | 130 | // TODO: more sophisticated guard 131 | if _, ok := sub.Message.Attributes["eventType"]; !ok { 132 | log.Warningf(ctx, "Not GCS notification") 133 | w.WriteHeader(http.StatusOK) 134 | return 135 | } 136 | 137 | typ := sub.Message.Attributes["eventType"] 138 | objectId := sub.Message.Attributes["objectId"] 139 | 140 | if typ != "OBJECT_FINALIZE" { 141 | log.Infof(ctx, "Not OBJECT_FINALIZE event: %s", typ) 142 | w.WriteHeader(http.StatusOK) 143 | return 144 | } 145 | 146 | bucketName, err := file.DefaultBucketName(ctx) 147 | if err != nil { 148 | log.Criticalf(ctx, "failed to get default GCS bucket name: %v", err) 149 | w.WriteHeader(http.StatusInternalServerError) 150 | return 151 | } 152 | 153 | client, err := storage.NewClient(ctx) 154 | if err != nil { 155 | log.Criticalf(ctx, "failed to init gcs client: %v", err) 156 | w.WriteHeader(http.StatusInternalServerError) 157 | return 158 | } 159 | defer client.Close() 160 | 161 | reader, err := client.Bucket(bucketName).Object(objectId).NewReader(ctx) 162 | if err != nil { 163 | log.Criticalf(ctx, "unable to open file from bucket %v, object %v: %v", bucketName, objectId, err) 164 | w.WriteHeader(http.StatusInternalServerError) 165 | return 166 | } 167 | defer reader.Close() 168 | 169 | i := 0 170 | scanner := bufio.NewScanner(reader) 171 | for scanner.Scan() { 172 | line := scanner.Text() 173 | log.Infof(ctx, "Read line: %s", line) 174 | 175 | header := make(http.Header) 176 | header.Set("Content-Type", "application/json") 177 | 178 | body := &IndexCreateRequestBody{ 179 | Url: line, 180 | } 181 | bodyBytes, err := json.Marshal(body) 182 | if err != nil { 183 | log.Criticalf(ctx, "json marshal error: %s", err) 184 | continue 185 | } 186 | 187 | task := &taskqueue.Task{ 188 | Path: "/indexes", 189 | Payload: bodyBytes, 190 | Header: header, 191 | Method: "POST", 192 | Delay: 5 * time.Second * time.Duration(i), 193 | } 194 | taskqueue.Add(ctx, task, "index-create-queue") 195 | 196 | i++ 197 | } 198 | 199 | fmt.Fprintf(w, "ok") 200 | } 201 | -------------------------------------------------------------------------------- /indexer/indexer.go: -------------------------------------------------------------------------------- 1 | package indexer 2 | 3 | import ( 4 | "context" 5 | "crypto/sha256" 6 | "encoding/base64" 7 | "encoding/hex" 8 | "fmt" 9 | "strings" 10 | 11 | "google.golang.org/appengine/datastore" 12 | "google.golang.org/appengine/log" 13 | "google.golang.org/appengine/search" 14 | ) 15 | 16 | const ( 17 | MINIMUM_UML_SOURCE_LENGTH = 50 18 | ) 19 | 20 | type Indexer struct { 21 | Renderer *Renderer 22 | SyntaxChecker *SyntaxChecker 23 | } 24 | 25 | type Uml struct { 26 | GitHubUrl string `datastore:"gitHubUrl"` 27 | Source string `datastore:"source,noindex"` 28 | SourceSHA256 string `datastore:"sourceSHA256"` 29 | DiagramType DiagramType `datastore:"diagramType"` 30 | Svg string `datastore:"svg,noindex"` 31 | PngBase64 string `datastore:"pngBase64,noindex"` 32 | Ascii string `datastore:"ascii,noindex"` 33 | } 34 | 35 | type DiagramType string 36 | 37 | type FTSDocument struct { 38 | Document string `search:"document"` 39 | } 40 | 41 | const ( 42 | TypeSequence DiagramType = "sequence" 43 | TypeUsecase DiagramType = "usecase" 44 | TypeClass DiagramType = "class" 45 | TypeActivity DiagramType = "activity" 46 | TypeComponent DiagramType = "component" 47 | TypeState DiagramType = "state" 48 | // TypeObject DiagramType = "object" // object is rarely detected 49 | TypeUnknwon DiagramType = "__unknown__" 50 | ) 51 | 52 | func guessDiagramType(source string, result *SyntaxCheckResult) DiagramType { 53 | switch result.DiagramType { 54 | case "SEQUENCE": 55 | return TypeSequence 56 | case "DESCRIPTION": 57 | // Both of Usecase and Component diagram's syntax check results are "DESCRIPTION", 58 | // so distinct them ad hoc 59 | if strings.Contains(source, "actor") || strings.Contains(source, "usecase") { 60 | return TypeUsecase 61 | } else { 62 | return TypeComponent 63 | } 64 | case "CLASS": 65 | return TypeClass 66 | case "ACTIVITY": 67 | return TypeActivity 68 | case "STATE": 69 | return TypeState 70 | default: 71 | return TypeUnknwon 72 | } 73 | } 74 | 75 | func NewIndexer(renderer *Renderer, syntaxChecker *SyntaxChecker) *Indexer { 76 | return &Indexer{ 77 | Renderer: renderer, 78 | SyntaxChecker: syntaxChecker, 79 | } 80 | } 81 | 82 | func (idxr *Indexer) CreateIndexes(ctx context.Context, text string, gitHubUrl string) error { 83 | renderer := idxr.Renderer 84 | syntaxChecker := idxr.SyntaxChecker 85 | 86 | sources := findSources(ctx, text) 87 | for _, source := range sources { 88 | log.Infof(ctx, "process source: %s", source) 89 | if len(source) < MINIMUM_UML_SOURCE_LENGTH { 90 | log.Infof(ctx, "under minimum length: length=%d", len(source)) 91 | continue 92 | } 93 | 94 | hash := sha256.Sum256([]byte(source)) 95 | sourceHash := hex.EncodeToString(hash[:]) 96 | log.Debugf(ctx, "source hash: %s", sourceHash) 97 | 98 | var existing []Uml 99 | q := datastore.NewQuery("Uml").Filter("sourceSHA256 =", sourceHash).Limit(1) 100 | _, err := q.GetAll(ctx, &existing) 101 | if err != nil { 102 | log.Criticalf(ctx, "failed to fetch existing umls: %v", err) 103 | return err 104 | } 105 | if len(existing) == 1 { 106 | log.Infof(ctx, "there is same uml existing: %#v", existing[0]) 107 | continue 108 | } 109 | 110 | result, err := syntaxChecker.CheckSyntax(source) 111 | if err != nil { 112 | log.Criticalf(ctx, "failed to check syntax: %s", err) 113 | return err 114 | } 115 | log.Infof(ctx, "syntax check result: %v", result) 116 | 117 | if !result.Valid { 118 | log.Infof(ctx, "invalid syntax: %s", source) 119 | continue 120 | } 121 | if !result.HasValidDiagram() { 122 | log.Infof(ctx, "invalid diagram: %s", source) 123 | continue 124 | } 125 | 126 | typ := guessDiagramType(source, result) 127 | 128 | svg, err := renderer.RenderSvg(source) 129 | if err != nil { 130 | log.Criticalf(ctx, "failed to render svg: %s", err) 131 | return err 132 | } 133 | 134 | png, err := renderer.RenderPng(source) 135 | if err != nil { 136 | log.Criticalf(ctx, "failed to render png: %s", err) 137 | return err 138 | } 139 | pngBase64 := base64.StdEncoding.EncodeToString(png) 140 | 141 | ascii, err := renderer.RenderAscii(source) 142 | if err != nil { 143 | log.Criticalf(ctx, "failed to render ascii: %s", err) 144 | return err 145 | } 146 | 147 | log.Infof(ctx, "make index: type=%s, svg=%s, pngBase64=%s, ascii=%s", typ, svg, pngBase64, ascii) 148 | uml := &Uml{ 149 | GitHubUrl: gitHubUrl, 150 | Source: source, 151 | SourceSHA256: sourceHash, 152 | DiagramType: typ, 153 | Svg: svg, 154 | PngBase64: pngBase64, 155 | Ascii: ascii, 156 | } 157 | 158 | key := datastore.NewIncompleteKey(ctx, "Uml", nil) 159 | key, err = datastore.Put(ctx, key, uml) 160 | if err != nil { 161 | log.Criticalf(ctx, "put error: %s", err) 162 | return err 163 | } 164 | 165 | // Register to full-text search index 166 | doc := FTSDocument{ 167 | Document: source, 168 | } 169 | fts, err := search.Open("uml_source") 170 | if err != nil { 171 | log.Criticalf(ctx, "failed to open FTS: %s", err) 172 | return err 173 | } 174 | _, err = fts.Put(ctx, fmt.Sprintf("%d", key.IntID()), &doc) 175 | if err != nil { 176 | log.Criticalf(ctx, "failed to put document to FTS: %s", err) 177 | // Ignore error 178 | continue 179 | } 180 | } 181 | 182 | return nil 183 | } 184 | 185 | func findSources(ctx context.Context, text string) []string { 186 | sources := make([]string, 0) 187 | for { 188 | startIdx := strings.Index(text, "@startuml") 189 | endIdx := strings.Index(text, "@enduml") 190 | log.Debugf(ctx, "length:%d, startIdx:%d, endIdx:%d", len(text), startIdx, endIdx) 191 | if startIdx == -1 || endIdx == -1 { 192 | break 193 | } 194 | if startIdx < endIdx { 195 | source := fmt.Sprintf("%s@enduml", text[startIdx:endIdx]) 196 | sources = append(sources, source) 197 | } 198 | 199 | text = text[(endIdx + len("@enduml")):] 200 | } 201 | return sources 202 | } 203 | -------------------------------------------------------------------------------- /web/handler.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "html/template" 7 | "net/http" 8 | "os" 9 | "regexp" 10 | "strconv" 11 | "strings" 12 | 13 | "github.com/go-chi/chi" 14 | 15 | "google.golang.org/appengine" 16 | "google.golang.org/appengine/log" 17 | ) 18 | 19 | const NUM_OF_ITEMS_PER_PAGE = 21 20 | 21 | type CommonTemplateVars struct { 22 | GATrackingID string 23 | Context context.Context 24 | DiagramType DiagramType 25 | Query string 26 | } 27 | 28 | type UmlListTemplateVars struct { 29 | *CommonTemplateVars 30 | Umls []*Uml 31 | NextCursor string 32 | } 33 | 34 | type Handler struct { 35 | GATrackingID string 36 | FuncMap template.FuncMap 37 | } 38 | 39 | func (h *Handler) ToHandlerFunc(handle func(w http.ResponseWriter, r *http.Request) error) http.HandlerFunc { 40 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 41 | ctx := appengine.NewContext(r) 42 | err := handle(w, r) 43 | if err != nil { 44 | log.Criticalf(ctx, "%s", err) 45 | w.WriteHeader(http.StatusInternalServerError) 46 | 47 | tmpl := template.Must(template.New("").Funcs(h.FuncMap).ParseFiles( 48 | "templates/base.html", 49 | "templates/500.html", 50 | )) 51 | _ = tmpl.ExecuteTemplate(w, "base", struct { 52 | *CommonTemplateVars 53 | }{ 54 | CommonTemplateVars: &CommonTemplateVars{ 55 | GATrackingID: h.GATrackingID, 56 | Context: ctx, 57 | }, 58 | }) 59 | } 60 | }) 61 | } 62 | 63 | func NewHandler(gaTrackingID string) *Handler { 64 | funcMap := template.FuncMap{ 65 | "safehtml": func(text string) template.HTML { 66 | return template.HTML(text) 67 | }, 68 | "loopLineTimes": func(text string) []struct{} { 69 | return make([]struct{}, strings.Count(text, "\n")+1) 70 | }, 71 | "githubUrlToAnchorText": func(url string) string { 72 | re := regexp.MustCompile(`^https://github.com/([^/]+)/([^/]+)/(.+)/(.+)$`) 73 | matched := re.FindStringSubmatch(url) 74 | if len(matched) != 5 { 75 | return "" 76 | } 77 | 78 | owner := matched[1] 79 | repo := matched[2] 80 | _ = matched[3] 81 | file := matched[4] 82 | text := fmt.Sprintf("%s/%s - %s", owner, repo, file) 83 | // abbreviation 84 | if len(text) > 40 { 85 | text = fmt.Sprintf("%s...%s", text[0:20], text[len(text)-20:len(text)]) 86 | } 87 | return text 88 | }, 89 | "staticPath": func(ctx context.Context, filePath string) string { 90 | return fmt.Sprintf("/static/%s?v=%s", filePath, os.Getenv("GAE_VERSION")) 91 | }, 92 | "highlight": func(word, code string) string { 93 | if word == "" { 94 | return code 95 | } 96 | re, err := regexp.Compile(fmt.Sprintf("(?i)(%s)", word)) 97 | if err != nil { 98 | return code 99 | } 100 | return re.ReplaceAllString(code, "$1") 101 | }, 102 | "toUpperCase": func(word string) string { 103 | return strings.ToUpper(word) 104 | }, 105 | } 106 | 107 | return &Handler{ 108 | GATrackingID: gaTrackingID, 109 | FuncMap: funcMap, 110 | } 111 | } 112 | 113 | func (h *Handler) Warmup(w http.ResponseWriter, r *http.Request) error { 114 | fmt.Fprintf(w, "ok") 115 | return nil 116 | } 117 | 118 | func (h *Handler) GetIndex(w http.ResponseWriter, r *http.Request) error { 119 | ctx := appengine.NewContext(r) 120 | 121 | queryParams := r.URL.Query() 122 | typ := DiagramType(queryParams.Get("type")) 123 | cursor := queryParams.Get("cursor") 124 | 125 | umls, nextCursor, err := FetchUmls(ctx, typ, NUM_OF_ITEMS_PER_PAGE, cursor) 126 | if err != nil { 127 | return err 128 | } 129 | log.Debugf(ctx, "next cursor: %s", nextCursor) 130 | 131 | tmpl := template.Must(template.New("").Funcs(h.FuncMap).ParseFiles( 132 | "templates/base.html", 133 | "templates/index.html", 134 | "templates/components/uml_list.html", 135 | )) 136 | 137 | err = tmpl.ExecuteTemplate(w, "base", UmlListTemplateVars{ 138 | CommonTemplateVars: &CommonTemplateVars{ 139 | GATrackingID: h.GATrackingID, 140 | Context: ctx, 141 | DiagramType: typ, 142 | }, 143 | Umls: umls, 144 | NextCursor: nextCursor, 145 | }) 146 | if err != nil { 147 | return err 148 | } 149 | 150 | return nil 151 | } 152 | 153 | func (h *Handler) GetSearch(w http.ResponseWriter, r *http.Request) error { 154 | ctx := appengine.NewContext(r) 155 | 156 | queryParams := r.URL.Query() 157 | query := queryParams.Get("q") 158 | cursor := queryParams.Get("cursor") 159 | 160 | if query == "" { 161 | return h.GetIndex(w, r) 162 | } 163 | 164 | umls, nextCursor, err := SearchUmls(ctx, query, NUM_OF_ITEMS_PER_PAGE, cursor) 165 | if err != nil { 166 | return err 167 | } 168 | log.Debugf(ctx, "next cursor: %s", nextCursor) 169 | 170 | tmpl := template.Must(template.New("").Funcs(h.FuncMap).ParseFiles( 171 | "templates/base.html", 172 | "templates/search.html", 173 | "templates/components/uml_list.html", 174 | )) 175 | 176 | err = tmpl.ExecuteTemplate(w, "base", UmlListTemplateVars{ 177 | CommonTemplateVars: &CommonTemplateVars{ 178 | GATrackingID: h.GATrackingID, 179 | Context: ctx, 180 | Query: query, 181 | }, 182 | Umls: umls, 183 | NextCursor: nextCursor, 184 | }) 185 | if err != nil { 186 | return err 187 | } 188 | 189 | return nil 190 | } 191 | 192 | func (h *Handler) GetUml(w http.ResponseWriter, r *http.Request) error { 193 | ctx := appengine.NewContext(r) 194 | umlID, _ := strconv.ParseInt(chi.URLParam(r, "umlID"), 10, 64) 195 | 196 | uml, err := FetchUmlById(ctx, umlID) 197 | if err != nil { 198 | return err 199 | } 200 | 201 | if uml == nil { 202 | return h.NotFound(w, r) 203 | } 204 | 205 | umls, nextCursor, err := FetchUmls(ctx, "", NUM_OF_ITEMS_PER_PAGE, "") 206 | if err != nil { 207 | return err 208 | } 209 | log.Debugf(ctx, "next cursor: %s", nextCursor) 210 | 211 | // insert to 1st position 212 | umls = append([]*Uml{uml}, umls...) 213 | 214 | tmpl := template.Must(template.New("").Funcs(h.FuncMap).ParseFiles( 215 | "templates/base.html", 216 | "templates/index.html", 217 | "templates/components/uml_list.html", 218 | )) 219 | 220 | err = tmpl.ExecuteTemplate(w, "base", UmlListTemplateVars{ 221 | CommonTemplateVars: &CommonTemplateVars{ 222 | GATrackingID: h.GATrackingID, 223 | Context: ctx, 224 | DiagramType: "", 225 | }, 226 | Umls: umls, 227 | NextCursor: nextCursor, 228 | }) 229 | if err != nil { 230 | return err 231 | } 232 | 233 | return nil 234 | } 235 | 236 | func (h *Handler) NotFound(w http.ResponseWriter, r *http.Request) error { 237 | ctx := appengine.NewContext(r) 238 | w.WriteHeader(http.StatusNotFound) 239 | 240 | tmpl := template.Must(template.New("").Funcs(h.FuncMap).ParseFiles( 241 | "templates/base.html", 242 | "templates/404.html", 243 | )) 244 | _ = tmpl.ExecuteTemplate(w, "base", struct { 245 | *CommonTemplateVars 246 | }{ 247 | CommonTemplateVars: &CommonTemplateVars{ 248 | GATrackingID: h.GATrackingID, 249 | Context: ctx, 250 | }, 251 | }) 252 | 253 | return nil 254 | } 255 | 256 | func (h *Handler) DebugRegisterDummyUml(w http.ResponseWriter, r *http.Request) error { 257 | ctx := appengine.NewContext(r) 258 | err := RegisterDummyUml(ctx) 259 | if err != nil { 260 | return err 261 | } 262 | fmt.Fprintf(w, "done") 263 | return nil 264 | } 265 | -------------------------------------------------------------------------------- /web/static/css/main.css: -------------------------------------------------------------------------------- 1 | html { 2 | height: 100%; 3 | } 4 | 5 | body { 6 | display: flex; 7 | flex-direction: column; 8 | padding: 0; 9 | margin: 0; 10 | box-sizing: border-box; 11 | position: relative; 12 | min-height: 100%; 13 | background-color: #f4f5f6; 14 | font-family: "Avenir Next", Verdana, Meiryo, Osaka, sans-serif; 15 | font-weight: 500; 16 | overflow-y: scroll; /* always show scroll because of https://q-az.net/appear-scrollbar-problem/ */ 17 | } 18 | 19 | header { 20 | height: 84px; 21 | margin: 0 auto; 22 | position: relative; 23 | } 24 | 25 | .header_inner { 26 | position: relative; 27 | float: left; 28 | clear: both; 29 | margin: 0 auto; 30 | padding: 24px 0; 31 | width: 944px; 32 | } 33 | 34 | .title { 35 | float: left; 36 | color: #822156; 37 | height: 14px; 38 | width: 205px; 39 | padding-top: 14px; 40 | } 41 | 42 | .search_form { 43 | display: block; 44 | float: right; 45 | } 46 | .header_search { 47 | text-align: right; 48 | color: #989292; 49 | } 50 | .header_search>input { 51 | border-radius: 20px; 52 | border: none; 53 | height: 36px; 54 | padding: 0 0 0 20px; 55 | width: 300px; 56 | color: #989292; 57 | font-size: 13px; 58 | } 59 | 60 | ::-webkit-input-placeholder { /* Chrome/Opera/Safari */ 61 | color: #989292; 62 | font-family: "Avenir Next", Verdana, Meiryo, Osaka, sans-serif; 63 | 64 | } 65 | 66 | ::-moz-placeholder { /* Firefox 19+ */ 67 | color: #989292; 68 | font-family: "Avenir Next", Verdana, Meiryo, Osaka, sans-serif; 69 | } 70 | 71 | input[type="text"]:focus { 72 | outline: 0; 73 | } 74 | 75 | .content-holder { 76 | padding-bottom: 64px; 77 | } 78 | 79 | .content { 80 | display: flex; 81 | /*flex: 1 1 auto;*/ 82 | height: 100%; 83 | box-sizing: border-box; 84 | margin: 0 auto; 85 | width: 944px; 86 | } 87 | 88 | .category-list>ul { 89 | list-style: none; 90 | margin: 0; 91 | padding: 0; 92 | } 93 | 94 | .category-link { 95 | text-decoration: none; 96 | } 97 | .category { 98 | background-color: #fff; 99 | border-radius: 30px; 100 | border: 2px solid #fff; 101 | width: 200px; 102 | height: 44px; 103 | color: #989292; 104 | margin: 12px 0; 105 | display: block; 106 | } 107 | 108 | .category:first-child { 109 | margin-top: 0; 110 | } 111 | 112 | .category__icon { 113 | display: inline-block; 114 | height: auto; 115 | width: 24px; 116 | vertical-align: middle; 117 | padding-left: 32px; 118 | } 119 | 120 | .category__name { 121 | font-size: 14px; 122 | line-height: 44px; 123 | height: 44px; 124 | display: inline-block; 125 | padding-left: 10px; 126 | } 127 | .category--selected { 128 | border: 2px solid #822156; 129 | color: #822156; 130 | } 131 | .category:hover { 132 | border: 2px solid #822156; 133 | color: #822156; 134 | } 135 | 136 | main { 137 | width: 100%; 138 | } 139 | 140 | .container { 141 | margin: 0 0 0 40px; 142 | } 143 | 144 | .uml-list { 145 | display: grid; 146 | grid-gap: 20px; 147 | grid-template-columns: repeat(auto-fit, 220px); 148 | } 149 | 150 | .uml { 151 | background: #FFFFFF; 152 | box-shadow: 0 6px 5px 2px rgba(0,0,0,0.04); 153 | border-radius: 8px; 154 | } 155 | 156 | .uml__svg { 157 | display: inline-block; 158 | padding: 10px; 159 | vertical-align: top; 160 | width: 200px; 161 | cursor: pointer; 162 | } 163 | .uml__svg__wrapper { 164 | width: 200px; 165 | height: 200px; 166 | } 167 | .uml__svg--raw { 168 | display: inline-block; 169 | border: solid 1px #aaa; 170 | padding: 10px; 171 | vertical-align: top; 172 | } 173 | 174 | /********* 175 | * modal * 176 | *********/ 177 | .uml__modal__container { 178 | background-color: #fff; 179 | border-radius: 10px; 180 | border: none; 181 | padding: 30px; 182 | } 183 | .uml__modal__header { 184 | } 185 | .uml__modal__header__category { 186 | font-size: 14px; 187 | color: #950029; 188 | } 189 | .uml__modal__header__id { 190 | color: #999; 191 | font-size: 12px; 192 | } 193 | .uml__modal__body { 194 | display: grid; 195 | grid-gap: 10px; 196 | grid-template-columns: auto 530px; 197 | } 198 | .uml__modal__body__svg { 199 | padding: 20px; 200 | background-color: #fff; 201 | } 202 | .uml__modal__body__source { 203 | display: inline-block; 204 | margin: 0 0 0 20px; 205 | width: 500px; 206 | } 207 | .uml__modal__body__source__header { 208 | position: relative; 209 | height: 40px; 210 | padding: 0 20px; 211 | font-size: 14px; 212 | background-color: #bcb7b7; 213 | } 214 | .uml__modal__body__source__header__octocat { 215 | width: 20px; 216 | padding-top: 9px; 217 | } 218 | .uml__modal__body__source__header__ref { 219 | display: inline-block; 220 | vertical-align: top; 221 | margin: 0 0 0 8px; 222 | } 223 | .uml__modal__body__source__header__ref>a { 224 | color: #2D2525; 225 | text-decoration: none; 226 | vertical-align: middle; 227 | display: inline-block; 228 | height: 40px; 229 | line-height: 40px; 230 | } 231 | .uml__modal__body__source__header__copy { 232 | position: absolute; 233 | top: 8px; 234 | right: 16px; 235 | background-color: #C9C3C3; 236 | color: #2D2525; 237 | font-weight: 500; 238 | border: 2px solid #fff; 239 | border-radius: 100px; 240 | padding: 4px 12px; 241 | height: 25px; 242 | cursor: pointer; 243 | user-select: none; 244 | -webkit-user-select: none; 245 | -moz-user-select: none; 246 | -ms-user-select: none; 247 | box-shadow: 0 2px 9px 0 rgba(0,0,0,0.26); 248 | } 249 | .uml__modal__body__source__content { 250 | position: relative; 251 | font-size: 12px; 252 | font-weight: 100; 253 | color: #675A5A; 254 | padding: 10px 20px 20px 40px; 255 | margin: 0; 256 | white-space: pre; 257 | overflow: auto; 258 | background-color: #efefef; 259 | } 260 | 261 | /* cf. https://qiita.com/Ria0130/items/b49b13e4ff935993c813 */ 262 | .uml__modal__body__source__content__line_numbers { 263 | display: block; 264 | position: absolute; 265 | pointer-events: none; 266 | top: 10px; 267 | left: -20px; 268 | width: 50px; 269 | font-size: 100%; 270 | letter-spacing: -1px; 271 | user-select: none; 272 | -webkit-user-select: none; 273 | -moz-user-select: none; 274 | -ms-user-select: none; 275 | } 276 | .uml__modal__body__source__content__line_numbers>span { 277 | pointer-events: none; 278 | display: block; 279 | counter-increment: linenumber; 280 | } 281 | .uml__modal__body__source__content__line_numbers>span:before { 282 | content: counter(linenumber); 283 | color: #aaa; 284 | display: block; 285 | padding-right: .8em; 286 | text-align: right; 287 | } 288 | 289 | .uml__category { 290 | margin: 14px 0 0 0; 291 | font-size: 14px; 292 | color: #950029; 293 | } 294 | .uml__id { 295 | color: #8B8B8B; 296 | font-size: 12px; 297 | padding-top: 4px; 298 | } 299 | 300 | .next_link { 301 | margin: 40px 0 30px 0; 302 | width: 100px; 303 | } 304 | .next_link>a { 305 | color: #950029; 306 | } 307 | 308 | /********** 309 | * footer * 310 | **********/ 311 | footer { 312 | height: 45px; 313 | background-color: #989292; 314 | color: #fff; 315 | text-align: center; 316 | padding: 5px 0 5px 0; 317 | font-size: 14px; 318 | width: 100%; 319 | bottom: 0; 320 | position: absolute; 321 | } 322 | .footer__contact { 323 | } 324 | .footer__contact a { 325 | color: #fff; 326 | text-decoration: none; 327 | } 328 | .footer__contact__github { 329 | vertical-align: text-top; 330 | } 331 | .footer__license { 332 | font-style: italic; 333 | } 334 | 335 | .error { 336 | margin: 20px 0 0 10px; 337 | } 338 | -------------------------------------------------------------------------------- /web/uml.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "encoding/xml" 6 | "strconv" 7 | "strings" 8 | 9 | "google.golang.org/appengine" 10 | "google.golang.org/appengine/datastore" 11 | "google.golang.org/appengine/log" 12 | "google.golang.org/appengine/search" 13 | ) 14 | 15 | type Uml struct { 16 | ID int64 `datastore:"-"` 17 | GitHubUrl string `datastore:"gitHubUrl"` 18 | Source string `datastore:"source,noindex"` 19 | SourceSHA256 string `datastore:"sourceSHA256"` 20 | DiagramType DiagramType `datastore:"diagramType"` 21 | Svg string `datastore:"svg,noindex"` 22 | SvgViewBox string `datastore:"-"` 23 | PngBase64 string `datastore:"pngBase64,noindex"` 24 | Ascii string `datastore:"ascii,noindex"` 25 | HighlightWord string `datastore:"-"` 26 | } 27 | 28 | type SvgXml struct { 29 | ViewBox string `xml:"viewBox,attr"` 30 | } 31 | 32 | type DiagramType string 33 | 34 | const ( 35 | TypeSequence DiagramType = "sequence" 36 | TypeUsecase DiagramType = "usecase" 37 | TypeClass DiagramType = "class" 38 | TypeActivity DiagramType = "activity" 39 | TypeComponent DiagramType = "component" 40 | TypeState DiagramType = "state" 41 | ) 42 | 43 | func (d DiagramType) ToHumanString() string { 44 | switch d { 45 | case TypeSequence: 46 | return "Sequence" 47 | case TypeUsecase: 48 | return "Use case" 49 | case TypeClass: 50 | return "Class" 51 | case TypeActivity: 52 | return "Activity" 53 | case TypeComponent: 54 | return "Component" 55 | case TypeState: 56 | return "State" 57 | } 58 | return "" 59 | } 60 | 61 | func FetchUmls(ctx context.Context, typ DiagramType, count int, cursor string) ([]*Uml, string, error) { 62 | q := datastore.NewQuery("Uml").Limit(count).KeysOnly() 63 | 64 | // Set filter 65 | if typ == TypeSequence || typ == TypeUsecase || typ == TypeClass || typ == TypeActivity || typ == TypeComponent || typ == TypeState { 66 | q = q.Filter("diagramType =", typ) 67 | } 68 | 69 | // Set cursor 70 | if cursor != "" { 71 | decoded, err := datastore.DecodeCursor(cursor) 72 | if err == nil { 73 | q = q.Start(decoded) 74 | } 75 | } 76 | 77 | // Do query 78 | iter := q.Run(ctx) 79 | var ids []int64 80 | for { 81 | key, err := iter.Next(nil) 82 | if err == datastore.Done { 83 | break 84 | } 85 | if err != nil { 86 | log.Criticalf(ctx, "datastore fetch error: %v", err) 87 | return nil, "", err 88 | } 89 | ids = append(ids, key.IntID()) 90 | } 91 | 92 | umls, err := fetchUmlsByIds(ctx, ids) 93 | if err != nil { 94 | return nil, "", err 95 | } 96 | 97 | // Get nextCursor 98 | var nextCursor string 99 | if len(umls) == count { 100 | dsCursor, err := iter.Cursor() 101 | if err == nil { 102 | nextCursor = dsCursor.String() 103 | } 104 | } 105 | 106 | return umls, nextCursor, nil 107 | } 108 | 109 | func FetchUmlById(ctx context.Context, id int64) (*Uml, error) { 110 | umls, err := fetchUmlsByIds(ctx, []int64{id}) 111 | if err != nil || len(umls) == 0 { 112 | return nil, err 113 | } 114 | return umls[0], nil 115 | } 116 | 117 | func SearchUmls(ctx context.Context, queryWord string, count int, cursor string) ([]*Uml, string, error) { 118 | fts, err := search.Open("uml_source") 119 | if err != nil { 120 | log.Criticalf(ctx, "failed to open FTS: %s", err) 121 | return nil, "", err 122 | } 123 | 124 | options := search.SearchOptions{ 125 | Limit: count, 126 | IDsOnly: true, 127 | } 128 | 129 | if cursor != "" { 130 | options.Cursor = search.Cursor(cursor) 131 | } 132 | 133 | query := strings.Join(strings.Split(queryWord, " "), " AND ") 134 | 135 | var ids []int64 136 | iter := fts.Search(ctx, query, &options) 137 | for { 138 | id, err := iter.Next(nil) 139 | if err == search.Done { 140 | break 141 | } 142 | if err != nil { 143 | log.Criticalf(ctx, "FTS search unexpected error: %v", err) 144 | break 145 | } 146 | intId, _ := strconv.ParseInt(id, 10, 64) 147 | ids = append(ids, intId) 148 | } 149 | log.Infof(ctx, "query result: %v", ids) 150 | 151 | var nextCursor string 152 | if len(ids) >= count { 153 | nextCursor = string(iter.Cursor()) 154 | } 155 | 156 | umls, err := fetchUmlsByIds(ctx, ids) 157 | 158 | // for rendering 159 | for _, uml := range umls { 160 | uml.HighlightWord = queryWord 161 | } 162 | 163 | return umls, nextCursor, err 164 | } 165 | 166 | func fetchUmlsByIds(ctx context.Context, ids []int64) ([]*Uml, error) { 167 | keys := make([]*datastore.Key, len(ids)) 168 | for i, id := range ids { 169 | keys[i] = datastore.NewKey(ctx, "Uml", "", id, nil) 170 | } 171 | umls := make([]*Uml, len(keys)) 172 | notFounds := make([]bool, len(keys)) 173 | 174 | err := datastore.GetMulti(ctx, keys, umls) 175 | if err != nil { 176 | multiErr, ok := err.(appengine.MultiError) 177 | if !ok { 178 | log.Criticalf(ctx, "Datastore fetch error: %v", err) 179 | return nil, err 180 | } 181 | for i, e := range multiErr { 182 | if e == nil { 183 | continue 184 | } 185 | if e == datastore.ErrNoSuchEntity { 186 | log.Warningf(ctx, "FTS index found, but datastore entity not found: %v", ids[i]) 187 | notFounds[i] = true 188 | continue 189 | } 190 | log.Criticalf(ctx, "Datastore fetch partial error: %v", e) 191 | return nil, err 192 | } 193 | } 194 | 195 | var foundUmls []*Uml 196 | for i, notFound := range notFounds { 197 | if !notFound { 198 | uml := umls[i] 199 | uml.ID = ids[i] 200 | 201 | // Set viewBox 202 | var svgXml SvgXml 203 | err = xml.Unmarshal([]byte(uml.Svg), &svgXml) 204 | if err != nil { 205 | log.Criticalf(ctx, "svg parse error: %v", err) 206 | } 207 | uml.SvgViewBox = svgXml.ViewBox 208 | 209 | foundUmls = append(foundUmls, uml) 210 | } 211 | } 212 | 213 | return foundUmls, nil 214 | } 215 | 216 | func RegisterDummyUml(ctx context.Context) error { 217 | uml := &Uml{ 218 | GitHubUrl: "https://github.com/yfuruyama/real-world-plantuml/blob/master/README.md", 219 | Source: `@startuml 220 | Alice -> Bob: Authentication Request 221 | Bob --> Alice: Authentication Response 222 | @enduml`, 223 | SourceSHA256: "", 224 | DiagramType: TypeSequence, 225 | Svg: `AliceAliceBobBobAuthentication RequestAuthentication Response`, 226 | PngBase64: `iVBORw0KGgoAAAANSUhEUgAAAPUAAACbCAIAAAA1LUoYAAAQ50lEQVR42u2dC0xUVxrHQeRVuwUfRVheVrS2MQXfFbUircFFiaut2VajTYyaWK2tae2GolVs1WyFQbEPdDE8bIs4IiMjKj4AG7Zsd1xk01KX0gerLSqClpcKaN3917u5mQxz78ygzL0z8//nZHLm3HvPnDPzO9/9vjPwjdt/Kcp55ca3gHI5vrt/aWssr1JP6W5p50elTqkBFRk8zPONa/LdJqmnXD1TRZLUKTWgIoOHHN+1O1Iby/OVLbVpqeRb/XwrhYpFPOT4xvV3755Ttlwpyyff6udbKVQs4uEYfJekZVZWVlZXV9fV1TU0NLS2thIs8m0NHo7BtzZZo9frS0tLDQYD5tDU1ESwyLc1eDgG35+8vS0vL0+n02EOWKZYowSLfFuDh2PwvS9xa05ODuaAZYo7UX19PcEi39bg4Rh8H9iUignk5uZqtVqsUdyDCBb5tgYP8k2Rb+uKm5ubSYV8k+9eFOv56Su+NZo3vb29duxYR77JtxQqbkby8fEaPjz4tdcWNjeXOwDfUVGPZ2ZuHDNmVO+GRb5dhG+xfvPml+fPF65Y8fzMmU+rne9z5/ZPnTpGoLy6Ol/efh8+vGP8+Cdh7MPCArEkjNuxPNCOZf3uu6u6u8+SbyfmWygw3g895CM+zchYHxER4unZH4979mwwvhCHRowIxSHgkZWVbFe+cZf57LNtqKSn/3nt2kUyfB85kh4UNESvT29r+1tdXdGSJXOE9oqKrMjIkXjs6KhEe1xc9JYtq8m3c9vv2lrdypULRPt96JAmJGTo6dN7Wlsr8Ih6UdFO8cLw8KDy8kxgU1b2V1jGkpKP7MR3V5dh9OiIzs5/oH7t2pnQ0KFokeI7OjpSq93esxNM0mD4VHx68eJxLFby7cT+tyBAfOHCceHolClRhYUa8WTgLjgFwoUi6yg4LSZmvJ34xjiSkpaJTxcu/INOlybFt6+vt9l4YsgQfw+PfiiQu7s7zkedfDux/YZBrKkpSEh45uWXE4SWgQMfgX0UT0AdLeKF169/bnxo0CA/O/E9d26MyaKcNy9Wim8MyyzfiKYbGk4yvnQ1//vSpVP+/r+T4luEWDG+GxtL/fwehsMktrS0VKDl6tUys3zPmDHh4MGUnsPCnejjj5PIt6vxDaM2eLCf6J+Id37BCZHxT6ZPH2cPvjWaNxcvnm3SuGhRvLAR3pNvBAfBwQHFxbtM4stTp3ZjRWZnb25qKm9v/wJPZ8+eRr5dwT9Zvny+6OgicAQhYhBpHF8OG/Z74/jy2LEP7cF3VNTjYNGk8eTJDGEj3Oz+YEFBKo56eXlixHv3bhLbMfrY2IkDBvjCR0cFETT5duL4UtjpS0xc2tFRKZ6Ae3hEREj//h499wfFQ489FmyMDf/+hFIL3/z7KvJNvsk3+Sbf5Jsi3+SbIt/kmyLf5Jsi3+SbfJNv8k2+7c93bVoqrle2CAnmyLfK+VYKFYt4OEb+WPKtcr5Vi4dE/u+W9qtnqoRSkpapTdZ88va2fYlb0ZEyJXsf+VanVIGKNB6Wf7+hsrJSr9fn5eXlKC3mr1K5lEXFhvxVxqqursaa0Ol0uD5XOTH/oPqlICq25R80Fqy9wWDAlVgcWuXE/LHql4Ko2JY/1lhYDbgGywKWv7RXylmZVHrfYv5v9et+ULlPSGzL/20snI0Fgcvg1tT1Sume4+ruW3h1jAEjwXg6OzsJkwp1P6jcJyRSeNjj9wHz3Sbxs6cUgYR8U+SbfFPkW0o1yZn8/ChFIOHvc1POLPJNkW+KIt8U5Yp8M76knDm+5P4gpRQk5Jsi3+SbIt/km3JFvvsuvnRz4/4P40ul+e479RHfD6Rbrj1VEKL4CN5//30PD4+UlJReQPOgGFIt0GJ++MGDB8+ZM0fZf6x2xBWr8Ih//fXX4cOHf/DBB3hEnXxL9dnc3PzOO+9ER0eTb0fiu7i4eNy4cahMnDjx6NGj8hwb/96F2J6RkREeHu7j4zN58uSvv/5aXDbvvffesGHDBg4cuHTp0o6ODpnzzXYrVG7fvg2qwsLC/P39U1NThcZvv/32hRdeGDRokJ+f3/z584X/9pPppLOz8/XXXw8MDBw6dCgq4n+XSA1eCqm2tjZfX1/5CXZ1da1atQpjw2tt376952BMnkr1c/r06bFjx2JgGF5mZqbZCZJvy6FDfHx8VlYWKtnZ2bj/WrTTPdvnzZtXX1+PD2bz5s1Tp04V2jUazXPPPffjjz9ev3598eLFb7zxhvz5Ui+3ZcuWGTNmfP/99+hn7dq1QmNkZGRZWdnNmzdbWlpeffXV5cuXy3eCFTJz5syf7ik2Nnbjxo3ygzHbybVr1zZs2DBp0iT5CW7atAmv9fPPPwuvZZFvqX6CgoIKCgqwFC9cuLBs2TI72G8n/P7yhx9+ePTRR2/duoU6HlHHG20r35cvXxbqN27cEM3bE088UVtbK9SvXLkCIyR/vtTLjRgxwqxZFdXa2hoSEiLfCVyvb775Rqijt4iICPnBmPW/ITAnZvaQmiA6N34ti3xL9RMaGrpr166LFy/azT9xwv3vdevWmfxU7FtvvWUr32afghXjbvv169e7bnGDFpafsc6ePfvss8/ihi50juDY+k5QwVPrYwmh8e7du9999920adMKCwvlJ2jyWhYnKNVPVVUV7i0IakeOHHns2DHybfPQBYNtnGrI2Jzjc4JJE9ph5MR31t3d3Rq+R40aZTbHldT5Ut3i0+1pv2Ejc3Nz4TDcuXMHt3WLncjYbyv5FgRXAU48vHCZCaLz8+fP//+OX1NjvMbMvp9S/QjCukKAhBc1O0HyLTd0ONwJCQk93fGcnBxU4IzCJYVjCo9l7ty54ueBBSB+fjKI7Ny5E24ozkS89dVXX7344ovy50t1u3XrVvjfWHjG/jc+b51OB98U7Qg0LXayfv160f+G4Ycb3Tu+oQULFuzevVtmgvD1Z82a9fM94QTxcqn3U6qfl156CWsSjeAbfpHZCZJvudBhwoQJ4o1PlF6vnzhxomDnJk+eLMTvGRkZxvGQv7+/NdsCcB/hXHp7ez/11FNFRUUWwyyz3XZ3dyclJcHDhjeSlpYmNB49ehRmz9PTMywsDK9isRPckdasWTP0nlAR/Yde8H3ixAlhu0lqglh1K1euxGgDAgJSUlLEy6XeT6l+9u/fjzni/LFjxyKYNjtBxpeU0rtjSu/l3fip8aeCsju3ulx0/5tybr4h8F04aOa5NSmt/64n35Sz8Q39uLco3/23RPQnxi25kH/SnuacfFN2QvxA/2ggfujhGQUPx9jNnPP/Lyn7Ia69h/hvvyjSP/qg7zPG5tyxv79kYelZCgbEHPCYfDgwXvgRHwfmm9aL+v6jgnz3pwWyj49+qTji+SPhfzz/l9xbl5v/y/9Po5wA7oJHYkvGLsHjFwsSL5f83Q6QkG/KHnDD4dZ6TjE22PaBhPEl1bdqqvjXIb9nexps+0DC/UGqD3Xjp8a6Dw+aNdj2EfmmnFnkmyLfFEW+GV9SaoOE+4OUKsT9b4p8k2+KfLsI38wASL6dOb5k9k3Gl2p/l5l9U75P9WTfVKdUzTezb1rZpxqyb5Jvm8Xsmw82+2bPrJlCJ7hJBgQEYMyrV6/u6urq3cDMdi41EvL9m5h988Fm35TKmimk5BRSAiUnJ/duYGY7lxqJU/Hdu9CB2TcfePZNqayZ4gBqamrEAdg6MLOdS43EqeLL3m39MPumRffd1uybUlkzzQ7A1oGZ7VxqJE61P9iLoTP7Zl9k3xRkkjUTnYhZBTESa+y3zMBMOpcfievyzeybfZF902zWTHQipuSMi4sT/WxbB2a2c6mRuDrfzL7ZF9k3zWbNFPdPMItXXnlF3CexdWBmO5caiVPxbTF0uN1+8z+fHu/+pY37tQrsEKvjm1Tn/P6y+cuaL/6UdDgwvqniX0TNlfl2qv1vGOxvtmYXBcbfS2I0nXCTbyfhGwb7TNyaA55TQLZucJwuYBbhphyeb9FgH/CYLGToOhL+R8JNOQPflX9ar/WeapJbUes9rT6nGFEF6kJswbrL1oXiqHxjJh31l/75yvsFA2K0XlMEvvXBCUVBsxXJ6U+pUM6w/3339p2LB06fGLtE6/WbOdc9OouIU87DtyjRnB/o9zS8cCJOOeH3l4I5L5224nBgPBEn347Kt8XQAeb82535/P7SlcX8sRRFvimKfFPkm6LIt3KhA8X4UhV8M/8gpRQk5Jsi3+SbIt/km3JFvhlfUuqKL7t/aWssr1JP6W5pJwHqlBpQkcHDPN+4xuTfEZQtV89UkSR1Sg2oyOAhx3ftjtTG8nxlS21aKvlWP99KoWIRDzm+cf3du+eULVfK8sm3+vlWChWLeDgG3yVpmZWVldXV1XV1dQ0NDa2trQSLfFuDh2PwrU3W6PX60tJSg8GAOQhJ4ynybREPx+D7k7e35eXl6XQ6zAHLFGuUYJFva/BwDL73JW7NycnBHLBMcSeyMuUu5SJ8y+DhGHwf2JSKCeTm5mq1WqxR/lAY+bYSD/JNkW/yTZFvNzc3kwr5Jt+9KNbz01d8azRvent77dixjnyTbylUjH9ZysfHa/jw4NdeW9jcXO4AfEdFPZ6ZuXHMmFG9Gxb5dhG+xfrNm1+eP1+4YsXzM2c+rXa+z53bP3XqGIHy6up8eft9+PCO8eOfhLEPCwvEkjBux/JAO5b1u++u6u4+S76dmG+hwHg/9JCP+DQjY31ERIinZ3887tmzwfhCHBoxIhSHgEdWVrJd+cZd5rPPtqGSnv7ntWsXyfB95Eh6UNAQvT69re1vdXVFS5bMEdorKrIiI0fisaOjEu1xcdFbtqwm385tv2trdStXLhDt96FDmpCQoadP72ltrcAj6kVFO8ULw8ODysszgU1Z2V9hGUtKPrIT311dhtGjIzo7/4H6tWtnQkOHokWK7+joSK12e89OMEmD4VPx6cWLx7FYybcT+9+CAPGFC8eFo1OmRBUWasSTgbvgFAgXiqyj4LSYmPF24hvjSEpaJj5duPAPOl2aFN++vt5m44khQ/w9PPqhQO7u7vd+57cf+XZi+w2DWFNTkJDwzMsvJwgtAwc+AvsonoA6WsQLr1//3PjQoEF+duJ77twYk0U5b16sFN8Yllm+EU03NJxkfOlq/velS6f8/X8nxbcIsWJ8NzaW+vk9DIdJbGlpqUDL1atlZvmeMWPCwYMpPYeFO9HHHyeRb1fjG0Zt8GA/0T8R7/yCEyLjn0yfPs4efGs0by5ePNukcdGieGEjvCffCA6CgwOKi3eZxJenTu3GiszO3tzUVN7e/gWezp49jXy7gn+yfPl80dFF4AhCxCDSOL4cNuz3xvHlsWMf2oPvqKjHwaJJ48mTGcJGuNn9wYKCVBz18vLEiPfu3SS2Y/SxsRMHDPCFj44KImjy7cTxpbDTl5i4tKOjUjwB9/CIiJD+/T167g+Khx57LNgYG/79CaUWvvn3VeSbfJNv8k2+yTdFvsk3Rb7JN0W+yTdFvsk3+VYr37Vpqbhe2SIkmCPfKudbKVQs4uEY+WPJt8r5Vi0eEvm/W9qvnqkSSklapjZZ88nb2/YlbkVHypTsfeRbnVIFKtJ4WP79hsrKSr1en5eXl6O0mL9K5VIWFRvyVxmruroaa0Kn0+H6XOXE/IPql4Ko2JZ/0Fiw9gaDAVdicWiVE/PHql8KomJb/lhjYTXgGiwLWP5S5cT83+qXgqjYlv/bWDgbCwKXwa2pU054dYwBI8F4Ojs7CZMKpSAqUni48VOhnFjkmyLfFOWY+h9mcXwFmRNs4wAAAABJRU5ErkJggg==`, 227 | Ascii: `┌─────┐ ┌───┐ 228 | │Alice│ │Bob│ 229 | └──┬──┘ └─┬─┘ 230 | │Authentication Request │ 231 | ””€└€€└—€€───────────────────>│ 232 | │ │ 233 | │Authentication Response │ 234 | │<─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─│ 235 | ┌──┴──┐ ┌─┴─┐ 236 | │Alice│ │Bob│ 237 | └─────┘ └───┘ 238 | `, 239 | } 240 | 241 | key := datastore.NewIncompleteKey(ctx, "Uml", nil) 242 | _, err := datastore.Put(ctx, key, uml) 243 | return err 244 | } 245 | -------------------------------------------------------------------------------- /scraping/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "requires": true, 3 | "lockfileVersion": 1, 4 | "dependencies": { 5 | "@types/core-js": { 6 | "version": "0.9.43", 7 | "resolved": "https://registry.npmjs.org/@types/core-js/-/core-js-0.9.43.tgz", 8 | "integrity": "sha512-Y11dktBJ5YwKXX8DfHSb9V6shXKSHN5P2URPZLHTRjX3OsO/u8u1kZnSJvsuSH74aTg8f5ZKcpEeCdIJOcBkHg==" 9 | }, 10 | "@types/mkdirp": { 11 | "version": "0.3.29", 12 | "resolved": "https://registry.npmjs.org/@types/mkdirp/-/mkdirp-0.3.29.tgz", 13 | "integrity": "sha1-fyrX7FX5FEgvybHsS7GuYCjUYGY=" 14 | }, 15 | "@types/node": { 16 | "version": "6.0.66", 17 | "resolved": "https://registry.npmjs.org/@types/node/-/node-6.0.66.tgz", 18 | "integrity": "sha1-VoC3SmE10z1MAER+fD3GkaRgFiU=" 19 | }, 20 | "ajv": { 21 | "version": "5.5.2", 22 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", 23 | "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", 24 | "requires": { 25 | "co": "4.6.0", 26 | "fast-deep-equal": "1.0.0", 27 | "fast-json-stable-stringify": "2.0.0", 28 | "json-schema-traverse": "0.3.1" 29 | } 30 | }, 31 | "asn1": { 32 | "version": "0.2.3", 33 | "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", 34 | "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=" 35 | }, 36 | "assert-plus": { 37 | "version": "1.0.0", 38 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", 39 | "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" 40 | }, 41 | "async-chain-proxy": { 42 | "version": "0.1.5", 43 | "resolved": "https://registry.npmjs.org/async-chain-proxy/-/async-chain-proxy-0.1.5.tgz", 44 | "integrity": "sha512-JYUzBrCWkKdBQ02H2f1N8xR4JXeWGcw2V8i2AzJjeXGTz40rqqbKkDmQieL8iHNp70W1M44WXqFsvk4Cx49H1Q==", 45 | "requires": { 46 | "babel-polyfill": "6.26.0" 47 | } 48 | }, 49 | "asynckit": { 50 | "version": "0.4.0", 51 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 52 | "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" 53 | }, 54 | "aws-sign2": { 55 | "version": "0.7.0", 56 | "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", 57 | "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" 58 | }, 59 | "aws4": { 60 | "version": "1.6.0", 61 | "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", 62 | "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=" 63 | }, 64 | "babel-polyfill": { 65 | "version": "6.26.0", 66 | "resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.26.0.tgz", 67 | "integrity": "sha1-N5k3q8Z9eJWXCtxiHyhM2WbPIVM=", 68 | "requires": { 69 | "babel-runtime": "6.26.0", 70 | "core-js": "2.5.3", 71 | "regenerator-runtime": "0.10.5" 72 | } 73 | }, 74 | "babel-runtime": { 75 | "version": "6.26.0", 76 | "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", 77 | "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", 78 | "requires": { 79 | "core-js": "2.5.3", 80 | "regenerator-runtime": "0.11.1" 81 | }, 82 | "dependencies": { 83 | "regenerator-runtime": { 84 | "version": "0.11.1", 85 | "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", 86 | "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" 87 | } 88 | } 89 | }, 90 | "balanced-match": { 91 | "version": "1.0.0", 92 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 93 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" 94 | }, 95 | "bcrypt-pbkdf": { 96 | "version": "1.0.1", 97 | "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", 98 | "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", 99 | "optional": true, 100 | "requires": { 101 | "tweetnacl": "0.14.5" 102 | } 103 | }, 104 | "bignumber.js": { 105 | "version": "2.4.0", 106 | "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-2.4.0.tgz", 107 | "integrity": "sha1-g4qZLan51zfg9LLbC+YrsJ3Qxeg=" 108 | }, 109 | "bmp-js": { 110 | "version": "0.0.3", 111 | "resolved": "https://registry.npmjs.org/bmp-js/-/bmp-js-0.0.3.tgz", 112 | "integrity": "sha1-ZBE+nHzxICs3btYHvzBibr5XsYo=" 113 | }, 114 | "boom": { 115 | "version": "4.3.1", 116 | "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", 117 | "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", 118 | "requires": { 119 | "hoek": "4.2.0" 120 | } 121 | }, 122 | "brace-expansion": { 123 | "version": "1.1.8", 124 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", 125 | "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", 126 | "requires": { 127 | "balanced-match": "1.0.0", 128 | "concat-map": "0.0.1" 129 | } 130 | }, 131 | "buffer-equal": { 132 | "version": "0.0.1", 133 | "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-0.0.1.tgz", 134 | "integrity": "sha1-kbx0sR6kBbyRa8aqkI+q+ltKrEs=" 135 | }, 136 | "caseless": { 137 | "version": "0.12.0", 138 | "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", 139 | "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" 140 | }, 141 | "chrome-launcher": { 142 | "version": "0.4.0", 143 | "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.4.0.tgz", 144 | "integrity": "sha512-Uq34nQ2peVRwyjsyoLs01mL9aEQDbc5RCZWNyYjGPt5ZFPL2B4OazSc98hO6HZOvMUILLL4MyAEVMzA5OvwWug==", 145 | "requires": { 146 | "@types/core-js": "0.9.43", 147 | "@types/mkdirp": "0.3.29", 148 | "@types/node": "6.0.66", 149 | "lighthouse-logger": "1.0.1", 150 | "mkdirp": "0.5.1", 151 | "rimraf": "2.6.2" 152 | } 153 | }, 154 | "chrome-remote-interface": { 155 | "version": "0.23.3", 156 | "resolved": "https://registry.npmjs.org/chrome-remote-interface/-/chrome-remote-interface-0.23.3.tgz", 157 | "integrity": "sha512-Bj3zMOEqJNVOll/5LrtvSdpbXSsCiSdnSQPmKUQDmAofahHczR3Qp5VJaAKrhNC/nlv9jj74aYzxTUPKrez8rA==", 158 | "requires": { 159 | "commander": "2.1.0", 160 | "ws": "2.0.3" 161 | } 162 | }, 163 | "chromy": { 164 | "version": "0.5.8", 165 | "resolved": "https://registry.npmjs.org/chromy/-/chromy-0.5.8.tgz", 166 | "integrity": "sha512-2IqMmeJGZeIbXDFM7JJIRtpDog54S4eZ1SrXNV+jX9gMwnKHgieFxQdJJ+h9rTCWZTa/6i3NGiHReUD3zrq9sQ==", 167 | "requires": { 168 | "async-chain-proxy": "0.1.5", 169 | "babel-runtime": "6.26.0", 170 | "chrome-launcher": "0.4.0", 171 | "chrome-remote-interface": "0.23.3", 172 | "jimp": "0.2.28", 173 | "uuid": "3.1.0" 174 | } 175 | }, 176 | "co": { 177 | "version": "4.6.0", 178 | "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", 179 | "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" 180 | }, 181 | "combined-stream": { 182 | "version": "1.0.5", 183 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", 184 | "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", 185 | "requires": { 186 | "delayed-stream": "1.0.0" 187 | } 188 | }, 189 | "commander": { 190 | "version": "2.1.0", 191 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.1.0.tgz", 192 | "integrity": "sha1-0SG7roYNmZKj1Re6lvVliOR8Z4E=" 193 | }, 194 | "concat-map": { 195 | "version": "0.0.1", 196 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 197 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" 198 | }, 199 | "core-js": { 200 | "version": "2.5.3", 201 | "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.3.tgz", 202 | "integrity": "sha1-isw4NFgk8W2DZbfJtCWRaOjtYD4=" 203 | }, 204 | "core-util-is": { 205 | "version": "1.0.2", 206 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 207 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" 208 | }, 209 | "cryptiles": { 210 | "version": "3.1.2", 211 | "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", 212 | "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", 213 | "requires": { 214 | "boom": "5.2.0" 215 | }, 216 | "dependencies": { 217 | "boom": { 218 | "version": "5.2.0", 219 | "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", 220 | "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", 221 | "requires": { 222 | "hoek": "4.2.0" 223 | } 224 | } 225 | } 226 | }, 227 | "dashdash": { 228 | "version": "1.14.1", 229 | "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", 230 | "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", 231 | "requires": { 232 | "assert-plus": "1.0.0" 233 | } 234 | }, 235 | "debug": { 236 | "version": "2.6.9", 237 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 238 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 239 | "requires": { 240 | "ms": "2.0.0" 241 | } 242 | }, 243 | "delayed-stream": { 244 | "version": "1.0.0", 245 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 246 | "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" 247 | }, 248 | "dom-walk": { 249 | "version": "0.1.1", 250 | "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.1.tgz", 251 | "integrity": "sha1-ZyIm3HTI95mtNTB9+TaroRrNYBg=" 252 | }, 253 | "ecc-jsbn": { 254 | "version": "0.1.1", 255 | "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", 256 | "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", 257 | "optional": true, 258 | "requires": { 259 | "jsbn": "0.1.1" 260 | } 261 | }, 262 | "es6-promise": { 263 | "version": "3.3.1", 264 | "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz", 265 | "integrity": "sha1-oIzd6EzNvzTQJ6FFG8kdS80ophM=" 266 | }, 267 | "exif-parser": { 268 | "version": "0.1.12", 269 | "resolved": "https://registry.npmjs.org/exif-parser/-/exif-parser-0.1.12.tgz", 270 | "integrity": "sha1-WKnS1ywCwfbwKg70qRZicrd2CSI=" 271 | }, 272 | "extend": { 273 | "version": "3.0.1", 274 | "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", 275 | "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=" 276 | }, 277 | "extsprintf": { 278 | "version": "1.3.0", 279 | "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", 280 | "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" 281 | }, 282 | "fast-deep-equal": { 283 | "version": "1.0.0", 284 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz", 285 | "integrity": "sha1-liVqO8l1WV6zbYLpkp0GDYk0Of8=" 286 | }, 287 | "fast-json-stable-stringify": { 288 | "version": "2.0.0", 289 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", 290 | "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" 291 | }, 292 | "file-type": { 293 | "version": "3.9.0", 294 | "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", 295 | "integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek=" 296 | }, 297 | "for-each": { 298 | "version": "0.3.2", 299 | "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.2.tgz", 300 | "integrity": "sha1-LEBFC5NI6X8oEyJZO6lnBLmr1NQ=", 301 | "requires": { 302 | "is-function": "1.0.1" 303 | } 304 | }, 305 | "forever-agent": { 306 | "version": "0.6.1", 307 | "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", 308 | "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" 309 | }, 310 | "form-data": { 311 | "version": "2.3.1", 312 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.1.tgz", 313 | "integrity": "sha1-b7lPvXGIUwbXPRXMSX/kzE7NRL8=", 314 | "requires": { 315 | "asynckit": "0.4.0", 316 | "combined-stream": "1.0.5", 317 | "mime-types": "2.1.17" 318 | } 319 | }, 320 | "fs.realpath": { 321 | "version": "1.0.0", 322 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 323 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" 324 | }, 325 | "getpass": { 326 | "version": "0.1.7", 327 | "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", 328 | "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", 329 | "requires": { 330 | "assert-plus": "1.0.0" 331 | } 332 | }, 333 | "glob": { 334 | "version": "7.1.2", 335 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", 336 | "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", 337 | "requires": { 338 | "fs.realpath": "1.0.0", 339 | "inflight": "1.0.6", 340 | "inherits": "2.0.3", 341 | "minimatch": "3.0.4", 342 | "once": "1.4.0", 343 | "path-is-absolute": "1.0.1" 344 | } 345 | }, 346 | "global": { 347 | "version": "4.3.2", 348 | "resolved": "https://registry.npmjs.org/global/-/global-4.3.2.tgz", 349 | "integrity": "sha1-52mJJopsdMOJCLEwWxD8DjlOnQ8=", 350 | "requires": { 351 | "min-document": "2.19.0", 352 | "process": "0.5.2" 353 | } 354 | }, 355 | "har-schema": { 356 | "version": "2.0.0", 357 | "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", 358 | "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" 359 | }, 360 | "har-validator": { 361 | "version": "5.0.3", 362 | "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", 363 | "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", 364 | "requires": { 365 | "ajv": "5.5.2", 366 | "har-schema": "2.0.0" 367 | } 368 | }, 369 | "hawk": { 370 | "version": "6.0.2", 371 | "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz", 372 | "integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==", 373 | "requires": { 374 | "boom": "4.3.1", 375 | "cryptiles": "3.1.2", 376 | "hoek": "4.2.0", 377 | "sntp": "2.1.0" 378 | } 379 | }, 380 | "hoek": { 381 | "version": "4.2.0", 382 | "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.0.tgz", 383 | "integrity": "sha512-v0XCLxICi9nPfYrS9RL8HbYnXi9obYAeLbSP00BmnZwCK9+Ih9WOjoZ8YoHCoav2csqn4FOz4Orldsy2dmDwmQ==" 384 | }, 385 | "http-signature": { 386 | "version": "1.2.0", 387 | "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", 388 | "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", 389 | "requires": { 390 | "assert-plus": "1.0.0", 391 | "jsprim": "1.4.1", 392 | "sshpk": "1.13.1" 393 | } 394 | }, 395 | "inflight": { 396 | "version": "1.0.6", 397 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 398 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 399 | "requires": { 400 | "once": "1.4.0", 401 | "wrappy": "1.0.2" 402 | } 403 | }, 404 | "inherits": { 405 | "version": "2.0.3", 406 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 407 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 408 | }, 409 | "ip-regex": { 410 | "version": "1.0.3", 411 | "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-1.0.3.tgz", 412 | "integrity": "sha1-3FiQdvZZ9BnCIgOaMzFvHHOH7/0=" 413 | }, 414 | "is-function": { 415 | "version": "1.0.1", 416 | "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.1.tgz", 417 | "integrity": "sha1-Es+5i2W1fdPRk6MSH19uL0N2ArU=" 418 | }, 419 | "is-typedarray": { 420 | "version": "1.0.0", 421 | "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", 422 | "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" 423 | }, 424 | "isstream": { 425 | "version": "0.1.2", 426 | "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", 427 | "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" 428 | }, 429 | "jimp": { 430 | "version": "0.2.28", 431 | "resolved": "https://registry.npmjs.org/jimp/-/jimp-0.2.28.tgz", 432 | "integrity": "sha1-3VKak3GQ9ClXp5N9Gsw6d2KZbqI=", 433 | "requires": { 434 | "bignumber.js": "2.4.0", 435 | "bmp-js": "0.0.3", 436 | "es6-promise": "3.3.1", 437 | "exif-parser": "0.1.12", 438 | "file-type": "3.9.0", 439 | "jpeg-js": "0.2.0", 440 | "load-bmfont": "1.3.0", 441 | "mime": "1.6.0", 442 | "mkdirp": "0.5.1", 443 | "pixelmatch": "4.0.2", 444 | "pngjs": "3.3.1", 445 | "read-chunk": "1.0.1", 446 | "request": "2.83.0", 447 | "stream-to-buffer": "0.1.0", 448 | "tinycolor2": "1.4.1", 449 | "url-regex": "3.2.0" 450 | } 451 | }, 452 | "jpeg-js": { 453 | "version": "0.2.0", 454 | "resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.2.0.tgz", 455 | "integrity": "sha1-U+RI7J0mPmgyZkZ+lELSxaLvVII=" 456 | }, 457 | "jsbn": { 458 | "version": "0.1.1", 459 | "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", 460 | "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", 461 | "optional": true 462 | }, 463 | "json-schema": { 464 | "version": "0.2.3", 465 | "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", 466 | "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" 467 | }, 468 | "json-schema-traverse": { 469 | "version": "0.3.1", 470 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", 471 | "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" 472 | }, 473 | "json-stringify-safe": { 474 | "version": "5.0.1", 475 | "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", 476 | "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" 477 | }, 478 | "jsprim": { 479 | "version": "1.4.1", 480 | "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", 481 | "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", 482 | "requires": { 483 | "assert-plus": "1.0.0", 484 | "extsprintf": "1.3.0", 485 | "json-schema": "0.2.3", 486 | "verror": "1.10.0" 487 | } 488 | }, 489 | "lighthouse-logger": { 490 | "version": "1.0.1", 491 | "resolved": "https://registry.npmjs.org/lighthouse-logger/-/lighthouse-logger-1.0.1.tgz", 492 | "integrity": "sha1-8HPYP3rLyWcpvxAKEhyPAGmRrmE=", 493 | "requires": { 494 | "debug": "2.6.9" 495 | } 496 | }, 497 | "load-bmfont": { 498 | "version": "1.3.0", 499 | "resolved": "https://registry.npmjs.org/load-bmfont/-/load-bmfont-1.3.0.tgz", 500 | "integrity": "sha1-u358cQ3mvK/LE8s7jIHgwBMey8k=", 501 | "requires": { 502 | "buffer-equal": "0.0.1", 503 | "mime": "1.6.0", 504 | "parse-bmfont-ascii": "1.0.6", 505 | "parse-bmfont-binary": "1.0.6", 506 | "parse-bmfont-xml": "1.1.3", 507 | "xhr": "2.4.1", 508 | "xtend": "4.0.1" 509 | } 510 | }, 511 | "mime": { 512 | "version": "1.6.0", 513 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", 514 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" 515 | }, 516 | "mime-db": { 517 | "version": "1.30.0", 518 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", 519 | "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=" 520 | }, 521 | "mime-types": { 522 | "version": "2.1.17", 523 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", 524 | "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", 525 | "requires": { 526 | "mime-db": "1.30.0" 527 | } 528 | }, 529 | "min-document": { 530 | "version": "2.19.0", 531 | "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", 532 | "integrity": "sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=", 533 | "requires": { 534 | "dom-walk": "0.1.1" 535 | } 536 | }, 537 | "minimatch": { 538 | "version": "3.0.4", 539 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 540 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 541 | "requires": { 542 | "brace-expansion": "1.1.8" 543 | } 544 | }, 545 | "minimist": { 546 | "version": "0.0.8", 547 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", 548 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" 549 | }, 550 | "mkdirp": { 551 | "version": "0.5.1", 552 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", 553 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", 554 | "requires": { 555 | "minimist": "0.0.8" 556 | } 557 | }, 558 | "ms": { 559 | "version": "2.0.0", 560 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 561 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 562 | }, 563 | "oauth-sign": { 564 | "version": "0.8.2", 565 | "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", 566 | "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=" 567 | }, 568 | "once": { 569 | "version": "1.4.0", 570 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 571 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 572 | "requires": { 573 | "wrappy": "1.0.2" 574 | } 575 | }, 576 | "parse-bmfont-ascii": { 577 | "version": "1.0.6", 578 | "resolved": "https://registry.npmjs.org/parse-bmfont-ascii/-/parse-bmfont-ascii-1.0.6.tgz", 579 | "integrity": "sha1-Eaw8P/WPfCAgqyJ2kHkQjU36AoU=" 580 | }, 581 | "parse-bmfont-binary": { 582 | "version": "1.0.6", 583 | "resolved": "https://registry.npmjs.org/parse-bmfont-binary/-/parse-bmfont-binary-1.0.6.tgz", 584 | "integrity": "sha1-0Di0dtPp3Z2x4RoLDlOiJ5K2kAY=" 585 | }, 586 | "parse-bmfont-xml": { 587 | "version": "1.1.3", 588 | "resolved": "https://registry.npmjs.org/parse-bmfont-xml/-/parse-bmfont-xml-1.1.3.tgz", 589 | "integrity": "sha1-1rZqNxr9OcUAfZ8O6yYqTyzOe3w=", 590 | "requires": { 591 | "xml-parse-from-string": "1.0.1", 592 | "xml2js": "0.4.19" 593 | } 594 | }, 595 | "parse-headers": { 596 | "version": "2.0.1", 597 | "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.1.tgz", 598 | "integrity": "sha1-aug6eqJanZtwCswoaYzR8e1+lTY=", 599 | "requires": { 600 | "for-each": "0.3.2", 601 | "trim": "0.0.1" 602 | } 603 | }, 604 | "path-is-absolute": { 605 | "version": "1.0.1", 606 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 607 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" 608 | }, 609 | "performance-now": { 610 | "version": "2.1.0", 611 | "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", 612 | "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" 613 | }, 614 | "pixelmatch": { 615 | "version": "4.0.2", 616 | "resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-4.0.2.tgz", 617 | "integrity": "sha1-j0fc7FARtHe2fbA8JDvB8wheiFQ=", 618 | "requires": { 619 | "pngjs": "3.3.1" 620 | } 621 | }, 622 | "pngjs": { 623 | "version": "3.3.1", 624 | "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.3.1.tgz", 625 | "integrity": "sha512-ggXCTsqHRIsGMkHlCEhbHhUmNTA2r1lpkE0NL4Q9S8spkXbm4vE9TVmPso2AGYn90Gltdz8W5CyzhcIGg2Gejg==" 626 | }, 627 | "process": { 628 | "version": "0.5.2", 629 | "resolved": "https://registry.npmjs.org/process/-/process-0.5.2.tgz", 630 | "integrity": "sha1-FjjYqONML0QKkduVq5rrZ3/Bhc8=" 631 | }, 632 | "punycode": { 633 | "version": "1.4.1", 634 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", 635 | "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" 636 | }, 637 | "qs": { 638 | "version": "6.5.1", 639 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", 640 | "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==" 641 | }, 642 | "read-chunk": { 643 | "version": "1.0.1", 644 | "resolved": "https://registry.npmjs.org/read-chunk/-/read-chunk-1.0.1.tgz", 645 | "integrity": "sha1-X2jKswfmY/GZk1J9m1icrORmEZQ=" 646 | }, 647 | "regenerator-runtime": { 648 | "version": "0.10.5", 649 | "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz", 650 | "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=" 651 | }, 652 | "request": { 653 | "version": "2.83.0", 654 | "resolved": "https://registry.npmjs.org/request/-/request-2.83.0.tgz", 655 | "integrity": "sha512-lR3gD69osqm6EYLk9wB/G1W/laGWjzH90t1vEa2xuxHD5KUrSzp9pUSfTm+YC5Nxt2T8nMPEvKlhbQayU7bgFw==", 656 | "requires": { 657 | "aws-sign2": "0.7.0", 658 | "aws4": "1.6.0", 659 | "caseless": "0.12.0", 660 | "combined-stream": "1.0.5", 661 | "extend": "3.0.1", 662 | "forever-agent": "0.6.1", 663 | "form-data": "2.3.1", 664 | "har-validator": "5.0.3", 665 | "hawk": "6.0.2", 666 | "http-signature": "1.2.0", 667 | "is-typedarray": "1.0.0", 668 | "isstream": "0.1.2", 669 | "json-stringify-safe": "5.0.1", 670 | "mime-types": "2.1.17", 671 | "oauth-sign": "0.8.2", 672 | "performance-now": "2.1.0", 673 | "qs": "6.5.1", 674 | "safe-buffer": "5.1.1", 675 | "stringstream": "0.0.5", 676 | "tough-cookie": "2.3.3", 677 | "tunnel-agent": "0.6.0", 678 | "uuid": "3.1.0" 679 | } 680 | }, 681 | "rimraf": { 682 | "version": "2.6.2", 683 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", 684 | "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", 685 | "requires": { 686 | "glob": "7.1.2" 687 | } 688 | }, 689 | "safe-buffer": { 690 | "version": "5.1.1", 691 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", 692 | "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" 693 | }, 694 | "sax": { 695 | "version": "1.2.4", 696 | "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", 697 | "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" 698 | }, 699 | "sntp": { 700 | "version": "2.1.0", 701 | "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz", 702 | "integrity": "sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg==", 703 | "requires": { 704 | "hoek": "4.2.0" 705 | } 706 | }, 707 | "sshpk": { 708 | "version": "1.13.1", 709 | "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz", 710 | "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=", 711 | "requires": { 712 | "asn1": "0.2.3", 713 | "assert-plus": "1.0.0", 714 | "bcrypt-pbkdf": "1.0.1", 715 | "dashdash": "1.14.1", 716 | "ecc-jsbn": "0.1.1", 717 | "getpass": "0.1.7", 718 | "jsbn": "0.1.1", 719 | "tweetnacl": "0.14.5" 720 | } 721 | }, 722 | "stream-to": { 723 | "version": "0.2.2", 724 | "resolved": "https://registry.npmjs.org/stream-to/-/stream-to-0.2.2.tgz", 725 | "integrity": "sha1-hDBgmNhf25kLn6MAsbPM9V6O8B0=" 726 | }, 727 | "stream-to-buffer": { 728 | "version": "0.1.0", 729 | "resolved": "https://registry.npmjs.org/stream-to-buffer/-/stream-to-buffer-0.1.0.tgz", 730 | "integrity": "sha1-JnmdkDqyAlyb1VCsRxcbAPjdgKk=", 731 | "requires": { 732 | "stream-to": "0.2.2" 733 | } 734 | }, 735 | "stringstream": { 736 | "version": "0.0.5", 737 | "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", 738 | "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=" 739 | }, 740 | "tinycolor2": { 741 | "version": "1.4.1", 742 | "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.4.1.tgz", 743 | "integrity": "sha1-9PrTM0R7wLB9TcjpIJ2POaisd+g=" 744 | }, 745 | "tough-cookie": { 746 | "version": "2.3.3", 747 | "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.3.tgz", 748 | "integrity": "sha1-C2GKVWW23qkL80JdBNVe3EdadWE=", 749 | "requires": { 750 | "punycode": "1.4.1" 751 | } 752 | }, 753 | "trim": { 754 | "version": "0.0.1", 755 | "resolved": "https://registry.npmjs.org/trim/-/trim-0.0.1.tgz", 756 | "integrity": "sha1-WFhUf2spB1fulczMZm+1AITEYN0=" 757 | }, 758 | "tunnel-agent": { 759 | "version": "0.6.0", 760 | "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", 761 | "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", 762 | "requires": { 763 | "safe-buffer": "5.1.1" 764 | } 765 | }, 766 | "tweetnacl": { 767 | "version": "0.14.5", 768 | "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", 769 | "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", 770 | "optional": true 771 | }, 772 | "ultron": { 773 | "version": "1.1.1", 774 | "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", 775 | "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==" 776 | }, 777 | "url-regex": { 778 | "version": "3.2.0", 779 | "resolved": "https://registry.npmjs.org/url-regex/-/url-regex-3.2.0.tgz", 780 | "integrity": "sha1-260eDJ4p4QXdCx8J9oYvf9tIJyQ=", 781 | "requires": { 782 | "ip-regex": "1.0.3" 783 | } 784 | }, 785 | "uuid": { 786 | "version": "3.1.0", 787 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", 788 | "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==" 789 | }, 790 | "verror": { 791 | "version": "1.10.0", 792 | "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", 793 | "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", 794 | "requires": { 795 | "assert-plus": "1.0.0", 796 | "core-util-is": "1.0.2", 797 | "extsprintf": "1.3.0" 798 | } 799 | }, 800 | "wrappy": { 801 | "version": "1.0.2", 802 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 803 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" 804 | }, 805 | "ws": { 806 | "version": "2.0.3", 807 | "resolved": "https://registry.npmjs.org/ws/-/ws-2.0.3.tgz", 808 | "integrity": "sha1-Uy/UmcP319cg5UPx+AcQbPxX2cs=", 809 | "requires": { 810 | "ultron": "~1.1.0" 811 | } 812 | }, 813 | "xhr": { 814 | "version": "2.4.1", 815 | "resolved": "https://registry.npmjs.org/xhr/-/xhr-2.4.1.tgz", 816 | "integrity": "sha512-pAIU5vBr9Hiy5cpFIbPnwf0C18ZF86DBsZKrlsf87N5De/JbA6RJ83UP/cv+aljl4S40iRVMqP4pr4sF9Dnj0A==", 817 | "requires": { 818 | "global": "4.3.2", 819 | "is-function": "1.0.1", 820 | "parse-headers": "2.0.1", 821 | "xtend": "4.0.1" 822 | } 823 | }, 824 | "xml-parse-from-string": { 825 | "version": "1.0.1", 826 | "resolved": "https://registry.npmjs.org/xml-parse-from-string/-/xml-parse-from-string-1.0.1.tgz", 827 | "integrity": "sha1-qQKekp09vN7RafPG4oI42VpdWig=" 828 | }, 829 | "xml2js": { 830 | "version": "0.4.19", 831 | "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", 832 | "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", 833 | "requires": { 834 | "sax": "1.2.4", 835 | "xmlbuilder": "9.0.4" 836 | } 837 | }, 838 | "xmlbuilder": { 839 | "version": "9.0.4", 840 | "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.4.tgz", 841 | "integrity": "sha1-UZy0ymhtAFqEINNJbz8MruzKWA8=" 842 | }, 843 | "xtend": { 844 | "version": "4.0.1", 845 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", 846 | "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" 847 | } 848 | } 849 | } 850 | -------------------------------------------------------------------------------- /scraping/results/20180125_01.txt: -------------------------------------------------------------------------------- 1 | https://github.com/tabahara/plantuml-view/blob/df5fb53ed00c26d3f7c9d9a9a64270378b4dd025/src/test/res/test1.puml 2 | https://github.com/maximesinclair/for-testing-purpose/blob/7708aa7c3240b7935f432dc220dc24d3778829dd/twodiaguml.puml 3 | https://github.com/rndsolutions/hawkcd/blob/5659fbbc0ba8e72801179991af7a9d41bb757f70/Server/Classes.puml 4 | https://github.com/danielvanmil/testuml/blob/6689914c9ca6d5776f1effc2cedceb9819dbd1b5/testuml/test.puml 5 | https://github.com/openim/openim/blob/dde89d36ad7dd6fb26e44d02f9b22ff0b6c95a06/docs/uml/sample.puml 6 | https://github.com/eucalyptus/architecture-docs/blob/a503c9ae4646b491c7405f2fab51c5db94e7d84e/diagrams/arch-overview/components/adminui.puml 7 | https://github.com/eucalyptus/architecture-docs/blob/a503c9ae4646b491c7405f2fab51c5db94e7d84e/service-architecture/diagrams/components/adminui.puml 8 | https://github.com/rootjs/design/blob/7993e9892f2c4bc684ed388766b64bff13f2580b/diagrams/plantuml/config/sequenceConfig.puml 9 | https://github.com/vladv75/DesignPatterns/blob/fa1bdee0798f47c0a850481f67db6aab8d30156a/src/SingletonPattern/UML.puml 10 | https://github.com/VadimKirilchuk/assignment/blob/187f9541717c03fb4edecbed66553eca317406c5/diagrams/common.puml 11 | https://github.com/profesig/exosOO/blob/56ec1d91ea4d4f8c1a6480e3e43d483593878e60/Diagramme%20de%20classe/L1-%20Classes%20et%20attributs/exemples/dc_3/dc_3.puml 12 | https://github.com/profesig/exosOO/blob/56ec1d91ea4d4f8c1a6480e3e43d483593878e60/Diagramme%20de%20classe/L2%20-%20M%C3%A9thodes%20et%20visibilit%C3%A9/exemples/dc_1/dc_1.puml 13 | https://github.com/profesig/exosOO/blob/56ec1d91ea4d4f8c1a6480e3e43d483593878e60/Diagramme%20de%20classe/L5%20-%20Associations/exemples/l5dc4/dc_4.puml 14 | https://github.com/jss3228aa333/java-design-patterns/blob/4ca205c03cc03ea5bc80fe27c0a4594f0d087582/page-object/etc/page-object.urm.puml 15 | https://github.com/jss3228aa333/java-design-patterns/blob/4ca205c03cc03ea5bc80fe27c0a4594f0d087582/publish-subscribe/etc/publish-subscribe.urm.puml 16 | https://github.com/jss3228aa333/java-design-patterns/blob/4ca205c03cc03ea5bc80fe27c0a4594f0d087582/message-channel/etc/message-channel.urm.puml 17 | https://github.com/esamson/plantumlnb/blob/2a63699858c5074714fca3af286ae542a32142bd/Sample/Class/Visibility.puml 18 | https://github.com/CollaborationInEncapsulation/snooker/blob/18c02b8cb20fccc8b6fa08b743583fb0c9d0f387/src/docs/domain/championship/Season.puml 19 | https://github.com/CollaborationInEncapsulation/snooker/blob/18c02b8cb20fccc8b6fa08b743583fb0c9d0f387/src/docs/domain/performance/Performance.puml 20 | https://github.com/CollaborationInEncapsulation/snooker/blob/18c02b8cb20fccc8b6fa08b743583fb0c9d0f387/src/docs/domain/ranking/Rank.puml 21 | https://github.com/zealousduck/PicYaPalette/blob/f9be43e584bdd9cb2c4b33896ad01f961a60b2ce/app/UML/SSDRandomPalette.puml 22 | https://github.com/zealousduck/PicYaPalette/blob/f9be43e584bdd9cb2c4b33896ad01f961a60b2ce/app/UML/SSDViewFavorites.puml 23 | https://github.com/llaville/umlwriter/blob/99c6919b8ab5e7d3836ea6690325048a83e249ff/tests/fixtures/002_simpleClassExtends.puml 24 | https://github.com/llaville/umlwriter/blob/99c6919b8ab5e7d3836ea6690325048a83e249ff/tests/fixtures/008_Property.puml 25 | https://github.com/Dedda/scheisse/blob/3be0a21e432179b5521df6416388e67e63510653/server/uml/classes/org/dedda/games/scheisse_server/util/Pages.puml 26 | https://github.com/Mithlond/mithlond-codestyle/blob/42272e30a9f9280b3ccc85cc44981b7f9040d4ff/src/site/markdown/plantuml/modularity_component.puml 27 | https://github.com/maorun/lotto/blob/5d32cd903234f63a8532912dfb9f03c8e70680f3/docs/ablauf.puml 28 | https://github.com/RestComm/mediaserver/blob/5f664bf8c2f37c819cf2e56f9b60250c56d70218/architecture-diagrams/rtp/rtp-netty-handler-state.puml 29 | https://github.com/lennartj/nazgul_tools/blob/f35d5c8b09b28ee87b9c630090c6de6684273a50/src/site/markdown/plantuml/modularity_component.puml 30 | https://github.com/lengyijun/lib_v2/blob/a307300c87357aa79d058e6a1388137fdd466625/app/src/main/java/com/example/steven/sjtu_lib_v2/uml/%E6%97%B6%E5%BA%8F%E5%9B%BE/SIngle%E8%B1%86%E7%93%A3%E5%A4%B1%E8%B4%A5.puml 31 | https://github.com/thomasbroussard/website/blob/741833605e90871159b0d66c13d07716ad60be60/tbr-website/src/main/webapp/graph/Identity.puml 32 | https://github.com/thomasbroussard/website/blob/741833605e90871159b0d66c13d07716ad60be60/tbr-website/src/main/webapp/images/puml/oop-uml/oop-identity-def.puml 33 | https://github.com/thomasbroussard/website/blob/741833605e90871159b0d66c13d07716ad60be60/tbr-website/src/main/webapp/graph/SP.puml 34 | https://github.com/thomasbroussard/website/blob/741833605e90871159b0d66c13d07716ad60be60/tbr-website/src/main/webapp/images/puml/java-bases/java-bases-democlass.puml 35 | https://github.com/thomasbroussard/website/blob/741833605e90871159b0d66c13d07716ad60be60/tbr-website/src/main/webapp/images/puml/java-bases/java-bases-for.puml 36 | https://github.com/thomasbroussard/website/blob/741833605e90871159b0d66c13d07716ad60be60/tbr-website/src/main/webapp/images/puml/java-bases/java-bases-idDAO.puml 37 | https://github.com/thomasbroussard/website/blob/741833605e90871159b0d66c13d07716ad60be60/tbr-website/src/main/webapp/images/puml/oop-uml/oop-activity-diagram-fork.puml 38 | https://github.com/azige/PlantUML-NB/blob/468bccd99a98009064a67fc3438cfd5faf1365aa/Sample/Class/Visibility.puml 39 | https://github.com/mhaidarh/kargu/blob/87e2833a4ec4426bf8d778d4735f648ff2bb4de5/misc/diagram/sequence/kargu_sequence_check-condition.puml 40 | https://github.com/mhaidarh/kargu/blob/87e2833a4ec4426bf8d778d4735f648ff2bb4de5/misc/diagram/sequence/kargu_sequence_close-doc.puml 41 | https://github.com/thomasbroussard/website/blob/741833605e90871159b0d66c13d07716ad60be60/tbr-website/src/main/webapp/images/puml/oop-uml/oop-activity-diagram-fork.puml 42 | https://github.com/azige/PlantUML-NB/blob/468bccd99a98009064a67fc3438cfd5faf1365aa/Sample/Class/Visibility.puml 43 | https://github.com/mhaidarh/kargu/blob/87e2833a4ec4426bf8d778d4735f648ff2bb4de5/misc/diagram/sequence/kargu_sequence_check-condition.puml 44 | https://github.com/mhaidarh/kargu/blob/87e2833a4ec4426bf8d778d4735f648ff2bb4de5/misc/diagram/sequence/kargu_sequence_close-doc.puml 45 | https://github.com/mhaidarh/kargu/blob/87e2833a4ec4426bf8d778d4735f648ff2bb4de5/misc/diagram/sequence/kargu_sequence_close-page.puml 46 | https://github.com/mhaidarh/kargu/blob/87e2833a4ec4426bf8d778d4735f648ff2bb4de5/misc/diagram/sequence/kargu_sequence_copy-result-file.puml 47 | https://github.com/mhaidarh/kargu/blob/87e2833a4ec4426bf8d778d4735f648ff2bb4de5/misc/diagram/sequence/kargu_sequence_copy-result.puml 48 | https://github.com/mhaidarh/kargu/blob/87e2833a4ec4426bf8d778d4735f648ff2bb4de5/misc/diagram/sequence/kargu_sequence_offer-revert-changes.puml 49 | https://github.com/mhaidarh/kargu/blob/87e2833a4ec4426bf8d778d4735f648ff2bb4de5/misc/diagram/sequence/kargu_sequence_print-doc.puml 50 | https://github.com/mhaidarh/kargu/blob/87e2833a4ec4426bf8d778d4735f648ff2bb4de5/misc/diagram/sequence/kargu_sequence_print-page.puml 51 | https://github.com/ming13/generics/blob/f4376fb2917695b20f9af9c53ec407eccc4da5e2/uml/activity.puml 52 | https://github.com/isel-leic-mpd/1415v-LI41D-LI61D/blob/743bd30b71491ea7fb5db18aadb0a117a459834a/src/test/java/test.puml 53 | https://github.com/jruizaranguren/atoming/blob/b1dafaaee1c194bee2417111d0dbe7ab773d0e8f/docs/component.puml 54 | https://github.com/saywithu/git_test/blob/9ec0935a1cd666fa587d21a5bc72372da75d23ca/page-object/etc/page-object.urm.puml 55 | https://github.com/errorx666/error-bot/blob/886bed930d7c784bde6e4bbd8e7bd6ef89ae9b83/doc/nodebb-events.puml 56 | https://github.com/shripad-agashe/shripad-agashe.github.io/blob/256654241e57805cf35e58ee346e07ae3102b728/_puml/disorderly-programming/Account.puml 57 | https://github.com/rkiranchowdhary/java-design-patterns/blob/6bbccfd5947ef5a547f8abdcfcc2f799f0ce052c/message-channel/etc/message-channel.urm.puml 58 | https://github.com/rkiranchowdhary/java-design-patterns/blob/6bbccfd5947ef5a547f8abdcfcc2f799f0ce052c/page-object/etc/page-object.urm.puml 59 | https://github.com/rkiranchowdhary/java-design-patterns/blob/6bbccfd5947ef5a547f8abdcfcc2f799f0ce052c/publish-subscribe/etc/publish-subscribe.urm.puml 60 | https://github.com/dheerajksingh/designpattern/blob/cca4760f6990886c0dd47dea93a6c0d359917073/page-object/etc/page-object.urm.puml 61 | https://github.com/k2works/etude_op10_no10/blob/ebdd65aa141485b1f0399705782bb6650bfabf2a/docs/diagrams/use_case.puml 62 | https://github.com/IUT-Blagnac/MPA2014G1A2/blob/701701670b215a51cdea31d43415e88ee80550ff/sprint_5/srcdoc/diag0.puml 63 | https://github.com/mthamil/PlantUMLStudio/blob/0b3695fc82957237c238366d980fadfea9c4adff/PlantUmlStudio/DesignTimeData/class.puml 64 | https://github.com/mthamil/PlantUMLStudio/blob/0b3695fc82957237c238366d980fadfea9c4adff/Tests.Unit/TestDiagrams/class.puml 65 | https://github.com/olive-llo/PUML-cleaner/blob/4bedee29e4928f2fdeb5e15f1eb3bb97ba4b75c1/src/org/olivier/ressources/newpumlTemplate_clean.puml 66 | https://github.com/IUT-Blagnac/MPA2015G1A1/blob/4ee2dfcb256b25d1ed95cce2143da2d26890ffed/sprint_5/srcdoc/diag0.puml 67 | https://github.com/profesig/exosOO/blob/56ec1d91ea4d4f8c1a6480e3e43d483593878e60/Diagramme%20de%20classe/L2%20-%20M%C3%A9thodes%20et%20visibilit%C3%A9/exemples/dc_2/dc_2.puml 68 | https://github.com/profesig/exosOO/blob/56ec1d91ea4d4f8c1a6480e3e43d483593878e60/Diagramme%20de%20classe/L4%20-%20Constructeurs%20et%20instances/exemples/l4_dc_1/dc_1.puml 69 | https://github.com/profesig/exosOO/blob/56ec1d91ea4d4f8c1a6480e3e43d483593878e60/Diagramme%20de%20classe/L5%20-%20Associations/exemples/l5dc3/dc_3.puml 70 | https://github.com/profesig/exosOO/blob/56ec1d91ea4d4f8c1a6480e3e43d483593878e60/Diagramme%20de%20classe/L6%20-%20Packages/exemples/l6dc2/dc_2.puml 71 | https://github.com/IUT-Blagnac/MPA2014G2A2/blob/5075bea484a2286b75754c604f7e3856bc72bc6d/sprint_5/srcdoc/diag0.puml 72 | https://github.com/IUT-Blagnac/MPA2014G2A2/blob/5075bea484a2286b75754c604f7e3856bc72bc6d/sprint_5/srcdoc/images/diag0.puml 73 | https://github.com/pierre3/CsvEditSharp/blob/f588332df985b2587f67991792989d306d5cc94d/Documents/uml/Services/ConfigSettingsDialogService.puml 74 | https://github.com/earring/testgenerator/blob/3f5a6269657110ed529c952eceeb0e956adff7c7/diags/classes/wholeClassDiagram.puml 75 | https://github.com/huanle0610/Samantabhadra/blob/9f3c10c66c98a34e2bc42a77e7a24f6a988adf34/platuml_example/component.puml 76 | https://github.com/jmxtrans/jmxtrans2/blob/c68a801b38c4b2e29c0ed83a2b6f6d0b4da607e0/src/plantuml/main-components.puml 77 | https://github.com/zealousduck/PicYaPalette/blob/f9be43e584bdd9cb2c4b33896ad01f961a60b2ce/app/UML/SSDViewPaletteDetails.puml 78 | https://github.com/enolive/mock-heuristics/blob/b56934269459a61e00e19f0365b450e4e684d23d/images/extract-dependency-after.puml 79 | https://github.com/enolive/mock-heuristics/blob/b56934269459a61e00e19f0365b450e4e684d23d/images/extract-dependency-before.puml 80 | https://github.com/longforfreedom/learn-spark/blob/55ddd60e092674bd593b0f9c8981d3e6c752f288/code/mspark/src/main/resources/Rpc.puml 81 | https://github.com/sseletskyy/grape-api-tdd-example/blob/a8850b6b07cd4113346e0d35384d77cea661fd1e/docs/factory_girl_example.puml 82 | https://github.com/IUT-Blagnac/MPA2014G2A2/blob/5075bea484a2286b75754c604f7e3856bc72bc6d/sprint_5/doc/images/diag0.puml 83 | https://github.com/IUT-Blagnac/MPA2014G2A2/blob/5075bea484a2286b75754c604f7e3856bc72bc6d/sprint_5/srcdoc/diag0.puml 84 | https://github.com/IUT-Blagnac/MPA2014G2A2/blob/5075bea484a2286b75754c604f7e3856bc72bc6d/sprint_5/srcdoc/images/diag0.puml 85 | https://github.com/pierre3/CsvEditSharp/blob/f588332df985b2587f67991792989d306d5cc94d/Documents/uml/Services/ConfigSettingsDialogService.puml 86 | https://github.com/pierre3/CsvEditSharp/blob/fee136aa4cffd7beb4a1e0626f4b4e593fefa32a/Documents/uml/Bindings/BindableBase.puml 87 | https://github.com/pierre3/CsvEditSharp/blob/b008e4950b010034e8cd505fc782f291eb4faf54/Documents/uml/Views/MainWindow.xaml.puml 88 | https://github.com/earring/testgenerator/blob/3f5a6269657110ed529c952eceeb0e956adff7c7/diags/classes/wholeClassDiagram.puml 89 | https://github.com/huanle0610/Samantabhadra/blob/9f3c10c66c98a34e2bc42a77e7a24f6a988adf34/platuml_example/component.puml 90 | https://github.com/gourav-singhal-24/shopping-app-service-node/blob/ec781bf0c76a16e23f5869c7f75ee58aa608d0ce/docs/arch/admin_user/nodes_auth_admin.puml 91 | https://github.com/IUT-Blagnac/MPA2015G2A2/blob/2f0a74bce3d15b33e88c54ce767ea259c6a9f127/sprint_5/srcdoc/diag0.puml 92 | https://github.com/arc42/docs.arc42.org-site/blob/61312959caf58901875e109e47b0a391654a0eab/originals/plantuml-diagrams/component-diagrams/03-context-compact.puml 93 | https://github.com/VitorPeixoto/ArtexSavior/blob/09a212d6bf74890bef0610321a10d415501c3b01/UMLs/EntityMoveType-Method.puml 94 | https://github.com/lengyijun/lib_v2/blob/a307300c87357aa79d058e6a1388137fdd466625/app/src/main/java/com/example/steven/sjtu_lib_v2/uml/%E6%97%B6%E5%BA%8F%E5%9B%BE/SIngle%E8%B1%86%E7%93%A3%E6%88%90%E5%8A%9F.puml 95 | https://github.com/piotr-polanski/EyeOfBeholder/blob/94768b6760730f05286b58978db5c4113be8e810/EyeOfBeholder.Uml.Tests/testData/Attributes.puml 96 | https://github.com/piotr-polanski/EyeOfBeholder/blob/6084e659eba796c50057b3d441cb55b15869df82/EyeOfBeholder.Uml.Tests/testData/Operations.puml 97 | https://github.com/david-w-millar/grails-plantuml-plugin/blob/5203aa32aa9809c18e632a530a98f4fd8404a94d/src/resources/ExampleSequenceDiagram.puml 98 | https://github.com/gabino-profesor/phpbasico/blob/2711fcc82a311633eed94f9dbd77957a98ad00e8/inventario3/esquema2.3.puml 99 | https://github.com/walthaas/Drupal-7-PlantUML/blob/0aafb8527314c92fa7bff237158e28ab416afba3/field_info_field.puml 100 | https://github.com/oroques72/MPA2015G3A1/blob/4a8b04a98ce9898cfdeced47ab8a64b5fba822a8/sprint_5/srcdoc/diag0.puml 101 | https://github.com/axgtz/AyM-de-Sistemas-de-Software/blob/2c87d8d767e8eebcf34535a68c75a19a63d6dad0/Clase/Singleton/Singleton/Singleton.puml 102 | https://github.com/IUT-Blagnac/MPA2014G3A2/blob/a4003c3d0c3ef04b4f1f76a44fd5226b4cb08afe/sprint_5/srcdoc/diag0.puml 103 | https://github.com/asi219/PHP_completo/blob/536845675975e1c5e6652279cf722d6a761b9f06/inventario3/esquema2.3.puml 104 | https://github.com/tnarnold/SimpleManagerParks/blob/4ca5601abc716065a9d6eb76d72d751698f97cb6/src/main/uml/OltModel.puml 105 | https://github.com/zmer007/Dagger2Coffee/blob/8bb2c864c9ef1ededac6c1dff697111226d0cf01/app/src/main/java/rubo/dagger2coffee/module/module.puml 106 | https://github.com/deadbok/eal_programming/blob/6231cc42350184ef20b268a367b8e410bd25c4d1/ass12/py2puml.py.puml 107 | https://github.com/deadbok/eal_programming/blob/6231cc42350184ef20b268a367b8e410bd25c4d1/ass12/questions.py.puml 108 | https://github.com/deadbok/eal_programming/blob/6231cc42350184ef20b268a367b8e410bd25c4d1/ass12/quiz.py.puml 109 | https://github.com/IUT-Blagnac/MPA2015G3B1/blob/38761a69484bf2cdb5e48e1c9f644854ee33b93d/sprint_5/srcdoc/diag0.puml 110 | https://github.com/cxd/au.id.cxd.Math/blob/588ffc726d86df42a7f9ac96c01091bd4c8c3d33/au.id.cxd.Math.HttpUI/static/doc/project_add_click.puml 111 | https://github.com/bondden/esf-puml/blob/f8325ef4bf93fb97477029c30833f9501ebf319f/tst/d/inp_rel/sub/test6.puml 112 | https://github.com/k2works/ruby-design-pattern/blob/551ff4ecd8fd83b33afa3abb02751a22c641a50d/adapter/adapter.puml 113 | https://github.com/k2works/ruby-design-pattern/blob/551ff4ecd8fd83b33afa3abb02751a22c641a50d/builder/builder.puml 114 | https://github.com/saywithu/git_test/blob/9ec0935a1cd666fa587d21a5bc72372da75d23ca/message-channel/etc/message-channel.urm.puml 115 | https://github.com/saywithu/git_test/blob/9ec0935a1cd666fa587d21a5bc72372da75d23ca/publish-subscribe/etc/publish-subscribe.urm.puml 116 | https://github.com/sapo/sapo-broker/blob/ee16dae91ba0c09d3ff2d21a145b68b37ca04eb3/docs/flows/ping.puml 117 | https://github.com/Pablo-Aviles-Prieto/phpbasico/blob/663e06ea50ed8d4de23b5028a3b11312b93a09d8/inventario3/esquema2.3.puml 118 | https://github.com/ivaneiroadominguez/phpbasico/blob/a79bfae131901999453f5d04ebfdf2e3e517c464/inventario3/esquema2.3.puml 119 | https://github.com/IUT-Blagnac/MPA2015G1A2/blob/5d67e3963ca034cb4f542e8026fb8e209f0c7e9c/sprint_5/srcdoc/diag0.puml 120 | https://github.com/asantoro/tests/blob/9f9265409365cf79d832958bcd1c3d283fb9cb6d/magento/foo.puml 121 | https://github.com/bondden/esf-puml/blob/f8325ef4bf93fb97477029c30833f9501ebf319f/tst/d/inp_rel/sub/test6.puml 122 | https://github.com/k2works/ruby-design-pattern/blob/551ff4ecd8fd83b33afa3abb02751a22c641a50d/adapter/adapter.puml 123 | https://github.com/k2works/ruby-design-pattern/blob/551ff4ecd8fd83b33afa3abb02751a22c641a50d/builder/builder.puml 124 | https://github.com/k2works/etude-op10-no8/blob/1623147899fb0ed8deb9c18e50e78b69a76de559/docs/uml/use_case_07_3.puml 125 | https://github.com/saywithu/git_test/blob/9ec0935a1cd666fa587d21a5bc72372da75d23ca/message-channel/etc/message-channel.urm.puml 126 | https://github.com/saywithu/git_test/blob/9ec0935a1cd666fa587d21a5bc72372da75d23ca/publish-subscribe/etc/publish-subscribe.urm.puml 127 | https://github.com/sapo/sapo-broker/blob/ee16dae91ba0c09d3ff2d21a145b68b37ca04eb3/docs/flows/ping.puml 128 | https://github.com/Pablo-Aviles-Prieto/phpbasico/blob/663e06ea50ed8d4de23b5028a3b11312b93a09d8/inventario3/esquema2.3.puml 129 | https://github.com/ivaneiroadominguez/phpbasico/blob/a79bfae131901999453f5d04ebfdf2e3e517c464/inventario3/esquema2.3.puml 130 | https://github.com/IUT-Blagnac/MPA2015G1A2/blob/5d67e3963ca034cb4f542e8026fb8e209f0c7e9c/sprint_5/srcdoc/diag0.puml 131 | https://github.com/BelkhousNabil/Projets-Informatiques/blob/47ffd6526bb66ae263c34725fe2b515b751127bb/Projet%20de%20UML%20Reverse/src/main/resources/examples/uc.puml 132 | https://github.com/BelkhousNabil/Projets-Informatiques/blob/47ffd6526bb66ae263c34725fe2b515b751127bb/Projet%20de%20UML%20Reverse/target/classes/examples/uc.puml 133 | https://github.com/saywithu/git_test/blob/9ec0935a1cd666fa587d21a5bc72372da75d23ca/message-channel/etc/message-channel.urm.puml 134 | https://github.com/saywithu/git_test/blob/9ec0935a1cd666fa587d21a5bc72372da75d23ca/publish-subscribe/etc/publish-subscribe.urm.puml 135 | https://github.com/sapo/sapo-broker/blob/ee16dae91ba0c09d3ff2d21a145b68b37ca04eb3/docs/flows/ping.puml 136 | https://github.com/Pablo-Aviles-Prieto/phpbasico/blob/663e06ea50ed8d4de23b5028a3b11312b93a09d8/inventario3/esquema2.3.puml 137 | https://github.com/ivaneiroadominguez/phpbasico/blob/a79bfae131901999453f5d04ebfdf2e3e517c464/inventario3/esquema2.3.puml 138 | https://github.com/IUT-Blagnac/MPA2015G1A2/blob/5d67e3963ca034cb4f542e8026fb8e209f0c7e9c/sprint_5/srcdoc/diag0.puml 139 | https://github.com/junix/org-design/blob/c2de01ffed0afeb51e2d0e8dbd30f4e5d7b003f8/uml/services.puml 140 | https://github.com/lsy563193/mybot/blob/03c1668edf8d6dc85b3b7169c4b8dc167ddfa92d/mybot_nav/nodes/app_layer2.puml 141 | https://github.com/DOMA0101/tienda/blob/b7c182bacf272159f7a48156422e3488414bf05a/public/dise%C3%B1o/casodeuso1.puml 142 | https://github.com/hcitlife/DesignPattern/blob/e807217c0fc8b376df09c137ea370baea175e870/observerdemo/src/main/java/com/hc/demo1/ee.puml 143 | https://github.com/vsch/MarkdownTest/blob/8ec30eb5beacffeabaf958561a9fa18e3701f7b1/test.puml 144 | https://github.com/bolironman/bolironman.github.io/blob/ccb8c32edd4e6d8bb97b327aabd39da3c6668df9/_site/assets/img/2015-03-02-relation-in-parse/publisher-book-associationfree.puml 145 | https://github.com/bolironman/bolironman.github.io/blob/ccb8c32edd4e6d8bb97b327aabd39da3c6668df9/assets/img/2015-03-02-relation-in-parse/publisher-book-associationfree.puml 146 | https://github.com/christianblos/codedocs-plugin-plantuml/blob/9ecc9d16b5a7195da2f55c10c03714afd155470c/example/docs/sequence.puml 147 | https://github.com/christianblos/codedocs-plugin-plantuml/blob/9ecc9d16b5a7195da2f55c10c03714afd155470c/example/export/sequence.puml 148 | https://github.com/suzuki-hoge/dev-note/blob/5e5569f4d29f369584186be5ae29ffe8cac8a598/haskell/ddd/02-identity-and-entity/doc/Item.puml 149 | https://github.com/suzuki-hoge/dev-note/blob/5e5569f4d29f369584186be5ae29ffe8cac8a598/tip/online-plant-viewing/doc/foo_seq.puml 150 | https://github.com/mikhtonyuk/quantify.me/blob/d38bc2529d10d172d5924bcd77674b260d396f41/doc/objects.puml 151 | https://github.com/PainNarrativesLab/IOMNarratives/blob/7f2dd4d6e2f77b26404d1b7ef6410a7d1d166daf/docs/data_movement.puml 152 | https://github.com/nibralab/joomla-architecture/blob/49e963e19a0ec4ded859d393c71964c2908ccd16/src/incl/symfony/component/console/input/string-input.puml 153 | https://github.com/msimmons/auction/blob/91b09fe0aaf965edc52aa8c367c538c8823b78cf/docs/src/plantuml/test.puml 154 | https://github.com/Barackbar/Reverse_Frogger/blob/e7735819633a6c8cfb6c3c1a72c04e72e3a63bf9/app/UML/Use%20Cases.puml 155 | https://github.com/buharin/fastbuild_python/blob/4d8cace03c94021f5ee30a3d8c8730b37312118a/doc/simulation_default_activity_plan.puml 156 | https://github.com/mathiasverraes/mathiasverraes.github.com/blob/866e4d3ffac7880e71d26fbb9f89074f305bb3ef/img/posts/2016-02-29-type-safety-and-money/Money.puml 157 | https://github.com/mathiasverraes/mathiasverraes.github.com/blob/866e4d3ffac7880e71d26fbb9f89074f305bb3ef/img/posts/2016-02-29-type-safety-and-money/MoneyFormatter.puml 158 | https://github.com/DOMA0101/tienda/blob/b7c182bacf272159f7a48156422e3488414bf05a/public/dise%C3%B1o/casodeuso1.puml 159 | https://github.com/dfremy/WirelessSoftwareDevelopment/blob/c21d618ce7dfd4e1470db99362919ad5e9edaf3d/Challenge03/SystemSequenceDiagram.puml 160 | https://github.com/eriklupander/gotling/blob/f297e93ce4718458bd2efb3b598cfdbd273b82c0/docs/gotling-seq.puml 161 | https://github.com/rootjs/design/blob/7993e9892f2c4bc684ed388766b64bff13f2580b/presentation/classes/StructProxy.puml 162 | https://github.com/rootjs/design/blob/7993e9892f2c4bc684ed388766b64bff13f2580b/presentation/classes/TemplateProxy.puml 163 | https://github.com/vsch/MarkdownTest/blob/8ec30eb5beacffeabaf958561a9fa18e3701f7b1/test.puml 164 | https://github.com/bolironman/bolironman.github.io/blob/ccb8c32edd4e6d8bb97b327aabd39da3c6668df9/_site/assets/img/2015-03-02-relation-in-parse/publisher-book-associationfree.puml 165 | https://github.com/bolironman/bolironman.github.io/blob/ccb8c32edd4e6d8bb97b327aabd39da3c6668df9/assets/img/2015-03-02-relation-in-parse/publisher-book-associationfree.puml 166 | https://github.com/suzuki-hoge/dev-note/blob/5e5569f4d29f369584186be5ae29ffe8cac8a598/haskell/ddd/02-identity-and-entity/doc/Item.puml 167 | https://github.com/suzuki-hoge/dev-note/blob/5e5569f4d29f369584186be5ae29ffe8cac8a598/tip/online-plant-viewing/doc/foo_seq.puml 168 | https://github.com/mikhtonyuk/quantify.me/blob/d38bc2529d10d172d5924bcd77674b260d396f41/doc/objects.puml 169 | https://github.com/mikhtonyuk/quantify.me/blob/d38bc2529d10d172d5924bcd77674b260d396f41/doc/resources.puml 170 | https://github.com/roliygu/CNKICrawler/blob/237973911e68de4336dc57f45fa59840fc67f973/doc/uml/process.puml 171 | https://github.com/profesig/exosOO/blob/56ec1d91ea4d4f8c1a6480e3e43d483593878e60/Diagramme%20de%20classe/L5%20-%20Associations/exemples/l5dc2/dc_2.puml 172 | https://github.com/byeungchun/Bankexam/blob/61444f2b9185a6cec0bbe3f97b036174008fa33b/Doc/Workflow.puml 173 | https://github.com/SharafGabel/GYMTONIK/blob/121a7c6f216cc42e5d4d48b37d933edd7e15ed3c/diagrams/EnregistrementAutresMesures.puml 174 | https://github.com/SharafGabel/GYMTONIK/blob/121a7c6f216cc42e5d4d48b37d933edd7e15ed3c/diagrams/EnregistrementTravailEffectue.puml 175 | https://github.com/esteinberg/plantuml4idea/blob/cb320f2b2c4f22a192e144a474203315c62ade27/testData/reverseArrowIntention/afterSequenceArrows.puml 176 | https://github.com/cranebird/slime-reading/blob/3beb4b6313719d6a8bf6093086d0466ecf077dbe/seq-slime-boot.puml 177 | https://github.com/esamson/plantumlnb/blob/2a63699858c5074714fca3af286ae542a32142bd/Sample/Sequence.puml 178 | https://github.com/esamson/plantumlnb/blob/2a63699858c5074714fca3af286ae542a32142bd/src/test/resources/org/netbeans/modules/plantumlnb/Sequence.puml 179 | https://github.com/zhangzuoqiang/WebRiskMonitor/blob/7e24c3ca21ba866823ad43fe1b553e8572096fa7/doc/relations.puml 180 | https://github.com/vbauer/lein-plantuml/blob/9fa00269116e008ce070e4890044c8994ad1872d/example/doc/example-04.puml 181 | https://github.com/zhangzuoqiang/WebRiskMonitor/blob/7e24c3ca21ba866823ad43fe1b553e8572096fa7/doc/relations.puml 182 | https://github.com/kaltura/player-sdk-native-android/blob/79613da5d9f2cb62fbc65c31ecfac7401b4e077e/docs/ChromeCastActivity.puml 183 | https://github.com/vbauer/lein-plantuml/blob/9fa00269116e008ce070e4890044c8994ad1872d/example/doc/example-04.puml 184 | https://github.com/pierre3/CsvEditSharp/blob/f588332df985b2587f67991792989d306d5cc94d/Documents/uml/Services/IModalDialogService.puml 185 | https://github.com/pierre3/CsvEditSharp/blob/fee136aa4cffd7beb4a1e0626f4b4e593fefa32a/Documents/uml/Bindings/DelegateCommand.puml 186 | https://github.com/pierre3/CsvEditSharp/blob/b008e4950b010034e8cd505fc782f291eb4faf54/Documents/uml/Models/ColumnValidation.puml 187 | https://github.com/pierre3/CsvEditSharp/blob/b008e4950b010034e8cd505fc782f291eb4faf54/Documents/uml/Models/CustomBooleanConverter.puml 188 | https://github.com/pierre3/CsvEditSharp/blob/b008e4950b010034e8cd505fc782f291eb4faf54/Documents/uml/Services/GenerageConfigDialogService.puml 189 | https://github.com/pierre3/CsvEditSharp/blob/b008e4950b010034e8cd505fc782f291eb4faf54/Documents/uml/Services/OpenFileDialogService.puml 190 | https://github.com/pierre3/CsvEditSharp/blob/b008e4950b010034e8cd505fc782f291eb4faf54/Documents/uml/Services/SaveConfigDialogService.puml 191 | https://github.com/mikhtonyuk/quantify.me/blob/d38bc2529d10d172d5924bcd77674b260d396f41/doc/resources.puml 192 | https://github.com/roliygu/CNKICrawler/blob/237973911e68de4336dc57f45fa59840fc67f973/doc/uml/process.puml 193 | https://github.com/mthamil/PlantUMLStudio/blob/0b3695fc82957237c238366d980fadfea9c4adff/PlantUmlStudio/DesignTimeData/sequence.puml 194 | https://github.com/mthamil/PlantUMLStudio/blob/0b3695fc82957237c238366d980fadfea9c4adff/PlantUmlStudio/samples/sample%20class.puml 195 | https://github.com/mthamil/PlantUMLStudio/blob/0b3695fc82957237c238366d980fadfea9c4adff/PlantUmlStudio/samples/sample%20sequence.puml 196 | https://github.com/jacksyen/stepbystep/blob/6059422c9fed641e0f8c27988d60f1ed862bb862/stepbystep-java/basicjava/src/main/java/com/hedwig/stepbystep/javatutorial/webtest/pageobjects/pagefactory.puml 197 | https://github.com/olive-llo/PUML-cleaner/blob/4bedee29e4928f2fdeb5e15f1eb3bb97ba4b75c1/src/org/olivier/ressources/newpumlTemplate.puml 198 | https://github.com/ivaneye/ivaneye.github.com/blob/e50e7ff882c45c94c456031b68bddb6ca6f3e052/assets/zookeeper/consensus/2pc.puml 199 | https://github.com/profesig/exosOO/blob/56ec1d91ea4d4f8c1a6480e3e43d483593878e60/Diagramme%20de%20classe/L3%20-%20Classes%20abstraites%20et%20h%C3%A9ritage/exemples/dc_2/dc_2.puml 200 | https://github.com/profesig/exosOO/blob/56ec1d91ea4d4f8c1a6480e3e43d483593878e60/Diagramme%20de%20classe/L5%20-%20Associations/exemples/l5dc2/dc_2.puml 201 | https://github.com/terrex/SentimentAnalysis/blob/77f7bf0b0ef0090f74e0da39224302af4c8579d5/memoria/diag1.puml 202 | https://github.com/cranebird/slime-reading/blob/3beb4b6313719d6a8bf6093086d0466ecf077dbe/seq-slime-boot.puml 203 | https://github.com/der-lange-christian/networkWarden/blob/8af8f78b316d02c23d238e66bd1ccb11ad3886ee/networkWarden/src/site/plantuml/test.puml 204 | https://github.com/esteinberg/plantuml4idea/blob/cb320f2b2c4f22a192e144a474203315c62ade27/testData/reverseArrowIntention/afterSequenceArrows.puml 205 | https://github.com/lennartj/nazgul_core/blob/b9c025f9ddcc4311c416ed832af75ab2d2dc6784/core/persistence/persistence-model/src/site/markdown/plantuml/jpa_entity_relations.puml 206 | https://github.com/lennartj/nazgul_core/blob/b9c025f9ddcc4311c416ed832af75ab2d2dc6784/core/persistence/persistence-model/src/site/markdown/plantuml/jpa_primitive_collections.puml 207 | https://github.com/lennartj/nazgul_core/blob/b9c025f9ddcc4311c416ed832af75ab2d2dc6784/core/quickstart/src/site/markdown/plantuml/modularity_components.puml 208 | https://github.com/lennartj/nazgul_core/blob/b9c025f9ddcc4311c416ed832af75ab2d2dc6784/src/site/markdown/plantuml/modularity_components.puml 209 | https://github.com/lennartj/nazgul_core/blob/b9c025f9ddcc4311c416ed832af75ab2d2dc6784/test/persistence/src/site/markdown/plantuml/0_overview.puml 210 | https://github.com/esamson/plantumlnb/blob/2a63699858c5074714fca3af286ae542a32142bd/Sample/Sequence.puml 211 | https://github.com/if-h4102/pld-mars/blob/8aad15bcdc9eb21d0b41cfe2c2ccd7c540df5ffe/CU003%20-%20Gestion%20des%20contacts%20clients%20(Zone%20Relation%20Banque-Client)/DA003.puml 212 | https://github.com/if-h4102/pld-mars/blob/b4da6c4fc81f750628e2461e8d77b38575a139d5/CU001%20-%20Consultation%20du%20dossier%20Client%20-%20Vue%20360%C2%B0/DA001.puml 213 | https://github.com/phillipjf/SNMPrint/blob/1cdfc793661c00db0aca29628b0e60ca71843acb/UML/DesignActivityDiagrams/Show%20Printer%20Status%20Activity.puml 214 | https://github.com/llaville/umlwriter/blob/99c6919b8ab5e7d3836ea6690325048a83e249ff/tests/fixtures/004_Method.puml 215 | https://github.com/llaville/umlwriter/blob/99c6919b8ab5e7d3836ea6690325048a83e249ff/tests/fixtures/005_InheritMethod.puml 216 | https://github.com/llaville/umlwriter/blob/99c6919b8ab5e7d3836ea6690325048a83e249ff/tests/fixtures/007_InheritConstant.puml 217 | https://github.com/MarysolRojas/tiendavirtual/blob/c10df462c99b1bda4cc2fefbc4710e82d1036818/public/dise%C3%B1o/casodeuso1.puml 218 | https://github.com/max8github/cloudio/blob/397ef65187393b1dd42fa840ac39ba78ee2b9268/tip/hood/goog/storg/src/site/resources/uml/dataserver.puml 219 | https://github.com/liunian/demos/blob/cff34ec24f994270b276a8a9fde1e1b8f400e360/plantUML/puml/1.17.puml 220 | https://github.com/liunian/demos/blob/cff34ec24f994270b276a8a9fde1e1b8f400e360/plantUML/puml/1.21.puml 221 | https://github.com/huanle0610/Samantabhadra/blob/9f3c10c66c98a34e2bc42a77e7a24f6a988adf34/lnmp/nginx/nginx_php_file_upload.puml 222 | https://github.com/huanle0610/Samantabhadra/blob/9f3c10c66c98a34e2bc42a77e7a24f6a988adf34/platuml_example/activity.puml 223 | https://github.com/huanle0610/Samantabhadra/blob/9f3c10c66c98a34e2bc42a77e7a24f6a988adf34/platuml_example/linking1.puml 224 | https://github.com/huanle0610/Samantabhadra/blob/9f3c10c66c98a34e2bc42a77e7a24f6a988adf34/platuml_example/user_case2.puml 225 | https://github.com/duanshengze/AiLePlayer/blob/a8d9620a98cf8eed7c39d7dd074f4a7552f8694a/struct.puml 226 | https://github.com/Kar1o/Viracopos/blob/3d50c1dc2dd1a72ce88f9f3ef782f631360da68b/UseCaseDiagram.puml 227 | https://github.com/findmypast/tech-blog-diagrams/blob/585a0c12c86c946705556996ecbf37c98979d1af/diagrams/puml/diagram-activity.puml 228 | https://github.com/poldotz/transfer2014/blob/a09db19e8516d94373f53cbeeeaf018cafb04847/apps/backend/modules/serviceHostess/actions/webex.puml 229 | https://github.com/zealousduck/PicYaPalette/blob/f9be43e584bdd9cb2c4b33896ad01f961a60b2ce/app/UML/SSDChoosePic.puml 230 | https://github.com/phillipjf/SNMPrint/blob/1cdfc793661c00db0aca29628b0e60ca71843acb/UML/DesignActivityDiagrams/Show%20Printer%20Status%20Activity.puml 231 | https://github.com/wflfei/kits/blob/6f09290b8aa6485780f58097079df78970a0c3b3/app/src/main/java/com/wfl/kits/uml/Te.puml 232 | https://github.com/ivaneye/ivanpig.github.com/blob/7635f81759abaad80c186ad791410e9e9b094ec8/assets/zookeeper/consensus/2pc.puml 233 | https://github.com/cobertura/cobertura/blob/db3bedf3334d8f35bad7ca3c6f4d777be6a09fc5/src/site/plantuml/software_component.puml 234 | https://github.com/findmypast/haar/blob/037eb37e2818c0a1db520a89f69fbf3a6b6b0790/haar/diagrams/haar.puml 235 | https://github.com/findmypast/haar/blob/037eb37e2818c0a1db520a89f69fbf3a6b6b0790/templates/dummy-activity.puml 236 | https://github.com/grze/archexamples/blob/8e470a48d814af456108aae86a6be08f52d160f9/4.0/autoscaling/deployment.puml 237 | https://github.com/grze/archexamples/blob/8e470a48d814af456108aae86a6be08f52d160f9/4.0/autoscaling/sequence.puml 238 | https://github.com/RickieES/localizethat/blob/b372489be6b5ce873f703a187e65570fffe0f8ca/src/doc/en-locale-usecase.puml 239 | https://github.com/RickieES/localizethat/blob/b372489be6b5ce873f703a187e65570fffe0f8ca/src/doc/en-product-usecase.puml 240 | https://github.com/RickieES/localizethat/blob/b372489be6b5ce873f703a187e65570fffe0f8ca/src/doc/es-locale-usecase.puml 241 | https://github.com/ming13/generics/blob/f4376fb2917695b20f9af9c53ec407eccc4da5e2/uml/component.puml 242 | https://github.com/PainNarrativesLab/PainPrayerProject/blob/c378402160da9e36f606ce8503746117e788eb4a/docs/f.puml 243 | https://github.com/useblocks/presentations/blob/0237653dfc5e029decbc5789212d6decab13d71c/diagrams/metric_services.puml 244 | https://github.com/der-lange-christian/english-numbers/blob/321283a38b3f3a47252c791236ca4ee86e62f017/src/site/plantuml/test.puml 245 | https://github.com/BelkhousNabil/Projets-Informatiques/blob/47ffd6526bb66ae263c34725fe2b515b751127bb/Projet%20de%20UML%20Reverse/documents/diagrammes_architecture/DiagrammesVersion%20trash/GestionnaireDeFichiers/view.puml 246 | https://github.com/BelkhousNabil/Projets-Informatiques/blob/47ffd6526bb66ae263c34725fe2b515b751127bb/Projet%20de%20UML%20Reverse/documents/trash/DAL/DiagrammesVersion%20trash/GestionnaireDeFichiers/view.puml 247 | https://github.com/jruizaranguren/atoming/blob/b1dafaaee1c194bee2417111d0dbe7ab773d0e8f/docs/activity.puml 248 | https://github.com/saywithu/git_test/blob/9ec0935a1cd666fa587d21a5bc72372da75d23ca/aggregator-microservices/etc/information-microservice.urm.puml 249 | https://github.com/saywithu/git_test/blob/9ec0935a1cd666fa587d21a5bc72372da75d23ca/aggregator-microservices/etc/inventory-microservice.urm.puml 250 | https://github.com/saywithu/git_test/blob/9ec0935a1cd666fa587d21a5bc72372da75d23ca/api-gateway/etc/image-microservice.urm.puml 251 | https://github.com/nikolakg/EAPWebSocial/blob/036de1572fe359dfff24f7d5ce7e77e9611b1b1a/src/main/resources/plantuml/sequence_test.puml 252 | https://github.com/wflfei/kits/blob/6f09290b8aa6485780f58097079df78970a0c3b3/app/src/main/java/com/wfl/kits/uml/Te.puml 253 | https://github.com/stts-se/wikispeech_mockup/blob/dafad2a50f78066d029f81950a798ce814f2840f/docs/uml/WikispeechApi.puml 254 | https://github.com/rvazquezglez/design-patterns-workshop/blob/1554f393e0cb78ffaa2f1b800a9a843f7669fa3a/strategy/strategy-classes.puml 255 | https://github.com/cobertura/cobertura/blob/db3bedf3334d8f35bad7ca3c6f4d777be6a09fc5/src/site/plantuml/software_component.puml 256 | https://github.com/grze/archexamples/blob/8e470a48d814af456108aae86a6be08f52d160f9/4.0/autoscaling/deployment.puml 257 | https://github.com/grze/archexamples/blob/8e470a48d814af456108aae86a6be08f52d160f9/4.0/autoscaling/sequence.puml 258 | https://github.com/RickieES/localizethat/blob/b372489be6b5ce873f703a187e65570fffe0f8ca/src/doc/en-locale-usecase.puml 259 | https://github.com/RickieES/localizethat/blob/b372489be6b5ce873f703a187e65570fffe0f8ca/src/doc/en-product-usecase.puml 260 | https://github.com/RickieES/localizethat/blob/b372489be6b5ce873f703a187e65570fffe0f8ca/src/doc/es-locale-usecase.puml 261 | https://github.com/axgtz/AyM-de-Sistemas-de-Software/blob/7b31e358e67b6c92533c9080edcff8ac21c48292/Clase/FactoryMethod/FactoryMethod/template.puml 262 | https://github.com/azige/PlantUML-NB/blob/468bccd99a98009064a67fc3438cfd5faf1365aa/Sample/Sequence.puml 263 | https://github.com/azige/PlantUML-NB/blob/468bccd99a98009064a67fc3438cfd5faf1365aa/src/test/resources/org/netbeans/modules/plantumlnb/Sequence.puml 264 | https://github.com/juven/portable-config-maven-plugin/blob/68a4206f1c87a2bfdec84fa254f25feb3a0a3cf5/class.puml 265 | https://github.com/mhaidarh/kargu/blob/87e2833a4ec4426bf8d778d4735f648ff2bb4de5/misc/diagram/activity/kargu_activity_print.puml 266 | https://github.com/mhaidarh/kargu/blob/87e2833a4ec4426bf8d778d4735f648ff2bb4de5/misc/diagram/sequence/kargu_sequence_choose-group.puml 267 | https://github.com/mhaidarh/kargu/blob/87e2833a4ec4426bf8d778d4735f648ff2bb4de5/misc/diagram/sequence/kargu_sequence_choose-power.puml 268 | https://github.com/mhaidarh/kargu/blob/87e2833a4ec4426bf8d778d4735f648ff2bb4de5/misc/diagram/sequence/kargu_sequence_quit-application.puml 269 | https://github.com/Aleks-Ya/yaal_examples/blob/14acad25463f810139d0a4e02519c6a0559b6b92/PlantUml/sequences.puml 270 | https://github.com/dpisarenko/econsim-tr01/blob/89c9608922d19b1d9ab2638cc2ca8cdc9ce0e979/src/main/java/cc/altruix/econsimtr01/ch03/2016_05_11_img01.puml 271 | https://github.com/Dedda/paintball/blob/fb18cf11e2fc3f7eca7e0d26a2847743b560dc2f/documentation/uml/class/myTable.puml 272 | https://github.com/elvis-bi/pumlstyle/blob/5f3fed349433fe860ce61113358ce43d45fc8761/examples/context.puml 273 | https://github.com/linux-china/plantuml-gist/blob/c0e13ac479a6b4ccfe7f9517223e2c8ddcfc70d7/src/test/resources/demo-sequence.puml 274 | https://github.com/nabsha/ascender/blob/63f666d228cdec5e680ae4aaf254e041b1ea58c8/src/main/docs/StateDiagram.puml 275 | https://github.com/hash52/DesignPatternSample/blob/f19c607b9f8adcfdf6b9a6cbc246e21a7eebc45e/aggregator-microservices/etc/information-microservice.urm.puml 276 | https://github.com/hash52/DesignPatternSample/blob/f19c607b9f8adcfdf6b9a6cbc246e21a7eebc45e/aggregator-microservices/etc/inventory-microservice.urm.puml 277 | https://github.com/hash52/DesignPatternSample/blob/f19c607b9f8adcfdf6b9a6cbc246e21a7eebc45e/api-gateway/etc/image-microservice.urm.puml 278 | https://github.com/hash52/DesignPatternSample/blob/f19c607b9f8adcfdf6b9a6cbc246e21a7eebc45e/api-gateway/etc/price-microservice.urm.puml 279 | https://github.com/algebrakit/mathunited/blob/14968d5cc97ed630baac11d7abf4398a6fb1c9c7/Author-java/MathUnited/doc/uml/subversion/000-template.puml 280 | https://github.com/p-goetz/arc42-maven/blob/5e400f821f4f3c4ac5b98f6f7619d879cb124da8/src/site/plantuml/test.puml 281 | https://github.com/dpisarenko/econsim-tr01/blob/89c9608922d19b1d9ab2638cc2ca8cdc9ce0e979/src/main/java/cc/altruix/econsimtr01/ch03/2016_05_11_img01.puml 282 | https://github.com/juangutierrezm/tvirtual/blob/29cbdf072616436c4051b63d09e4fe25a1ffc8a0/public/dise%C3%B1o/casodeuso1.puml 283 | https://github.com/juangutierrezm/tvirtual/blob/29cbdf072616436c4051b63d09e4fe25a1ffc8a0/public/dise%C3%B1o/casos%20de%20uso.puml 284 | https://github.com/c-lopez12/tvirtual/blob/92879b482079e34e105000f51a4ac5bc3afddc8e/public/dise%C3%B1o/casodeuso1.puml 285 | https://github.com/deadbok/eal_programming/blob/6231cc42350184ef20b268a367b8e410bd25c4d1/ass12/cashregister.py.puml 286 | https://github.com/goeckeler/katas-sessions/blob/d851ef83985bd220c4d875bacc743ae12fef9787/Object%20Calisthenics/kata/docs/Self%20Shunt%20Pattern.puml 287 | https://github.com/goeckeler/katas-sessions/blob/d851ef83985bd220c4d875bacc743ae12fef9787/Object%20Calisthenics/sessions/Checkout/docs/Self%20Shunt%20Pattern.puml 288 | https://github.com/legenddcr/plantUML/blob/b70f3a155c1097b400ff01c9803f0a9d04782b7e/azure_iot.puml 289 | https://github.com/cxd/au.id.cxd.Math/blob/588ffc726d86df42a7f9ac96c01091bd4c8c3d33/au.id.cxd.Math.HttpUI/static/doc/project_selected.puml 290 | https://github.com/ming13/generics/blob/f4376fb2917695b20f9af9c53ec407eccc4da5e2/uml/component.puml 291 | https://github.com/junxiong/design-project/blob/8ed221d474860ee7671feaef1768122503c77b32/src/main/design/4.Sequence/AccountManagement/CreateNewUser.puml 292 | https://github.com/junxiong/design-project/blob/8ed221d474860ee7671feaef1768122503c77b32/src/main/design/4.Sequence/CapabilityAccess%26OAuth/CreateCapabilityAccess.puml 293 | https://github.com/junxiong/design-project/blob/8ed221d474860ee7671feaef1768122503c77b32/src/main/design/4.Sequence/Login/LoginWithIDP.puml 294 | https://github.com/junxiong/design-project/blob/8ed221d474860ee7671feaef1768122503c77b32/src/main/design/4.Sequence/ProductManagement/ViewActiveProducts.puml 295 | https://github.com/junxiong/design-project/blob/8ed221d474860ee7671feaef1768122503c77b32/src/main/design/4.Sequence/Register/RegisterEnterpriseCustomer.puml 296 | https://github.com/AndreasAnemyrLNU/1DV449_AA223IG/blob/31c542ec68618c600d827cc3da8c1211547e3886/controller/controller.puml 297 | https://github.com/thomasbroussard/website/blob/741833605e90871159b0d66c13d07716ad60be60/tbr-website/src/main/webapp/graph/SRO.puml 298 | https://github.com/thomasbroussard/website/blob/741833605e90871159b0d66c13d07716ad60be60/tbr-website/src/main/webapp/images/puml/adv_project/advpj_iamusecase.puml 299 | https://github.com/thomasbroussard/website/blob/741833605e90871159b0d66c13d07716ad60be60/tbr-website/src/main/webapp/images/puml/java-bases/java-bases-shapes1.puml 300 | https://github.com/thomasbroussard/website/blob/741833605e90871159b0d66c13d07716ad60be60/tbr-website/src/main/webapp/images/puml/oop-uml/oop-accounts.puml 301 | https://github.com/thomasbroussard/website/blob/741833605e90871159b0d66c13d07716ad60be60/tbr-website/src/main/webapp/images/puml/oop-uml/oop-accounts.puml 302 | https://github.com/thomasbroussard/website/blob/741833605e90871159b0d66c13d07716ad60be60/tbr-website/src/main/webapp/images/puml/oop-uml/oop-activity-diagram.puml 303 | https://github.com/thomasbroussard/website/blob/741833605e90871159b0d66c13d07716ad60be60/tbr-website/src/main/webapp/images/puml/oop-uml/oop-inheritance.puml 304 | https://github.com/javy-liu/jmh/blob/6fcbfb193bb0937bbf252ce25bda9a984faf62ef/a.puml 305 | https://github.com/alex2010/eclub_n/blob/f5d0a0ef013faeffb0c69a4b434cd15463deaa98/doc/desgin/activity.puml 306 | https://github.com/alex2010/eclub_n/blob/f5d0a0ef013faeffb0c69a4b434cd15463deaa98/doc/desgin/frame.puml 307 | https://github.com/axgtz/AyM-de-Sistemas-de-Software/blob/7b31e358e67b6c92533c9080edcff8ac21c48292/Clase/FactoryMethod/FactoryMethod/template.puml 308 | https://github.com/azige/PlantUML-NB/blob/468bccd99a98009064a67fc3438cfd5faf1365aa/Sample/Sequence.puml 309 | https://github.com/azige/PlantUML-NB/blob/468bccd99a98009064a67fc3438cfd5faf1365aa/src/test/resources/org/netbeans/modules/plantumlnb/Sequence.puml 310 | https://github.com/juven/portable-config-maven-plugin/blob/68a4206f1c87a2bfdec84fa254f25feb3a0a3cf5/class.puml 311 | https://github.com/gabrielgio/Vivacity/blob/59b41fea0c90c65b09114c506d7c7bca8f83f1a1/Flow%20Cities.puml 312 | https://github.com/junxiong/design-project/blob/8ed221d474860ee7671feaef1768122503c77b32/src/main/design/4.Sequence/AccountManagement/CreateNewUser.puml 313 | https://github.com/junxiong/design-project/blob/8ed221d474860ee7671feaef1768122503c77b32/src/main/design/4.Sequence/CapabilityAccess%26OAuth/CreateCapabilityAccess.puml 314 | https://github.com/junxiong/design-project/blob/8ed221d474860ee7671feaef1768122503c77b32/src/main/design/4.Sequence/Login/LoginWithIDP.puml 315 | https://github.com/junxiong/design-project/blob/8ed221d474860ee7671feaef1768122503c77b32/src/main/design/4.Sequence/ProductManagement/ViewActiveProducts.puml 316 | https://github.com/junxiong/design-project/blob/8ed221d474860ee7671feaef1768122503c77b32/src/main/design/4.Sequence/Register/RegisterEnterpriseCustomer.puml 317 | https://github.com/AndreasAnemyrLNU/1DV449_AA223IG/blob/31c542ec68618c600d827cc3da8c1211547e3886/controller/controller.puml 318 | https://github.com/thomasbroussard/website/blob/741833605e90871159b0d66c13d07716ad60be60/tbr-website/src/main/webapp/graph/SRO.puml 319 | https://github.com/thomasbroussard/website/blob/741833605e90871159b0d66c13d07716ad60be60/tbr-website/src/main/webapp/images/puml/adv_project/advpj_iamusecase.puml 320 | https://github.com/thomasbroussard/website/blob/741833605e90871159b0d66c13d07716ad60be60/tbr-website/src/main/webapp/images/puml/java-bases/java-bases-shapes1.puml 321 | https://github.com/scatalin/licenta/blob/9349d677b9ade4da41b32c95429ce80ee7049e72/AutoCompletionSystem/src/InterogatorFraza.puml 322 | https://github.com/scatalin/licenta/blob/9349d677b9ade4da41b32c95429ce80ee7049e72/AutoCompletionSystem/src/component.puml 323 | https://github.com/CampAsAChamp/School-Programs/blob/f716c30639adf7585a6d0346dede5e6fe37543f5/CS%203/Quiz%203%20Review/src/Another.puml 324 | https://github.com/frenchfrie/jToxCore/blob/8bf8ba79f0d7047098f29789992998dc482d780f/src/site/plantuml/HLD.puml 325 | https://github.com/frenchfrie/jToxCore/blob/8bf8ba79f0d7047098f29789992998dc482d780f/src/site/skin.puml 326 | https://github.com/Belolme/javalearn/blob/4aded53adfe81fee7cf7055f28c9f9ece252d4e0/designPattern/uml/Adapter..puml 327 | https://github.com/Belolme/javalearn/blob/4aded53adfe81fee7cf7055f28c9f9ece252d4e0/designPattern/uml/FactoryMethod..puml 328 | https://github.com/Belolme/javalearn/blob/4aded53adfe81fee7cf7055f28c9f9ece252d4e0/designPattern/uml/Singleton.puml 329 | https://github.com/Shinsuke-Abe/IgoKnowledgeModeling/blob/4177185ea4858a9ef4e8f46ce061e9a198972587/trivia/idiom.puml 330 | https://github.com/wohensinide98/JustDoIt/blob/9bbf5aa92f3cb71d580e74293871904d01685ded/JustDoItAPI/src/main/java/com/iwjw/cyb/web/puml/%E6%97%B6%E5%BA%8F%E5%9B%BE/d.puml 331 | https://github.com/LucasIsasmendi/lisk-core-plantuml/blob/e0941f6e800dc16a9dc0f8367304149fbf2200e1/class/classes/modules/server.puml 332 | https://github.com/suzuki-hoge/dev-note/blob/5e5569f4d29f369584186be5ae29ffe8cac8a598/haskell/ddd/02-identity-and-entity/doc/LifeCycle.puml 333 | https://github.com/lalloni/macom/blob/375ce71fdb7d4c2c30e1fad39cb7b2d5e48ce884/src/macom/web/templates/diagrams/systems_dependencies.puml 334 | https://github.com/Phalexei/Modeleur/blob/f143c85930c3b668670087693ec807a9cd4bda81/src/com/github/tomap/uml/analyse/sequenceDiagrams/delete.puml 335 | https://github.com/Phalexei/Modeleur/blob/f143c85930c3b668670087693ec807a9cd4bda81/src/com/github/tomap/uml/analyse/sequenceDiagrams/manageInterfaces.puml 336 | https://github.com/Phalexei/Modeleur/blob/f143c85930c3b668670087693ec807a9cd4bda81/src/com/github/tomap/uml/analyse/sequenceDiagrams/manageObjects.puml 337 | https://github.com/fuhrmanator/course-activity-planner/blob/a1759e5b5c042cc69a1bde8194b8bc2f0fc2e9a2/ooad/ActivitySynchronizeGradesLegacy.puml 338 | https://github.com/fuhrmanator/course-activity-planner/blob/a1759e5b5c042cc69a1bde8194b8bc2f0fc2e9a2/ooad/ActivityUpdateDetailsOneActivityLegacy.puml 339 | https://github.com/vtambourine/ini-processor/blob/78786b32bcd0e41e9f808ee5e5b6651edce0881f/docs/structure.puml 340 | https://github.com/ProgrammingLife2015/geex/blob/3f888b9411831955a84dfc59a73823650fb6950d/src/site/diagrams/geex-services.puml 341 | https://github.com/bolironman/bolironman.github.io/blob/ccb8c32edd4e6d8bb97b327aabd39da3c6668df9/assets/img/2015-03-02-relation-in-parse/publicLibrary-associations.puml 342 | https://github.com/suzuki-hoge/dev-note/blob/5e5569f4d29f369584186be5ae29ffe8cac8a598/haskell/ddd/02-identity-and-entity/doc/LifeCycle.puml 343 | https://github.com/lalloni/macom/blob/375ce71fdb7d4c2c30e1fad39cb7b2d5e48ce884/src/macom/web/templates/diagrams/systems_dependencies.puml 344 | https://github.com/Phalexei/Modeleur/blob/f143c85930c3b668670087693ec807a9cd4bda81/src/com/github/tomap/uml/analyse/sequenceDiagrams/delete.puml 345 | https://github.com/Phalexei/Modeleur/blob/f143c85930c3b668670087693ec807a9cd4bda81/src/com/github/tomap/uml/analyse/sequenceDiagrams/manageInterfaces.puml 346 | https://github.com/Phalexei/Modeleur/blob/f143c85930c3b668670087693ec807a9cd4bda81/src/com/github/tomap/uml/analyse/sequenceDiagrams/manageObjects.puml 347 | https://github.com/fuhrmanator/course-activity-planner/blob/a1759e5b5c042cc69a1bde8194b8bc2f0fc2e9a2/ooad/ActivitySynchronizeGradesLegacy.puml 348 | https://github.com/fuhrmanator/course-activity-planner/blob/a1759e5b5c042cc69a1bde8194b8bc2f0fc2e9a2/ooad/ActivityUpdateDetailsOneActivityLegacy.puml 349 | https://github.com/vtambourine/ini-processor/blob/78786b32bcd0e41e9f808ee5e5b6651edce0881f/docs/structure.puml 350 | https://github.com/ProgrammingLife2015/geex/blob/3f888b9411831955a84dfc59a73823650fb6950d/src/site/diagrams/geex-services.puml 351 | https://github.com/eucalyptus/architecture-docs/blob/a503c9ae4646b491c7405f2fab51c5db94e7d84e/service-architecture/diagrams/components/euare.puml 352 | https://github.com/ultiferrago/ElStudioGato/blob/15c91c8a6859b513c5f4d2f2b8da2e76abff978e/app/UML/Domain%20Model/Domain%20Model.puml 353 | https://github.com/rootjs/design/blob/7993e9892f2c4bc684ed388766b64bff13f2580b/presentation/classes/NodeApplication.puml 354 | https://github.com/rootjs/design/blob/7993e9892f2c4bc684ed388766b64bff13f2580b/presentation/classes/ObjectProxyFactory.puml 355 | https://github.com/rootjs/design/blob/7993e9892f2c4bc684ed388766b64bff13f2580b/presentation/classes/TemplateFactory.puml 356 | https://github.com/LucasIsasmendi/lisk-core-plantuml/blob/e0941f6e800dc16a9dc0f8367304149fbf2200e1/class/classes/modules/server.puml 357 | https://github.com/IUT-Blagnac/MPA2014G1B2/blob/866b543a10a4127e641ccad2a764c7d12dcca6fc/sprint_5/srcdoc/OPTI/doc_tech/srcdoc/diag0.puml 358 | https://github.com/bolironman/bolironman.github.io/blob/ccb8c32edd4e6d8bb97b327aabd39da3c6668df9/_site/assets/img/2015-03-02-relation-in-parse/book-author-associationfree.puml 359 | https://github.com/bolironman/bolironman.github.io/blob/ccb8c32edd4e6d8bb97b327aabd39da3c6668df9/assets/img/2015-03-02-relation-in-parse/book-author-associationfree.puml 360 | https://github.com/bolironman/bolironman.github.io/blob/ccb8c32edd4e6d8bb97b327aabd39da3c6668df9/_site/assets/img/2015-03-02-relation-in-parse/publicLibrary-associations.puml 361 | https://github.com/mathiasverraes/mathiasverraes.github.com/blob/866e4d3ffac7880e71d26fbb9f89074f305bb3ef/img/posts/2016-02-29-type-safety-and-money/FactorOutCurrency.puml 362 | https://github.com/eucalyptus/architecture-docs/blob/a503c9ae4646b491c7405f2fab51c5db94e7d84e/diagrams/arch-overview/components/euare.puml 363 | https://github.com/eucalyptus/architecture-docs/blob/a503c9ae4646b491c7405f2fab51c5db94e7d84e/diagrams/arch-overview/components/userui.puml 364 | https://github.com/eucalyptus/architecture-docs/blob/a503c9ae4646b491c7405f2fab51c5db94e7d84e/service-architecture/diagrams/components/userui.puml 365 | https://github.com/eucalyptus/architecture-docs/blob/a503c9ae4646b491c7405f2fab51c5db94e7d84e/service-architecture/diagrams/components/euare.puml 366 | https://github.com/ultiferrago/ElStudioGato/blob/15c91c8a6859b513c5f4d2f2b8da2e76abff978e/app/UML/Domain%20Model/Domain%20Model.puml 367 | https://github.com/rootjs/design/blob/7993e9892f2c4bc684ed388766b64bff13f2580b/presentation/classes/NodeApplication.puml 368 | https://github.com/rootjs/design/blob/7993e9892f2c4bc684ed388766b64bff13f2580b/presentation/classes/ObjectProxyFactory.puml 369 | https://github.com/rootjs/design/blob/7993e9892f2c4bc684ed388766b64bff13f2580b/presentation/classes/TemplateFactory.puml 370 | https://github.com/LucasIsasmendi/lisk-core-plantuml/blob/e0941f6e800dc16a9dc0f8367304149fbf2200e1/class/classes/modules/server.puml 371 | https://github.com/rattri/CariKuliner/blob/b125abb67741acc418037d0b96d026b191b6ec5f/app/sequence.puml 372 | https://github.com/eftov-old-projects/it340/blob/3b5b850736bb0855d9aaf295322223358eb75819/it340/doc/conception/activity_diagram.puml 373 | https://github.com/lsy563193/mybot/blob/03c1668edf8d6dc85b3b7169c4b8dc167ddfa92d/mybot_nav/nodes/app_layer.puml 374 | https://github.com/agussuhardii/raport/blob/6311e1ab6c06049be15e53b81d1c43d5cea654a3/coba/CobaActivity.puml 375 | https://github.com/CampAsAChamp/School-Programs/blob/f716c30639adf7585a6d0346dede5e6fe37543f5/CS%203/Quiz%203%20Review/src/Another.puml 376 | https://github.com/frenchfrie/jToxCore/blob/8bf8ba79f0d7047098f29789992998dc482d780f/src/site/plantuml/HLD.puml 377 | https://github.com/frenchfrie/jToxCore/blob/8bf8ba79f0d7047098f29789992998dc482d780f/src/site/skin.puml 378 | https://github.com/Shinsuke-Abe/IgoKnowledgeModeling/blob/4177185ea4858a9ef4e8f46ce061e9a198972587/trivia/idiom.puml 379 | https://github.com/rkiranchowdhary/java-design-patterns/blob/6bbccfd5947ef5a547f8abdcfcc2f799f0ce052c/aggregator-microservices/etc/information-microservice.urm.puml 380 | https://github.com/rkiranchowdhary/java-design-patterns/blob/6bbccfd5947ef5a547f8abdcfcc2f799f0ce052c/aggregator-microservices/etc/inventory-microservice.urm.puml 381 | https://github.com/davidfuhr/php-plantumlwriter/blob/b71ffcdf1eae0f567fc5772e97148689bd62b5c8/tests/Flagbit/Plantuml/Fixtures/testInheritMethod.puml 382 | https://github.com/davidfuhr/php-plantumlwriter/blob/b71ffcdf1eae0f567fc5772e97148689bd62b5c8/tests/Flagbit/Plantuml/Fixtures/testProperty.puml 383 | https://github.com/grze/archexamples/blob/8e470a48d814af456108aae86a6be08f52d160f9/examples/prd-199.puml 384 | https://github.com/grze/archexamples/blob/8e470a48d814af456108aae86a6be08f52d160f9/examples/prd-215-use-case.puml 385 | https://github.com/mihailov-vf/siscourb/blob/d0947d61e7396a9658c9cd7dbf3d445d9fb1a276/docs/UML/classes_entidade.puml 386 | https://github.com/darodriguezalv/LatticeData/blob/f324971d6af90c99e374a0baaa0b41e731d0d9d6/seq.puml 387 | https://github.com/akeost/silly/blob/8beb25c1615c4eb13e62637d2fb631ab4d547118/m/uml/Client_sequence.puml 388 | https://github.com/bh6025/Mobile_App_Development_Project/blob/c58f78cafe92cd2edf03b9683528f26f1c852f3a/app/src/main/java/sd.puml 389 | https://github.com/simonpatrick/stepbystep-java/blob/cf572fa12b2d550ab37f3e40dac81be361163a51/basicjava/src/main/java/com/hedwig/stepbystep/javatutorial/webtest/pageobjects/pagefactory.puml 390 | https://github.com/PainNarrativesLab/IOMNarratives/blob/7f2dd4d6e2f77b26404d1b7ef6410a7d1d166daf/docs/processing_plan.puml 391 | https://github.com/jayfans3/example/blob/6982e33d760dd8e4d94de40c81ae733434bf3f1b/servcie/src/main/slideruml.puml 392 | https://github.com/jayfans3/example/blob/6982e33d760dd8e4d94de40c81ae733434bf3f1b/servcie/src/test/java/slideruml.puml 393 | https://github.com/dheerajksingh/designpattern/blob/cca4760f6990886c0dd47dea93a6c0d359917073/aggregator-microservices/etc/information-microservice.urm.puml 394 | https://github.com/dheerajksingh/designpattern/blob/cca4760f6990886c0dd47dea93a6c0d359917073/aggregator-microservices/etc/inventory-microservice.urm.puml 395 | https://github.com/dheerajksingh/designpattern/blob/cca4760f6990886c0dd47dea93a6c0d359917073/api-gateway/etc/image-microservice.urm.puml 396 | https://github.com/dheerajksingh/designpattern/blob/cca4760f6990886c0dd47dea93a6c0d359917073/api-gateway/etc/price-microservice.urm.puml 397 | https://github.com/satishgoda/visualization/blob/5f12c7786f440a1e6efd0f19562238a645577cf7/tools/plantuml/examples/sequence/b.puml 398 | https://github.com/satishgoda/visualization/blob/5f12c7786f440a1e6efd0f19562238a645577cf7/tools/plantuml/examples/sequence/ab.puml 399 | https://github.com/sebhero/SkolaMah/blob/c373edd811f1ef3e846f8b8d9b9ebdd575523f7c/src/DA353A_programmering2_datastrukturer/tenta20160324/tenta140820/upg1.puml 400 | https://github.com/vkorolev/Bich/blob/71ac38bf01000d3aeb41f3e500331124ee0bc528/src/main/java/diagrams/logical/activity.puml 401 | https://github.com/onmurphy/AndroidTermProject/blob/159d37406df9faa0082b0b9fc64621fe2600f24f/app/UML/Activity%20Diagram/ShowResults.puml 402 | https://github.com/onmurphy/AndroidTermProject/blob/159d37406df9faa0082b0b9fc64621fe2600f24f/app/UML/Domain%20Model/DM.puml 403 | https://github.com/rattri/CariKuliner/blob/b125abb67741acc418037d0b96d026b191b6ec5f/app/sequence.puml 404 | https://github.com/eftov-old-projects/it340/blob/3b5b850736bb0855d9aaf295322223358eb75819/it340/doc/conception/activity_diagram.puml 405 | https://github.com/junix/org-design/blob/c2de01ffed0afeb51e2d0e8dbd30f4e5d7b003f8/uml/LogIn.puml 406 | https://github.com/junix/org-design/blob/c2de01ffed0afeb51e2d0e8dbd30f4e5d7b003f8/uml/UserEmplee.puml 407 | https://github.com/agussuhardii/raport/blob/6311e1ab6c06049be15e53b81d1c43d5cea654a3/coba/CobaActivity.puml 408 | https://github.com/scatalin/licenta/blob/9349d677b9ade4da41b32c95429ce80ee7049e72/AutoCompletionSystem/src/InterogatorCuvant.puml 409 | https://github.com/scatalin/licenta/blob/9349d677b9ade4da41b32c95429ce80ee7049e72/AutoCompletionSystem/src/InterogatorFraza.puml 410 | https://github.com/scatalin/licenta/blob/9349d677b9ade4da41b32c95429ce80ee7049e72/AutoCompletionSystem/src/component.puml 411 | https://github.com/RickieES/localizethat/blob/b372489be6b5ce873f703a187e65570fffe0f8ca/src/doc/es-product-l10n-usecase.puml 412 | https://github.com/lengyijun/lib_v2/blob/a307300c87357aa79d058e6a1388137fdd466625/app/src/main/java/com/example/steven/sjtu_lib_v2/uml/%E6%97%B6%E5%BA%8F%E5%9B%BE/%E8%8E%B7%E5%8F%96jaccoung%E5%92%8C%E5%A7%93%E5%90%8D.puml 413 | https://github.com/Dedda/paintball/blob/fb18cf11e2fc3f7eca7e0d26a2847743b560dc2f/documentation/uml/activity/calculate_to_pay.puml 414 | https://github.com/Dedda/paintball/blob/fb18cf11e2fc3f7eca7e0d26a2847743b560dc2f/documentation/uml/class/SalaryTableCellRenderer.puml 415 | https://github.com/Dedda/paintball/blob/fb18cf11e2fc3f7eca7e0d26a2847743b560dc2f/documentation/uml/class/StaffProvider.puml 416 | https://github.com/Dedda/paintball/blob/fb18cf11e2fc3f7eca7e0d26a2847743b560dc2f/documentation/uml/class/StaffTableCellRenderer.puml 417 | https://github.com/physicsLoveJava/java-miscellaneous/blob/411c656abd4b47dec90e4ba7bf1b9f0c0dc6369b/casual-things/src/main/resources/framework-uml/design-patterns/Observer-seq.puml 418 | https://github.com/physicsLoveJava/java-miscellaneous/blob/411c656abd4b47dec90e4ba7bf1b9f0c0dc6369b/casual-things/src/main/resources/framework-uml/design-patterns/Observer.puml 419 | https://github.com/linux-china/plantuml-gist/blob/c0e13ac479a6b4ccfe7f9517223e2c8ddcfc70d7/src/main/uml/plantuml_gist.puml 420 | https://github.com/theforeman/foreman_deployments/blob/4e74f1341dd88c6d27855f6d65ff50c55b977f38/doc/design/complete_stack.puml 421 | https://github.com/leggyman/Ghosts/blob/4f705f95921ff68942bd70942ae4786367fc321f/uml/main_menu.puml 422 | https://github.com/AndreasAnemyrLNU/iwish/blob/3af58274887570a27ed40d4a0fa838f1a4b1b682/controller/controller.puml 423 | https://github.com/Jacobliu8/Pattern/blob/901f78d5e7e5c008d141316c90a57a428bbceab4/RefactorBook/Chapter1/src/main/resources/generateList1.puml 424 | https://github.com/Jacobliu8/Pattern/blob/901f78d5e7e5c008d141316c90a57a428bbceab4/RefactorBook/Chapter1/target/classes/generateList1.puml 425 | https://github.com/Jacobliu8/Pattern/blob/901f78d5e7e5c008d141316c90a57a428bbceab4/RefactorBook/Chapter6/src/main/resources/generateList1.puml 426 | https://github.com/Jacobliu8/Pattern/blob/901f78d5e7e5c008d141316c90a57a428bbceab4/RefactorBook/Chapter6/target/classes/generateList1.puml 427 | https://github.com/liunian/demos/blob/cff34ec24f994270b276a8a9fde1e1b8f400e360/plantUML/puml/1.13.puml 428 | https://github.com/enolive/mock-heuristics/blob/b56934269459a61e00e19f0365b450e4e684d23d/images/split-collaborator-before.puml 429 | https://github.com/enolive/mock-heuristics/blob/b56934269459a61e00e19f0365b450e4e684d23d/images/testable-facade-after.puml 430 | https://github.com/enolive/mock-heuristics/blob/b56934269459a61e00e19f0365b450e4e684d23d/images/testable-facade-before.puml 431 | https://github.com/lionelz/networking-bambuk/blob/85c0a466dcc1302dad956caa4fe2eb6609cf3cec/doc/source/interfaces.puml 432 | https://github.com/webdizz/fault-tolerance-talk/blob/58cc1d870aae37dfb462e1987ca6adafc5b2c272/diagrams/architecture.puml 433 | https://github.com/eclipse/microprofile-conference/blob/693e8d21054f00eba1c4ea2a7bd3677b84f5a518/docs/src/main/plantuml/architecture.puml 434 | https://github.com/eclipse/microprofile-conference/blob/693e8d21054f00eba1c4ea2a7bd3677b84f5a518/docs/src/main/plantuml/schedule.puml 435 | https://github.com/CampagneLaboratory/UML_Diagrams/blob/ef1eb91c9de27b5846b7777e67a9c01015f5e119/solutions/Sandbox/classes_gen/Self/TestLanguageView.puml 436 | https://github.com/earring/testgenerator/blob/3f5a6269657110ed529c952eceeb0e956adff7c7/diags/classes/generation.puml 437 | https://github.com/earring/testgenerator/blob/3f5a6269657110ed529c952eceeb0e956adff7c7/diags/sequences/generatingTestsSequenceDiagram.puml 438 | https://github.com/earring/testgenerator/blob/3f5a6269657110ed529c952eceeb0e956adff7c7/diags/sequences/mainUseCaseDiagram.puml 439 | https://github.com/jorgwel/AndroidAutomationEspressoPresentation/blob/2fd0199c46ceff89f41b1baa740df14c1697c10c/figures/pumls/types_of_testing.puml 440 | https://github.com/justnero-ru/university/blob/df7d3a05fb7ca235a5e67520f7b18ad5630ade3b/semestr.05/%D0%A2%D0%9F%D0%9E/Lab.14/use.puml 441 | https://github.com/chenjianjx/srb4j/blob/4bedc008537098d03a9d26ae8c4dee63f2433a9d/documents/project-organization/fo-only.puml 442 | https://github.com/arc42/docs.arc42.org-site/blob/cb6233d21f7afce4b50a90f309d151b1313e75f5/originals/plantuml-diagrams/activity-diagrams/activity-with-swimlane.puml 443 | https://github.com/RobberPhex/laravel-queue-slides/blob/5e62ff53f129adaa3c50b6c5b3bbbbc582d7e0d2/queue-flow.puml 444 | https://github.com/rvazquezglez/design-patterns-workshop/blob/1554f393e0cb78ffaa2f1b800a9a843f7669fa3a/command-excercise/command-excercise-classes.puml 445 | https://github.com/rvazquezglez/design-patterns-workshop/blob/1554f393e0cb78ffaa2f1b800a9a843f7669fa3a/command/command-classes.puml 446 | https://github.com/rvazquezglez/design-patterns-workshop/blob/1554f393e0cb78ffaa2f1b800a9a843f7669fa3a/decorator/decorator-classes.puml 447 | https://github.com/cobertura/cobertura/blob/db3bedf3334d8f35bad7ca3c6f4d777be6a09fc5/src/site/plantuml/arch_overall_step1.puml 448 | https://github.com/bcdev/esa-pfa/blob/862de186ed17b04aa476961d265ae8843212eef9/uml/components.puml 449 | https://github.com/grze/archexamples/blob/8e470a48d814af456108aae86a6be08f52d160f9/arch-67/arch-67-use-case-user-1.inc.puml 450 | https://github.com/grze/archexamples/blob/8e470a48d814af456108aae86a6be08f52d160f9/examples.puml 451 | https://github.com/grze/archexamples/blob/8e470a48d814af456108aae86a6be08f52d160f9/arch-67/arch-67-use-case-user-1.inc.puml 452 | https://github.com/grze/archexamples/blob/8e470a48d814af456108aae86a6be08f52d160f9/examples.puml 453 | https://github.com/jqueraltmo/prova/blob/1009f962e5490ffd0bfcdc48af91e960ef8648c5/a.puml 454 | https://github.com/4nu81/python_trainee/blob/292ac1270838d728eff54124ab8496759f3a6813/trainings/doku/tree.puml 455 | https://github.com/RickieES/localizethat/blob/b372489be6b5ce873f703a187e65570fffe0f8ca/src/doc/en-product-l10n-usecase.puml 456 | https://github.com/RickieES/localizethat/blob/b372489be6b5ce873f703a187e65570fffe0f8ca/src/doc/es-product-l10n-usecase.puml 457 | https://github.com/lengyijun/lib_v2/blob/a307300c87357aa79d058e6a1388137fdd466625/app/src/main/java/com/example/steven/sjtu_lib_v2/uml/%E6%97%B6%E5%BA%8F%E5%9B%BE/%E8%8E%B7%E5%8F%96jaccoung%E5%92%8C%E5%A7%93%E5%90%8D.puml 458 | https://github.com/Dedda/paintball/blob/fb18cf11e2fc3f7eca7e0d26a2847743b560dc2f/documentation/uml/activity/calculate_to_pay.puml 459 | https://github.com/Dedda/paintball/blob/fb18cf11e2fc3f7eca7e0d26a2847743b560dc2f/documentation/uml/class/SalaryTableCellRenderer.puml 460 | https://github.com/Dedda/paintball/blob/fb18cf11e2fc3f7eca7e0d26a2847743b560dc2f/documentation/uml/class/StaffProvider.puml 461 | https://github.com/ccincd/exp/blob/0924e0a6d47a3e1d5c3b9281808935a0badbad8b/src/main/test/UMLs/noteActivity.puml 462 | https://github.com/ccincd/exp/blob/0924e0a6d47a3e1d5c3b9281808935a0badbad8b/src/main/test/UMLs/withTitleActivity.puml 463 | https://github.com/4minitz/4minitz/blob/ebc23717e8c806767ef4e4372f38583e05947af4/doc/developer/figures_source/cls_MeetingSeries.puml 464 | https://github.com/leggyman/Ghosts/blob/4f705f95921ff68942bd70942ae4786367fc321f/uml/main_menu.puml 465 | https://github.com/liunian/demos/blob/cff34ec24f994270b276a8a9fde1e1b8f400e360/plantUML/puml/1.13.puml 466 | https://github.com/kawasima/parallel-api-example/blob/6e17aeb250f0bed1659c27e0607bbbe4bc3860ba/doc/parallelsync.puml 467 | https://github.com/kawasima/parallel-api-example/blob/6e17aeb250f0bed1659c27e0607bbbe4bc3860ba/doc/sequentialsync.puml 468 | https://github.com/kawasima/parallel-api-example/blob/6e17aeb250f0bed1659c27e0607bbbe4bc3860ba/doc/sse.puml 469 | https://github.com/enolive/mock-heuristics/blob/b56934269459a61e00e19f0365b450e4e684d23d/images/split-collaborator-before.puml 470 | https://github.com/enolive/mock-heuristics/blob/b56934269459a61e00e19f0365b450e4e684d23d/images/testable-facade-after.puml 471 | https://github.com/kawasima/parallel-api-example/blob/6e17aeb250f0bed1659c27e0607bbbe4bc3860ba/doc/sequentialsync.puml 472 | https://github.com/kawasima/parallel-api-example/blob/6e17aeb250f0bed1659c27e0607bbbe4bc3860ba/doc/sse.puml 473 | https://github.com/antitoine/INSA-4IF-ASI-SOA/blob/69c559dbda4471a262f658ada81a7b2ad841b909/diagram/CU3_SuiviDeLActionCommercial/DA_CU3.puml 474 | https://github.com/libzl/libCommon/blob/a6bcc2fed99db669a039a2d1c9537432d4942cd2/common/src/main/java/com/easyhome/uml/debug.puml 475 | https://github.com/Blazar3C273/ContentManagerApp/blob/27497fc3ff3fb9fb1a849afd03c2c3cb48cfa6f0/Diagrams/ManagerApp.puml 476 | https://github.com/Dedda/scheisse/blob/3be0a21e432179b5521df6416388e67e63510653/server/uml/classes/org/dedda/games/scheisse_server/util/Config.puml 477 | https://github.com/Dedda/scheisse/blob/3be0a21e432179b5521df6416388e67e63510653/server/uml/classes/org/dedda/games/scheisse_server/util/Login.puml 478 | https://github.com/NeAn-nodejs-dashboard/doc/blob/8c086ec5b11af32f1e659fa3003866cf5e8daa1a/UML/struktur.puml 479 | https://github.com/chenjianjx/srb4j/blob/4bedc008537098d03a9d26ae8c4dee63f2433a9d/documents/project-organization/fo-and-bo.puml 480 | https://github.com/chenjianjx/srb4j/blob/4bedc008537098d03a9d26ae8c4dee63f2433a9d/documents/project-organization/fo-only.puml 481 | --------------------------------------------------------------------------------