├── .gitattributes ├── .gitignore ├── 00_persisting_go ├── README.md ├── build_binary.md ├── generate_SSL.md ├── go_resources.md ├── godoc.md ├── golint.md ├── installing_go.md ├── persisting_using_systemd.md ├── persisting_using_upstart.md └── random │ ├── RSA_key_pair.go │ ├── any_type_can_serve_http.go │ ├── cgo.go │ ├── copy_example.go │ ├── do_it_once_a_second.go │ ├── envron.go │ ├── fizzbuzz.go │ ├── mp3.go │ ├── print_on_same_line.go │ ├── rand5_to_rand7.go │ ├── test_random_generator.go │ └── write_to_slice.go ├── 01_data_type ├── anytype_parameter.go ├── buffers.md ├── convert_ip_to_string.go ├── custom_error.go ├── dataType.go ├── display_slice_totals.go ├── display_slice_totals2.go ├── display_slice_totals3.go ├── functionAcceptAnyType.go ├── randomSortExample.go ├── recursion.go ├── referenceTypes.go ├── slice_example_and_practice.go ├── sort_slice.go └── type_assertion.go ├── 02_mongodb_aggregate_cli ├── README.md ├── command │ ├── buildInfo.go │ ├── command.go │ └── distinct.go ├── log_mongodb_logs.go ├── main.go └── mongodb_dial_with_info.go ├── 03_mongodb_find_sort_cli ├── README.md ├── anotherWay.go ├── collectionInfo.go ├── main.go ├── mongoVariables.go └── serverStatus.go ├── 04_get_url_variable ├── README.md ├── main.go └── templates │ └── index.gohtml ├── 05_mongodb_crud_cli ├── README.md └── main.go ├── 06_go_ajax_send_receive ├── README.md ├── main.go └── templates │ ├── index.gohtml │ └── read.gohtml ├── 07_one_file_template └── main.go ├── 08_gowiki ├── edit.gohtml ├── main.go └── view.gohtml ├── 09_todo_list_html ├── simple_http.go ├── todos.go └── todos.html ├── 10_mongodb_and_html └── main.go ├── 11_socket_send_receive ├── tcp-client.go └── tcp-server.go ├── 12_mongodb_pipeline └── main.go ├── 13_qr_barcode └── main.go ├── 14_read_txt_file ├── .gitignore ├── main.go ├── readline.go └── write_to_file.go ├── 15_png_or_svg_barchart └── main.go ├── 16_drop_down_menu_form ├── main.go ├── main.go-old └── template.html ├── 17_mysql_user_login ├── another_mysql_example.go ├── index.html ├── login.html ├── main.go ├── readme.md └── signup.html ├── 18_cookie_authentication ├── login.go ├── login_with_pkg.go ├── main.go ├── sess │ └── sess.go ├── simple_login.go └── users.txt ├── 19_os_global_variables ├── linux_commands.go ├── main.go └── osCommand.go ├── 20_mongodb_crud ├── README.md ├── config │ ├── db.go │ └── tpl.go ├── main.go ├── records │ ├── handlers.go │ └── models.go └── templates │ ├── books.gohtml │ ├── create.gohtml │ ├── created.gohtml │ ├── show.gohtml │ ├── update.gohtml │ └── updated.gohtml ├── 21_httprouter_template ├── main.go ├── static │ ├── index.html │ └── mongodb.png └── templates │ ├── footer.html │ ├── header.html │ ├── page-02.html │ └── page.html ├── 22_mongodb_crud_rest_html ├── config │ ├── db.go │ └── tpl.go ├── main.go ├── records │ ├── handlers.go │ └── models.go ├── static │ ├── greynoise1.png │ ├── index.html │ ├── mongodb.png │ └── style.css └── templates │ ├── all.gohtml │ ├── books.gohtml │ ├── create.gohtml │ ├── created.gohtml │ ├── old.gohtml │ ├── show.gohtml │ ├── update.gohtml │ └── updated.gohtml ├── 23_file_uploader ├── main.go └── templates │ ├── include-footer.gohtml │ ├── include-header.gohtml │ └── index.gohtml ├── 24_calculate_time ├── EST.go ├── calculate_months.go ├── check_time_window.go ├── dayInterval.go ├── filename.go ├── func_execution_time.go ├── hours_since_then.go ├── listWeeks.go ├── milliseconds.go ├── unix_time_stamp.go ├── week_of_the_year.go └── weekday.go ├── 25_https_static_files ├── main.go ├── public │ └── index.gohtml └── webpage │ └── handlers.go ├── 26_url_not_found_handler ├── main.go ├── public │ ├── img │ │ └── toby.jpg │ └── test.txt └── test.go ├── 27_mongodb_bulk_upsert ├── .gitignore ├── temp │ └── main.go └── test.go ├── 28_markdown ├── main.go └── public │ └── index.gohtml ├── 29_go_crud_json_api ├── main.go ├── old-1.go ├── old-2.go ├── public │ ├── multipart_untested.gohtml │ ├── post_main_crud.gohtml │ ├── post_only.gohtml │ └── post_only_form.gohtml ├── readme.md └── rest_api_gorilla │ └── main.go ├── 30_mongodb_crud_json_api ├── .gitignore ├── config │ └── config.go ├── dao │ └── movies_dao.go ├── main.go ├── models │ └── movie.go └── sample-config.toml ├── 31_send_email ├── main.go └── main.goNEW ├── 32_colorful_cli └── main.go ├── 33_testing ├── compare_data.go ├── game.go ├── game_test.go ├── helpers.go ├── helpers_test.go └── testing.md ├── 34_channels ├── 01_bufferedChannel.go ├── 02_unbufferedChannel.go ├── 03_forkChannel.go ├── 04_stopGoroutine.go ├── 05_rangeOverClosedChannel.go ├── 06_close_on_separate_goroutine.go ├── 07_continuouslySendMSG.go ├── 08_known_length.go └── 09_known_length_buffered.go ├── 35_mongodb_pipeline_page ├── db.go ├── main.go └── template.html ├── 36_concurrency_channel ├── channel │ ├── channel_example.go │ ├── channel_waiting.go │ ├── concurrency_example.go │ ├── concurrrency_and_channel.go │ ├── counter.go │ ├── goroutine_sends_back_message.go │ ├── no_need_for_wait_group.go │ ├── select_all_channels_in_order_they_arrive.go │ ├── select_only_one.go │ ├── send_receive.go │ ├── simple_channel.go │ └── simple_example.go └── concurrency_wait_groups │ ├── do_it_once.go │ ├── waitgroup.go │ └── waitgroup_duration.go ├── 37_html_template ├── README.md ├── main.go ├── pub │ ├── css │ │ ├── main.css │ │ └── style.css │ └── img │ │ └── toby.jpg └── templates │ ├── about.gohtml │ ├── apply.gohtml │ ├── contact.gohtml │ ├── includes-hdr-ftr.gohtml │ ├── includes-nav-main.gohtml │ └── index.gohtml ├── 38_url_request_JSON ├── data_from_JSON.go ├── data_to_JSON.go ├── getJSON_file.go ├── getJSONandParse.go ├── main.go ├── post_file.go └── test.go ├── 39_read_directory_content ├── http_list_directory.md ├── ioutilReadDir.go └── osOpen.go ├── 40_cron_scheduler └── main.go ├── 41_cli_arguments ├── go-prompt.go └── main.go ├── 42_upload_many_files └── main.go ├── 43_resize_jpg_png_image ├── jpg.go └── png.go ├── 44_csv_file ├── read_csv.go └── write_csv.go ├── 45_image_exif_data ├── IMG_6958.JPG ├── main.go ├── recreate.go └── samples │ ├── IMG_6958.JPG │ └── IMG_7291.JPG ├── 46_video_capture └── main.go ├── 47_download_slice_as_csv └── main.go ├── 48_keyboard_driver └── main.go ├── 49_constructor ├── main.go └── play │ └── lib.go ├── 50_golf_framework ├── login.gohtml └── main.go ├── 51_blur_image ├── blur_image.go ├── generate_thumbnail.go ├── graphics │ ├── affine.go │ ├── blur.go │ ├── blur_test.go │ ├── convolve │ │ ├── convolve.go │ │ └── convolve_test.go │ ├── detect │ │ ├── detect.go │ │ ├── detect_test.go │ │ ├── doc.go │ │ ├── integral.go │ │ ├── integral_test.go │ │ ├── opencv_parser.go │ │ ├── opencv_parser_test.go │ │ ├── projector.go │ │ └── projector_test.go │ ├── graphicstest │ │ └── graphicstest.go │ ├── interp │ │ ├── bilinear.go │ │ ├── bilinear_test.go │ │ ├── doc.go │ │ └── interp.go │ ├── rotate.go │ ├── rotate_test.go │ ├── scale.go │ ├── scale_test.go │ ├── shared_test.go │ ├── thumbnail.go │ └── thumbnail_test.go ├── original.jpg └── rotate_image.go ├── 52_jpg_image_watermark ├── add_watermark.go ├── dimentions.go ├── grayscale.go ├── icon.png └── original.jpg ├── 53_regular_expression ├── convert_to_snake_case.go ├── is_date_format_valid.go ├── keep_special_characters.go ├── main.go ├── phone_number.go └── remove_special_characters.go ├── 54_rotate_image ├── icon.png ├── main.go ├── original.jpg └── rotate │ ├── rotations.go │ └── scan.go ├── 55_html_template_std_lib ├── image.tmpl ├── index.tmpl └── main.go ├── 56_HTML_formatter ├── main.go ├── original.gohtml └── original_updated.gohtml ├── 57_valid_interface ├── accept_interface.go └── main.go ├── 58_GO_HTML_template ├── map_to_template.go ├── other │ ├── HTML_template.go │ ├── HTML_template_2.go │ └── escape_and_unescape.go ├── simple │ ├── simple.html │ └── simpleExample.go ├── static_vs_dynamic_template.go └── templates │ ├── home.html │ └── test.html ├── 59_zip_and_unzip ├── download_zipfile_http.go ├── unzip_cli.go ├── zip.go └── zip2.go ├── 60_http_response_as_file └── main.go ├── 61_logging_middleware └── test.go ├── 62_download_progress └── main.go ├── 63_graphql_todo_example └── main.go ├── 65_books_example ├── config │ ├── db.go │ ├── db_connection.go │ └── tpl.go ├── main.go ├── records │ ├── handlers.go │ └── models.go ├── static │ └── style.css └── templates │ ├── all.gohtml │ ├── books.gohtml │ ├── create.gohtml │ ├── created.gohtml │ ├── show.gohtml │ ├── update.gohtml │ └── updated.gohtml ├── 66_server_sent_events ├── example2.html ├── index.html └── main.go ├── 67_stringutil ├── reverse.go └── reverse_test.go ├── 68_iota ├── fileSizes.go ├── seasons.go └── weekdays.go ├── 69_JSON └── read_many_objects.go ├── LICENSE └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 3 | *.exe 4 | .idea 5 | 6 | # TLS files 7 | *.pem 8 | 9 | # Linux compiled 10 | test 11 | web 12 | 13 | -------------------------------------------------------------------------------- /00_persisting_go/README.md: -------------------------------------------------------------------------------- 1 | 2 | ### Validate Input 3 | ```go 4 | func validInput(input string) bool { 5 | switch input { 6 | case "Option1", "OPtion2", "valid1", "valid2", "valid3": 7 | return true 8 | } 9 | return false 10 | } 11 | ``` 12 | 13 | ### AlphaNumeric 14 | ```go 15 | func alphaNumeric(input string) string { 16 | reg, _ := regexp.Compile("[^a-zA-Z0-9]+") 17 | return reg.ReplaceAllString(input, "") 18 | } 19 | ``` 20 | -------------------------------------------------------------------------------- /00_persisting_go/build_binary.md: -------------------------------------------------------------------------------- 1 | # Building executable 2 | Exporting binary file. 3 | 4 | ## Build on Linux 5 | * `export GOPATH=/var/go/web/` 6 | * `echo $GOPATH` 7 | ``` 8 | GOOS=linux GOARCH=amd64 go build -o web 9 | ``` 10 | 11 | ## Build on Windows 12 | ### Command Prompt 13 | * `set GOARCH=amd64` 14 | * `set GOARCH=386` 15 | * `set GOOS=linux` 16 | * `set GOOS=windows` 17 | * `echo %GOROOT%` 18 | 19 | ### PowerShell 20 | * `$env:GOARCH = "amd64"` 21 | * `$env:GOARCH = "386"` 22 | * `$env:GOOS = "linux"` 23 | * `$env:GOOS = "windows"` 24 | * `echo $env:GOOS` 25 | ``` 26 | go build -o hello.exe hello.go 27 | ``` 28 | [List of GOOS/GOARCH supported by Go](https://gist.github.com/asukakenji/f15ba7e588ac42795f421b48b8aede63#go-golang-goos-and-goarch) 29 | 30 | ## to build on Windows for Linux 31 | * `set GOOS=linux` 32 | * `set GOARCH=amd64` 33 | * `echo %GOARCH%` 34 | * `go build -o web main.go mux.go` 35 | 36 | To execute the file on linux in the directory, it needs to be executable, so chmod 744, then run: `./web` 37 | -------------------------------------------------------------------------------- /00_persisting_go/generate_SSL.md: -------------------------------------------------------------------------------- 1 | # Generate unsigned certificate 2 | `go run $(go env GOROOT)/src/crypto/tls/generate_cert.go --host=somedomainname.com` 3 | 4 | ### Generate unsigned certificate on WINDOWS 5 | windows may have issues with go env GOROOT 6 | `go run %(go env GOROOT)%/src/crypto/tls/generate_cert.go --host=localhost` 7 | 8 | Instead of go env GOROOT you can just use the path to the GO SDK wherever it is on your computer 9 | 10 | ### Generate unsigned certificate on Debian 8 (jessie) 11 | `sudo apt-get install certbot -t jessie-backports` 12 | 13 | `sudo certbot certonly --webroot -w /var/www/example -d example.com -d www.example.com -w /var/www/thing -d thing.is -d m.thing.is` 14 | 15 | ### To generate self-signed SSL using Open SSL: 16 | `openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout key.pem -out cert.pem` 17 | -------------------------------------------------------------------------------- /00_persisting_go/godoc.md: -------------------------------------------------------------------------------- 1 | To display all function declarations in browser: run this command: 2 | 3 | `godoc -http=":8080"` 4 | 5 | Anything you put, save, or download into **GOPATH/src** folder will show up on http://localhost:8080/pkg/ 6 | 7 | You can replace the port number "8080" with different port number. 8 | 9 | 10 | To display the results in CLI: 11 | 12 | `godoc ` 13 | 14 | Replace `` with your folder in **GOPATH/src**. 15 | 16 | -------------------------------------------------------------------------------- /00_persisting_go/golint.md: -------------------------------------------------------------------------------- 1 | # Installing golint 2 | To download it run: 3 | ``` 4 | go get -u golang.org/x/lint/golint 5 | ``` 6 | 7 | To build it run: 8 | ``` 9 | go build golang.org/x/lint/golint 10 | ``` 11 | 12 | Put it into `GOROOT/bin` where other executables are. 13 | 14 | To use it run: 15 | ``` 16 | golint ./... 17 | ``` 18 | 19 | -------------------------------------------------------------------------------- /00_persisting_go/persisting_using_systemd.md: -------------------------------------------------------------------------------- 1 | 2 | # Persisting Go using systemd 3 | Start your go app when the server starts. In other word _daemonize_ your golang program. 4 | 5 | ## Systemd 6 | `cd /etc/systemd/system/` 7 | 8 | `nano golang.service` 9 | 10 | ``` 11 | [Unit] 12 | Description=Go Server 13 | 14 | [Service] 15 | ExecStart=/var/www/web 16 | WorkingDirectory=/var/www/ 17 | User=root 18 | Group=root 19 | Restart=always 20 | 21 | [Install] 22 | WantedBy=multi-user.target 23 | ``` 24 | 25 | ### Start the service 26 | * `systemctl enable golang.service` 27 | * `systemctl start golang.service` 28 | * `systemctl status golang.service` 29 | * `systemctl stop golang.service` 30 | 31 | #### Find the version of systemd 32 | * `dpkg -l systemd` will give you name, version, and architecture description. 33 | * `systemctl --version` Print a short version string -------------------------------------------------------------------------------- /00_persisting_go/persisting_using_upstart.md: -------------------------------------------------------------------------------- 1 | # Starting GO binary using UPSTART 2 | _Upstart is used by Amazon Machine Images (AMI)_ 3 | 4 | Find out the version of Upstart: 5 | `initctl version` 6 | 7 | Upstart configuration files are located in this folder: 8 | * `/etc/init` folder is for Upstart 9 | * `/etc/init.d` folder is for SysVinit 10 | 11 | **Go to folder: /etc/init** 12 | `cd /etc/init` 13 | 14 | create file: go.conf 15 | `sudo nano go.conf` 16 | 17 | "go.conf" file contents 18 | ``` 19 | description "go binary" 20 | author "Developer" 21 | 22 | # start on (local-filesystems and net-device-up) 23 | start on runlevel [2345] 24 | stop on runlevel [!2345] 25 | 26 | respawn 27 | chdir /home/user-name/go 28 | exec /home/user-name/go/web-binary 29 | ``` 30 | --- 31 | 32 | ### Reload configuration: 33 | `sudo initctl reload-configuration` 34 | 35 | 36 | ### To start the service: 37 | `sudo start go` 38 | or 39 | `sudo initctl start go` 40 | 41 | To see the status: 42 | `sudo initctl list | grep go` 43 | or 44 | `sudo status go` 45 | 46 | ### Update binary 47 | If binary is updated, or overridden by newer version, then need to restart the service: 48 | `sudo restart go` 49 | or 50 | `sudo initctl restart go` 51 | 52 | 53 | 54 | --- 55 | # Build commands 56 | generate build using specific Go file. If file not specified, all files are used. 57 | `go build -o web-binary http.go` 58 | 59 | test to see if the executable is working 60 | `sudo /home/user-name/go/web-binary` 61 | -------------------------------------------------------------------------------- /00_persisting_go/random/RSA_key_pair.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | 6 | "crypto/rand" 7 | "crypto/rsa" 8 | "crypto/x509" 9 | "encoding/pem" 10 | "fmt" 11 | 12 | "golang.org/x/crypto/ssh" 13 | ) 14 | 15 | func main() { 16 | key, b, err := generatePrivateKey() 17 | if err != nil { 18 | fmt.Println(err) 19 | return 20 | } 21 | 22 | fmt.Println(string(b)) 23 | 24 | public2, err := generateSSHPublicKey(key) 25 | if err != nil { 26 | fmt.Println(err) 27 | return 28 | } 29 | fmt.Println(string(public2)) 30 | } 31 | 32 | func generatePrivateKey() (*rsa.PrivateKey, []byte, error) { 33 | // keyBytes, err := rsa.GenerateKey(rand.Reader, 2048) 34 | keyBytes, err := rsa.GenerateKey(rand.Reader, 4096) 35 | if err != nil { 36 | return nil, nil, err 37 | } 38 | 39 | certBytes := new(bytes.Buffer) 40 | 41 | err = pem.Encode(certBytes, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(keyBytes)}) 42 | if err != nil { 43 | return nil, nil, err 44 | } 45 | 46 | return keyBytes, certBytes.Bytes(), nil 47 | } 48 | 49 | func generateSSHPublicKey(key *rsa.PrivateKey) ([]byte, error) { 50 | 51 | public, err := ssh.NewPublicKey(&key.PublicKey) // *rsaPublicKey 52 | if err != nil { 53 | return nil, err 54 | } 55 | 56 | certBytes := new(bytes.Buffer) 57 | 58 | err = pem.Encode(certBytes, &pem.Block{Type: "PUBLIC KEY", Bytes: public.Marshal()}) 59 | if err != nil { 60 | return nil, err 61 | } 62 | 63 | return certBytes.Bytes(), nil 64 | } 65 | -------------------------------------------------------------------------------- /00_persisting_go/random/any_type_can_serve_http.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | ) 7 | 8 | // AnyType defines a type for the response 9 | // type AnyTypeCopy struct{} 10 | // type AnyType string 11 | // type AnyType interface {} // interface does not work 12 | type AnyType int 13 | 14 | // let that type implement the ServeHTTP method (defined in interface http.Handler) 15 | func (h AnyType) ServeHTTP(w http.ResponseWriter, r *http.Request) { 16 | fmt.Fprint(w, "Any type can say Hello!") 17 | } 18 | 19 | func main() { 20 | var h AnyType 21 | fmt.Println(http.ListenAndServe(":8080", h)) 22 | } 23 | -------------------------------------------------------------------------------- /00_persisting_go/random/cgo.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // #include 4 | // 5 | // #cgo LDFLAGS: -L. -lcrypt 6 | // 7 | // char* mycrypt(char* s, char* salt) { 8 | // return crypt(s, salt); 9 | // } 10 | import "C" 11 | import "fmt" 12 | 13 | func main() { 14 | test() 15 | } 16 | 17 | func getHash(username, pass string) string { 18 | return C.GoString(C.mycrypt(C.CString(pass), C.CString("$1$"+username))) 19 | } 20 | 21 | func test() { 22 | fmt.Println("put:", "$1$CONTRACT$BD2CbhFWoCU4ug9pJ6LR.1") 23 | fmt.Println("got:", getHash("CONTRACTOR", "test")) 24 | } 25 | 26 | // tested on Linux 27 | -------------------------------------------------------------------------------- /00_persisting_go/random/copy_example.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "unsafe" 6 | ) 7 | 8 | // main is the entry point for the program. 9 | func main() { 10 | copy((*(*[512]byte)(unsafe.Pointer(argp)))[:], data[:]) 11 | fmt.Print(">") 12 | } 13 | -------------------------------------------------------------------------------- /00_persisting_go/random/do_it_once_a_second.go: -------------------------------------------------------------------------------- 1 | // Do something so often until condition is met 2 | package main 3 | 4 | import ( 5 | "fmt" 6 | "time" 7 | ) 8 | 9 | const dotsPerLine = 50 10 | const linesPerPage = 20 11 | 12 | // main is the entry point for the program. 13 | func main() { 14 | 15 | i, line := 0, 1 16 | fmt.Print("\n", line, "\t ") // print the first line 17 | 18 | // do it once in two milliseconds 19 | for range time.Tick(time.Millisecond * 2) { 20 | 21 | fmt.Print(".") 22 | i++ 23 | 24 | // At end of the line do this: 25 | if i%dotsPerLine == 0 { 26 | 27 | // end loop if all lines are printed 28 | if line >= linesPerPage { 29 | break 30 | } 31 | 32 | i = 0 // reset dot counter 33 | 34 | // start a new line 35 | line++ 36 | fmt.Print("\n", line, "\t ") 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /00_persisting_go/random/envron.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "syscall" 6 | ) 7 | 8 | func main() { 9 | list := syscall.Environ() 10 | for _, v := range list { 11 | fmt.Println(v) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /00_persisting_go/random/fizzbuzz.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | for i := 1; i <= 100; i++ { 7 | 8 | if i%3 == 0 { 9 | // Multiple of 3 10 | fmt.Printf("fizz") 11 | } 12 | if i%5 == 0 { 13 | // Multiple of 5 14 | fmt.Printf("buzz") 15 | } 16 | 17 | if i%3 != 0 && i%5 != 0 { 18 | // Neither, so print the number itself 19 | //fmt.Printf("%d", i) 20 | fmt.Print(i) 21 | } 22 | 23 | // A trailing new line (so both fizz + buzz can be printed on the same line) 24 | fmt.Printf("\n") 25 | 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /00_persisting_go/random/print_on_same_line.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | "strings" 7 | "time" 8 | ) 9 | 10 | func main() { 11 | for i := 0; i < 11; i++ { 12 | fmt.Print("\r", "line ", strconv.Itoa(i)) 13 | time.Sleep(1 * time.Second) 14 | } 15 | 16 | fmt.Printf("\r%s", strings.Repeat(" ", 35)) // clear all characters 17 | fmt.Print("\r", "line1") 18 | time.Sleep(5 * time.Second) 19 | fmt.Print("\r", "line 2") 20 | } 21 | -------------------------------------------------------------------------------- /00_persisting_go/random/rand5_to_rand7.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "time" 7 | ) 8 | 9 | func main() { 10 | 11 | for i := 0; i < 110; i++ { 12 | print(randAB(1, 20), " ") 13 | } 14 | 15 | cryptRand() 16 | } 17 | 18 | func rand5() int { 19 | rand.Seed(time.Now().UnixNano()) 20 | num := rand.Intn(5) 21 | return num + 1 22 | } 23 | 24 | func rand7() int { 25 | //num := (rand5() + rand5() + rand5())%7 26 | num := 0 27 | for i := 0; i <= rand5(); i++ { 28 | num += rand5() 29 | } 30 | 31 | return num%7 + 1 32 | 33 | } 34 | 35 | func randAB(a, b int) int { 36 | rand.Seed(time.Now().UnixNano()) 37 | return a + rand.Intn(b-a+1) // a ≤ n ≤ b 38 | } 39 | 40 | func randInt(min, max int) int { 41 | return min + rand.Intn(max-min+1) 42 | } 43 | 44 | func cryptRand() { 45 | b := make([]byte, 10) 46 | _, err := rand.Read(b) 47 | if err != nil { 48 | fmt.Println("error:", err) 49 | return 50 | } 51 | fmt.Println("b:", b, " | ", string(b)) 52 | 53 | } 54 | -------------------------------------------------------------------------------- /00_persisting_go/random/test_random_generator.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "crypto/rand" 5 | "encoding/base64" 6 | "math/big" 7 | ) 8 | 9 | func main() { 10 | for i := 0; i < 5; i++ { 11 | println(randomGenerator()) 12 | } 13 | 14 | for i := 0; i < 61; i++ { 15 | print(randomNumber(), " ") 16 | } 17 | } 18 | 19 | func randomGenerator() string { 20 | b := make([]byte, 32) 21 | if _, err := rand.Read(b); err != nil { 22 | return "" 23 | } 24 | return base64.URLEncoding.EncodeToString(b) 25 | } 26 | 27 | func randomString(l int) string { 28 | bytes := make([]byte, l) 29 | for i := 0; i < l; i++ { 30 | bytes[i] = byte(randInt(65, 90)) 31 | } 32 | return string(bytes) 33 | } 34 | 35 | func randomString(length int) string { 36 | b := make([]byte, length) 37 | if _, err := rand.Read(b); err != nil { 38 | return "" 39 | } 40 | // fmt.Println(b) 41 | return base64.StdEncoding.EncodeToString(b) 42 | } 43 | 44 | func randomNumber() string { 45 | min := big.NewInt(1) 46 | max := big.NewInt(5) 47 | nBig, _ := rand.Int(rand.Reader, max) 48 | nBig = nBig.Add(min, nBig) 49 | return nBig.String() 50 | } 51 | -------------------------------------------------------------------------------- /00_persisting_go/random/write_to_slice.go: -------------------------------------------------------------------------------- 1 | // Using io.Writer to write to underlying slice 2 | // fmt.Fprint is printing to a writer 3 | package main 4 | 5 | import ( 6 | "fmt" 7 | ) 8 | 9 | type pipe struct { 10 | name string 11 | } 12 | 13 | type pList struct { 14 | items []pipe 15 | } 16 | 17 | // list is a pointer to pList type 18 | var list = &pList{} 19 | 20 | // Write method for pList type to implement io.Writer 21 | func (l *pList) Write(p []byte) (n int, err error) { 22 | l.items = append(l.items, pipe{name: string(p)}) 23 | return 0, nil 24 | } 25 | 26 | // String method for pList type to implement stringer interface 27 | func (l *pList) String() string { 28 | out := "" 29 | for _, i := range l.items { 30 | out = out + i.name + ", " 31 | } 32 | return out 33 | } 34 | 35 | // main is the entry point for the program. 36 | func main() { 37 | list = &pList{items: []pipe{{name: "one"}, {name: "two"}}} 38 | fmt.Println(list) 39 | 40 | fmt.Fprint(list, "three") 41 | fmt.Fprint(list, "four") 42 | fmt.Println(list) 43 | } 44 | -------------------------------------------------------------------------------- /01_data_type/anytype_parameter.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | run([]string{"1", "2", "3"}) 7 | run("ok") 8 | run() 9 | } 10 | 11 | // function that accepts any type of data 12 | func run(i ...interface{}) { 13 | if i == nil { 14 | fmt.Println("input is null") 15 | return 16 | } 17 | 18 | for _, input := range i { 19 | switch input.(type) { 20 | case int: 21 | fmt.Println("integer:", input) 22 | case string: 23 | fmt.Println("string:", input) 24 | case bool: 25 | fmt.Println("bool:", input) 26 | case []string: 27 | fmt.Println("slice of string:", input) 28 | case []int: 29 | fmt.Println("slice of int:", input) 30 | default: 31 | fmt.Println("some other type:", input) 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /01_data_type/buffers.md: -------------------------------------------------------------------------------- 1 | There are two ways to make a buffer: 2 | 3 | ``` 4 | buffer := bytes.NewBuffer(make([]byte, 0)) 5 | buffer := &bytes.Buffer{} 6 | ``` 7 | 8 | buffer can take string 9 | `buffer.WriteString(line);` 10 | 11 | or buffer can read from io.Writer 12 | 13 | `buffer.ReadFrom() // takes io.Writer` 14 | 15 | 16 | buffer can take slice of byte or string 17 | ``` 18 | buffer.Write([]byte(strings.Join(record, "\t") + "\n")) 19 | buffer.WriteString(line) 20 | ``` 21 | 22 | -------------------------------------------------------------------------------- /01_data_type/convert_ip_to_string.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | ) 7 | 8 | // IPAddr is the IPv4 address 9 | type IPAddr [4]byte 10 | 11 | func main() { 12 | hosts := map[string]IPAddr{ 13 | "loopback": {127, 0, 0, 1}, 14 | "googleDNS": {8, 8, 8, 8}, 15 | } 16 | for name, ip := range hosts { 17 | fmt.Printf("%v: %v\n", name, ip) 18 | } 19 | } 20 | 21 | // String implements stringer interface 22 | func (p IPAddr) String() string { 23 | s := strconv.Itoa(int(p[0])) + "." + 24 | strconv.Itoa(int(p[1])) + "." + 25 | strconv.Itoa(int(p[2])) + "." + 26 | strconv.Itoa(int(p[3])) 27 | return `"` + s + `"` 28 | } 29 | -------------------------------------------------------------------------------- /01_data_type/custom_error.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | // MyError includes time and string 9 | type MyError struct { 10 | When time.Time 11 | What string 12 | } 13 | 14 | func (e *MyError) Error() string { 15 | return fmt.Sprintf("at %v, %s", 16 | e.When, e.What) 17 | } 18 | 19 | func run() error { 20 | return &MyError{ 21 | time.Now(), 22 | "it didn't work", 23 | } 24 | } 25 | 26 | func main() { 27 | if err := run(); err != nil { 28 | fmt.Println(err) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /01_data_type/display_slice_totals.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func main() { 8 | quiz([]int{11, 9, 6, 11, 5}, 3) // expected answer "26, 16" 9 | quiz([]int{11, 9, 6, 11, 5, 1}, 3) // expected answer "26, 17" 10 | quiz([]int{11, 9, 6, 11, 5, 1, 1}, 3) // expected answer "26, 17, 1" 11 | } 12 | 13 | // quiz sums every n elements of arr and print. 14 | // also print the sum of any remaining elements 15 | func quiz(arr []int, n int) { 16 | 17 | out := 0 18 | 19 | for i := 0; i < len(arr); i++ { 20 | out += arr[i] 21 | 22 | if (i+1)%n == 0 { // because slice index starts with zero 23 | fmt.Printf("%d, ", out) 24 | out = 0 25 | } else if i+1 == len(arr) { // if the end of the slice 26 | fmt.Printf("%d ", out) 27 | out = 0 28 | } 29 | 30 | } 31 | fmt.Println("") 32 | } 33 | -------------------------------------------------------------------------------- /01_data_type/display_slice_totals2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | // main is the entry point for the program. 6 | func main() { 7 | numbers := []int{1, 2, 3, 4, 6, 7} 8 | 9 | check(numbers, 2) 10 | } 11 | 12 | func check(number []int, total int) { 13 | j := 0 14 | for i := range number { 15 | j = number[i] + j 16 | //fmt.Print(number[i], total, "\n") 17 | if (i+1)%total == 0 { 18 | fmt.Print(j, ",") 19 | j = 0 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /01_data_type/display_slice_totals3.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func main() { 8 | test([]int{1, 2, 3, 54, 6, 7, 78}, 2) 9 | test([]int{1, 2, 3, 54, 6, 7, 78}, 3) 10 | test([]int{1, 2, 3, 54, 6, 7, 78, 1}, 3) 11 | test([]int{1, 1, 1, 1, 1}, 5) 12 | } 13 | 14 | func test(n []int, t int) { 15 | 16 | out := 0 17 | for j := 0; j < len(n); j++ { 18 | 19 | out = out + n[j] 20 | if (j+1)%t == 0 { 21 | fmt.Printf("%d, ", out) 22 | out = 0 23 | } 24 | } 25 | if out != 0 { 26 | fmt.Printf("%d ", out) 27 | } 28 | fmt.Println() 29 | } 30 | -------------------------------------------------------------------------------- /01_data_type/functionAcceptAnyType.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | run([]string{"1", "2", "3"}) 7 | run("ok") 8 | run() 9 | } 10 | 11 | // run function accepts any parameter type 12 | func run(i ...interface{}) { 13 | if i == nil { 14 | fmt.Println("input is null") 15 | return 16 | } 17 | 18 | for _, input := range i { 19 | switch input.(type) { 20 | case int: 21 | fmt.Println("integer:", input) 22 | case string: 23 | fmt.Println("string:", input) 24 | case bool: 25 | fmt.Println("bool:", input) 26 | case []string: 27 | fmt.Println("slice of string:", input) 28 | case []int: 29 | fmt.Println("slice of int:", input) 30 | default: 31 | fmt.Println("some other type:", input) 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /01_data_type/randomSortExample.go: -------------------------------------------------------------------------------- 1 | // Quick Sort in Golang 2 | package main 3 | 4 | import ( 5 | "fmt" 6 | "math/rand" 7 | "time" 8 | ) 9 | 10 | func main() { 11 | 12 | rand.Seed(time.Now().UnixNano()) 13 | for i := 0; i <= 10; i++ { 14 | fmt.Print(95+rand.Intn(6), " ") 15 | } 16 | 17 | slice := generateSlice(20) 18 | fmt.Println("\n--- Unsorted --- \n\n", slice) 19 | sort(slice) 20 | fmt.Println("\n--- Sorted ---\n\n", slice) 21 | } 22 | 23 | // Generates a slice of size, size filled with random numbers 24 | func generateSlice(size int) []int { 25 | 26 | slice := make([]int, size, size) 27 | rand.Seed(time.Now().UnixNano()) 28 | for i := 0; i < size; i++ { 29 | slice[i] = rand.Intn(999) - rand.Intn(999) 30 | } 31 | return slice 32 | } 33 | 34 | func sort(a []int) []int { 35 | if len(a) < 2 { 36 | return a 37 | } 38 | 39 | left, right := 0, len(a)-1 40 | 41 | pivot := rand.Int() % len(a) 42 | 43 | a[pivot], a[right] = a[right], a[pivot] 44 | 45 | for i := range a { 46 | if a[i] < a[right] { 47 | a[left], a[i] = a[i], a[left] 48 | left++ 49 | } 50 | } 51 | 52 | a[left], a[right] = a[right], a[left] 53 | 54 | sort(a[:left]) 55 | sort(a[left+1:]) 56 | 57 | return a 58 | } 59 | -------------------------------------------------------------------------------- /01_data_type/recursion.go: -------------------------------------------------------------------------------- 1 | // Examples of Recursion in Go 2 | 3 | package main 4 | 5 | import ( 6 | "fmt" 7 | "strconv" 8 | ) 9 | 10 | // factorial recursion 11 | func factorial(i int) int { 12 | if i <= 1 { 13 | return 1 14 | } 15 | return i * factorial(i-1) 16 | } 17 | 18 | // countdown return decremental list of numbers 19 | func countdown(i int, s []string) (int, []string) { 20 | if i < 1 { 21 | return i, s 22 | } 23 | 24 | return countdown(i-1, append(s, strconv.Itoa(i))) 25 | } 26 | 27 | // main is the entry point for the program. 28 | func main() { 29 | var i = 15 30 | fmt.Printf("Factorial of %d is %d\n", i, factorial(i)) 31 | 32 | _, s := countdown(i, []string{}) 33 | fmt.Println("Countdown:", s) 34 | } 35 | -------------------------------------------------------------------------------- /01_data_type/referenceTypes.go: -------------------------------------------------------------------------------- 1 | /* 2 | The following are "reference" types: 3 | slices 4 | maps 5 | channels 6 | pointers 7 | functions 8 | 9 | 10 | otherwise it is Primitive 11 | */ 12 | 13 | package main 14 | 15 | import ( 16 | "fmt" 17 | ) 18 | 19 | // main is the entry point for the program. 20 | func main() { 21 | s := make([]string, 3) 22 | s[0] = "a" 23 | s[1] = "b" 24 | 25 | // show results before making changes via function 26 | fmt.Println("emp:", s) 27 | 28 | test(s) // update slice; s is pointer 29 | 30 | fmt.Println("apd:", s) // show results 31 | } 32 | 33 | // slice is "reference" type, so no need to return value 34 | func test(s []string) { // Passing by pointer 35 | s[2] = "c" 36 | } 37 | -------------------------------------------------------------------------------- /01_data_type/sort_slice.go: -------------------------------------------------------------------------------- 1 | // code samples using the sort package 2 | package main 3 | 4 | import ( 5 | "fmt" 6 | "sort" 7 | ) 8 | 9 | func main() { 10 | sl := []string{"mumbai", "london", "tokyo", "seattle"} 11 | // sort.Strings(sl) 12 | sort.Sort(sort.Reverse(sort.StringSlice(sl))) 13 | // sort.Sort(sort.StringSlice(sl)) 14 | fmt.Println(sl) 15 | 16 | intSlice := []int{3, 5, 6, 4, 2, 293, -34} 17 | sort.Ints(intSlice) 18 | //sort.Sort(sort.IntSlice(intSlice)) 19 | fmt.Println(intSlice) 20 | 21 | a := []int{5, 3, 4, 7, 8, 9} 22 | sort.Slice(a, func(i, j int) bool { 23 | return a[i] < a[j] 24 | }) 25 | for _, v := range a { 26 | fmt.Print(v, " ") 27 | } 28 | 29 | // sort slice 30 | people := []struct { 31 | Name string 32 | Age int 33 | }{ 34 | {"Gopher", 7}, 35 | {"Alice", 55}, 36 | {"Vera", 24}, 37 | {"Bob", 75}, 38 | } 39 | sort.Slice(people, func(i, j int) bool { return people[i].Name < people[j].Name }) 40 | fmt.Println("By name:", people) 41 | 42 | } 43 | -------------------------------------------------------------------------------- /01_data_type/type_assertion.go: -------------------------------------------------------------------------------- 1 | // A type assertion provides access to an interface value's underlying concrete value. 2 | package main 3 | 4 | import "fmt" 5 | 6 | func main() { 7 | var i interface{} = "hello" 8 | 9 | s := i.(string) 10 | fmt.Println(s) 11 | 12 | s, ok := i.(string) 13 | fmt.Println(s, ok) 14 | 15 | f, ok := i.(float64) 16 | fmt.Println(f, ok) 17 | 18 | //f = i.(float64) // panic 19 | //fmt.Println(f) 20 | 21 | t := interface{}("test") // string as interface 22 | fmt.Println(t) 23 | 24 | s, ok = t.(string) 25 | fmt.Println(s, ok) 26 | } 27 | -------------------------------------------------------------------------------- /02_mongodb_aggregate_cli/README.md: -------------------------------------------------------------------------------- 1 | # MongoDB aggregate command 2 | This code selects aggregate data from MongoDB and displays it in CLI 3 | -------------------------------------------------------------------------------- /02_mongodb_aggregate_cli/command/buildInfo.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "dblogin" 5 | "fmt" 6 | "gopkg.in/mgo.v2" 7 | //"gopkg.in/mgo.v2/bson" 8 | ) 9 | 10 | func main() { 11 | session, err := mgo.Dial(dblogin.Userpass) // mongodb://username:yourpasscode@serverip:27017/database?authSource=admin 12 | if err != nil { 13 | panic(err) 14 | } 15 | defer session.Close() 16 | 17 | var result struct { 18 | Version string 19 | VersionArray []int `bson:"versionArray"` // On MongoDB 2.0+; assembled from Version otherwise 20 | GitVersion string `bson:"gitVersion"` 21 | OpenSSLVersion string `bson:"OpenSSLVersion"` 22 | SysInfo string `bson:"sysInfo"` // Deprecated and empty on MongoDB 3.2+. 23 | Bits int 24 | Debug bool 25 | MaxObjectSize int `bson:"maxBsonObjectSize"` 26 | } 27 | 28 | // Optional. Switch the session to a monotonic behavior. 29 | session.SetMode(mgo.Monotonic, true) 30 | 31 | result, _ = session.BuildInfo() 32 | 33 | fmt.Println("Results All: ", result.Version) 34 | for _, v := range result.VersionArray { 35 | fmt.Println(v, "\t=") 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /02_mongodb_aggregate_cli/command/command.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "dblogin" 5 | "fmt" 6 | 7 | "gopkg.in/mgo.v2" 8 | "gopkg.in/mgo.v2/bson" 9 | ) 10 | 11 | func main() { 12 | session, err := mgo.Dial(dblogin.Userpass) // mongodb://username:yourpasscode@serverip:27017/database?authSource=admin 13 | if err != nil { 14 | panic(err) 15 | } 16 | defer session.Close() 17 | 18 | // Optional. Switch the session to a monotonic behavior. 19 | session.SetMode(mgo.Monotonic, true) 20 | 21 | // Run command, works 22 | result := bson.M{} 23 | if err := session.DB("admin").Run("serverStatus", &result); err != nil { 24 | check(err) 25 | } else { 26 | fmt.Println(result) 27 | } 28 | 29 | // Run a command, works 30 | var serverStatus = &bson.M{} 31 | if err := session.Run("serverStatus", serverStatus); err != nil { 32 | check(err) 33 | } else { 34 | fmt.Println(*serverStatus) 35 | } 36 | 37 | // Run a command with an argument, works 38 | var startupWarnings = &bson.M{} 39 | if err := session.Run(bson.D{{Name: "getLog", Value: "startupWarnings"}}, startupWarnings); err != nil { 40 | check(err) 41 | } else { 42 | fmt.Println(*startupWarnings) 43 | } 44 | 45 | if err := session.DB("test").Run("dbstats", &result); err != nil { 46 | check(err) 47 | } else { 48 | fmt.Println(result) 49 | } 50 | if err := session.DB("admin").Run("replSetGetStatus", &result); err != nil { 51 | check(err) 52 | } else { 53 | fmt.Println(result) 54 | } 55 | 56 | } 57 | 58 | func check(err error) { 59 | if err != nil { 60 | fmt.Println("Error: ", err.Error()) 61 | //http.Error(w, "Error: " + err.Error(), 500) 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /02_mongodb_aggregate_cli/command/distinct.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "dblogin" 5 | "fmt" 6 | "gopkg.in/mgo.v2" 7 | "gopkg.in/mgo.v2/bson" 8 | ) 9 | 10 | func main() { 11 | session, err := mgo.Dial(dblogin.Userpass) // mongodb://username:yourpasscode@serverip:27017/database?authSource=admin 12 | if err != nil { 13 | panic(err) 14 | } 15 | defer session.Close() 16 | 17 | // Optional. Switch the session to a monotonic behavior. 18 | session.SetMode(mgo.Monotonic, true) 19 | 20 | c := session.DB("onlinestore").C("products3") 21 | 22 | var result []string 23 | err = c.Find(bson.M{"category": bson.M{"$exists": 1}}).Distinct("category", &result) 24 | if err != nil { 25 | panic(err) 26 | } 27 | 28 | //fmt.Println("Results All: ", result) 29 | for _, v := range result { 30 | fmt.Println(v, "\t=") 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /02_mongodb_aggregate_cli/log_mongodb_logs.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "gopkg.in/mgo.v2" 5 | "log" 6 | "os" 7 | ) 8 | 9 | func main() { 10 | logger := log.New(os.Stderr, "", 0) 11 | mgo.SetLogger(logger) 12 | mgo.SetDebug(true) 13 | session, err := mgo.Dial("localhost") 14 | if err != nil { 15 | panic(err) 16 | } 17 | defer session.Close() 18 | } 19 | -------------------------------------------------------------------------------- /02_mongodb_aggregate_cli/main.go: -------------------------------------------------------------------------------- 1 | // This code selects aggregate data from mongodb and displays it in CLI 2 | 3 | package main 4 | 5 | import ( 6 | "dblogin" 7 | "fmt" 8 | "gopkg.in/mgo.v2" 9 | "gopkg.in/mgo.v2/bson" 10 | ) 11 | 12 | func main() { 13 | 14 | session, err := mgo.Dial(dblogin.Userpass) // mongodb://username:yourpasscode@serverip:27017/database?authSource=admin 15 | if err != nil { 16 | panic(err) 17 | } 18 | defer session.Close() 19 | 20 | // Optional. Switch the session to a monotonic behavior. 21 | session.SetMode(mgo.Monotonic, true) 22 | 23 | c := session.DB("onlinestore").C("products3") 24 | 25 | /* 26 | // Same command for use in mongodb Shell 27 | db.products.aggregate([ 28 | {$group : {_id:"$category", count:{$sum:1}}}, 29 | {$sort:{"count":-1}}, 30 | {$limit: 15} 31 | ]) 32 | */ 33 | 34 | pipeline := []bson.M{ 35 | { 36 | "$group": bson.M{ 37 | "_id": "$category", 38 | "count": bson.M{"$sum": 1}, 39 | }, 40 | }, 41 | { 42 | "$sort": bson.M{ 43 | "count": -1, 44 | }, 45 | }, 46 | { 47 | "$limit": 15, 48 | }, 49 | } 50 | 51 | pipe := c.Pipe(pipeline) 52 | 53 | //pipe := c.Pipe([]bson.M{{"$match": bson.M{"user":"John"}}}) 54 | //resp := []bson.M{} 55 | 56 | // Declaring type 57 | resp := []struct { 58 | ID string `json:"id,omitempty" bson:"_id"` 59 | Count int `json:"count,omitempty" bson:"count"` 60 | }{{}} 61 | 62 | err = pipe.All(&resp) 63 | checkErr(err) 64 | 65 | //fmt.Println(resp) // simple print proving it's working 66 | 67 | for _, v := range resp { 68 | fmt.Println(v.Count, "\t", v.ID) 69 | } 70 | 71 | } 72 | 73 | func checkErr(err error) { 74 | if err != nil { 75 | fmt.Println(err) 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /02_mongodb_aggregate_cli/mongodb_dial_with_info.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "gopkg.in/mgo.v2" 5 | ) 6 | 7 | func main() { 8 | dialInfo, err := mgo.ParseURL("mongodb://localhost:27017") 9 | if err != nil { 10 | panic(err) 11 | } 12 | dialInfo.Direct = true 13 | dialInfo.FailFast = true 14 | session, err := mgo.DialWithInfo(dialInfo) 15 | if err != nil { 16 | panic(err) 17 | } 18 | defer session.Close() 19 | } 20 | -------------------------------------------------------------------------------- /03_mongodb_find_sort_cli/README.md: -------------------------------------------------------------------------------- 1 | # MongoDB Find All, Sort commands. 2 | Results displayed in CLI 3 | -------------------------------------------------------------------------------- /03_mongodb_find_sort_cli/collectionInfo.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "dblogin" 5 | "fmt" 6 | "gopkg.in/mgo.v2" 7 | "gopkg.in/mgo.v2/bson" 8 | "log" 9 | ) 10 | 11 | func main() { 12 | 13 | session, err := mgo.Dial(dblogin.Bookstore) // mongodb://username:yourpasscode@serverip:27017/database?authSource=admin 14 | if err != nil { 15 | log.Fatalf("Error connecting to MongoDB: %s", err) 16 | } 17 | defer session.Close() 18 | 19 | db := session.DB("test") 20 | 21 | collectionName := "people" 22 | 23 | result := &bson.D{} 24 | err = db.Run(&bson.D{bson.DocElem{Name: "collstats", Value: collectionName}}, result) 25 | if err != nil { 26 | log.Fatalf("Failed to get collection stats: %s", err) 27 | } 28 | 29 | storageSize := result.Map()["storageSize"] 30 | 31 | size := result.Map()["size"] 32 | count := result.Map()["count"] 33 | avgObjSize := result.Map()["avgObjSize"] 34 | 35 | fmt.Println("Storage === Size: ", size) 36 | fmt.Println("Storage == count: ", count) 37 | fmt.Println("Storage StorageS: ", storageSize) 38 | fmt.Println("Stora avgObjSize: ", avgObjSize) 39 | 40 | } 41 | 42 | /* 43 | "ns" : "onlinestore.traffic", 44 | "size" : 166377, 45 | "count" : 638, 46 | "avgObjSize" : 260, 47 | "storageSize" : 77824, 48 | */ 49 | -------------------------------------------------------------------------------- /03_mongodb_find_sort_cli/main.go: -------------------------------------------------------------------------------- 1 | // CLI only. Exports results from MongoDB to CLI. That's all 2 | 3 | package main 4 | 5 | import ( 6 | "dblogin" 7 | "fmt" 8 | "time" 9 | 10 | "gopkg.in/mgo.v2" 11 | "gopkg.in/mgo.v2/bson" 12 | ) 13 | 14 | // main is the entry point for the program 15 | type personaFields struct { 16 | ID bson.ObjectId `bson:"_id,omitempty"` 17 | Name string 18 | Phone string 19 | Timestamp time.Time 20 | } 21 | 22 | func main() { 23 | p := fmt.Println 24 | 25 | session, err := mgo.Dial(dblogin.Userpass) // mongodb://username:yourpasscode@serverip:27017/database?authSource=admin 26 | if err != nil { 27 | panic(err) 28 | } 29 | 30 | defer session.Close() 31 | session.SetMode(mgo.Monotonic, true) 32 | 33 | // Collection People 34 | c := session.DB("test").C("people") 35 | var results []personaFields 36 | 37 | // Query All 38 | err = c.Find(bson.M{}).Sort("-timestamp").All(&results) 39 | if err != nil { 40 | panic(err) 41 | } 42 | 43 | for _, v := range results { 44 | //t1, e := time.Parse(time.RFC3339, "2012-08-11T22:08:41+00:00") 45 | p(v.Phone, "\t", v.Timestamp.Format("2006-01-02 3:04PM"), "\t", v.Name, "\t") 46 | } 47 | fmt.Printf("Total results: %d\n", len(results)) 48 | } 49 | -------------------------------------------------------------------------------- /03_mongodb_find_sort_cli/mongoVariables.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "dblogin" 5 | "fmt" 6 | "reflect" 7 | 8 | "gopkg.in/mgo.v2" 9 | "gopkg.in/mgo.v2/bson" 10 | ) 11 | 12 | // main is the entry point for the program 13 | func main() { 14 | 15 | // Create a mgo session 16 | session, err := mgo.Dial(dblogin.Userpass) // mongodb://username:yourpasscode@serverip:27017/database?authSource=admin 17 | if err != nil { 18 | panic(err) 19 | } 20 | 21 | // Close the session when the function ends 22 | defer session.Close() 23 | 24 | fmt.Println("You connected to your mongo database.") 25 | 26 | // Run a command 27 | var serverStatus = &bson.M{} 28 | if err := session.Run("serverStatus", serverStatus); err != nil { 29 | panic(err) 30 | } else { 31 | //fmt.Println(*serverStatus) 32 | printMap(serverStatus) 33 | } 34 | 35 | // Run a command with an argument 36 | var startupWarnings = &bson.M{} 37 | if err := session.Run(bson.D{{Name: "getLog", Value: "startupWarnings"}}, startupWarnings); err != nil { 38 | panic(err) 39 | } else { 40 | //fmt.Println(*startupWarnings) 41 | //printMap(startupWarnings) 42 | } 43 | 44 | } 45 | 46 | func printMap(input *bson.M) { 47 | 48 | for k, v := range *input { 49 | if reflect.ValueOf(v).Kind() == reflect.Map { 50 | // print map 51 | printMap(*v) 52 | fmt.Println("it is a map") 53 | } else { 54 | fmt.Println("k:", k, "v:", v) 55 | } 56 | 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /03_mongodb_find_sort_cli/serverStatus.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "dblogin" 5 | "fmt" 6 | "gopkg.in/mgo.v2" 7 | "gopkg.in/mgo.v2/bson" 8 | "log" 9 | ) 10 | 11 | func main() { 12 | 13 | session, err := mgo.Dial(dblogin.Bookstore) // mongodb://username:yourpasscode@serverip:27017/database?authSource=admin 14 | if err != nil { 15 | log.Fatalf("Error connecting to MongoDB: %s", err) 16 | } 17 | defer session.Close() 18 | 19 | db := session.DB("test") 20 | 21 | //collectionName := "people" 22 | 23 | result := &bson.D{} 24 | err = db.Run(&bson.D{bson.DocElem{Name: "serverStatus", Value: 1}}, result) 25 | if err != nil { 26 | log.Fatalf("Failed to get collection stats: %s", err) 27 | } 28 | 29 | c := result.Map()["connections"] 30 | cu := result.Map()["current"] 31 | pid := result.Map()["pid"] 32 | 33 | fmt.Println("connections: ", c) 34 | fmt.Println("connections: ", cu) 35 | fmt.Println("connections pid: ", pid) 36 | 37 | } 38 | 39 | /* 40 | "host" : "mongodb", 41 | "version" : "3.4.6", 42 | "process" : "mongod", 43 | "pid" : NumberLong(535), 44 | "uptime" : 4247807, 45 | "uptimeMillis" : NumberLong("4247807370"), 46 | "uptimeEstimate" : NumberLong(4247807), 47 | "localTime" : ISODate("2018-01-06T04:05:34.783Z"), 48 | "asserts" : { 49 | "regular" : 0, 50 | "warning" : 0, 51 | "msg" : 0, 52 | "user" : 113, 53 | "rollovers" : 0 54 | }, 55 | "connections" : { 56 | "current" : 14, 57 | "available" : 805, 58 | "totalCreated" : 717 59 | }, 60 | "extra_info" : { 61 | "note" : "fields vary by platform", 62 | "page_faults" : 515 63 | */ 64 | -------------------------------------------------------------------------------- /04_get_url_variable/README.md: -------------------------------------------------------------------------------- 1 | # Get "FormValue" variable from URL 2 | Results displayed on port 8080 3 | * HTML template 4 | * Declare and initialize struct 5 | * Convert string to integer 6 | -------------------------------------------------------------------------------- /04_get_url_variable/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // Created to test GET from url 4 | import ( 5 | "fmt" 6 | "html/template" 7 | "net/http" 8 | "strconv" 9 | ) 10 | 11 | var tpl *template.Template 12 | 13 | func init() { 14 | tpl = template.Must(template.ParseGlob("templates/*.gohtml")) 15 | } 16 | 17 | func main() { 18 | http.HandleFunc("/", index) 19 | http.ListenAndServe(":8080", nil) 20 | } 21 | 22 | func index(w http.ResponseWriter, r *http.Request) { 23 | 24 | if r.Method == http.MethodPost { 25 | fmt.Println("method was post") 26 | } 27 | 28 | if r.Method == http.MethodGet { 29 | fmt.Println("method was get") 30 | } 31 | 32 | // Convert string to integer 33 | next, err := strconv.Atoi(r.FormValue("next")) 34 | if err != nil { 35 | fmt.Println(err) 36 | } 37 | 38 | // Declare and initialize struct 39 | senddata := struct { 40 | Prev int 41 | Now int 42 | Next int 43 | }{ 44 | next - 1, 45 | next, 46 | next + 1, 47 | } 48 | 49 | // Template 50 | err = tpl.ExecuteTemplate(w, "index.gohtml", senddata) 51 | if err != nil { 52 | fmt.Println(err) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /04_get_url_variable/templates/index.gohtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PAGINATION 6 | 7 | 8 | 9 |

RECORD: {{.Now}}

10 | 11 | Previous {{.Prev}} - Next {{.Next}} 12 | 13 | -------------------------------------------------------------------------------- /05_mongodb_crud_cli/README.md: -------------------------------------------------------------------------------- 1 | # MongoDB: Insert, Update, Drop, Find All, Index commands. 2 | Results displayed in CLI 3 | -------------------------------------------------------------------------------- /06_go_ajax_send_receive/README.md: -------------------------------------------------------------------------------- 1 | # Two Ajax examples 2 | * http://localhost:8080/process/ 3 | * http://localhost:8080/read/ 4 | * Results displayed on port 8080 5 | * HTML template 6 | * Read from file 7 | * Post results from HTML form 8 | * JavaScript is in *.gohtml files 9 | -------------------------------------------------------------------------------- /06_go_ajax_send_receive/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "html/template" 6 | "net/http" 7 | ) 8 | 9 | var tpl *template.Template 10 | 11 | func init() { 12 | tpl = template.Must(template.ParseGlob("templates/*.gohtml")) 13 | } 14 | 15 | func main() { 16 | http.HandleFunc("/", index) 17 | http.HandleFunc("/process", process) 18 | http.HandleFunc("/read", read) 19 | http.ListenAndServe(":8080", nil) 20 | } 21 | 22 | func index(w http.ResponseWriter, r *http.Request) { 23 | tpl.ExecuteTemplate(w, "index.gohtml", nil) 24 | } 25 | 26 | func process(w http.ResponseWriter, r *http.Request) { 27 | 28 | subscribe := r.FormValue("subscribe") 29 | dessert := r.FormValue("dessert") 30 | dow := r.FormValue("dow") 31 | fmt.Println("RESULTS:", subscribe, " - ", dessert, " - ", dow) 32 | } 33 | 34 | func read(w http.ResponseWriter, r *http.Request) { 35 | tpl.ExecuteTemplate(w, "read.gohtml", nil) 36 | } 37 | -------------------------------------------------------------------------------- /06_go_ajax_send_receive/templates/index.gohtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Document 6 | 7 | 8 |

read example Output from this code is presented on the CLI.

9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /07_one_file_template/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "html/template" 5 | "net/http" 6 | ) 7 | 8 | var tmpl = ` 9 | 10 | {{ . }} 11 | 12 | 13 | {{ . }} 14 |

15 | main | 16 | view 17 |

18 | 19 | 20 | 21 | ` 22 | 23 | func handler(w http.ResponseWriter, r *http.Request) { 24 | t := template.New("main") //name of the template is main 25 | t, _ = t.Parse(tmpl) // parsing of template string 26 | t.Execute(w, "Hello World!") 27 | } 28 | 29 | func main() { 30 | server := http.Server{ 31 | Addr: ":8080", 32 | } 33 | http.HandleFunc("/view/", handler) 34 | http.HandleFunc("/", index) 35 | server.ListenAndServe() 36 | } 37 | 38 | func index(w http.ResponseWriter, r *http.Request) { 39 | t := template.New("main") //name of the template is main 40 | t, _ = t.Parse(tmpl) // parsing of template string 41 | t.Execute(w, "Main page") 42 | } 43 | -------------------------------------------------------------------------------- /08_gowiki/edit.gohtml: -------------------------------------------------------------------------------- 1 |

Editing {{.Title}}

2 | 3 |
4 |
5 |
6 |
7 | -------------------------------------------------------------------------------- /08_gowiki/view.gohtml: -------------------------------------------------------------------------------- 1 |

{{.Title}}

2 | 3 |

[edit]

4 | 5 |
{{printf "%s" .Body}}
6 | -------------------------------------------------------------------------------- /09_todo_list_html/simple_http.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | ) 7 | 8 | func main() { 9 | http.HandleFunc("/", index) 10 | http.HandleFunc("/hello", hello) 11 | fmt.Println(http.ListenAndServe(":8080", nil)) 12 | } 13 | 14 | func index(w http.ResponseWriter, r *http.Request) { 15 | w.Header().Set("Content-Type", "text/html; charset=utf-8") 16 | fmt.Fprintf(w, `Hello World! test`) 17 | } 18 | 19 | func hello(w http.ResponseWriter, r *http.Request) { 20 | w.Header().Set("Content-Type", "text/html; charset=utf-8") 21 | fmt.Fprintf(w, `Hello World! home`) 22 | } 23 | -------------------------------------------------------------------------------- /09_todo_list_html/todos.go: -------------------------------------------------------------------------------- 1 | // todos.go 2 | package main 3 | 4 | import ( 5 | "html/template" 6 | "net/http" 7 | ) 8 | 9 | // Todo fields 10 | type Todo struct { 11 | Task string 12 | Done bool 13 | } 14 | 15 | func main() { 16 | tmpl := template.Must(template.ParseFiles("todos.html")) 17 | todos := []Todo{ 18 | {"Learn Go", true}, 19 | {"Read Go Web Examples", true}, 20 | {"Create a web app in Go", false}, 21 | } 22 | 23 | http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 24 | tmpl.Execute(w, struct{ Todos []Todo }{todos}) 25 | }) 26 | 27 | http.ListenAndServe(":8080", nil) 28 | } 29 | -------------------------------------------------------------------------------- /09_todo_list_html/todos.html: -------------------------------------------------------------------------------- 1 | 2 |

Todos

3 | {{ . }} 4 | 5 |
    6 | {{range .Todos}} 7 | {{if .Done}} 8 |
  • {{.Task}}
  • 9 | {{else}} 10 |
  • {{.Task}}
  • 11 | {{end}} 12 | {{end}} 13 |
-------------------------------------------------------------------------------- /11_socket_send_receive/tcp-client.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "net" 4 | import "fmt" 5 | import "bufio" 6 | import "os" 7 | 8 | func main() { 9 | 10 | // connect to this socket 11 | conn, _ := net.Dial("tcp", "127.0.0.1:8081") 12 | for { 13 | // read in input from stdin 14 | reader := bufio.NewReader(os.Stdin) 15 | fmt.Print("Text to send: ") 16 | text, _ := reader.ReadString('\n') 17 | // send to socket 18 | fmt.Fprintf(conn, text+"\n") 19 | // listen for reply 20 | message, _ := bufio.NewReader(conn).ReadString('\n') 21 | fmt.Print("Message from server: " + message) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /11_socket_send_receive/tcp-server.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "net" 4 | import "fmt" 5 | import "bufio" 6 | import "strings" // only needed below for sample processing 7 | 8 | func main() { 9 | 10 | fmt.Println("Launching server...") 11 | 12 | // listen on all interfaces 13 | ln, _ := net.Listen("tcp", ":8081") 14 | 15 | // accept connection on port 16 | conn, _ := ln.Accept() 17 | 18 | // run loop forever (or until ctrl-c) 19 | for { 20 | // will listen for message to process ending in newline (\n) 21 | message, _ := bufio.NewReader(conn).ReadString('\n') 22 | // output message received 23 | fmt.Print("Message Received:", string(message)) 24 | // sample process for string received 25 | newmessage := strings.ToUpper(message) 26 | // send new string back to client 27 | conn.Write([]byte(newmessage + "\n")) 28 | 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /14_read_txt_file/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Text File 3 | *.txt 4 | -------------------------------------------------------------------------------- /14_read_txt_file/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "bytes" 6 | "fmt" 7 | "io" 8 | "os" 9 | "strings" 10 | ) 11 | 12 | // Read a whole file into the memory and store it as array of lines 13 | func readLines(path string) (lines []string, err error) { 14 | var ( 15 | file *os.File 16 | part []byte 17 | prefix bool 18 | ) 19 | if file, err = os.Open(path); err != nil { 20 | return 21 | } 22 | defer file.Close() 23 | 24 | reader := bufio.NewReader(file) 25 | buffer := bytes.NewBuffer(make([]byte, 0)) 26 | for { 27 | if part, prefix, err = reader.ReadLine(); err != nil { 28 | break 29 | } 30 | buffer.Write(part) 31 | if !prefix { 32 | lines = append(lines, buffer.String()) 33 | buffer.Reset() 34 | } 35 | } 36 | if err == io.EOF { 37 | err = nil 38 | } 39 | return 40 | } 41 | 42 | func writeLines(lines []string, path string) (err error) { 43 | var ( 44 | file *os.File 45 | ) 46 | 47 | if file, err = os.Create(path); err != nil { 48 | return 49 | } 50 | defer file.Close() 51 | 52 | //writer := bufio.NewWriter(file) 53 | for _, item := range lines { 54 | //fmt.Println(item) 55 | _, err := file.WriteString(strings.TrimSpace(item) + "\n") 56 | //file.Write([]byte(item)); 57 | if err != nil { 58 | //fmt.Println("debug") 59 | fmt.Println(err) 60 | break 61 | } 62 | } 63 | /*content := strings.Join(lines, "\n") 64 | _, err = writer.WriteString(content)*/ 65 | return 66 | } 67 | 68 | func main() { 69 | lines, err := readLines("foo.txt") 70 | if err != nil { 71 | fmt.Printf("Error: %s\n", err) 72 | return 73 | } 74 | for _, line := range lines { 75 | fmt.Println(line) 76 | } 77 | //array := []string{"7.0", "8.5", "9.1"} 78 | err = writeLines(lines, "foo2.txt") 79 | fmt.Println(err) 80 | } 81 | -------------------------------------------------------------------------------- /14_read_txt_file/write_to_file.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "os" 7 | ) 8 | 9 | func main() { 10 | txtFile, err := os.Create("test.txt") 11 | if err != nil { 12 | log.Fatal("Cannot create new file", err) 13 | } 14 | defer txtFile.Close() 15 | 16 | fmt.Fprintf(txtFile, "Line 1\nLine2") 17 | } 18 | -------------------------------------------------------------------------------- /16_drop_down_menu_form/main.go-old: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/julienschmidt/httprouter" 6 | "log" 7 | "net/http" 8 | ) 9 | 10 | func index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { 11 | fmt.Fprint(w, "Welcome!\n") 12 | } 13 | 14 | func hello(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { 15 | fmt.Fprintf(w, "hello, %s!\n", ps.ByName("name")) 16 | } 17 | 18 | func main() { 19 | router := httprouter.New() 20 | router.GET("/", index) 21 | router.GET("/hello/:name", hello) 22 | 23 | log.Fatal(http.ListenAndServe(":8080", router)) 24 | } 25 | -------------------------------------------------------------------------------- /16_drop_down_menu_form/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{ . }} 4 | 5 | 6 | {{ . }} 7 |

8 | Main | 9 | List | 10 | Products | 11 | View 12 |

13 | 14 | {{ template "body" }} 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /17_mysql_user_login/another_mysql_example.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "database/sql" 5 | "fmt" 6 | "log" 7 | 8 | _ "github.com/go-sql-driver/mysql" 9 | ) 10 | 11 | const ( 12 | dbUser = "" 13 | dbPass = "" 14 | dbName = "" 15 | dbCharset = "utf8" 16 | ) 17 | 18 | func main() { 19 | db, err := sql.Open("mysql", dbUser+":"+dbPass+"@/"+dbName+"?charset="+dbCharset) 20 | if err != nil { 21 | log.Fatal("Cannot open DB connection", err) 22 | } 23 | 24 | stmt, err := db.Prepare("INSERT data SET content=?") 25 | if err != nil { 26 | log.Fatal("Cannot prepare DB statement", err) 27 | } 28 | 29 | res, err := stmt.Exec("value") 30 | if err != nil { 31 | log.Fatal("Cannot run insert statement", err) 32 | } 33 | 34 | id, _ := res.LastInsertId() 35 | 36 | fmt.Printf("Inserted row: %d", id) 37 | } 38 | -------------------------------------------------------------------------------- /17_mysql_user_login/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |

Home Page

11 | Login 12 | Sign Up 13 | All Users 14 | 15 | 16 | -------------------------------------------------------------------------------- /17_mysql_user_login/login.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |

Login Page

11 |
12 | 13 | 14 | 15 |
16 | Home page 17 | 18 | 19 | -------------------------------------------------------------------------------- /17_mysql_user_login/readme.md: -------------------------------------------------------------------------------- 1 | # Create table in MySQL database 2 | 3 | ``` 4 | CREATE TABLE go_users( 5 | id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, 6 | username VARCHAR(50), 7 | password VARCHAR(120) 8 | ); 9 | ``` 10 | 11 | Another way: 12 | 13 | ``` 14 | CREATE TABLE `go_users` ( 15 | `id` int(11) NOT NULL AUTO_INCREMENT, 16 | `username` varchar(50) DEFAULT NULL, 17 | `password` varchar(120) DEFAULT NULL, 18 | PRIMARY KEY (`id`) 19 | ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8; 20 | ``` 21 | -------------------------------------------------------------------------------- /17_mysql_user_login/signup.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |

Sign up

11 |
12 | 13 | 14 | 15 |
16 | 17 | 18 | -------------------------------------------------------------------------------- /18_cookie_authentication/login_with_pkg.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2018 Zelenko. All rights reserved. 2 | 3 | package main 4 | 5 | import ( 6 | "./sess" 7 | "fmt" 8 | ) 9 | 10 | // main is the entry point for the program. 11 | func main() { 12 | mgr := sess.NewManager() 13 | defer mgr.Close() 14 | 15 | mgr.RegisterUser("user8", "userPass5") 16 | mgr.RegisterUser("user10", "userPass61") 17 | 18 | for _, i := range mgr.ShowUsers() { 19 | fmt.Println(i) 20 | } 21 | 22 | fmt.Println("> " + mgr.RandomSession()) 23 | fmt.Println("> " + mgr.RandomSession()) 24 | fmt.Println("> " + mgr.RandomSession()) 25 | fmt.Println("> " + mgr.RandomSession()) 26 | fmt.Println("> " + mgr.RandomSession()) 27 | fmt.Println("> " + mgr.RandomSession()) 28 | fmt.Println("> " + mgr.RandomSession()) 29 | } 30 | -------------------------------------------------------------------------------- /18_cookie_authentication/users.txt: -------------------------------------------------------------------------------- 1 | ID Date Registered Hash 2 | user6 2016-04-07_08-02-06pm userPass6 3 | user1 2018-07-07_07-42-23pm userPass1 4 | user4 2018-07-07_07-42-23pm userPass4 5 | user9 2018-04-07_08-45-46pm userPass6 6 | user10 2018-04-07_09-55-56pm userPass61 7 | user5 2018-04-07_08-02-06pm userPass5 8 | user8 2018-04-07_09-55-56pm userPass5 9 | user51 2015-04-07_08-46-04pm userPass61 10 | -------------------------------------------------------------------------------- /19_os_global_variables/linux_commands.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "os/exec" 7 | ) 8 | 9 | func main() { 10 | /* 11 | // Not working on Windows 10 12 | dateCmd := exec.Command("ver") 13 | 14 | dateOut, err := dateCmd.Output() 15 | if err != nil { 16 | panic(err) 17 | } 18 | fmt.Println("> ver") 19 | fmt.Println(string(dateOut)) 20 | */ 21 | 22 | // Not working on Windows 10 23 | grepCmd := exec.Command("ver") 24 | grepIn, err := grepCmd.StdinPipe() 25 | if err != nil { 26 | panic(err) 27 | } 28 | grepOut, err := grepCmd.StdoutPipe() 29 | if err != nil { 30 | panic(err) 31 | } 32 | grepCmd.Start() 33 | grepIn.Write([]byte("hello grep\ngoodbye grep")) 34 | grepIn.Close() 35 | grepBytes, _ := ioutil.ReadAll(grepOut) 36 | grepCmd.Wait() 37 | 38 | fmt.Println("> ver") 39 | fmt.Println(string(grepBytes)) 40 | 41 | } 42 | -------------------------------------------------------------------------------- /19_os_global_variables/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | ) 7 | 8 | func main() { 9 | // Works on Windows 10 10 | fmt.Println(os.Getenv("GOPATH")) 11 | 12 | // Works on Windows 10; Shows all the Environmental variables 13 | list := os.Environ() 14 | for i := range list { 15 | fmt.Println(list[i]) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /19_os_global_variables/osCommand.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "syscall" 4 | import "os" 5 | import "os/exec" 6 | 7 | func main() { 8 | 9 | // Not working on Windows 10 10 | // Will it work on Linux? 11 | binary, lookErr := exec.LookPath("ver") 12 | if lookErr != nil { 13 | panic(lookErr) 14 | } 15 | 16 | args := []string{""} 17 | 18 | env := os.Environ() 19 | 20 | execErr := syscall.Exec(binary, args, env) 21 | if execErr != nil { 22 | panic(execErr) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /20_mongodb_crud/README.md: -------------------------------------------------------------------------------- 1 | # Notes 2 | #### Make a request via Curl 3 | ``` 4 | curl -i 192.168.0.2:8080/items 5 | ``` 6 | 7 | 8 | #### Insert items using Curl 9 | ``` 10 | curl -i -X POST -d "isbn=001-8484314701&title=How to run Windows&author=Bill Gates&price=1.90" 192.168.0.2:8080/items/create/process 11 | ``` 12 | 13 | #### Insert items in MongoDB shell 14 | ``` 15 | db.books.insert([{"isbn":"978-1505255607","title":"The Time Machine","author":"H. G. Wells","price":5.99},{"isbn":"978-1503261960","title":"Wind Sand \u0026 Stars","author":"Antoine","price":14.99},{"isbn":"978-1503261961","title":"West With The Night","author":"Beryl Markham","price":14.99}]) 16 | ``` -------------------------------------------------------------------------------- /20_mongodb_crud/config/db.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "dblogin" 5 | "fmt" 6 | "gopkg.in/mgo.v2" 7 | ) 8 | 9 | // DB variables 10 | var ( 11 | DB *mgo.Database 12 | Books *mgo.Collection 13 | ) 14 | 15 | func init() { 16 | // S get a mongo sessions 17 | s, err := mgo.Dial(dblogin.Bookstore) // mongodb://username:yourpasscode@serverip:27017/database?authSource=admin 18 | if err != nil { 19 | panic(err) 20 | } 21 | 22 | if err = s.Ping(); err != nil { 23 | panic(err) 24 | } 25 | 26 | DB = s.DB("bookstore") 27 | Books = DB.C("books") 28 | 29 | fmt.Println("You connected to your mongo database.") 30 | } 31 | -------------------------------------------------------------------------------- /20_mongodb_crud/config/tpl.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import "html/template" 4 | 5 | // TPL is all the HTML templates in the "templates" folder 6 | var TPL *template.Template 7 | 8 | func init() { 9 | TPL = template.Must(template.ParseGlob("templates/*.gohtml")) 10 | } 11 | -------------------------------------------------------------------------------- /20_mongodb_crud/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "./records" 5 | "fmt" 6 | "github.com/julienschmidt/httprouter" 7 | "net/http" 8 | ) 9 | 10 | func main() { 11 | fmt.Println("HTTP port :3000") 12 | r := httprouter.New() // methods GET, POST, PUT, PATCH and DELETE 13 | 14 | r.GET("/", index) 15 | r.GET("/items", records.Index) 16 | http.Handle("/favicon.ico", http.NotFoundHandler()) 17 | r.GET("/items/show", records.Show) 18 | r.GET("/items/create", records.Create) 19 | r.POST("/items/create/process", records.CreateProcess) 20 | r.GET("/items/update", records.Update) 21 | r.POST("/items/update/process", records.UpdateProcess) 22 | r.GET("/items/delete/process", records.DeleteProcess) 23 | http.ListenAndServe(":3000", r) 24 | } 25 | 26 | // redirect 27 | func index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { 28 | http.Redirect(w, r, "/items", http.StatusSeeOther) 29 | } 30 | -------------------------------------------------------------------------------- /20_mongodb_crud/templates/books.gohtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | All Books 6 | 28 | 29 | 30 | {{range .}} 31 |

{{.Isbn}} - {{.Title}} - {{.Author}} - {{.Price}} - update - delete

32 | {{end}} 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /20_mongodb_crud/templates/create.gohtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Create Book 6 | 26 | 27 | 28 | 29 |

Create A New Book

30 |
31 | 32 | 33 | 34 | 35 | 36 |
37 | 38 | 39 | -------------------------------------------------------------------------------- /20_mongodb_crud/templates/created.gohtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Created Book 6 | 28 | 29 | 30 | 31 |

Created A New Book

32 | 33 |

{{.Isbn}} - {{.Title}} - {{.Author}} {{.Price}}

34 | 35 | 36 | -------------------------------------------------------------------------------- /20_mongodb_crud/templates/show.gohtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | One Book 6 | 28 | 29 | 30 | 31 |

{{.Isbn}} - {{.Title}} - {{.Author}} {{.Price}}

32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /20_mongodb_crud/templates/update.gohtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Create Book 6 | 26 | 27 | 28 | 29 |

Update A Book

30 |
31 | 32 | 33 | 34 | 35 | 36 |
37 | 38 | 39 | -------------------------------------------------------------------------------- /20_mongodb_crud/templates/updated.gohtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Create Book 6 | 28 | 29 | 30 | 31 |

Updated Book

32 | 33 |

{{.Isbn}} - {{.Title}} - {{.Author}} {{.Price}}

34 | 35 | 36 | -------------------------------------------------------------------------------- /21_httprouter_template/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/julienschmidt/httprouter" 6 | "html/template" 7 | "net/http" 8 | ) 9 | 10 | var tpl *template.Template 11 | 12 | func init() { 13 | tpl = template.Must(template.ParseGlob("templates/*.html")) 14 | } 15 | 16 | func index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { 17 | err := tpl.ExecuteTemplate(w, "page-02.html", nil) 18 | checkErr(err) 19 | } 20 | 21 | func serveTemplate(w http.ResponseWriter, r *http.Request, params httprouter.Params) { 22 | // Declare template 23 | //tpl, err := template.ParseFiles(fp) // can have multiple, separated by comas 24 | 25 | output := params.ByName("tmpl") + " | " + r.URL.Path 26 | 27 | // Run template 28 | if err := tpl.ExecuteTemplate(w, "page.html", output); err != nil { 29 | checkErr(err) 30 | // Return a generic "Internal Server Error" message 31 | // http.Error(w, http.StatusText(500), 500) 32 | } 33 | } 34 | 35 | func checkErr(err error) { 36 | if err != nil { 37 | fmt.Println("Error: ", err.Error()) 38 | } 39 | } 40 | 41 | func main() { 42 | fmt.Println("Listeting on port 8080") 43 | r := httprouter.New() 44 | r.ServeFiles("/static/*filepath", http.Dir("static")) 45 | r.GET("/", index) 46 | r.GET("/test/:tmpl", serveTemplate) 47 | http.ListenAndServe("localhost:8080", r) 48 | } 49 | -------------------------------------------------------------------------------- /21_httprouter_template/static/index.html: -------------------------------------------------------------------------------- 1 | test static/index.html
2 | main
3 | -------------------------------------------------------------------------------- /21_httprouter_template/static/mongodb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zelenko/go/2c97fc39fc36510054ca51a57b7659976a02dd4d/21_httprouter_template/static/mongodb.png -------------------------------------------------------------------------------- /21_httprouter_template/templates/footer.html: -------------------------------------------------------------------------------- 1 | {{define "footer"}} 2 | 3 | 4 | 5 | 6 | {{end}} 7 | -------------------------------------------------------------------------------- /21_httprouter_template/templates/header.html: -------------------------------------------------------------------------------- 1 | {{define "template-one"}}
content - one{{end}} 2 | 3 | 4 | {{define "header"}} 5 | 6 | 7 | 8 | 9 | {{ . }} 10 | 33 | 34 | 35 | {{end}} -------------------------------------------------------------------------------- /21_httprouter_template/templates/page-02.html: -------------------------------------------------------------------------------- 1 | {{define "sub-template"}}
content{{end}} 2 | {{template "header"}} 3 | 4 |

5 | main page | 6 | 00 | 7 | 01 | 8 | 02 | 9 | 03 | 10 | static | 11 | {{template "sub-template"}} 12 | {{template "template-one"}}
13 | {{ . }} 14 |

15 | 16 | 17 | 18 | {{template "footer"}} 19 | -------------------------------------------------------------------------------- /21_httprouter_template/templates/page.html: -------------------------------------------------------------------------------- 1 | {{define "sub-template"}}
content{{end}} 2 | {{template "header"}} 3 | 4 |

5 | main | 6 | 00 | 7 | 01 | 8 | 02 | 9 | 03 | 10 | static | 11 | {{template "sub-template"}} 12 | {{template "template-one"}}
13 | {{ . }} 14 |

15 | 16 | 17 | 18 | {{template "footer"}} 19 | -------------------------------------------------------------------------------- /22_mongodb_crud_rest_html/config/db.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "dblogin" 5 | "fmt" 6 | "gopkg.in/mgo.v2" 7 | ) 8 | 9 | // DB variables 10 | var ( 11 | DB *mgo.Database 12 | OS *mgo.Database 13 | Books *mgo.Collection 14 | Products3 *mgo.Collectio 15 | ) 16 | 17 | func init() { 18 | // get a mongo sessions 19 | s, err := mgo.Dial(dblogin.Bookstore) // mongodb://username:yourpasscode@serverip:27017/database?authSource=admin 20 | if err != nil { 21 | panic(err) 22 | } 23 | 24 | if err = s.Ping(); err != nil { 25 | panic(err) 26 | } 27 | 28 | DB = s.DB("bookstore") 29 | Books = DB.C("books") 30 | 31 | OS = s.DB("onlinestore") 32 | Products3 = OS.C("products3") 33 | 34 | fmt.Println("You connected to your mongo database.") 35 | } 36 | -------------------------------------------------------------------------------- /22_mongodb_crud_rest_html/config/tpl.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import "html/template" 4 | 5 | // TPL are all the html templates in the "templates" folder 6 | var TPL *template.Template 7 | 8 | func init() { 9 | TPL = template.Must(template.ParseGlob("templates/*.gohtml")) 10 | } 11 | -------------------------------------------------------------------------------- /22_mongodb_crud_rest_html/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "./records" 5 | "github.com/julienschmidt/httprouter" 6 | "net/http" 7 | ) 8 | 9 | func main() { 10 | r := httprouter.New() 11 | r.ServeFiles("/static/*filepath", http.Dir("static")) 12 | r.GET("/", index) 13 | r.GET("/items", records.Index) 14 | r.GET("/items/show", records.Show) 15 | r.GET("/items/create", records.Create) 16 | r.POST("/items/create/process", records.CreateProcess) 17 | r.GET("/items/update", records.Update) 18 | r.POST("/items/update/process", records.UpdateProcess) 19 | r.GET("/items/delete/process", records.DeleteProcess) 20 | r.GET("/old", records.OldDesign) 21 | http.ListenAndServe(":2080", r) 22 | } 23 | 24 | func index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { 25 | http.Redirect(w, r, "/items", http.StatusSeeOther) 26 | } 27 | -------------------------------------------------------------------------------- /22_mongodb_crud_rest_html/static/greynoise1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zelenko/go/2c97fc39fc36510054ca51a57b7659976a02dd4d/22_mongodb_crud_rest_html/static/greynoise1.png -------------------------------------------------------------------------------- /22_mongodb_crud_rest_html/static/index.html: -------------------------------------------------------------------------------- 1 | test static/index.html
2 | main
3 | -------------------------------------------------------------------------------- /22_mongodb_crud_rest_html/static/mongodb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zelenko/go/2c97fc39fc36510054ca51a57b7659976a02dd4d/22_mongodb_crud_rest_html/static/mongodb.png -------------------------------------------------------------------------------- /22_mongodb_crud_rest_html/templates/books.gohtml: -------------------------------------------------------------------------------- 1 | {{template "header"}} 2 | 3 | 4 | 5 | 6 | {{range .}} 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | {{end}} 15 |
ISBNTitleAuthor - PriceUpdateDelete
{{.Isbn}}{{.Title}}{{.Author}} - {{.Price}}updatedelete
16 | 17 | 18 | 19 | {{template "footer"}} -------------------------------------------------------------------------------- /22_mongodb_crud_rest_html/templates/create.gohtml: -------------------------------------------------------------------------------- 1 | {{template "header"}} 2 | 3 |

Create A New Book

4 |
5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | {{template "footer"}} -------------------------------------------------------------------------------- /22_mongodb_crud_rest_html/templates/created.gohtml: -------------------------------------------------------------------------------- 1 | {{template "header"}} 2 | 3 |

Created A New Book

4 | 5 |

{{.Isbn}} - {{.Title}} - {{.Author}} {{.Price}}

6 | 7 | {{template "footer"}} -------------------------------------------------------------------------------- /22_mongodb_crud_rest_html/templates/old.gohtml: -------------------------------------------------------------------------------- 1 | {{template "header"}} 2 | 3 | 4 | 5 | 6 | 7 | {{range .}} 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | {{end}} 16 | 17 |
Product ID & BuylineProduct DescriptionOnhand: BRID12 Mo SalesCategory
{{.Pline}}{{.Bline}}{{.Category}} -{{.Price}}--
18 | 19 | {{template "footer"}} 20 | -------------------------------------------------------------------------------- /22_mongodb_crud_rest_html/templates/show.gohtml: -------------------------------------------------------------------------------- 1 | {{template "header"}} 2 | 3 |

{{.Isbn}} - {{.Title}} - {{.Author}} {{.Price}}

4 | 5 | 6 | {{template "footer"}} -------------------------------------------------------------------------------- /22_mongodb_crud_rest_html/templates/update.gohtml: -------------------------------------------------------------------------------- 1 | {{template "header"}} 2 | 3 |

Update A Book

4 |
5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | {{template "footer"}} -------------------------------------------------------------------------------- /22_mongodb_crud_rest_html/templates/updated.gohtml: -------------------------------------------------------------------------------- 1 | {{template "header"}} 2 |

Updated Book

3 | 4 |

{{.Isbn}} - {{.Title}} - {{.Author}} {{.Price}}

5 | 6 | {{template "footer"}} -------------------------------------------------------------------------------- /23_file_uploader/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | _ "fmt" 5 | "html/template" 6 | "io/ioutil" 7 | "net/http" 8 | "os" 9 | "path/filepath" 10 | ) 11 | 12 | var tpl *template.Template 13 | 14 | func init() { 15 | tpl = template.Must(template.ParseGlob("templates/*")) 16 | } 17 | 18 | func main() { 19 | http.HandleFunc("/", foo) 20 | http.Handle("/favicon.ico", http.NotFoundHandler()) 21 | http.ListenAndServe(":8080", nil) 22 | } 23 | 24 | func foo(w http.ResponseWriter, req *http.Request) { 25 | 26 | var s string 27 | if req.Method == http.MethodPost { 28 | 29 | // open 30 | f, h, err := req.FormFile("q") 31 | if err != nil { 32 | http.Error(w, err.Error(), http.StatusInternalServerError) 33 | return 34 | } 35 | defer f.Close() 36 | 37 | // for your information 38 | //fmt.Println("\nfile:", f, "\nheader:", h, "\nerr", err) 39 | //fmt.Println("\nheader:", h, "\nerr", err) 40 | 41 | // read 42 | bs, err := ioutil.ReadAll(f) 43 | if err != nil { 44 | http.Error(w, err.Error(), http.StatusInternalServerError) 45 | return 46 | } 47 | // s = string(bs) 48 | s = "File was received." 49 | 50 | // store on server 51 | dst, err := os.Create(filepath.Join("./saved_files/", h.Filename)) 52 | if err != nil { 53 | http.Error(w, err.Error(), http.StatusInternalServerError) 54 | return 55 | } 56 | defer dst.Close() 57 | 58 | _, err = dst.Write(bs) 59 | if err != nil { 60 | http.Error(w, err.Error(), http.StatusInternalServerError) 61 | } 62 | } 63 | 64 | w.Header().Set("Content-Type", "text/html; charset=utf-8") 65 | tpl.ExecuteTemplate(w, "index.gohtml", s) 66 | } 67 | -------------------------------------------------------------------------------- /23_file_uploader/templates/include-footer.gohtml: -------------------------------------------------------------------------------- 1 | {{define "footer"}} 2 | 3 | 4 | {{end}} -------------------------------------------------------------------------------- /23_file_uploader/templates/include-header.gohtml: -------------------------------------------------------------------------------- 1 | {{define "header"}} 2 | 3 | 4 | 5 | 6 | Document 7 | 8 | 9 | {{end}} -------------------------------------------------------------------------------- /23_file_uploader/templates/index.gohtml: -------------------------------------------------------------------------------- 1 | {{template "header"}} 2 | 3 |
4 | 5 | 6 |
7 | 8 |
9 | 10 | {{if .}} 11 | {{.}} 12 | {{end}} 13 | 14 | {{template "footer"}} -------------------------------------------------------------------------------- /24_calculate_time/EST.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func main() { 9 | t := time.Now() 10 | z, _ := t.Zone() 11 | fmt.Println("ZONE : ", z, " Time : ", t) // local time 12 | 13 | location, err := time.LoadLocation("EST") 14 | if err != nil { 15 | fmt.Println(err) 16 | } 17 | fmt.Println("ZONE : ", location, " Time : ", t.In(location)) // EST 18 | 19 | loc, _ := time.LoadLocation("UTC") 20 | now := time.Now().In(loc) 21 | fmt.Println("ZONE : ", loc, " Time : ", now) // UTC 22 | 23 | loc, _ = time.LoadLocation("MST") 24 | now = time.Now().In(loc) 25 | fmt.Println("ZONE : ", loc, " Time : ", now) // MST 26 | 27 | year, week := t.ISOWeek() 28 | fmt.Println("week: ", week, ", Year: ", year) 29 | } 30 | -------------------------------------------------------------------------------- /24_calculate_time/calculate_months.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func main() { 9 | originalTime := time.Date(2011, 9, 2, 0, 0, 0, 0, time.UTC) 10 | fmt.Println("months:", countMonthsSince(originalTime)) 11 | 12 | originalTime = time.Date(2018, 9, 2, 0, 0, 0, 0, time.UTC) 13 | fmt.Println("months:", countMonthsSince(originalTime)) 14 | 15 | originalTime = time.Date(2017, 9, 2, 0, 0, 0, 0, time.UTC) 16 | fmt.Println("months:", countMonthsSince(originalTime)) 17 | } 18 | 19 | // countMonthsSince calculates the months between now 20 | // and the createdAtTime time.Time value passed 21 | func countMonthsSince(createdAtTime time.Time) int { 22 | now := time.Now() 23 | months := 0 24 | month := createdAtTime.Month() 25 | for createdAtTime.Before(now) { // loop through months until current month 26 | createdAtTime = createdAtTime.Add(time.Hour * 24) // add one day 27 | nextMonth := createdAtTime.Month() // get the month 28 | if nextMonth != month { // if not current month then increment 29 | months++ 30 | } 31 | month = nextMonth 32 | } 33 | 34 | return months 35 | } 36 | -------------------------------------------------------------------------------- /24_calculate_time/dayInterval.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func main() { 9 | oneDay := 24 * time.Hour 10 | start := time.Unix(1485307713, 0) 11 | end := time.Unix(1516411773, 0) 12 | rounded := time.Date(start.Year(), start.Month(), start.Day(), 0, 0, 0, 0, time.UTC) 13 | 14 | // print all dates from start date to end date 15 | for rounded.Before(end) { 16 | fmt.Println(rounded) 17 | rounded = rounded.Add(oneDay) 18 | } 19 | } 20 | 21 | // Bod is Begining of Day 22 | func Bod(t time.Time) time.Time { 23 | year, month, day := t.Date() 24 | return time.Date(year, month, day, 0, 0, 0, 0, t.Location()) 25 | } 26 | 27 | // Eod is End of Day 28 | func Eod(t time.Time) time.Time { 29 | year, month, day := t.Date() 30 | return time.Date(year, month, day, 0, 0, 0, 0, t.Location()).Add((-1 + (24 * 60 * 60)) * time.Second) 31 | } 32 | -------------------------------------------------------------------------------- /24_calculate_time/filename.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func main() { 9 | filename := time.Now().Format("2006-01-02_03-04-05pm") + ".csv" 10 | fmt.Printf(filename) 11 | 12 | filename = time.Now().Format("2006-01-02_3pm") + ".csv" 13 | fmt.Printf(filename) 14 | } 15 | -------------------------------------------------------------------------------- /24_calculate_time/func_execution_time.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "time" 6 | ) 7 | 8 | func main() { 9 | // Add these two lines to show function execution time 10 | stop := StartTimer("exampleFunc") 11 | defer stop() 12 | 13 | time.Sleep(1 * time.Second) 14 | } 15 | 16 | // StartTimer measures time it took to run function 17 | func StartTimer(name string) func() { 18 | startTime := time.Now() 19 | log.Println(name, "started") 20 | return func() { 21 | duration := time.Now().Sub(startTime) 22 | log.Println(name, "took", duration) 23 | 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /24_calculate_time/hours_since_then.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | import "time" 5 | 6 | func main() { 7 | // Create new date. 8 | a := time.Date(2018, 4, 11, 0, 0, 0, 0, time.UTC) 9 | 10 | delta := time.Now().Sub(a) 11 | fmt.Println(delta.Hours()) 12 | 13 | duration := time.Since(a) 14 | fmt.Println(duration.Hours()) 15 | } 16 | -------------------------------------------------------------------------------- /24_calculate_time/listWeeks.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | // defining Day and Week 9 | const ( 10 | Day = 24 * time.Hour 11 | Week = 7 * Day 12 | ) 13 | 14 | func main() { 15 | now := time.Now() 16 | 17 | // print weeks, from newest to oldest 18 | for i := 1; i < 50; i++ { 19 | fmt.Println(Time(now.Add(Week * (-time.Duration(i))))) // subtract week for each iteration 20 | } 21 | } 22 | 23 | // Time return as end of day as a string (example 11:59pm) 24 | func Time(then time.Time) string { 25 | //then = Bod(then) 26 | then = Eod(then) 27 | return then.Format("2006-01-02_03-04-05pm") 28 | //return then.Format("January 2, 2006") 29 | } 30 | 31 | // Bod is Beginning of day 32 | func Bod(t time.Time) time.Time { 33 | year, month, day := t.Date() 34 | return time.Date(year, month, day, 0, 0, 0, 0, t.Location()) 35 | } 36 | 37 | // Eod End of day 38 | func Eod(t time.Time) time.Time { 39 | year, month, day := t.Date() 40 | return time.Date(year, month, day, 0, 0, 0, 0, t.Location()).Add(((24 * 60 * 60) - 1) * time.Second) 41 | } 42 | -------------------------------------------------------------------------------- /24_calculate_time/milliseconds.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | "time" 7 | ) 8 | 9 | func main() { 10 | start := time.Now() 11 | time.Sleep(1 * time.Millisecond) 12 | 13 | println(strconv.FormatInt(time.Since(start).Nanoseconds()/int64(time.Millisecond), 10)) 14 | println(strconv.FormatInt(time.Since(start).Nanoseconds()/(int64(time.Millisecond)/int64(time.Nanosecond)), 10)) 15 | println(time.Since(start)) 16 | println(time.Since(start).Seconds()) 17 | fmt.Printf("Seconds [%v]", time.Since(start)) 18 | 19 | diff := now.Sub(start) 20 | second := int(diff.Seconds()) 21 | fmt.Printf("Diffrence in Seconds : %d Seconds\n", second) 22 | } 23 | -------------------------------------------------------------------------------- /24_calculate_time/unix_time_stamp.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func main() { 9 | fmt.Println("unix:", time.Now().Unix()) 10 | fmt.Println("now:", time.Unix(time.Now().Unix(), 0).Format("2006-01-02_03-04-05pm MST")) // 2001-09-31_09-05-03am 11 | fmt.Println("old date:", time.Unix(int64(1009807503), 0).Format("2006-01-02_03-04-05pm MST")) // 2001-09-31_09-05-03am 12 | } 13 | -------------------------------------------------------------------------------- /24_calculate_time/week_of_the_year.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func main() { 9 | year, month, day := time.Now().Date() 10 | fmt.Println("Year : ", year) 11 | fmt.Println("Month : ", month) 12 | fmt.Println("Day : ", day) 13 | fmt.Println("DayYear:", time.Now().YearDay()) 14 | 15 | _, week := time.Now().ISOWeek() 16 | fmt.Println("Week : ", week) 17 | 18 | hour, min, sec := time.Now().Clock() 19 | fmt.Println("Hour : ", hour) 20 | fmt.Println("Min : ", min) 21 | fmt.Println("Sec : ", sec) 22 | 23 | if month == time.November && day == 10 { 24 | fmt.Println("Happy Go day!") 25 | } 26 | } 27 | 28 | // https://www.socketloop.com/tutorials/golang-how-to-get-year-month-and-day/?utm_source=socketloop&utm_medium=search 29 | -------------------------------------------------------------------------------- /24_calculate_time/weekday.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func main() { 9 | t, _ := time.Parse("2006 01 02 15 04", "2015 11 11 16 50") 10 | fmt.Println(t.YearDay()) // 315 11 | fmt.Println(t.Weekday()) // Wednesday 12 | 13 | t, _ = time.Parse("2006 01 02 15 04", "2018 04 12 0 00") 14 | fmt.Println(t.YearDay()) 15 | fmt.Println(t.Weekday()) 16 | } 17 | -------------------------------------------------------------------------------- /25_https_static_files/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "./webpage" 5 | "github.com/julienschmidt/httprouter" 6 | "log" 7 | "net/http" 8 | ) 9 | 10 | func main() { 11 | log.Println("HTTPS port :443") 12 | log.Println("HTTP port :80") 13 | 14 | r := httprouter.New() 15 | r.GET("/", webpage.Secure) 16 | r.GET("/test/", webpage.Test) 17 | r.GET("/test", webpage.Test2) 18 | r.GET("/v", webpage.List) 19 | r.GET("/html", webpage.HTMLPage) 20 | r.NotFound = http.FileServer(http.Dir("public")) 21 | 22 | // r.ServeFiles("/static/*filepath", http.Dir("/var/www/public/")) 23 | // http.Handle("/resources/", http.StripPrefix("/resources/", http.FileServer(http.Dir("/home/www/")))) 24 | 25 | // Start HTTP 26 | go func() { 27 | // redirect all HTTP to HTTPS 28 | err := http.ListenAndServe(":80", http.HandlerFunc(webpage.Redirect)) 29 | if err != nil { 30 | log.Fatalln("Web server (HTTP): ", err) 31 | } 32 | }() 33 | 34 | // Start HTTPS 35 | err := http.ListenAndServeTLS(":443", "cert.pem", "key.pem", r) 36 | if err != nil { 37 | log.Fatal("Web server (HTTPS): ", err) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /25_https_static_files/public/index.gohtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | index.gohtml 4 | 5 | 6 |

index.gohtml in public folder

7 |

8 | main | 9 | /test/ | 10 | /test | 11 | index.gohtml | 12 | html | 13 | 14 | 15 |

16 | 17 | 18 | -------------------------------------------------------------------------------- /26_url_not_found_handler/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | "os" 7 | "path" 8 | ) 9 | 10 | // NotFound displays custom page 11 | func NotFound(w http.ResponseWriter, r *http.Request) { 12 | fmt.Fprintf(w, "my 404 page!") 13 | } 14 | 15 | // FileServerWithCustom404 servers files 16 | func FileServerWithCustom404(fs http.FileSystem) http.Handler { 17 | fsh := http.FileServer(fs) 18 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 19 | _, err := fs.Open(path.Clean(r.URL.Path)) 20 | if os.IsNotExist(err) { 21 | NotFound(w, r) 22 | return 23 | } 24 | fsh.ServeHTTP(w, r) 25 | }) 26 | } 27 | 28 | func main() { 29 | http.ListenAndServe(":80", FileServerWithCustom404(http.Dir("public"))) 30 | } 31 | -------------------------------------------------------------------------------- /26_url_not_found_handler/public/img/toby.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zelenko/go/2c97fc39fc36510054ca51a57b7659976a02dd4d/26_url_not_found_handler/public/img/toby.jpg -------------------------------------------------------------------------------- /26_url_not_found_handler/public/test.txt: -------------------------------------------------------------------------------- 1 | test file -------------------------------------------------------------------------------- /26_url_not_found_handler/test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/julienschmidt/httprouter" 6 | "net/http" 7 | ) 8 | 9 | // RegularPage displays custom page 10 | func RegularPage(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { 11 | fmt.Fprintf(w, "Regular page!") 12 | } 13 | 14 | func main() { 15 | RunServer(":80") 16 | } 17 | 18 | // MyNotFound test 19 | func MyNotFound(w http.ResponseWriter, r *http.Request) { 20 | w.Header().Set("Content-Type", "text/plain; charset=utf-8") 21 | w.WriteHeader(http.StatusNotFound) // StatusNotFound = 404 22 | w.Write([]byte("My own Not Found handler.")) 23 | w.Write([]byte(" The page you requested could not be found.")) 24 | } 25 | 26 | // RunServer test 27 | func RunServer(host string) error { 28 | r := httprouter.New() 29 | r.GET("/", RegularPage) 30 | r.GET("/test/", RegularPage) 31 | //r.NotFound = http.FileServer(http.Dir("public")) 32 | r.ServeFiles("/public/*filepath", http.Dir("public")) 33 | r.NotFound = http.HandlerFunc(MyNotFound) 34 | return http.ListenAndServe(host, r) 35 | } 36 | -------------------------------------------------------------------------------- /27_mongodb_bulk_upsert/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # text 3 | *.txt 4 | -------------------------------------------------------------------------------- /28_markdown/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/russross/blackfriday" 7 | ) 8 | 9 | // main is the entry point for the program 10 | func main() { 11 | http.HandleFunc("/markdown", GenerateMarkdown) 12 | http.Handle("/", http.FileServer(http.Dir("public"))) 13 | http.ListenAndServe(":8080", nil) 14 | } 15 | 16 | // GenerateMarkdown is func 17 | func GenerateMarkdown(rw http.ResponseWriter, r *http.Request) { 18 | markdown := blackfriday.MarkdownCommon([]byte(r.FormValue("body"))) 19 | rw.Write(markdown) 20 | } 21 | -------------------------------------------------------------------------------- /28_markdown/public/index.gohtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 |
10 |

Markdown Generator

11 |

Generate your markdown with Go

12 |
13 |
14 | 15 |
16 |
17 | 18 |
19 | 20 |
21 | 22 |
23 |
24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /29_go_crud_json_api/public/post_only.gohtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Post Only - No Form 8 | 21 | 22 | 23 |

This is to test the API 24 |

Sending data in JSON format using POST method 25 |

This is working by opening http://localhost/post_only.gohtml in browser 26 | 27 | -------------------------------------------------------------------------------- /29_go_crud_json_api/public/post_only_form.gohtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Post Only Form 8 | 34 | 35 | 36 | 37 | 38 | 39 |

40 | 41 | 42 | 43 |
44 | 45 | 46 | -------------------------------------------------------------------------------- /29_go_crud_json_api/readme.md: -------------------------------------------------------------------------------- 1 | # Curl commands 2 | ## Get all records, both commands return the same results 3 | `curl -i 192.168.1.2:3000/todos` 4 | 5 | `curl -i -X GET 192.168.1.2:3000/todos` 6 | 7 | ## Create record 8 | `curl -i -X POST -d '{"description":"How to run Windows","complete":false}' 192.168.1.2:3000/todos` 9 | 10 | ## Update. If record does not exist, creates new record. 11 | `curl -i -X PUT -d '{"description":"How to run Linux","complete":false}' 192.168.1.2:3000/todos/2` 12 | 13 | ## Update record, but description field becomes blank 14 | `curl -i -X PUT -d '{"complete":true}' 192.168.1.2:3000/todos/2` 15 | 16 | ## DELETE record 17 | `curl -i -X DELETE 192.168.1.2:3000/todos/2` 18 | -------------------------------------------------------------------------------- /30_mongodb_crud_json_api/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Configuration 3 | config.toml 4 | -------------------------------------------------------------------------------- /30_mongodb_crud_json_api/config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "github.com/BurntSushi/toml" 5 | "log" 6 | ) 7 | 8 | // Configuration Represents database server and credentials 9 | type Configuration struct { 10 | Server string 11 | Database string 12 | } 13 | 14 | // Read and parse the configuration file 15 | func (c *Configuration) Read() { 16 | if _, err := toml.DecodeFile("config.toml", &c); err != nil { 17 | log.Fatal(err) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /30_mongodb_crud_json_api/models/movie.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import "gopkg.in/mgo.v2/bson" 4 | 5 | // Movie struct uses bson keyword to tell the mgo driver how to name 6 | // the properties in mongodb document 7 | type Movie struct { 8 | ID bson.ObjectId `bson:"_id" json:"id"` 9 | Name string `bson:"name" json:"name"` 10 | CoverImage string `bson:"cover_image" json:"cover_image"` 11 | Description string `bson:"description" json:"description"` 12 | } 13 | -------------------------------------------------------------------------------- /30_mongodb_crud_json_api/sample-config.toml: -------------------------------------------------------------------------------- 1 | server="mongodb://username:yourpasscode@serverip:27017/database?authSource=admin" 2 | database="bockstore" 3 | -------------------------------------------------------------------------------- /31_send_email/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "crypto/tls" 5 | 6 | "gopkg.in/gomail.v2" 7 | ) 8 | 9 | func main() { 10 | 11 | // Send emails using d. 12 | 13 | m := gomail.NewMessage() 14 | m.SetHeader("From", "alex@example.com") 15 | m.SetHeader("To", "bob@example.com", "cora@example.com") 16 | m.SetAddressHeader("Cc", "dan@example.com", "Dan") 17 | m.SetHeader("Subject", "Hello!") 18 | m.SetBody("text/html", "Hello Bob and Cora!") 19 | m.Attach("/home/Alex/lolcat.jpg") 20 | 21 | d := gomail.NewDialer("smtp.example.com", 587, "user", "123456") 22 | 23 | d.TLSConfig = &tls.Config{InsecureSkipVerify: true} 24 | // Send the email to Bob, Cora and Dan. 25 | if err := d.DialAndSend(m); err != nil { 26 | panic(err) 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /31_send_email/main.goNEW: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "crypto/tls" 5 | 6 | "gopkg.in/gomail.v2" 7 | ) 8 | 9 | func main() { 10 | 11 | // Send emails using d. 12 | 13 | m := gomail.NewMessage() 14 | m.SetHeader("From", "dan@example.com") 15 | m.SetHeader("To", "dan@example.com") 16 | //m.SetAddressHeader("Cc", "dan@example.com", "Dan") 17 | m.SetHeader("Subject", "Hello!") 18 | m.SetBody("text/html", "Hello Bob and Cora!") 19 | //m.Attach("/home/Alex/lolcat.jpg") 20 | 21 | // Common SMTP ports: 25 or 2525 or 587 22 | // NewDialer(host string, port int, username, password string) 23 | d := gomail.NewDialer("192.168.100.10", 25, "", "") 24 | 25 | d.TLSConfig = &tls.Config{InsecureSkipVerify: true} 26 | // Send the email to Bob, Cora and Dan. 27 | if err := d.DialAndSend(m); err != nil { 28 | panic(err) 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /32_colorful_cli/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/fatih/color" 6 | ) 7 | 8 | func main() { 9 | minion := color.New(color.FgBlue).Add(color.BgYellow).Add(color.Bold) 10 | minion.Println("Minion says: banana!!!!!!") 11 | 12 | m := minion.PrintlnFunc() 13 | m("I want another banana!!!!!") 14 | 15 | //slantedRed := color.New(color.FgRed, color.BgWhite, color.Italic).SprintFunc() 16 | slantedRed := color.New(color.FgRed, color.BgWhite, color.Bold).SprintFunc() 17 | fmt.Println("I've made a huge", slantedRed("mistake")) 18 | 19 | color.Red("Roses are red") 20 | color.Blue("Violets are blue") 21 | 22 | // Print with default helper functions 23 | color.Cyan("Prints text in cyan.") 24 | 25 | // A newline will be appended automatically 26 | color.Blue("Prints %s in blue.", "text") 27 | 28 | // These are using the default foreground colors 29 | color.Red("We have red") 30 | color.Magenta("And many others ..") 31 | 32 | // Use handy standard colors 33 | color.Set(color.FgYellow) 34 | 35 | fmt.Println("Existing text will now be in yellow") 36 | fmt.Printf("This one %s\n", "too") 37 | 38 | color.Unset() // Don't forget to unset 39 | 40 | // You can mix up parameters 41 | color.Set(color.FgMagenta, color.Bold) 42 | fmt.Println("All text will now be bold magenta.") 43 | color.Unset() // Use it in your function 44 | 45 | red := color.New(color.FgRed) 46 | whiteBackground := red.Add(color.BgWhite) 47 | whiteBackground.Println("Red text with white background.") 48 | 49 | } 50 | -------------------------------------------------------------------------------- /33_testing/game_test.go: -------------------------------------------------------------------------------- 1 | package vanilla 2 | 3 | import "testing" 4 | 5 | func TestGutterBalls(t *testing.T) { 6 | t.Log("Rolling all gutter balls... (expected score: 0)") 7 | game := NewGame() 8 | game.rollMany(20, 0) 9 | 10 | if score := game.Score(); score != 0 { 11 | t.Errorf("Expected score of 0, but it was %d instead.", score) 12 | } 13 | } 14 | 15 | func TestOnePinOnEveryThrow(t *testing.T) { 16 | t.Log("Each throw knocks down one pin... (expected score: 20)") 17 | game := NewGame() 18 | game.rollMany(20, 1) 19 | 20 | if score := game.Score(); score != 20 { 21 | t.Errorf("Expected score of 20, but it was %d instead.", score) 22 | } 23 | } 24 | 25 | func TestSingleSpare(t *testing.T) { 26 | t.Log("Rolling a spare, then a 3, then all gutters... (expected score: 16)") 27 | game := NewGame() 28 | game.rollSpare() 29 | game.Roll(3) 30 | game.rollMany(17, 0) 31 | 32 | if score := game.Score(); score != 16 { 33 | t.Errorf("Expected score of 16, but it was %d instead.", score) 34 | } 35 | } 36 | 37 | func TestSingleStrike(t *testing.T) { 38 | t.Log("Rolling a strike, then 3, then 7, then all gutters... (expected score: 24)") 39 | game := NewGame() 40 | game.rollStrike() 41 | game.Roll(3) 42 | game.Roll(4) 43 | game.rollMany(16, 0) 44 | 45 | if score := game.Score(); score != 24 { 46 | t.Errorf("Expected score of 24, but it was %d instead.", score) 47 | } 48 | } 49 | 50 | func TestPerfectGame(t *testing.T) { 51 | t.Log("Rolling all strikes... (expected score: 300)") 52 | game := NewGame() 53 | game.rollMany(21, 10) 54 | 55 | if score := game.Score(); score != 300 { 56 | t.Errorf("Expected score of 300, but it was %d instead.", score) 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /33_testing/helpers.go: -------------------------------------------------------------------------------- 1 | package vanilla 2 | 3 | import ( 4 | "encoding/json" 5 | "regexp" 6 | ) 7 | 8 | // JSON converts any data type to pretty JSON string 9 | func JSON(list interface{}) string { 10 | result, _ := json.MarshalIndent(list, "", " ") 11 | return string(result) 12 | } 13 | 14 | // AlphaNumeric removes special characters, keeps letters and numbers∏ 15 | func AlphaNumeric(input string) string { 16 | reg, _ := regexp.Compile("[^a-zA-Z0-9]+") 17 | return reg.ReplaceAllString(input, "") 18 | } 19 | -------------------------------------------------------------------------------- /33_testing/helpers_test.go: -------------------------------------------------------------------------------- 1 | package vanilla 2 | 3 | import "testing" 4 | 5 | func TestJSON(t *testing.T) { 6 | //var data = make(map[string]interface{}) 7 | expecting := []struct { 8 | original string 9 | result string 10 | }{ 11 | { 12 | "ab!", `"ab!"`, 13 | }, 14 | { 15 | "done#", `"done#"`, 16 | }, 17 | { 18 | "no Spaces", `"no Spaces"`, 19 | }, 20 | } 21 | 22 | for _, v := range expecting { 23 | t.Run(v.original, func(t *testing.T) { 24 | result := JSON(v.original) 25 | if result != v.result { 26 | t.Error("Expected ", v.result, "but got", result, "instead") 27 | } 28 | }) 29 | } 30 | } 31 | 32 | func TestAlphaNumeric(t *testing.T) { 33 | expecting := []struct { 34 | original string 35 | result string 36 | }{ 37 | { 38 | "ab!", "ab", 39 | }, 40 | { 41 | "done#", "done", 42 | }, 43 | { 44 | "no Spaces", "noSpaces", 45 | }, 46 | } 47 | 48 | for _, v := range expecting { 49 | t.Run(v.original, func(t *testing.T) { 50 | result := AlphaNumeric(v.original) 51 | if result != v.result { 52 | t.Error("Expected ", v.result, "but got", result, "instead") 53 | } 54 | }) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /33_testing/testing.md: -------------------------------------------------------------------------------- 1 | # Testing 2 | 3 | * `go test` run the test 4 | * `go test -cover` Find out how much of your code is covered by testing 5 | * `go test -v` show details 6 | * `go test -coverprofile cp.out` 7 | * `go tool cover -html=cp.out` 8 | * `go help test` more info on testing 9 | * `go get -u github.com/cweill/gotests/...` generate testfiles 10 | -------------------------------------------------------------------------------- /34_channels/01_bufferedChannel.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | 7 | // Specify the size (3), otherwize will throw error 8 | queue := make(chan string, 3) // buffered channel 9 | queue <- "one" 10 | addMore(queue, "two") 11 | addMore(queue, "three") 12 | addMore(queue, "four") 13 | 14 | // No need to close loop for Println. 15 | // Printing values removes them from channel. 16 | // fmt.Println(">", <-queue) 17 | // fmt.Println(">", <-queue) 18 | 19 | // Channel must be closed before using for loop. 20 | close(queue) 21 | //fmt.Println("len:", len(queue)) 22 | 23 | // Loop through rest of values in channel. 24 | // Looping through values removes them from channel. 25 | for elem := range queue { 26 | fmt.Println("==>", elem) 27 | } 28 | 29 | // No values left in the channel. 30 | fmt.Println(">", <-queue) 31 | fmt.Println(">", <-queue) 32 | } 33 | 34 | func addMore(c chan<- string, input string) { 35 | if len(c) < cap(c) { 36 | c <- input 37 | } else { 38 | fmt.Println("FULL CHANNEL ==> CANNOT ADD", input, "cap:", cap(c), "len:", len(c)) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /34_channels/02_unbufferedChannel.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func sendMore(s int, c chan<- int) { // send-only type chan<-, send TO channel 8 | c <- s 9 | } 10 | 11 | func main() { 12 | c := make(chan int) // unbuffered channel of ints 13 | go sendMore(20, c) // must be goroutine because unbuffered channel blocks 14 | go sendMore(30, c) 15 | show(c) 16 | show(c) 17 | //show(c) // Extra receive FROM unbuffered channel will return error. 18 | } 19 | 20 | func show(c <-chan int) { //receive-only type <-chan, receive FROM channel 21 | fmt.Println(<-c) 22 | } 23 | -------------------------------------------------------------------------------- /34_channels/04_stopGoroutine.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | // Generator returns a channel that produces the numbers 1, 2, 3,… 6 | // To stop the underlying goroutine, close the channel. 7 | func Generator() chan int { 8 | ch := make(chan int) 9 | go func() { 10 | n := 1 11 | for { 12 | select { 13 | case ch <- n: 14 | n++ 15 | case <-ch: 16 | return 17 | } 18 | } 19 | }() 20 | return ch 21 | } 22 | 23 | func main() { 24 | number := Generator() 25 | fmt.Println(<-number) 26 | fmt.Println(<-number) 27 | close(number) 28 | // … 29 | } 30 | 31 | // https://programming.guide/go/stop-goroutine.html 32 | -------------------------------------------------------------------------------- /34_channels/05_rangeOverClosedChannel.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | ) 7 | 8 | func pinger(c chan string) { 9 | for i := 0; i < 3; i++ { 10 | c <- "ping " + strconv.Itoa(i) 11 | } 12 | close(c) 13 | } 14 | 15 | func main() { 16 | var c = make(chan string) 17 | 18 | go pinger(c) 19 | 20 | // Channel must be closed before using for loop. 21 | for msg := range c { 22 | fmt.Println(msg) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /34_channels/06_close_on_separate_goroutine.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | "time" 7 | ) 8 | 9 | func main() { 10 | wg := new(sync.WaitGroup) 11 | messages := make(chan string) 12 | for x := 1; x <= 5; x++ { 13 | wg.Add(1) 14 | go func(count int) { 15 | defer wg.Done() 16 | sayhello(messages, count) 17 | }(x) 18 | } 19 | 20 | // will not work: 21 | // wg.Wait() 22 | // close(messages) 23 | 24 | // But this works: 25 | go func() { 26 | wg.Wait() 27 | close(messages) 28 | }() 29 | 30 | for msg := range messages { 31 | fmt.Println(msg) 32 | } 33 | } 34 | 35 | func sayhello(messages chan<- string, count int) { 36 | time.Sleep(time.Millisecond * time.Duration(1000)) 37 | messages <- fmt.Sprintf("hello: %d", count) 38 | } 39 | -------------------------------------------------------------------------------- /34_channels/07_continuouslySendMSG.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | "time" 7 | 8 | "gopkg.in/mgo.v2/bson" 9 | ) 10 | 11 | func pinger(c chan string, id int) { 12 | i := 1 13 | for { 14 | c <- strconv.Itoa(id) + " ping\t" + 15 | strconv.Itoa(i) + "\t" + 16 | bson.NewObjectId().Hex() + "\t" + 17 | strconv.FormatInt(time.Now().UnixNano(), 10) 18 | i++ 19 | // if i > 30 { 20 | // break 21 | // } 22 | time.Sleep(time.Millisecond * time.Duration(4)) 23 | } 24 | //close(c) 25 | } 26 | 27 | func main() { 28 | var c = make(chan string) 29 | for i := 1; i < 21; i++ { 30 | go pinger(c, i) 31 | } 32 | 33 | i := 0 34 | for { 35 | i++ 36 | msg, opened := <-c 37 | if !opened { 38 | break 39 | } 40 | fmt.Println(msg) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /34_channels/08_known_length.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | n := 10 7 | var queue = make(chan string, n) // n is recommended, but not required 8 | for i := 0; i < n; i++ { 9 | go addMore(queue, fmt.Sprintf("step - %d", i)) 10 | } 11 | 12 | for i := 0; i < n; i++ { 13 | fmt.Println(<-queue) 14 | } 15 | } 16 | 17 | func addMore(c chan<- string, input string) { 18 | c <- input 19 | } 20 | -------------------------------------------------------------------------------- /34_channels/09_known_length_buffered.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | "time" 7 | ) 8 | 9 | func main() { 10 | var ( 11 | jobs = 30 // Run 30 jobs in total. 12 | running = make(chan bool, 5) // Limit concurrent jobs to 5. 13 | wg sync.WaitGroup // Keep track of which jobs are finished. 14 | ) 15 | 16 | wg.Add(jobs) 17 | for i := 1; i <= jobs; i++ { 18 | running <- true // Fill running; this will block and wait if it's already full. 19 | 20 | // Start a job. 21 | go func(i int) { 22 | defer func() { 23 | <-running // Drain running so new jobs can be added. 24 | wg.Done() // Signal that this job is done. 25 | }() 26 | 27 | // "do work" 28 | time.Sleep(500 * time.Millisecond) 29 | fmt.Println(i) 30 | }(i) 31 | } 32 | 33 | wg.Wait() // Wait until all jobs are done. 34 | fmt.Println("done") 35 | } 36 | -------------------------------------------------------------------------------- /35_mongodb_pipeline_page/db.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "dblogin" 5 | "fmt" 6 | "gopkg.in/mgo.v2" 7 | ) 8 | 9 | // DB variables 10 | var ( 11 | //DB *mgo.Database 12 | OS *mgo.Database 13 | //Books *mgo.Collection 14 | Products3 *mgo.Collection 15 | s *mgo.Session 16 | ) 17 | 18 | func init() { 19 | // S get a mongodb sessions 20 | s, err := mgo.Dial(dblogin.Bookstore) // mongodb://username:yourpasscode@serverip:27017/database?authSource=admin 21 | if err != nil { 22 | panic(err) 23 | } 24 | 25 | if err = s.Ping(); err != nil { 26 | panic(err) 27 | } 28 | 29 | //DB = s.DB("bookstore") 30 | //Books = DB.C("books") 31 | 32 | OS = s.DB("onlinestore") 33 | Products3 = OS.C("products3") 34 | 35 | fmt.Println("You connected to your mongo database.") 36 | } 37 | -------------------------------------------------------------------------------- /35_mongodb_pipeline_page/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{ . }} 4 | 5 | 6 | {{ . }} 7 |

8 | Main | 9 | List | 10 | Products | 11 | Aggregate | 12 | View 13 |

14 | 15 | {{ template "body" }} 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /36_concurrency_channel/channel/channel_waiting.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | ) 7 | 8 | var wg sync.WaitGroup 9 | 10 | func main() { 11 | m := map[int]int{} 12 | m[4] = 7 13 | m[3] = 87 14 | m[72] = 19 15 | 16 | ch := make(chan int) 17 | 18 | // for closing ch 19 | ch2 := make(chan int) 20 | wg.Add(2) 21 | go func() { 22 | fmt.Println("start of func 1") 23 | var i int 24 | for n := range ch2 { 25 | i += n 26 | fmt.Println("ch2 n:", n, "i:", i) 27 | if i == len(m) { 28 | close(ch) 29 | fmt.Println("closing ch", len(m)) 30 | } 31 | } 32 | fmt.Println("end of func 1") 33 | wg.Done() 34 | }() 35 | 36 | // populating 37 | go func() { 38 | fmt.Println("start of func 2") 39 | for _, v := range m { 40 | ch <- v 41 | ch2 <- 1 42 | fmt.Println("populating:", v) 43 | //fmt.Println("ch2 length", len(ch2)) 44 | } 45 | fmt.Println("end of func 2") 46 | wg.Done() 47 | }() 48 | 49 | // printing ch 50 | for v := range ch { 51 | fmt.Println("ch:", v) 52 | } 53 | 54 | //for h := range ch2 { 55 | // fmt.Println("h:",h) 56 | //} 57 | 58 | fmt.Println("closing ch2") 59 | // good housekeeping 60 | close(ch2) 61 | wg.Wait() 62 | } 63 | -------------------------------------------------------------------------------- /36_concurrency_channel/channel/concurrency_example.go: -------------------------------------------------------------------------------- 1 | // Concurrency example 2 | // Five seconds given to type something, else program exits. 3 | 4 | package main 5 | 6 | import ( 7 | "fmt" 8 | "time" 9 | ) 10 | 11 | // channel is "reference" type, so no need to return value 12 | func readword(cha chan string) { 13 | fmt.Println("Type a word, then hit Enter.") 14 | var word string 15 | fmt.Scanf("%s", &word) 16 | cha <- word 17 | } 18 | 19 | func timeout(t chan bool) { 20 | time.Sleep(5 * time.Second) 21 | t <- true 22 | } 23 | 24 | // main is the entry point for the program. 25 | func main() { 26 | t := make(chan bool) 27 | go timeout(t) 28 | 29 | ch := make(chan string) 30 | go readword(ch) 31 | 32 | // select whoever brings results first 33 | // select the fastest channel 34 | select { 35 | case word := <-ch: 36 | fmt.Println("Received", word) 37 | case <-t: 38 | fmt.Println("Timeout.") 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /36_concurrency_channel/channel/concurrrency_and_channel.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | var webservice = make(chan int) 9 | 10 | func callWebService() { 11 | go func() { 12 | fmt.Println("Calling webservice") 13 | time.Sleep(2 * time.Second) 14 | fmt.Println("Webservice Finished") 15 | webservice <- 10 16 | }() 17 | } 18 | 19 | func showToUser() { 20 | fmt.Println("Showing info to User..") 21 | } 22 | 23 | // main is the entry point for the program. 24 | func main() { 25 | callWebService() 26 | 27 | showToUser() 28 | 29 | result := <-webservice 30 | 31 | fmt.Println("Execution finished with the result:", result) 32 | //time.Sleep(8 * time.Second) 33 | } 34 | -------------------------------------------------------------------------------- /36_concurrency_channel/channel/counter.go: -------------------------------------------------------------------------------- 1 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~// 2 | // Generator that counts to n // 3 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~// 4 | package main 5 | 6 | import ( 7 | "fmt" 8 | ) 9 | 10 | func main() { 11 | for i := range count(10) { 12 | fmt.Println("Counted", i) 13 | } 14 | } 15 | 16 | // count will create a channel 17 | func count(n int) chan int { 18 | ch := make(chan int) 19 | 20 | go func() { 21 | for i := 1; i <= n; i++ { 22 | ch <- i 23 | } 24 | close(ch) 25 | }() 26 | 27 | return ch 28 | } 29 | -------------------------------------------------------------------------------- /36_concurrency_channel/channel/goroutine_sends_back_message.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | // main is the entry point for the program. 9 | func main() { 10 | 11 | messages := make(chan string) 12 | 13 | go work(messages) 14 | 15 | msg := <-messages 16 | fmt.Println(msg) 17 | 18 | /// 19 | go work2(messages) 20 | fmt.Println(<-messages) 21 | } 22 | 23 | func work(messages1 chan<- string) { 24 | messages1 <- "done" 25 | } 26 | 27 | func work2(messages2 chan<- string) { 28 | time.Sleep(5 * time.Second) 29 | messages2 <- "done2" 30 | } 31 | -------------------------------------------------------------------------------- /36_concurrency_channel/channel/no_need_for_wait_group.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | var ch = make(chan int) // create channel 6 | 7 | // Pings prints few lines, then sends an int over channel back to main 8 | func Pings() { 9 | for i := 0; i < 3; i++ { 10 | fmt.Println("Step", i) 11 | } 12 | ch <- 1 // send channel value 13 | } 14 | 15 | func main() { 16 | go Pings() // concurrent execution 17 | fmt.Println("Start") 18 | <-ch // wait for channel value 19 | fmt.Println("The End") 20 | } 21 | -------------------------------------------------------------------------------- /36_concurrency_channel/channel/select_all_channels_in_order_they_arrive.go: -------------------------------------------------------------------------------- 1 | // Go's _select_ lets you wait on multiple channel 2 | // operations. Combining goroutines and channels with 3 | // select is a powerful feature of Go. 4 | // A select is only used with channels. 5 | // A switch is used with concrete types. 6 | // A select will choose multiple valid options at random, while a switch will go in sequence (and would require a fallthrough to match multiple.) 7 | 8 | package main 9 | 10 | import "time" 11 | import "fmt" 12 | 13 | func main() { 14 | 15 | // For our example we'll select across two channels. 16 | c1 := make(chan string) 17 | c2 := make(chan string) 18 | 19 | // Each channel will receive a value after some amount 20 | // of time, to simulate e.g. blocking RPC operations 21 | // executing in concurrent goroutines. 22 | go func() { 23 | time.Sleep(7 * time.Second) 24 | c1 <- "one" 25 | }() 26 | go func() { 27 | time.Sleep(1 * time.Second) 28 | c2 <- "two" 29 | }() 30 | 31 | // We'll use `select` to await both of these values 32 | // simultaneously, printing each one as it arrives. 33 | for i := 0; i < 2; i++ { 34 | select { 35 | case msg1 := <-c1: 36 | fmt.Println("received", msg1) 37 | case msg2 := <-c2: 38 | fmt.Println("received", msg2) 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /36_concurrency_channel/channel/select_only_one.go: -------------------------------------------------------------------------------- 1 | // "select case" selects only one, whichever is faster. 2 | package main 3 | 4 | import "time" 5 | import "fmt" 6 | 7 | func main() { 8 | 9 | // executing an external call that returns its result on a channel `c1` 10 | // after 2s. 11 | c1 := make(chan string, 1) 12 | go func() { 13 | time.Sleep(time.Second * 2) 14 | c1 <- "result 1" 15 | }() 16 | 17 | // which one is faster? 18 | // 1 sec is faster than 2 sec, so "timeout 1" is printed 19 | select { 20 | case res := <-c1: 21 | fmt.Println(res) 22 | case <-time.After(time.Second * 1): 23 | fmt.Println("timeout 1") 24 | } 25 | 26 | // Here is another example: 2 sec vs 3 sec 27 | 28 | // If we allow a longer timeout of 3s, then the receive 29 | // from `c2` will succeed and we'll print the result. 30 | c2 := make(chan string, 1) 31 | go func() { 32 | time.Sleep(time.Second * 2) 33 | c2 <- "result 2" 34 | }() 35 | select { 36 | case res := <-c2: 37 | fmt.Println(res) 38 | case <-time.After(time.Second * 3): 39 | fmt.Println("timeout 2") 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /36_concurrency_channel/channel/simple_channel.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | 7 | // Specify the size (3), otherwize will throw error 8 | queue := make(chan string, 3) 9 | queue <- "one" 10 | queue <- "two" 11 | queue <- "three" 12 | 13 | // No need to close loop for Println. 14 | // Printing values removes them from channel. 15 | fmt.Println("len:", len(queue)) 16 | fmt.Println(">", <-queue) 17 | fmt.Println(">", <-queue) 18 | 19 | // Channel must be closed before using for loop. 20 | close(queue) 21 | fmt.Println("len:", len(queue)) 22 | 23 | // Loop through rest of values in channel. 24 | // Looping through values removes them from channel. 25 | for elem := range queue { 26 | fmt.Println("==>", elem) 27 | } 28 | 29 | // No values left in the channel. 30 | fmt.Println(">", <-queue) 31 | } 32 | -------------------------------------------------------------------------------- /36_concurrency_channel/channel/simple_example.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | 7 | c := make(chan int) 8 | 9 | go func() { 10 | c <- 42 11 | }() 12 | 13 | x := <-c 14 | 15 | fmt.Println("==>", x) 16 | 17 | } 18 | -------------------------------------------------------------------------------- /36_concurrency_channel/concurrency_wait_groups/do_it_once.go: -------------------------------------------------------------------------------- 1 | // Run the function once, and never again. 2 | // Even if asked multiple times, do NOT run more than once. 3 | package main 4 | 5 | import ( 6 | "fmt" 7 | "sync" 8 | ) 9 | 10 | func main() { 11 | var once sync.Once 12 | 13 | onceBody := func() { 14 | fmt.Println("Only once") 15 | } 16 | 17 | done := make(chan bool) 18 | for i := 0; i < 10; i++ { 19 | go func(j int) { 20 | fmt.Println("ask again", j) 21 | once.Do(onceBody) 22 | done <- true 23 | 24 | }(i) 25 | } 26 | 27 | for i := 0; i < 10; i++ { 28 | <-done 29 | fmt.Println("check", i) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /36_concurrency_channel/concurrency_wait_groups/waitgroup.go: -------------------------------------------------------------------------------- 1 | // wait for goroutine to finish. 2 | 3 | package main 4 | 5 | import ( 6 | "fmt" 7 | "sync" 8 | ) 9 | 10 | var wg sync.WaitGroup // 1 11 | 12 | func main() { 13 | fmt.Println("start") 14 | 15 | wg.Add(1) // 2 16 | go doSomething() 17 | 18 | wg.Wait() // 4 19 | fmt.Println("end") 20 | } 21 | 22 | func doSomething() { 23 | fmt.Println("do something") 24 | wg.Done() // 3 25 | } 26 | -------------------------------------------------------------------------------- /36_concurrency_channel/concurrency_wait_groups/waitgroup_duration.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | "time" 7 | ) 8 | 9 | func dosomething(millisecs time.Duration, wg *sync.WaitGroup) { 10 | defer wg.Done() 11 | duration := millisecs * time.Millisecond 12 | time.Sleep(duration) 13 | fmt.Println("Function in background, duration:", duration) 14 | } 15 | 16 | func main() { 17 | wg := sync.WaitGroup{} 18 | wg.Add(4) 19 | go dosomething(200, &wg) 20 | go dosomething(400, &wg) 21 | go dosomething(150, &wg) 22 | go dosomething(600, &wg) 23 | 24 | wg.Wait() 25 | fmt.Println("Done") 26 | } 27 | -------------------------------------------------------------------------------- /37_html_template/README.md: -------------------------------------------------------------------------------- 1 | # FileServer and template 2 | HTML is served on port 80 3 | -------------------------------------------------------------------------------- /37_html_template/pub/css/main.css: -------------------------------------------------------------------------------- 1 | h1 { 2 | color: red; 3 | } 4 | -------------------------------------------------------------------------------- /37_html_template/pub/img/toby.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zelenko/go/2c97fc39fc36510054ca51a57b7659976a02dd4d/37_html_template/pub/img/toby.jpg -------------------------------------------------------------------------------- /37_html_template/templates/about.gohtml: -------------------------------------------------------------------------------- 1 | {{template "header" .}} 2 | 3 |

ABOUT

4 | 5 | {{template "nav-main"}} 6 | 7 | {{template "footer"}} -------------------------------------------------------------------------------- /37_html_template/templates/apply.gohtml: -------------------------------------------------------------------------------- 1 | {{template "header" .}} 2 | 3 |

APPLY

4 | 5 | {{template "nav-main"}} 6 | 7 | {{if .FirstName}} 8 | Your name is {{.FirstName}} 9 | {{end}} 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | {{template "footer"}} -------------------------------------------------------------------------------- /37_html_template/templates/contact.gohtml: -------------------------------------------------------------------------------- 1 | {{template "header" .}} 2 | 3 |

CONTACT

4 | 5 | {{template "nav-main"}} 6 | 7 | {{template "footer"}} -------------------------------------------------------------------------------- /37_html_template/templates/includes-hdr-ftr.gohtml: -------------------------------------------------------------------------------- 1 | {{define "header"}} 2 | 3 | 4 | 5 | 6 | {{if .FirstName}} 7 | {{.FirstName}} 8 | {{else}} 9 | {{.Title}} 10 | {{end}} 11 | 12 | 13 | 14 | {{end}} 15 | 16 | {{define "footer"}} 17 | 18 | 19 | {{end}} -------------------------------------------------------------------------------- /37_html_template/templates/includes-nav-main.gohtml: -------------------------------------------------------------------------------- 1 | {{define "nav-main"}} 2 | 10 | {{end}} -------------------------------------------------------------------------------- /37_html_template/templates/index.gohtml: -------------------------------------------------------------------------------- 1 | {{template "header" .}} 2 | 3 |

INDEX

4 | 5 | {{template "nav-main"}} 6 | 7 | {{template "footer"}} -------------------------------------------------------------------------------- /38_url_request_JSON/data_from_JSON.go: -------------------------------------------------------------------------------- 1 | // This sample program demonstrates how to decode a JSON string. 2 | 3 | package main 4 | 5 | import ( 6 | "encoding/json" // Encoding and Decoding Package 7 | "fmt" 8 | ) 9 | 10 | // JSON Contains a sample String to unmarshal. 11 | var JSON = `{ 12 | "name":"Mark Taylor", 13 | "jobtitle":"Software Developer", 14 | "phone":{ 15 | "home":"123-466-799", 16 | "office":"564-987-654" 17 | }, 18 | "email":"markt@gmail.com" 19 | }` 20 | 21 | func main() { 22 | // Unmarshal the JSON string into info map variable. 23 | var info map[string]interface{} 24 | json.Unmarshal([]byte(JSON), &info) 25 | 26 | // Print the output from info map. 27 | fmt.Println(info["name"]) 28 | fmt.Println(info["jobtitle"]) 29 | fmt.Println(info["email"]) 30 | fmt.Println(info["phone"].(map[string]interface{})["home"]) 31 | fmt.Println(info["phone"].(map[string]interface{})["office"]) 32 | } 33 | -------------------------------------------------------------------------------- /38_url_request_JSON/data_to_JSON.go: -------------------------------------------------------------------------------- 1 | // How to encode map data into a JSON string? 2 | 3 | package main 4 | 5 | import ( 6 | "encoding/json" // Encoding and Decoding Package 7 | "fmt" 8 | ) 9 | 10 | func main() { 11 | // Create a map of key/value pairs and parses the data into JSON 12 | emp := make(map[string]interface{}) 13 | emp["name"] = "John Doe" 14 | emp["age"] = "30" 15 | emp["phone"] = map[string]interface{}{ 16 | "mobil": "555-555-5555", 17 | "fax": "564-987-654", 18 | } 19 | emp["cars"] = map[string]interface{}{ 20 | "car1": "Ford", 21 | "car2": "BMW", 22 | "car3": "Fiat", 23 | } 24 | emp["email"] = "noreply@gmail.com" 25 | 26 | // Marshal the map into a JSON string. 27 | empData, err := json.Marshal(emp) 28 | if err != nil { 29 | fmt.Println(err.Error()) 30 | return 31 | } 32 | 33 | jsonStr := string(empData) 34 | fmt.Println("The JSON data is:") 35 | fmt.Println(jsonStr) 36 | 37 | } 38 | -------------------------------------------------------------------------------- /38_url_request_JSON/getJSON_file.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "net/http" 7 | ) 8 | 9 | func main() { 10 | 11 | url := "http://services.explorecalifornia.org/json/tours.php" 12 | 13 | resp, err := http.Get(url) 14 | check(err) 15 | 16 | fmt.Printf("Response type: %T\n", resp) 17 | 18 | defer resp.Body.Close() 19 | 20 | bytes, err := ioutil.ReadAll(resp.Body) 21 | check(err) 22 | 23 | fmt.Print(string(bytes)) 24 | 25 | } 26 | 27 | func check(err error) { 28 | if err != nil { 29 | fmt.Println("Error: ", err.Error()) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /38_url_request_JSON/getJSONandParse.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "io/ioutil" 7 | "math/big" 8 | "net/http" 9 | "strings" 10 | ) 11 | 12 | // Tour type has name and price 13 | type Tour struct { 14 | Name, Price string 15 | } 16 | 17 | func main() { 18 | 19 | url := "http://services.explorecalifornia.org/json/tours.php" 20 | content := contentFromServer(url) 21 | 22 | tours := toursFromJSON(content) 23 | 24 | for _, tour := range tours { 25 | price, _, _ := big.ParseFloat(tour.Price, 10, 2, big.ToZero) 26 | fmt.Printf("%v ($%.2f)\n", tour.Name, price) 27 | } 28 | } 29 | 30 | // check if error present 31 | func check(err error) { 32 | if err != nil { 33 | panic(err) 34 | } 35 | } 36 | 37 | // contentFromServer returns a string 38 | func contentFromServer(url string) string { 39 | 40 | resp, err := http.Get(url) 41 | check(err) 42 | 43 | defer resp.Body.Close() 44 | bytes, err := ioutil.ReadAll(resp.Body) 45 | check(err) 46 | 47 | return string(bytes) 48 | } 49 | 50 | // toursFromJSON parses json data into struct 51 | func toursFromJSON(content string) []Tour { 52 | tours := make([]Tour, 0, 20) 53 | 54 | decoder := json.NewDecoder(strings.NewReader(content)) 55 | _, err := decoder.Token() 56 | check(err) 57 | 58 | var tour Tour 59 | for decoder.More() { 60 | err := decoder.Decode(&tour) 61 | check(err) 62 | tours = append(tours, tour) 63 | } 64 | 65 | return tours 66 | } 67 | -------------------------------------------------------------------------------- /38_url_request_JSON/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "net/http" 7 | "net/url" 8 | "strconv" 9 | "strings" 10 | ) 11 | 12 | // main is the entry point for the program. 13 | func main() { 14 | apiURL := "https://talaikis.com/api/quotes/random/" 15 | //resource := "/user/" 16 | data := url.Values{} 17 | data.Set("name", "foo") 18 | data.Add("surname", "bar") 19 | 20 | u, _ := url.ParseRequestURI(apiURL) 21 | //u.Path = resource 22 | urlStr := u.String() // "https://talaikis.com/api/quotes/random/" 23 | 24 | client := &http.Client{} 25 | // r, _ := http.NewRequest("POST", urlStr, strings.NewReader(data.Encode())) // <-- URL-encoded payload 26 | r, _ := http.NewRequest("GET", urlStr, strings.NewReader(data.Encode())) // <-- URL-encoded payload 27 | r.Header.Add("Authorization", "auth_token=\"XXXXXXX\"") 28 | r.Header.Add("Content-Type", "application/x-www-form-urlencoded") 29 | r.Header.Add("Content-Length", strconv.Itoa(len(data.Encode()))) 30 | 31 | resp, _ := client.Do(r) 32 | fmt.Println(resp.Status) 33 | 34 | fmt.Println(resp.ContentLength) 35 | 36 | fmt.Println(resp.Header) 37 | 38 | defer resp.Body.Close() 39 | 40 | content, _ := ioutil.ReadAll(resp.Body) 41 | 42 | fmt.Println(string(content)) 43 | } 44 | -------------------------------------------------------------------------------- /38_url_request_JSON/post_file.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io" 7 | "mime/multipart" 8 | "net/http" 9 | "os" 10 | ) 11 | 12 | // Upload test 13 | func Upload(url, file string) (err error) { 14 | // Prepare a form that you will submit to that URL. 15 | var b bytes.Buffer 16 | w := multipart.NewWriter(&b) 17 | // Add your image file 18 | f, err := os.Open(file) 19 | if err != nil { 20 | return 21 | } 22 | defer f.Close() 23 | fw, err := w.CreateFormFile("image", file) 24 | if err != nil { 25 | return 26 | } 27 | if _, err = io.Copy(fw, f); err != nil { 28 | return 29 | } 30 | // Add the other fields 31 | if fw, err = w.CreateFormField("key"); err != nil { 32 | return 33 | } 34 | if _, err = fw.Write([]byte("KEY")); err != nil { 35 | return 36 | } 37 | // Don't forget to close the multipart writer. 38 | // If you don't close it, your request will be missing the terminating boundary. 39 | w.Close() 40 | 41 | // Now that you have a form, you can submit it to your handler. 42 | req, err := http.NewRequest("POST", url, &b) 43 | if err != nil { 44 | return 45 | } 46 | // Don't forget to set the content type, this will contain the boundary. 47 | req.Header.Set("Content-Type", w.FormDataContentType()) 48 | 49 | // Submit the request 50 | client := &http.Client{} 51 | res, err := client.Do(req) 52 | if err != nil { 53 | return 54 | } 55 | 56 | // Check the response 57 | if res.StatusCode != http.StatusOK { 58 | err = fmt.Errorf("bad status: %s", res.Status) 59 | } 60 | return 61 | } 62 | -------------------------------------------------------------------------------- /38_url_request_JSON/test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "crypto/tls" 5 | "fmt" 6 | "io/ioutil" 7 | "net/http" 8 | ) 9 | 10 | // main is the entry point for the program. 11 | func main() { 12 | 13 | link := "https://talaikis.com/api/quotes/random/" 14 | 15 | // skip TLS check 16 | tr := &http.Transport{ 17 | TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, 18 | } 19 | client := &http.Client{Transport: tr} 20 | response, err := client.Get(link) 21 | if err != nil { 22 | fmt.Println(err) 23 | } 24 | 25 | defer response.Body.Close() 26 | 27 | content, _ := ioutil.ReadAll(response.Body) 28 | fmt.Println(string(content)) 29 | 30 | } 31 | -------------------------------------------------------------------------------- /39_read_directory_content/http_list_directory.md: -------------------------------------------------------------------------------- 1 | # Listing directory in HTTP 2 | Taking notes before possible rewrite. 3 | 4 | dirList is the function on line 101 or this page: https://golang.org/src/net/http/fs.go#L705 5 | that lists directories and files on html page. 6 | 7 | example: 8 | 9 | ```go 10 | r.NotFound = http.FileServer(http.Dir("public")) 11 | 12 | func FileServer(root FileSystem) Handler { 13 | return &fileHandler{root} 14 | } 15 | 16 | Open(name string) (File, error) // is an interface 17 | ``` 18 | 19 | func `serveFile` calls dirList function 20 | 21 | `ServeFile` calls `serveFile` 22 | 23 | `Dir` is type; see https://golang.org/src/net/http/fs.go?h=Dir#L40 line 40 24 | 25 | ```go 26 | func (d Dir) Open(name string) (File, error) { 27 | 28 | func FileServer(root FileSystem) Handler 29 | 30 | type FileSystem interface { 31 | Open(name string) (File, error) 32 | } 33 | ``` -------------------------------------------------------------------------------- /39_read_directory_content/ioutilReadDir.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "log" 7 | "path/filepath" 8 | ) 9 | 10 | // main is the entry point for the program. 11 | func main() { 12 | // slash := string(os.PathSeparator) //or, 13 | slash := string(filepath.Separator) //to be impervious to OS... 14 | dirname := "." + slash 15 | fmt.Printf("dirname is: %s\n", dirname) 16 | 17 | //searchFiles("../") 18 | searchFiles(dirname) 19 | } 20 | 21 | func searchFiles(dir string) { // dir is the parent directory you what to search 22 | 23 | files, err := ioutil.ReadDir(dir) 24 | if err != nil { 25 | log.Fatal(err) 26 | } 27 | 28 | for _, file := range files { 29 | 30 | if !file.IsDir() { 31 | fmt.Println(" --", file.Name()) 32 | } else { 33 | fmt.Println(file.Name()) 34 | } 35 | 36 | } 37 | } 38 | 39 | /* 40 | https://golang.org/pkg/os/#FileInfo 41 | 42 | type FileInfo interface { 43 | Name() string // base name of the file 44 | Size() int64 // length in bytes for regular files; system-dependent for others 45 | Mode() FileMode // file mode bits 46 | ModTime() time.Time // modification time 47 | IsDir() bool // abbreviation for Mode().IsDir() 48 | Sys() interface{} // underlying data source (can return nil) 49 | } 50 | */ 51 | -------------------------------------------------------------------------------- /39_read_directory_content/osOpen.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "path/filepath" 7 | ) 8 | 9 | func main() { 10 | // slash := string(os.PathSeparator) //or, 11 | slash := string(filepath.Separator) //to be impervious to OS... 12 | dirname := "." + slash 13 | fmt.Printf("dirname is: %s\n", dirname) 14 | 15 | searchFiles(dirname) 16 | } 17 | 18 | func searchFiles(dirname string) { // dir is the parent directory you what to search 19 | d, err := os.Open(dirname) 20 | if err != nil { 21 | fmt.Println(err) 22 | os.Exit(1) 23 | } 24 | 25 | filesinfo, err := d.Readdir(-1) 26 | d.Close() 27 | if err != nil { 28 | fmt.Println(err) 29 | os.Exit(1) 30 | } 31 | 32 | /* type FileInfo interface { Name() string // base name of the file 33 | Size() int64 // in bytes for regular files; system-dependent for others 34 | Mode() FileMode // file mode bits 35 | ModTime() time.Time // modification time 36 | IsDir() bool // abbreviation for Mode().IsDir() 37 | Sys() interface{} // underlying data source (can return nil) 38 | } */ 39 | 40 | for _, fi := range filesinfo { 41 | if fi.Mode().IsRegular() { 42 | fmt.Printf("-----\nFileName: %s\nSize: \t%d bytes\n", 43 | fi.Name(), fi.Size()) 44 | } else { 45 | fmt.Printf("Name:%s Directory:%t", fi.Name(), fi.Mode().IsDir()) 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /40_cron_scheduler/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "time" 7 | 8 | "github.com/mileusna/crontab" 9 | ) 10 | 11 | // main is the entry point for the program. 12 | func main() { 13 | 14 | ctab := crontab.New() // create cron table 15 | 16 | // MustAddJob is like AddJob but panics on wrong syntax or problems with func/args 17 | // use for easier initialization 18 | ctab.MustAddJob("* * * * *", myFunc) // every minute 19 | ctab.MustAddJob("0 12 * * *", myFunc3) // noon lauch 20 | ctab.MustAddJob("/2 * * * *", myFunc2, "Monday and Tuesday midnight", 123) // run every two seconds 21 | 22 | // fn with args 23 | ctab.MustAddJob("0 0 * * 1,2", myFunc2, "Monday and Tuesday midnight", 123) 24 | ctab.MustAddJob("*/5 * * * *", myFunc2, "every five min", 0) 25 | 26 | // or use AddJob if you want to test the error 27 | err := ctab.AddJob("0 12 1 * *", myFunc) // on 1st day of month 28 | if err != nil { 29 | log.Println(err) 30 | return 31 | } 32 | 33 | // all your other app code as usual, or put sleep timer for demo 34 | time.Sleep(10 * time.Minute) 35 | // time.Sleep(5 * time.Second) 36 | } 37 | 38 | func myFunc() { 39 | fmt.Println("Helo, world") 40 | } 41 | 42 | func myFunc3() { 43 | fmt.Println("Noon!") 44 | } 45 | 46 | func myFunc2(s string, n int) { 47 | //fmt.Println("We have params here, string", s, "and number", n) 48 | fmt.Println(time.Now(), "- just ticked") 49 | 50 | } 51 | -------------------------------------------------------------------------------- /41_cli_arguments/go-prompt.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/c-bata/go-prompt" 6 | ) 7 | 8 | func completer(d prompt.Document) []prompt.Suggest { 9 | s := []prompt.Suggest{ 10 | {Text: "users", Description: "Store the username and age"}, 11 | {Text: "articles", Description: "Store the article text posted by user"}, 12 | {Text: "comments", Description: "Store the text commented to articles"}, 13 | {Text: "testing", Description: "This is just for testing"}, 14 | } 15 | return prompt.FilterHasPrefix(s, d.GetWordBeforeCursor(), true) 16 | } 17 | 18 | func main() { 19 | fmt.Println("Please select table.") 20 | t := prompt.Input("> ", completer) 21 | fmt.Println("You selected " + t) 22 | } 23 | -------------------------------------------------------------------------------- /41_cli_arguments/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | ) 7 | 8 | // main is the entry point for the program. 9 | func main() { 10 | 11 | // number of arguments 12 | l := len(os.Args) 13 | 14 | // display arguments using switch 15 | switch l { 16 | case 1: 17 | fmt.Println("No arguments") 18 | 19 | case 2: 20 | fmt.Print(1, ": ", os.Args[1], "\n") 21 | 22 | default: 23 | fmt.Printf("Number of arguments: %v\n", l) 24 | } 25 | 26 | // display arguments using loop 27 | if len(os.Args) > 1 { 28 | 29 | // loop through all arguments 30 | for i := 1; i < len(os.Args); i++ { 31 | fmt.Print(i, ": ", os.Args[i], "\n") 32 | } 33 | 34 | } else { 35 | fmt.Println("No arguments") 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /43_resize_jpg_png_image/jpg.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/nfnt/resize" 5 | "image/jpeg" 6 | "log" 7 | "os" 8 | ) 9 | 10 | func main() { 11 | resizeImage("original.jpg", "original_1.jpg") 12 | } 13 | 14 | func resizeImage(original, newFile string) { 15 | // open image 16 | file, err := os.Open(original) 17 | if err != nil { 18 | log.Fatal(err) 19 | } 20 | 21 | // decode jpeg into image.Image 22 | img, err := jpeg.Decode(file) 23 | if err != nil { 24 | log.Fatal(err) 25 | } 26 | file.Close() 27 | 28 | // resize to width 1000 using Lanczos resampling 29 | // and preserve aspect ratio 30 | m := resize.Resize(500, 0, img, resize.Lanczos3) 31 | 32 | out, err := os.Create(newFile) 33 | if err != nil { 34 | log.Fatal(err) 35 | } 36 | defer out.Close() 37 | 38 | // write new image to file 39 | jpeg.Encode(out, m, nil) 40 | } 41 | -------------------------------------------------------------------------------- /43_resize_jpg_png_image/png.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/nfnt/resize" 5 | "image/png" 6 | "log" 7 | "os" 8 | ) 9 | 10 | func main() { 11 | // open file 12 | file, err := os.Open("logo.png") 13 | if err != nil { 14 | log.Fatal(err) 15 | } 16 | 17 | // decode png into image.Image 18 | img, err := png.Decode(file) 19 | if err != nil { 20 | log.Fatal(err) 21 | } 22 | file.Close() 23 | 24 | // resize to width 1000 using Lanczos resampling 25 | // and preserve aspect ratio 26 | m := resize.Resize(0, 700, img, resize.Lanczos3) 27 | 28 | out, err := os.Create("logo_h700.png") 29 | if err != nil { 30 | log.Fatal(err) 31 | } 32 | defer out.Close() 33 | 34 | // write new image to file 35 | png.Encode(out, m) 36 | } 37 | -------------------------------------------------------------------------------- /44_csv_file/read_csv.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/csv" 5 | "fmt" 6 | "io" 7 | "log" 8 | "os" 9 | ) 10 | 11 | func main() { 12 | 13 | filename := `test2.csv` 14 | readCSV(filename) 15 | 16 | } 17 | 18 | func readCSV(filename string) { 19 | 20 | f, err := os.Open(filename) 21 | if err != nil { 22 | fmt.Println(err) 23 | return 24 | } 25 | defer f.Close() 26 | 27 | //r := csv.NewReader(strings.NewReader(in)) 28 | r := csv.NewReader(f) 29 | r.Comma = ',' 30 | r.Comment = '#' 31 | 32 | for { 33 | record, err := r.Read() 34 | if err == io.EOF { 35 | break 36 | } 37 | if err != nil { 38 | log.Fatal(err) 39 | } 40 | 41 | fmt.Println(record) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /44_csv_file/write_csv.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/csv" 5 | "log" 6 | "os" 7 | ) 8 | 9 | func main() { 10 | 11 | records := [][]string{ 12 | {"first_name", "last_name", "username"}, 13 | {"John", "Jeffeson", "jjeff"}, 14 | {"Daniel", "Smith", "dsmith"}, 15 | {"Andrew", "Johnson", "ajohnson"}, 16 | } 17 | 18 | filename := `test3.csv` 19 | createCSV(filename, records) 20 | } 21 | 22 | func createCSV(filename string, records [][]string) { 23 | csvFile, err := os.Create(filename) 24 | if err != nil { 25 | log.Fatal("Cannot create new file", err) 26 | } 27 | defer csvFile.Close() 28 | 29 | // w := csv.NewWriter(os.Stdout) 30 | w := csv.NewWriter(csvFile) 31 | 32 | for _, record := range records { 33 | if err := w.Write(record); err != nil { 34 | log.Fatalln("error writing record to csv:", err) 35 | } 36 | } 37 | 38 | // Write any buffered data to the underlying writer. 39 | w.Flush() 40 | 41 | if err := w.Error(); err != nil { 42 | log.Fatal(err) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /45_image_exif_data/IMG_6958.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zelenko/go/2c97fc39fc36510054ca51a57b7659976a02dd4d/45_image_exif_data/IMG_6958.JPG -------------------------------------------------------------------------------- /45_image_exif_data/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "os" 7 | 8 | "github.com/rwcarlsen/goexif/exif" 9 | "github.com/rwcarlsen/goexif/mknote" 10 | ) 11 | 12 | // ExampleDecode gets EXIF data from image 13 | func ExampleDecode() { 14 | fname := "IMG_6958.JPG" 15 | 16 | f, err := os.Open(fname) 17 | if err != nil { 18 | log.Fatal(err) 19 | } 20 | 21 | // Optionally register camera makenote data parsing - currently Nikon and 22 | // Canon are supported. 23 | exif.RegisterParsers(mknote.All...) 24 | 25 | x, err := exif.Decode(f) 26 | if err != nil { 27 | log.Fatal(err) 28 | } 29 | 30 | camModel, _ := x.Get(exif.Model) // normally, don't ignore errors! 31 | fmt.Println(camModel.StringVal()) 32 | 33 | focal, _ := x.Get(exif.FocalLength) 34 | numer, denom, _ := focal.Rat2(0) // retrieve first (only) rat. value 35 | fmt.Printf("%v/%v", numer, denom) 36 | 37 | // Two convenience functions exist for date/time taken and GPS coords: 38 | tm, _ := x.DateTime() 39 | fmt.Println("Taken: ", tm) 40 | 41 | lat, long, _ := x.LatLong() 42 | fmt.Println("lat, long: ", lat, ", ", long) 43 | } 44 | 45 | func main() { 46 | ExampleDecode() 47 | } 48 | -------------------------------------------------------------------------------- /45_image_exif_data/samples/IMG_6958.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zelenko/go/2c97fc39fc36510054ca51a57b7659976a02dd4d/45_image_exif_data/samples/IMG_6958.JPG -------------------------------------------------------------------------------- /45_image_exif_data/samples/IMG_7291.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zelenko/go/2c97fc39fc36510054ca51a57b7659976a02dd4d/45_image_exif_data/samples/IMG_7291.JPG -------------------------------------------------------------------------------- /46_video_capture/main.go: -------------------------------------------------------------------------------- 1 | // What it does: 2 | // 3 | // This example uses the VideoCapture class to capture frames from a connected webcam, 4 | // and displays the video in a Window class. 5 | // 6 | // How to run: 7 | // 8 | // go run ./cmd/capwindow/main.go 9 | // 10 | // +build example 11 | 12 | package main 13 | 14 | import ( 15 | "fmt" 16 | "os" 17 | "strconv" 18 | 19 | "gocv.io/x/gocv" 20 | ) 21 | 22 | func main() { 23 | if len(os.Args) < 2 { 24 | fmt.Println("How to run:\n\tcapwindow [camera ID]") 25 | return 26 | } 27 | 28 | // parse args 29 | deviceID, _ := strconv.Atoi(os.Args[1]) 30 | 31 | webcam, err := gocv.VideoCaptureDevice(int(deviceID)) 32 | if err != nil { 33 | fmt.Printf("Error opening video capture device: %v\n", deviceID) 34 | return 35 | } 36 | defer webcam.Close() 37 | 38 | window := gocv.NewWindow("Capture Window") 39 | defer window.Close() 40 | 41 | img := gocv.NewMat() 42 | defer img.Close() 43 | 44 | fmt.Printf("Start reading camera device: %v\n", deviceID) 45 | for { 46 | if ok := webcam.Read(img); !ok { 47 | fmt.Printf("Error cannot read device %d\n", deviceID) 48 | return 49 | } 50 | if img.Empty() { 51 | continue 52 | } 53 | 54 | window.IMShow(img) 55 | if window.WaitKey(1) == 27 { 56 | break 57 | } 58 | } 59 | } 60 | 61 | /* 62 | 63 | more info: 64 | https://github.com/go-opencv/go-opencv <== Windows insturctions 65 | https://github.com/go-opencv/go-opencv 66 | https://gocv.io/writing-code/more-examples/ 67 | https://github.com/hybridgroup/gocv/blob/master/cmd/capwindow/main.go <== this file 68 | 69 | */ 70 | -------------------------------------------------------------------------------- /48_keyboard_driver/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "gobot.io/x/gobot" 7 | "gobot.io/x/gobot/platforms/keyboard" 8 | ) 9 | 10 | func main() { 11 | keys := keyboard.NewDriver() 12 | 13 | work := func() { 14 | keys.On(keyboard.Key, func(data interface{}) { 15 | key := data.(keyboard.KeyEvent) 16 | 17 | if key.Key == keyboard.A { 18 | fmt.Println("A pressed!") 19 | } else { 20 | fmt.Println("keyboard event!", key, key.Char) 21 | } 22 | }) 23 | } 24 | 25 | robot := gobot.NewRobot("keyboardbot", 26 | []gobot.Connection{}, 27 | []gobot.Device{keys}, 28 | work, 29 | ) 30 | 31 | robot.Start() 32 | } 33 | -------------------------------------------------------------------------------- /50_golf_framework/login.gohtml: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | Name: 5 | 6 | 7 |
8 | 9 | -------------------------------------------------------------------------------- /51_blur_image/blur_image.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "./graphics" 5 | "image" 6 | "image/jpeg" 7 | "os" 8 | ) 9 | 10 | func main() { 11 | imagePath, _ := os.Open("original.jpg") 12 | defer imagePath.Close() 13 | srcImage, _, _ := image.Decode(imagePath) 14 | 15 | dstImage := image.NewRGBA(srcImage.Bounds()) 16 | // Blur Function 17 | graphics.Blur(dstImage, srcImage, &graphics.BlurOptions{StdDev: 5.5}) 18 | 19 | newImage, _ := os.Create("original_blurred.jpg") 20 | defer newImage.Close() 21 | jpeg.Encode(newImage, dstImage, &jpeg.Options{Quality: jpeg.DefaultQuality}) 22 | } 23 | -------------------------------------------------------------------------------- /51_blur_image/generate_thumbnail.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "./graphics" 5 | "image" 6 | "image/jpeg" 7 | "os" 8 | ) 9 | 10 | func main() { 11 | imagePath, _ := os.Open("original.jpg") 12 | defer imagePath.Close() 13 | srcImage, _, _ := image.Decode(imagePath) 14 | 15 | // Dimension of new thumbnail 80 X 80 16 | dstImage := image.NewRGBA(image.Rect(0, 0, 280, 80)) 17 | // Thumbnail function of Graphics 18 | graphics.Thumbnail(dstImage, srcImage) 19 | 20 | newImage, _ := os.Create("thumbnail_thumbnail.jpg") 21 | defer newImage.Close() 22 | jpeg.Encode(newImage, dstImage, &jpeg.Options{Quality: jpeg.DefaultQuality}) 23 | } 24 | -------------------------------------------------------------------------------- /51_blur_image/graphics/blur.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Graphics-Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package graphics 6 | 7 | import ( 8 | "./convolve" 9 | "errors" 10 | "image" 11 | "image/draw" 12 | "math" 13 | ) 14 | 15 | // DefaultStdDev is the default blurring parameter. 16 | var DefaultStdDev = 0.5 17 | 18 | // BlurOptions are the blurring parameters. 19 | // StdDev is the standard deviation of the normal, higher is blurrier. 20 | // Size is the size of the kernel. If zero, it is set to Ceil(6 * StdDev). 21 | type BlurOptions struct { 22 | StdDev float64 23 | Size int 24 | } 25 | 26 | // Blur produces a blurred version of the image, using a Gaussian blur. 27 | func Blur(dst draw.Image, src image.Image, opt *BlurOptions) error { 28 | if dst == nil { 29 | return errors.New("graphics: dst is nil") 30 | } 31 | if src == nil { 32 | return errors.New("graphics: src is nil") 33 | } 34 | 35 | sd := DefaultStdDev 36 | size := 0 37 | 38 | if opt != nil { 39 | sd = opt.StdDev 40 | size = opt.Size 41 | } 42 | 43 | if size < 1 { 44 | size = int(math.Ceil(sd * 6)) 45 | } 46 | 47 | kernel := make([]float64, 2*size+1) 48 | for i := 0; i <= size; i++ { 49 | x := float64(i) / sd 50 | x = math.Pow(1/math.SqrtE, x*x) 51 | kernel[size-i] = x 52 | kernel[size+i] = x 53 | } 54 | 55 | // Normalize the weights to sum to 1.0. 56 | sum := 0.0 57 | for _, k := range kernel { 58 | sum += k 59 | } 60 | for i, k := range kernel { 61 | kernel[i] = k / sum 62 | } 63 | 64 | return convolve.Convolve(dst, src, &convolve.SeparableKernel{ 65 | X: kernel, 66 | Y: kernel, 67 | }) 68 | } 69 | -------------------------------------------------------------------------------- /51_blur_image/graphics/detect/doc.go: -------------------------------------------------------------------------------- 1 | // Package detect implements an object detector cascade. 2 | // Copyright 2011 The Graphics-Go Authors. All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // Package detect implements an object detector cascade. 6 | // The technique used is a degenerate tree of Haar-like classifiers, commonly 7 | // used for face detection. It is described in 8 | // P. Viola, M. Jones. 9 | // Rapid Object Detection using a Boosted Cascade of Simple Features, 2001 10 | // IEEE Conference on Computer Vision and Pattern Recognition 11 | // A Cascade can be constructed manually from a set of Classifiers in stages, 12 | // or can be loaded from an XML file in the OpenCV format with 13 | // classifier, _, err := detect.ParseOpenCV(r) 14 | // The classifier can be used to determine if a full image is detected as an 15 | // object using Detect 16 | // if classifier.Match(m) { 17 | // // m is an image of a face. 18 | // } 19 | // It is also possible to search an image for occurrences of an object 20 | // objs := classifier.Find(m) 21 | package detect 22 | -------------------------------------------------------------------------------- /51_blur_image/graphics/detect/projector.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Graphics-Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package detect 6 | 7 | import ( 8 | "image" 9 | ) 10 | 11 | // projector allows projecting from a source Rectangle onto a target Rectangle. 12 | type projector struct { 13 | // rx, ry is the scaling factor. 14 | rx, ry float64 15 | // dx, dy is the translation factor. 16 | dx, dy float64 17 | // r is the clipping region of the target. 18 | r image.Rectangle 19 | } 20 | 21 | // newProjector creates a Projector with source src and target dst. 22 | func newProjector(dst image.Rectangle, src image.Rectangle) *projector { 23 | return &projector{ 24 | rx: float64(dst.Dx()) / float64(src.Dx()), 25 | ry: float64(dst.Dy()) / float64(src.Dy()), 26 | dx: float64(dst.Min.X - src.Min.X), 27 | dy: float64(dst.Min.Y - src.Min.Y), 28 | r: dst, 29 | } 30 | } 31 | 32 | // pt projects p from the source rectangle onto the target rectangle. 33 | func (s *projector) pt(p image.Point) image.Point { 34 | return image.Point{ 35 | clamp(s.rx*float64(p.X)+s.dx, s.r.Min.X, s.r.Max.X), 36 | clamp(s.ry*float64(p.Y)+s.dy, s.r.Min.Y, s.r.Max.Y), 37 | } 38 | } 39 | 40 | // rect projects r from the source rectangle onto the target rectangle. 41 | func (s *projector) rect(r image.Rectangle) image.Rectangle { 42 | return image.Rectangle{s.pt(r.Min), s.pt(r.Max)} 43 | } 44 | 45 | // clamp rounds and clamps o to the integer range [x0, x1]. 46 | func clamp(o float64, x0, x1 int) int { 47 | x := int(o + 0.5) 48 | if x < x0 { 49 | return x0 50 | } 51 | if x > x1 { 52 | return x1 53 | } 54 | return x 55 | } 56 | -------------------------------------------------------------------------------- /51_blur_image/graphics/detect/projector_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Graphics-Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package detect 6 | 7 | import ( 8 | "image" 9 | "reflect" 10 | "testing" 11 | ) 12 | 13 | type projectorTest struct { 14 | dst image.Rectangle 15 | src image.Rectangle 16 | pdst image.Rectangle 17 | psrc image.Rectangle 18 | } 19 | 20 | var projectorTests = []projectorTest{ 21 | { 22 | image.Rect(0, 0, 6, 6), 23 | image.Rect(0, 0, 2, 2), 24 | image.Rect(0, 0, 6, 6), 25 | image.Rect(0, 0, 2, 2), 26 | }, 27 | { 28 | image.Rect(0, 0, 6, 6), 29 | image.Rect(0, 0, 2, 2), 30 | image.Rect(3, 3, 6, 6), 31 | image.Rect(1, 1, 2, 2), 32 | }, 33 | { 34 | image.Rect(30, 30, 40, 40), 35 | image.Rect(10, 10, 20, 20), 36 | image.Rect(32, 33, 34, 37), 37 | image.Rect(12, 13, 14, 17), 38 | }, 39 | } 40 | 41 | func TestProjector(t *testing.T) { 42 | for i, tt := range projectorTests { 43 | pr := newProjector(tt.dst, tt.src) 44 | res := pr.rect(tt.psrc) 45 | if !reflect.DeepEqual(res, tt.pdst) { 46 | t.Errorf("%d: got %v want %v", i, res, tt.pdst) 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /51_blur_image/graphics/interp/doc.go: -------------------------------------------------------------------------------- 1 | // Package interp implements image interpolation. 2 | // Copyright 2012 The Graphics-Go Authors. All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // Package interp implements image interpolation. 6 | // An interpolator provides the Interp interface, which can be used 7 | // to interpolate a pixel: 8 | // c := interp.Bilinear.Interp(src, 1.2, 1.8) 9 | // To interpolate a large number of RGBA or Gray pixels, an implementation 10 | // may provide a fast-path by implementing the RGBA or Gray interfaces. 11 | // i1, ok := i.(interp.RGBA) 12 | // if ok { 13 | // c := i1.RGBA(src, 1.2, 1.8) 14 | // // use c.R, c.G, etc 15 | // return 16 | // } 17 | // c := i.Interp(src, 1.2, 1.8) 18 | // // use generic color.Color 19 | package interp 20 | -------------------------------------------------------------------------------- /51_blur_image/graphics/interp/interp.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Graphics-Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package interp 6 | 7 | import ( 8 | "image" 9 | "image/color" 10 | ) 11 | 12 | // Interp interpolates an image's color at fractional co-ordinates. 13 | type Interp interface { 14 | // Interp interpolates (x, y). 15 | Interp(src image.Image, x, y float64) color.Color 16 | } 17 | 18 | // RGBA is a fast-path interpolation implementation for image.RGBA. 19 | // It is common for an Interp to also implement RGBA. 20 | type RGBA interface { 21 | // RGBA interpolates (x, y). 22 | RGBA(src *image.RGBA, x, y float64) color.RGBA 23 | } 24 | 25 | // Gray is a fast-path interpolation implementation for image.Gray. 26 | type Gray interface { 27 | // Gray interpolates (x, y). 28 | Gray(src *image.Gray, x, y float64) color.Gray 29 | } 30 | -------------------------------------------------------------------------------- /51_blur_image/graphics/rotate.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Graphics-Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package graphics 6 | 7 | import ( 8 | "./interp" 9 | "errors" 10 | "image" 11 | "image/draw" 12 | ) 13 | 14 | // RotateOptions are the rotation parameters. 15 | // Angle is the angle, in radians, to rotate the image clockwise. 16 | type RotateOptions struct { 17 | Angle float64 18 | } 19 | 20 | // Rotate produces a rotated version of src, drawn onto dst. 21 | func Rotate(dst draw.Image, src image.Image, opt *RotateOptions) error { 22 | if dst == nil { 23 | return errors.New("graphics: dst is nil") 24 | } 25 | if src == nil { 26 | return errors.New("graphics: src is nil") 27 | } 28 | 29 | angle := 0.0 30 | if opt != nil { 31 | angle = opt.Angle 32 | } 33 | 34 | return I.Rotate(angle).TransformCenter(dst, src, interp.Bilinear) 35 | } 36 | -------------------------------------------------------------------------------- /51_blur_image/graphics/scale.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Graphics-Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package graphics 6 | 7 | import ( 8 | "./interp" 9 | "errors" 10 | "image" 11 | "image/draw" 12 | ) 13 | 14 | // Scale produces a scaled version of the image using bilinear interpolation. 15 | func Scale(dst draw.Image, src image.Image) error { 16 | if dst == nil { 17 | return errors.New("graphics: dst is nil") 18 | } 19 | if src == nil { 20 | return errors.New("graphics: src is nil") 21 | } 22 | 23 | b := dst.Bounds() 24 | srcb := src.Bounds() 25 | if b.Empty() || srcb.Empty() { 26 | return nil 27 | } 28 | sx := float64(b.Dx()) / float64(srcb.Dx()) 29 | sy := float64(b.Dy()) / float64(srcb.Dy()) 30 | return I.Scale(sx, sy).Transform(dst, src, interp.Bilinear) 31 | } 32 | -------------------------------------------------------------------------------- /51_blur_image/graphics/thumbnail.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Graphics-Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package graphics 6 | 7 | import ( 8 | "image" 9 | "image/draw" 10 | ) 11 | 12 | // Thumbnail scales and crops src so it fits in dst. 13 | func Thumbnail(dst draw.Image, src image.Image) error { 14 | // Scale down src in the dimension that is closer to dst. 15 | sb := src.Bounds() 16 | db := dst.Bounds() 17 | rx := float64(sb.Dx()) / float64(db.Dx()) 18 | ry := float64(sb.Dy()) / float64(db.Dy()) 19 | var b image.Rectangle 20 | if rx < ry { 21 | b = image.Rect(0, 0, db.Dx(), int(float64(sb.Dy())/rx)) 22 | } else { 23 | b = image.Rect(0, 0, int(float64(sb.Dx())/ry), db.Dy()) 24 | } 25 | 26 | buf := image.NewRGBA(b) 27 | if err := Scale(buf, src); err != nil { 28 | return err 29 | } 30 | 31 | // Crop. 32 | // TODO(crawshaw): improve on center-alignment. 33 | var pt image.Point 34 | if rx < ry { 35 | pt.Y = (b.Dy() - db.Dy()) / 2 36 | } else { 37 | pt.X = (b.Dx() - db.Dx()) / 2 38 | } 39 | draw.Draw(dst, db, buf, pt, draw.Src) 40 | return nil 41 | } 42 | -------------------------------------------------------------------------------- /51_blur_image/graphics/thumbnail_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Graphics-Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package graphics 6 | 7 | import ( 8 | "./graphicstest" 9 | "image" 10 | "testing" 11 | 12 | _ "image/png" 13 | ) 14 | 15 | func TestThumbnailGopher(t *testing.T) { 16 | dst := image.NewRGBA(image.Rect(0, 0, 80, 80)) 17 | 18 | src, err := graphicstest.LoadImage("../testdata/gopher.png") 19 | if err != nil { 20 | t.Fatal(err) 21 | } 22 | if err := Thumbnail(dst, src); err != nil { 23 | t.Fatal(err) 24 | } 25 | cmp, err := graphicstest.LoadImage("../testdata/gopher-thumb-80x80.png") 26 | if err != nil { 27 | t.Fatal(err) 28 | } 29 | err = graphicstest.ImageWithinTolerance(dst, cmp, 0) 30 | if err != nil { 31 | t.Error(err) 32 | } 33 | } 34 | 35 | func TestThumbnailLongGopher(t *testing.T) { 36 | dst := image.NewRGBA(image.Rect(0, 0, 50, 150)) 37 | 38 | src, err := graphicstest.LoadImage("../testdata/gopher.png") 39 | if err != nil { 40 | t.Fatal(err) 41 | } 42 | if err := Thumbnail(dst, src); err != nil { 43 | t.Fatal(err) 44 | } 45 | cmp, err := graphicstest.LoadImage("../testdata/gopher-thumb-50x150.png") 46 | if err != nil { 47 | t.Fatal(err) 48 | } 49 | err = graphicstest.ImageWithinTolerance(dst, cmp, 0) 50 | if err != nil { 51 | t.Error(err) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /51_blur_image/original.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zelenko/go/2c97fc39fc36510054ca51a57b7659976a02dd4d/51_blur_image/original.jpg -------------------------------------------------------------------------------- /51_blur_image/rotate_image.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "./graphics" 5 | "image" 6 | "image/jpeg" 7 | "math" 8 | "os" 9 | ) 10 | 11 | func main() { 12 | imagePath, _ := os.Open("original.jpg") 13 | defer imagePath.Close() 14 | srcImage, _, _ := image.Decode(imagePath) 15 | 16 | srcDim := srcImage.Bounds() 17 | dstImage := image.NewRGBA(image.Rect(0, 0, srcDim.Dy(), srcDim.Dx())) 18 | graphics.Rotate(dstImage, srcImage, &graphics.RotateOptions{math.Pi / 2.0}) 19 | 20 | newImage, _ := os.Create("original_rotated.jpg") 21 | defer newImage.Close() 22 | jpeg.Encode(newImage, dstImage, &jpeg.Options{Quality: jpeg.DefaultQuality}) 23 | } 24 | -------------------------------------------------------------------------------- /52_jpg_image_watermark/add_watermark.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "image" 5 | "image/draw" 6 | "image/jpeg" 7 | "image/png" 8 | "log" 9 | "os" 10 | ) 11 | 12 | func main() { 13 | image1, err := os.Open("original.jpg") 14 | if err != nil { 15 | log.Fatalf("failed to open: %s", err) 16 | } 17 | 18 | first, err := jpeg.Decode(image1) 19 | if err != nil { 20 | log.Fatalf("failed to decode: %s", err) 21 | } 22 | defer image1.Close() 23 | 24 | image2, err := os.Open("icon.png") 25 | if err != nil { 26 | log.Fatalf("failed to open: %s", err) 27 | } 28 | second, err := png.Decode(image2) 29 | if err != nil { 30 | log.Fatalf("failed to decode: %s", err) 31 | } 32 | defer image2.Close() 33 | 34 | offset := image.Pt(300, 200) 35 | b := first.Bounds() 36 | image3 := image.NewRGBA(b) 37 | draw.Draw(image3, b, first, image.ZP, draw.Src) 38 | draw.Draw(image3, second.Bounds().Add(offset), second, image.ZP, draw.Over) 39 | 40 | third, err := os.Create("result.jpg") 41 | if err != nil { 42 | log.Fatalf("failed to create: %s", err) 43 | } 44 | jpeg.Encode(third, image3, &jpeg.Options{Quality: jpeg.DefaultQuality}) 45 | defer third.Close() 46 | } 47 | -------------------------------------------------------------------------------- /52_jpg_image_watermark/dimentions.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "image" 6 | _ "image/gif" 7 | _ "image/jpeg" 8 | _ "image/png" 9 | "os" 10 | ) 11 | 12 | func main() { 13 | 14 | w, h, err := getImageSize("icon.png") 15 | if err != nil { 16 | fmt.Println("Cannot get size, error: ", err.Error()) 17 | } 18 | fmt.Print("width: ", w, " height: ", h, "\n") 19 | 20 | w, h, err = getImageSize("original.jpg") 21 | if err != nil { 22 | fmt.Println("Cannot get size, error: ", err.Error()) 23 | } 24 | fmt.Print("width: ", w, " height: ", h, "\n") 25 | 26 | w, h, err = getImageSize("result.jpg") 27 | if err != nil { 28 | fmt.Println("Cannot get size, error: ", err.Error()) 29 | } 30 | fmt.Print("width: ", w, " height: ", h, "\n") 31 | 32 | } 33 | 34 | func getImageSize(imagePath string) (int, int, error) { 35 | file, err := os.Open(imagePath) 36 | defer file.Close() 37 | if err != nil { 38 | return 0, 0, fmt.Errorf("Cannot open file. Error: %s", err.Error()) 39 | } 40 | 41 | img, _, err := image.DecodeConfig(file) 42 | if err != nil { 43 | return 0, 0, fmt.Errorf("Cannot decode. Error: %s", err.Error()) 44 | } 45 | return img.Width, img.Height, nil 46 | } 47 | -------------------------------------------------------------------------------- /52_jpg_image_watermark/grayscale.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "image" 5 | "image/color" 6 | _ "image/gif" 7 | _ "image/jpeg" 8 | _ "image/png" 9 | "log" 10 | "math" 11 | "os" 12 | //"image/png" 13 | "image/jpeg" 14 | ) 15 | 16 | func main() { 17 | grayScale("original.jpg", "original_grayScale2.jpg") 18 | } 19 | 20 | func grayScale(filename, newFileName string) { 21 | infile, err := os.Open(filename) 22 | 23 | if err != nil { 24 | log.Printf("failed opening %s: %s", filename, err) 25 | panic(err.Error()) 26 | } 27 | defer infile.Close() 28 | 29 | imgSrc, _, err := image.Decode(infile) 30 | if err != nil { 31 | log.Println("Cannot decode image.") 32 | panic(err.Error()) 33 | } 34 | 35 | // Create a new grayScale image 36 | bounds := imgSrc.Bounds() 37 | w, h := bounds.Max.X, bounds.Max.Y 38 | grayScale := image.NewGray(image.Rectangle{image.Point{0, 0}, image.Point{w, h}}) 39 | for x := 0; x < w; x++ { 40 | for y := 0; y < h; y++ { 41 | imageColor := imgSrc.At(x, y) 42 | rr, gg, bb, _ := imageColor.RGBA() 43 | r := math.Pow(float64(rr), 2.2) 44 | g := math.Pow(float64(gg), 2.2) 45 | b := math.Pow(float64(bb), 2.2) 46 | m := math.Pow(0.2125*r+0.7154*g+0.0721*b, 1/2.2) 47 | Y := uint16(m + 0.5) 48 | grayColor := color.Gray{uint8(Y >> 8)} 49 | grayScale.Set(x, y, grayColor) 50 | } 51 | } 52 | 53 | // Encode the grayScale image to the new file 54 | newFile, err := os.Create(newFileName) 55 | if err != nil { 56 | log.Printf("failed creating %s: %s", newFile.Name(), err) 57 | panic(err.Error()) 58 | } 59 | defer newFile.Close() 60 | 61 | // png.Encode(newFile,grayScale) 62 | jpeg.Encode(newFile, grayScale, &jpeg.Options{Quality: jpeg.DefaultQuality}) 63 | } 64 | -------------------------------------------------------------------------------- /52_jpg_image_watermark/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zelenko/go/2c97fc39fc36510054ca51a57b7659976a02dd4d/52_jpg_image_watermark/icon.png -------------------------------------------------------------------------------- /52_jpg_image_watermark/original.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zelenko/go/2c97fc39fc36510054ca51a57b7659976a02dd4d/52_jpg_image_watermark/original.jpg -------------------------------------------------------------------------------- /53_regular_expression/convert_to_snake_case.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "regexp" 6 | "strings" 7 | ) 8 | 9 | var matchFirstCap = regexp.MustCompile("(.)([A-Z][a-z]+)") 10 | var matchAllCap = regexp.MustCompile("([a-z0-9])([A-Z])") 11 | 12 | // ToSnakeCase converts string 13 | func ToSnakeCase(str string) string { 14 | snake := matchFirstCap.ReplaceAllString(str, "${1}_${2}") 15 | snake = matchAllCap.ReplaceAllString(snake, "${1}_${2}") 16 | return strings.ToLower(snake) 17 | } 18 | 19 | func main() { 20 | fmt.Println(ToSnakeCase("JapanCanadaAustralia")) 21 | fmt.Println(ToSnakeCase("JapanCanadaAUSTRALIA")) 22 | fmt.Println(ToSnakeCase("JAPANCanadaAUSTRALIA")) 23 | fmt.Println(ToSnakeCase("Japan125Canada130Australia150")) 24 | } 25 | -------------------------------------------------------------------------------- /53_regular_expression/is_date_format_valid.go: -------------------------------------------------------------------------------- 1 | // Regular expression validate the date format in "dd/mm/yyyy" 2 | 3 | package main 4 | 5 | import ( 6 | "fmt" 7 | "regexp" 8 | ) 9 | 10 | func main() { 11 | str1 := "31/07/2010" 12 | str2 := "1/13/2010" 13 | str3 := "29/2/2007" 14 | str4 := "31/08/2010" 15 | str5 := "29/02/200a" 16 | str6 := "29/02/200a" 17 | str7 := "55/02/200a" 18 | str8 := "2_/02/2009" 19 | 20 | re := regexp.MustCompile("(0?[1-9]|[12][0-9]|3[01])/(0?[1-9]|1[012])/((19|20)\\d\\d)") 21 | 22 | fmt.Printf("Pattern: %v\n", re.String()) // print pattern 23 | fmt.Printf("\nDate: %v :%v\n", str1, re.MatchString(str1)) 24 | fmt.Printf("Date: %v :%v\n", str2, re.MatchString(str2)) 25 | fmt.Printf("Date: %v :%v\n", str3, re.MatchString(str3)) 26 | fmt.Printf("Date: %v :%v\n", str4, re.MatchString(str4)) 27 | fmt.Printf("Date: %v :%v\n", str5, re.MatchString(str5)) 28 | fmt.Printf("Date: %v :%v\n", str6, re.MatchString(str6)) 29 | fmt.Printf("Date: %v :%v\n", str7, re.MatchString(str7)) 30 | fmt.Printf("Date: %v :%v\n", str8, re.MatchString(str8)) 31 | } 32 | -------------------------------------------------------------------------------- /53_regular_expression/keep_special_characters.go: -------------------------------------------------------------------------------- 1 | //Regular expression to extract all Non-Alphanumeric Characters from a String 2 | 3 | package main 4 | 5 | import ( 6 | "fmt" 7 | "regexp" 8 | ) 9 | 10 | func main() { 11 | str1 := "We @@@Love@@@@ #Go!$! ****Programming****Language^^^" 12 | 13 | re := regexp.MustCompile(`[^a-zA-Z0-9]+`) 14 | 15 | fmt.Printf("Pattern: %v\n", re.String()) // print pattern 16 | fmt.Println(re.MatchString(str1)) // true 17 | 18 | submatchall := re.FindAllString(str1, -1) 19 | for _, element := range submatchall { 20 | fmt.Println(element) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /53_regular_expression/main.go: -------------------------------------------------------------------------------- 1 | // Regular expression to extract date(YYYY-MM-DD) from string 2 | 3 | package main 4 | 5 | import ( 6 | "fmt" 7 | "regexp" 8 | ) 9 | 10 | // main is the entry point for the program 11 | func main() { 12 | str1 := "If I am 20 years 10 months and 14 days old as of August 17,2016 then my DOB would be 1995-10-03" 13 | 14 | re := regexp.MustCompile(`\d{4}-\d{2}-\d{2}`) 15 | 16 | fmt.Printf("Pattern: %v\n", re.String()) // print pattern 17 | 18 | fmt.Println(re.MatchString(str1)) // true 19 | 20 | submatchall := re.FindAllString(str1, -1) 21 | for _, element := range submatchall { 22 | fmt.Println(element) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /53_regular_expression/phone_number.go: -------------------------------------------------------------------------------- 1 | // Regular expression to validate phone number 2 | 3 | package main 4 | 5 | import ( 6 | "fmt" 7 | "regexp" 8 | ) 9 | 10 | func main() { 11 | str1 := "1(234)5678901x1234" 12 | str2 := "(+351) 282 43 50 50" 13 | str3 := "90191919908" 14 | //str4 := "555-8909" 15 | str4 := "a55-8909" 16 | str5 := "001 6867684" 17 | str6 := "001 6867684x1" 18 | str7 := "1 (234) 567-8901" 19 | str8 := "1-234-567-8901 ext1234" 20 | 21 | re := regexp.MustCompile(`^(?:(?:\(?(?:00|\+)([1-4]\d\d|[1-9]\d?)\)?)?[\-\.\ \\\/]?)?((?:\(?\d{1,}\)?[\-\.\ \\\/]?){0,})(?:[\-\.\ \\\/]?(?:#|ext\.?|extension|x)[\-\.\ \\\/]?(\d+))?$`) 22 | 23 | fmt.Printf("Pattern: %v\n", re.String()) // print pattern 24 | fmt.Printf("\nPhone: %v\t:%v\n", str1, re.MatchString(str1)) 25 | fmt.Printf("Phone: %v\t:%v\n", str2, re.MatchString(str2)) 26 | fmt.Printf("Phone: %v\t\t:%v\n", str3, re.MatchString(str3)) 27 | fmt.Printf("Phone: %v\t\t\t:%v\n", str4, re.MatchString(str4)) 28 | fmt.Printf("Phone: %v\t\t:%v\n", str5, re.MatchString(str5)) 29 | fmt.Printf("Phone: %v\t\t:%v\n", str6, re.MatchString(str6)) 30 | fmt.Printf("Phone: %v\t\t:%v\n", str7, re.MatchString(str7)) 31 | fmt.Printf("Phone: %v\t:%v\n", str8, re.MatchString(str8)) 32 | } 33 | -------------------------------------------------------------------------------- /53_regular_expression/remove_special_characters.go: -------------------------------------------------------------------------------- 1 | // replace special characters with dash 2 | package main 3 | 4 | import ( 5 | "fmt" 6 | "log" 7 | "regexp" 8 | ) 9 | 10 | func main() { 11 | 12 | reg, err := regexp.Compile("[^A-Za-z0-9]+") 13 | //reg, err := regexp.Compile("[^a-zA-Z0-9]+") 14 | if err != nil { 15 | log.Fatal(err) 16 | } 17 | string := "#Golang#Python$Php&Kotlin@@" 18 | fmt.Println(string) 19 | newStr := reg.ReplaceAllString(string, "-") 20 | fmt.Println(newStr) 21 | } 22 | -------------------------------------------------------------------------------- /54_rotate_image/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zelenko/go/2c97fc39fc36510054ca51a57b7659976a02dd4d/54_rotate_image/icon.png -------------------------------------------------------------------------------- /54_rotate_image/original.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zelenko/go/2c97fc39fc36510054ca51a57b7659976a02dd4d/54_rotate_image/original.jpg -------------------------------------------------------------------------------- /55_html_template_std_lib/image.tmpl: -------------------------------------------------------------------------------- 1 | {{define "content"}} 2 |
3 | {{.Title}} 4 |
5 | {{end}} 6 | 7 | {{define "sidebar"}} 8 | Back
9 | 10 |
    11 | {{- range nav}} 12 |
  • {{.Title}}
  • 13 | {{- end}} 14 |
15 | 16 | {{end}} 17 | -------------------------------------------------------------------------------- /55_html_template_std_lib/index.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | {{.Title}} 8 | 23 | 24 | 25 |

{{.Title}}

26 | 27 | 40 | 41 | {{block "content" .}} 42 |
43 | {{.Body}} 44 |
45 | {{end}} 46 | 47 | 48 | -------------------------------------------------------------------------------- /56_HTML_formatter/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | 7 | "github.com/yosssi/gohtml" 8 | ) 9 | 10 | func main() { 11 | html, err := ioutil.ReadFile("original.gohtml") 12 | checkErr(err, "cannot read file:") 13 | 14 | err = ioutil.WriteFile("original_updated.gohtml", gohtml.FormatBytes(html), 0644) 15 | checkErr(err, "cannot save file") 16 | } 17 | 18 | func checkErr(err error, message string) { 19 | if err != nil { 20 | fmt.Println(message, err) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /56_HTML_formatter/original.gohtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | test 7 | 14 | 15 | 16 |
17 |
18 |
19 |
20 |

Hello!

21 |
22 | 23 |
24 |
25 |
26 | 27 | 28 | -------------------------------------------------------------------------------- /56_HTML_formatter/original_updated.gohtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | test 8 | 9 | 16 | 17 | 18 |
19 |
20 |
21 |
22 |

23 | Hello! 24 |

25 |
26 |
27 |
28 |
29 | 30 | -------------------------------------------------------------------------------- /57_valid_interface/accept_interface.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func describe(i interface{}) { 8 | fmt.Printf("Type = %T, value = %v\n", i, i) 9 | } 10 | 11 | func main() { 12 | s := "Hello World" 13 | describe(s) 14 | i := 55 15 | describe(i) 16 | strt := struct{ name string }{name: "Go"} 17 | describe(strt) 18 | num := [...]byte{1, 2, 3} 19 | describe(num) 20 | slice := []byte{1, 2, 3} 21 | describe(slice) 22 | b := true 23 | describe(b) 24 | d := -1.2 25 | describe(d) 26 | p := &num 27 | describe(p) 28 | } 29 | -------------------------------------------------------------------------------- /57_valid_interface/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | "fmt" 7 | "io" 8 | "strings" 9 | ) 10 | 11 | // Valid interface has OK method 12 | type Valid interface { 13 | OK() error 14 | } 15 | 16 | // Person has name 17 | type Person struct { 18 | Name string 19 | } 20 | 21 | // OK method returns nil or error 22 | func (p Person) OK() error { 23 | if p.Name == "" { 24 | return errors.New("name required") 25 | } 26 | return nil 27 | } 28 | 29 | // Decode interface takes reader and converts 30 | func Decode(r io.Reader, v interface{}) error { 31 | err := json.NewDecoder(r).Decode(v) 32 | if err != nil { 33 | return errors.New("decoding error: " + err.Error()) 34 | } 35 | obj, ok := v.(Valid) // cast as type "Valid" interface 36 | // obj, ok := v.(Person) 37 | if !ok { 38 | //return nil // no OK method 39 | return errors.New("cannot convert 'v' to interface 'Valid'") 40 | } 41 | err = obj.OK() 42 | if err != nil { 43 | return errors.New("invalid interface: " + err.Error()) 44 | } 45 | return nil 46 | } 47 | 48 | // main is the entry point for the program. 49 | func main() { 50 | json := `{"Name": "John Doe"}` 51 | //user := &struct{ Name string }{} 52 | user := &Person{} 53 | err := Decode(strings.NewReader(json), user) 54 | if err != nil { 55 | fmt.Println("error:", err) 56 | goto end 57 | } 58 | fmt.Println("name:", user.Name) 59 | 60 | end: 61 | } 62 | -------------------------------------------------------------------------------- /58_GO_HTML_template/map_to_template.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "html/template" 5 | "io" 6 | "net/http" 7 | ) 8 | 9 | // HTMLfile is path and file to HTML template file 10 | type HTMLfile struct { 11 | Folder string 12 | File string 13 | } 14 | 15 | // Display converts data into HTML and writes to writer 16 | func (e HTMLfile) Display(wr io.Writer, data interface{}) error { 17 | t := template.Must(template.ParseFiles(e.Folder + e.File)) 18 | return t.ExecuteTemplate(wr, e.File, data) 19 | } 20 | 21 | func main() { 22 | http.HandleFunc("/test", index) 23 | http.HandleFunc("/", home) 24 | println("port 8080") 25 | http.ListenAndServe(":8080", nil) 26 | } 27 | 28 | func index(w http.ResponseWriter, r *http.Request) { 29 | body := make(map[string]interface{}) 30 | body["one"] = template.HTML("template") 31 | body["two"] = template.HTML("this is a test") 32 | HTMLfile{"templates/", "test.html"}.Display(w, body) 33 | } 34 | 35 | func home(w http.ResponseWriter, r *http.Request) { 36 | type Output struct { 37 | Message string 38 | Desc string 39 | } 40 | 41 | var rs []Output 42 | rs = append(rs, Output{"one -", "second field, description ...1"}) 43 | rs = append(rs, Output{"two-", "second field, description ...2"}) 44 | rs = append(rs, Output{"three-", "second field, description ...3"}) 45 | rs = append(rs, Output{"four-", "second field, description ...4"}) 46 | 47 | rs4 := make(map[string]string) 48 | rs4["one"] = "111111" 49 | rs4["two"] = "22222222222" 50 | 51 | body := make(map[string]interface{}) 52 | body["one"] = "this is one test" 53 | body["two"] = "two section" 54 | body["list"] = rs 55 | rs2 := []string{"one", "two222", "three"} 56 | body["list2"] = rs2 57 | body["list3"] = rs4 58 | HTMLfile{"templates/", "home.html"}.Display(w, body) 59 | } 60 | -------------------------------------------------------------------------------- /58_GO_HTML_template/other/HTML_template.go: -------------------------------------------------------------------------------- 1 | // text/template is a useful text generating tool. 2 | // Related examples: http://golang.org/pkg/text/template/#pkg-examples 3 | package main 4 | 5 | import ( 6 | "os" 7 | "text/template" 8 | ) 9 | 10 | var card1 = map[int]string{1: "S", 2: "H", 3: "C", 4: "D"} 11 | var card2 = map[string]string{"a": "S", "b": "H", 12 | "c": "C", "d": "D"} 13 | 14 | func check(err error) { 15 | if err != nil { 16 | panic(err) 17 | } 18 | } 19 | func main() { 20 | // The simplest template is the "dot", just printout the variable 21 | t := template.Must(template.New("t1"). 22 | Parse("Dot:{{.}}\n")) 23 | check(t.Execute(os.Stdout, card1)) 24 | 25 | // The following line will fail because key should be alphanumeric. 26 | //`t := template.Must(template.New("greet").Parse("Hi,{{.1}}\n"))` 27 | //`err := t.Execute(os.Stdout, card1)` 28 | 29 | t = template.Must(template.New("t2"). 30 | Parse("Hi,{{.a}}\n")) 31 | check(t.Execute(os.Stdout, card2)) 32 | 33 | // Use variable to ierate map. 34 | t = template.Must(template.New("t3").Parse(`For 35 | {{range $k,$v := .}} k={{printf "%03d" $k}} v={{$v}} 36 | {{end}} 37 | `)) 38 | check(t.Execute(os.Stdout, card1)) 39 | 40 | // * logic functions:and,or,not,eq,ne,lt,le,gt,ge 41 | // * escape convert functions: html,js,urlquery 42 | // * format functions: print,printf,println, 43 | // * other functions: call,index,len 44 | t = template.Must(template.New("t2"). 45 | Parse("{{index . 3}}\n")) 46 | check(t.Execute(os.Stdout, card1)) 47 | 48 | // Use {{define}} to prevent write multiple times. 49 | t = template.Must(template.New("t2").Parse(`Repeat 50 | {{define "T1"}}Apple{{end}} {{define "T2"}}Ape{{end}} 51 | {{template "T2"}} ate {{template "T1"}} 52 | `)) 53 | check(t.Execute(os.Stdout, card1)) 54 | } 55 | -------------------------------------------------------------------------------- /58_GO_HTML_template/other/escape_and_unescape.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "html" 6 | ) 7 | 8 | func main() { 9 | a := `"Fran & Freddie's Diner" ` 10 | fmt.Println(html.EscapeString(a)) 11 | 12 | b := `"Fran & Freddie's Diner" <tasty@example.com>` 13 | fmt.Println(html.UnescapeString(b)) 14 | } 15 | -------------------------------------------------------------------------------- /58_GO_HTML_template/simple/simple.html: -------------------------------------------------------------------------------- 1 | {{template "navigation" -}} 2 | 3 | Below are your account statement details for period from . 4 | 5 | Best Wishes, 6 | Customer Service 7 | 8 | {{signature}} 9 | 10 | {{- range list }} 11 | {{ .Message}} 12 | {{- end}} 13 | -------------------------------------------------------------------------------- /58_GO_HTML_template/static_vs_dynamic_template.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "html/template" 5 | "io" 6 | "net/http" 7 | ) 8 | 9 | // TemplateExecutor is of type interface 10 | type TemplateExecutor interface { 11 | ExecuteTemplate(wr io.Writer, name string, data interface{}) error 12 | } 13 | 14 | // DebugTemplateExecutor is 15 | // dynamic 16 | type DebugTemplateExecutor struct { 17 | Glob string 18 | } 19 | 20 | // ExecuteTemplate is 21 | // dynamic 22 | func (e DebugTemplateExecutor) ExecuteTemplate(wr io.Writer, name string, data interface{}) error { 23 | t := template.Must(template.ParseGlob(e.Glob)) 24 | return t.ExecuteTemplate(wr, name, data) 25 | } 26 | 27 | // ReleaseTemplateExecutor is 28 | // static 29 | type ReleaseTemplateExecutor struct { 30 | Template *template.Template 31 | } 32 | 33 | // ExecuteTemplate is 34 | // static 35 | func (e ReleaseTemplateExecutor) ExecuteTemplate(wr io.Writer, name string, data interface{}) error { 36 | return e.Template.ExecuteTemplate(wr, name, data) 37 | } 38 | 39 | //const templateGlob = "templates/*.html" 40 | const debug = true 41 | 42 | var executor TemplateExecutor 43 | 44 | func main() { 45 | if debug { 46 | executor = DebugTemplateExecutor{"templates/*.html"} 47 | 48 | } else { 49 | executor = ReleaseTemplateExecutor{ 50 | template.Must(template.ParseGlob("templates/*.html")), 51 | } 52 | } 53 | 54 | http.HandleFunc("/test", index) 55 | println("port 8080") 56 | 57 | http.ListenAndServe(":8080", nil) 58 | } 59 | 60 | func index(w http.ResponseWriter, r *http.Request) { 61 | executor.ExecuteTemplate(w, "test.html", nil) 62 | } 63 | -------------------------------------------------------------------------------- /58_GO_HTML_template/templates/home.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |

home.html /////

10 | home page !!!!!!!!!!!
11 | {{ .one }}
12 | {{.two}}
13 | 14 | {{- range .list }} 15 | {{ .Message}} ==> {{ .Desc}}
16 | {{- end}} 17 |
18 | {{- range .list2 }} 19 | {{ .}}
20 | {{- end}} 21 |
22 | {{- range .list3 }} 23 | {{ .}}
24 | {{- end}} 25 |
26 | 27 | {{ range $key, $value := .list3 }} 28 |
  • {{ $key }}: {{ $value }}
  • 29 | {{ end }} 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /58_GO_HTML_template/templates/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |

    test.html <==||||

    10 |
    11 | 12 | {{ .one }}
    13 | {{.two}} 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /59_zip_and_unzip/unzip_cli.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "archive/zip" 5 | "fmt" 6 | "io" 7 | "log" 8 | "os" 9 | "path/filepath" 10 | "strings" 11 | ) 12 | 13 | func main() { 14 | 15 | files, err := Unzip("Ex_Files_UaR_Go.zip", "output") 16 | if err != nil { 17 | log.Fatal(err) 18 | } 19 | 20 | fmt.Println("Unzipped:\n" + strings.Join(files, "\n")) 21 | } 22 | 23 | // Unzip will decompress a zip archive, moving all files and folders 24 | // within the zip file (parameter 1) to an output directory (parameter 2). 25 | func Unzip(src string, dest string) ([]string, error) { 26 | 27 | var filenames []string 28 | 29 | r, err := zip.OpenReader(src) 30 | if err != nil { 31 | return filenames, err 32 | } 33 | defer r.Close() 34 | 35 | for _, f := range r.File { 36 | 37 | rc, err := f.Open() 38 | if err != nil { 39 | return filenames, err 40 | } 41 | defer rc.Close() 42 | 43 | // Store filename/path for returning and using later on 44 | fpath := filepath.Join(dest, f.Name) 45 | filenames = append(filenames, fpath) 46 | 47 | if f.FileInfo().IsDir() { 48 | 49 | // Make Folder 50 | os.MkdirAll(fpath, os.ModePerm) 51 | 52 | } else { 53 | 54 | // Make File 55 | if err = os.MkdirAll(filepath.Dir(fpath), os.ModePerm); err != nil { 56 | return filenames, err 57 | } 58 | 59 | outFile, err := os.OpenFile(fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode()) 60 | if err != nil { 61 | return filenames, err 62 | } 63 | 64 | _, err = io.Copy(outFile, rc) 65 | 66 | // Close the file without defer to close before next iteration of loop 67 | outFile.Close() 68 | 69 | if err != nil { 70 | return filenames, err 71 | } 72 | 73 | } 74 | } 75 | return filenames, nil 76 | } 77 | -------------------------------------------------------------------------------- /59_zip_and_unzip/zip.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "archive/zip" 5 | "fmt" 6 | "io" 7 | "log" 8 | "os" 9 | ) 10 | 11 | func main() { 12 | 13 | // Files to Zip 14 | files := []string{"IMG_6869.JPG", "IMG_6911.JPG"} 15 | output := "images.zip" 16 | 17 | err := ZipFiles(output, files) 18 | 19 | if err != nil { 20 | log.Fatal(err) 21 | } 22 | 23 | fmt.Println("Zipped File: " + output) 24 | } 25 | 26 | // ZipFiles compresses one or many files into a single zip archive file 27 | func ZipFiles(filename string, files []string) error { 28 | 29 | newfile, err := os.Create(filename) 30 | if err != nil { 31 | return err 32 | } 33 | defer newfile.Close() 34 | 35 | zipWriter := zip.NewWriter(newfile) 36 | defer zipWriter.Close() 37 | 38 | // Add files to zip 39 | for _, file := range files { 40 | 41 | zipfile, err := os.Open(file) 42 | if err != nil { 43 | return err 44 | } 45 | defer zipfile.Close() 46 | 47 | // Get the file information 48 | info, err := zipfile.Stat() 49 | if err != nil { 50 | return err 51 | } 52 | 53 | header, err := zip.FileInfoHeader(info) 54 | if err != nil { 55 | return err 56 | } 57 | 58 | // Change to deflate to gain better compression 59 | // see http://golang.org/pkg/archive/zip/#pkg-constants 60 | header.Method = zip.Deflate 61 | 62 | writer, err := zipWriter.CreateHeader(header) 63 | if err != nil { 64 | return err 65 | } 66 | _, err = io.Copy(writer, zipfile) 67 | if err != nil { 68 | return err 69 | } 70 | } 71 | return nil 72 | } 73 | -------------------------------------------------------------------------------- /59_zip_and_unzip/zip2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "archive/zip" 5 | "io" 6 | "log" 7 | "os" 8 | "path/filepath" 9 | "strings" 10 | ) 11 | 12 | func main() { 13 | err := zipit("images", "images2.zip") 14 | if err != nil { 15 | log.Println(err) 16 | } 17 | 18 | } 19 | 20 | func zipit(source, target string) error { 21 | zipfile, err := os.Create(target) 22 | if err != nil { 23 | return err 24 | } 25 | defer zipfile.Close() 26 | 27 | archive := zip.NewWriter(zipfile) 28 | defer archive.Close() 29 | 30 | info, err := os.Stat(source) 31 | if err != nil { 32 | return nil 33 | } 34 | 35 | var baseDir string 36 | if info.IsDir() { 37 | baseDir = filepath.Base(source) 38 | } 39 | 40 | filepath.Walk(source, func(path string, info os.FileInfo, err error) error { 41 | if err != nil { 42 | return err 43 | } 44 | 45 | header, err := zip.FileInfoHeader(info) 46 | if err != nil { 47 | return err 48 | } 49 | 50 | if baseDir != "" { 51 | header.Name = filepath.Join(baseDir, strings.TrimPrefix(path, source)) 52 | } 53 | 54 | if info.IsDir() { 55 | header.Name += "/" 56 | } else { 57 | header.Method = zip.Deflate 58 | } 59 | 60 | writer, err := archive.CreateHeader(header) 61 | if err != nil { 62 | return err 63 | } 64 | 65 | if info.IsDir() { 66 | return nil 67 | } 68 | 69 | file, err := os.Open(path) 70 | if err != nil { 71 | return err 72 | } 73 | defer file.Close() 74 | _, err = io.Copy(writer, file) 75 | return err 76 | }) 77 | 78 | return err 79 | } 80 | -------------------------------------------------------------------------------- /60_http_response_as_file/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "io" 5 | "log" 6 | "net/http" 7 | "os" 8 | ) 9 | 10 | func main() { 11 | 12 | // Enable line numbers in logging 13 | log.SetFlags(log.LstdFlags | log.Lshortfile) 14 | 15 | httpServer := http.Server{ 16 | Addr: ":8080", 17 | } 18 | 19 | http.HandleFunc("/img", img) 20 | http.HandleFunc("/", index) 21 | 22 | // Run the server 23 | log.Println(httpServer.ListenAndServe()) 24 | } 25 | 26 | func index(w http.ResponseWriter, r *http.Request) { 27 | //fmt.Fprint(w, `zip | zip folder`) 28 | w.Write([]byte(`img`)) 29 | 30 | } 31 | 32 | func img(w http.ResponseWriter, r *http.Request) { 33 | //fmt.Fprint(w, `zip | zip folder`) 34 | //w.Write([]byte(`zip | zip folder`)) 35 | 36 | imgFile, err := os.Open("original.jpg") 37 | if err != nil { 38 | log.Println(err) 39 | } 40 | defer imgFile.Close() 41 | 42 | io.Copy(w, imgFile) 43 | } 44 | -------------------------------------------------------------------------------- /65_books_example/config/db.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "crypto/tls" 5 | "dblogin" 6 | "fmt" 7 | "gopkg.in/mgo.v2" 8 | "net" 9 | ) 10 | 11 | // DB variables 12 | var ( 13 | DB *mgo.Database 14 | Books *mgo.Collection 15 | s *mgo.Session 16 | ) 17 | 18 | func init() { 19 | dialInfo, err := mgo.ParseURL(dblogin.BookstoreM0) 20 | if err != nil { 21 | fmt.Println("Cannot parse mongodb URL: " + err.Error()) 22 | } 23 | tlsConfig := &tls.Config{} 24 | dialInfo.DialServer = func(addr *mgo.ServerAddr) (net.Conn, error) { 25 | conn, err := tls.Dial("tcp", addr.String(), tlsConfig) 26 | return conn, err 27 | } 28 | s, err := mgo.DialWithInfo(dialInfo) 29 | if err != nil { 30 | panic(err) 31 | } 32 | 33 | if err = s.Ping(); err != nil { 34 | panic(err) 35 | } 36 | 37 | DB = s.DB("web") 38 | Books = DB.C("books") 39 | 40 | fmt.Println("You connected to your mongo database.") 41 | } 42 | 43 | // CloseSession closes mongodb session 44 | func CloseSession() { 45 | s.Close() 46 | } 47 | -------------------------------------------------------------------------------- /65_books_example/config/db_connection.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | // import ( 4 | // "log" 5 | // "time" 6 | 7 | // "gopkg.in/mgo.v2" 8 | // ) 9 | 10 | // // connect establishes connection 11 | // func connect() { 12 | 13 | // mongoDBDialInfo := &mgo.DialInfo{ 14 | // Addrs: []string{MongoDBHosts}, 15 | // Timeout: 100 * 365 * 24 * time.Hour, 16 | // Database: AuthDatabase, 17 | // Username: AuthUserName, 18 | // Password: AuthPassword, 19 | // FailFast: true, 20 | // } 21 | 22 | // // session maintains a pool of socket connections 23 | // mongoSession, err := mgo.DialWithInfo(mongoDBDialInfo) 24 | // if err != nil { 25 | // log.Fatalf("CreateSession: %s\n", err) 26 | // } 27 | 28 | // } 29 | -------------------------------------------------------------------------------- /65_books_example/config/tpl.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import "html/template" 4 | 5 | // TPL are all the html templates in the "templates" folder 6 | var TPL *template.Template 7 | 8 | func init() { 9 | TPL = template.Must(template.ParseGlob("templates/*.gohtml")) 10 | } 11 | -------------------------------------------------------------------------------- /65_books_example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "./config" 5 | "./records" 6 | "github.com/julienschmidt/httprouter" 7 | "log" 8 | "net/http" 9 | ) 10 | 11 | func main() { 12 | 13 | defer config.CloseSession() 14 | 15 | r := httprouter.New() 16 | r.ServeFiles("/static/*filepath", http.Dir("static")) 17 | r.GET("/", mainPage) 18 | r.GET("/items", records.Index) 19 | r.GET("/items/show", records.Show) 20 | r.GET("/items/create", records.Create) 21 | r.POST("/items/create/process", records.CreateProcess) 22 | r.GET("/items/update", records.Update) 23 | r.POST("/items/update/process", records.UpdateProcess) 24 | r.GET("/items/delete/process", records.DeleteProcess) 25 | r.NotFound = http.FileServer(http.Dir("public")) 26 | 27 | // Start HTTP 28 | go func() { 29 | err := http.ListenAndServe(":80", http.HandlerFunc(redirect)) 30 | if err != nil { 31 | log.Fatalln("Web server (HTTP): ", err) 32 | } 33 | }() 34 | 35 | // Start HTTPS 36 | err := http.ListenAndServeTLS(":443", "cert.pem", "key.pem", r) 37 | if err != nil { 38 | log.Fatal("Web server (HTTPS): ", err) 39 | } 40 | } 41 | 42 | // redirect used to move traffic from HTTP to same page on HTTPS 43 | func redirect(w http.ResponseWriter, req *http.Request) { 44 | http.Redirect(w, req, 45 | "https://"+req.Host+req.URL.String(), 46 | http.StatusTemporaryRedirect) 47 | } 48 | 49 | // mainPage is a redirect to the main page 50 | func mainPage(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { 51 | http.Redirect(w, r, "/v", http.StatusSeeOther) 52 | } 53 | -------------------------------------------------------------------------------- /65_books_example/static/style.css: -------------------------------------------------------------------------------- 1 | table { 2 | border-collapse: collapse; 3 | } 4 | .table, .text-wrap table { 5 | width: 100%; 6 | max-width: 100%; 7 | margin-bottom: 1rem; 8 | background-color: transparent; 9 | } 10 | .table th, .text-wrap table th, 11 | .table td, 12 | .text-wrap table td { 13 | padding: 0.75rem; 14 | vertical-align: top; 15 | border-top: 1px solid #dee2e6; 16 | } 17 | 18 | .table thead th, .text-wrap table thead th { 19 | vertical-align: bottom; 20 | border-bottom: 2px solid #dee2e6; 21 | } 22 | 23 | .table tbody + tbody, .text-wrap table tbody + tbody { 24 | border-top: 2px solid #dee2e6; 25 | } 26 | 27 | .table .table, .text-wrap table .table, .table .text-wrap table, .text-wrap .table table, .text-wrap table table { 28 | background-color: #f5f7fb; 29 | } 30 | 31 | 32 | .card-table { 33 | margin-bottom: 0; 34 | } 35 | 36 | .card-table tr:first-child td, 37 | .card-table tr:first-child th { 38 | border-top: 0; 39 | } 40 | 41 | .card-table tr td:first-child, 42 | .card-table tr th:first-child { 43 | padding-left: 1.5rem; 44 | } 45 | 46 | .card-table tr td:last-child, 47 | .card-table tr th:last-child { 48 | padding-right: 1.5rem; 49 | } 50 | 51 | .card-body + .card-table { 52 | border-top: 1px solid rgba(0, 40, 100, 0.12); 53 | } 54 | 55 | 56 | .table-vcenter td, 57 | .table-vcenter th { 58 | vertical-align: middle; 59 | } 60 | 61 | .text-nowrap { 62 | white-space: nowrap !important; 63 | } -------------------------------------------------------------------------------- /65_books_example/templates/books.gohtml: -------------------------------------------------------------------------------- 1 | {{template "header"}} 2 | 3 | 4 | 5 | 6 | 7 | {{range .}} 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | {{end}} 16 |
    ISBNTitleAuthor - PriceUpdateDelete
    {{.Isbn}}{{.Title}}{{.Author}} - {{.Price}}updatedelete
    17 | 18 | 19 | 20 | {{template "footer"}} 21 | -------------------------------------------------------------------------------- /65_books_example/templates/create.gohtml: -------------------------------------------------------------------------------- 1 | {{template "header"}} 2 | 3 |

    Create A New Book

    4 |
    5 | 6 | 7 | 8 | 9 | 10 |
    11 | 12 | {{template "footer"}} 13 | -------------------------------------------------------------------------------- /65_books_example/templates/created.gohtml: -------------------------------------------------------------------------------- 1 | {{template "header"}} 2 | 3 |

    Created A New Book

    4 | 5 |

    {{.Isbn}} - {{.Title}} - {{.Author}} {{.Price}}

    6 | 7 | {{template "footer"}} 8 | -------------------------------------------------------------------------------- /65_books_example/templates/show.gohtml: -------------------------------------------------------------------------------- 1 | {{template "header"}} 2 | 3 |

    {{.Isbn}} - {{.Title}} - {{.Author}} {{.Price}}

    4 | 5 | 9 | {{template "footer"}} 10 | -------------------------------------------------------------------------------- /65_books_example/templates/update.gohtml: -------------------------------------------------------------------------------- 1 | {{template "header"}} 2 | 3 |

    Update A Book

    4 |
    5 | 6 | 7 | 8 | 9 | 10 |
    11 | 15 | 16 | 17 | {{template "footer"}} 18 | -------------------------------------------------------------------------------- /65_books_example/templates/updated.gohtml: -------------------------------------------------------------------------------- 1 | {{template "header"}} 2 |

    Updated Book

    3 | 4 |

    {{.Isbn}} - {{.Title}} - {{.Author}} {{.Price}}

    5 | 6 | {{template "footer"}} 7 | -------------------------------------------------------------------------------- /66_server_sent_events/example2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Server-sent events demo 6 | 7 | 8 | 9 | example 1 10 | 11 | 12 |
      13 |
    14 | 15 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /66_server_sent_events/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | The EventSource interface is web content's interface to server-sent events. 9 | 10 | 11 | 12 | example 2 13 |
    14 | 15 |
    16 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /66_server_sent_events/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | "strconv" 7 | "time" 8 | 9 | "gopkg.in/antage/eventsource.v1" 10 | ) 11 | 12 | func main() { 13 | es := eventsource.New(nil, nil) 14 | defer es.Close() 15 | http.Handle("/events", es) 16 | 17 | // send the message 18 | go func() { 19 | id := 1 20 | for { 21 | es.SendEventMessage("tick: "+strconv.Itoa(id), "", strconv.Itoa(id)) 22 | id++ 23 | time.Sleep(1 * time.Second) 24 | } 25 | }() 26 | 27 | // static content 28 | http.Handle("/", http.FileServer(http.Dir("."))) 29 | 30 | // run the server 31 | fmt.Println(http.ListenAndServe(":8080", nil)) 32 | } 33 | 34 | // https://developer.mozilla.org/en-US/docs/Web/API/EventSource 35 | -------------------------------------------------------------------------------- /67_stringutil/reverse.go: -------------------------------------------------------------------------------- 1 | // Package stringutil contains utility functions for working with strings. 2 | package stringutil 3 | 4 | // Reverse returns its argument string reversed rune-wise left to right. 5 | func Reverse(s string) string { 6 | r := []rune(s) 7 | for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 { 8 | r[i], r[j] = r[j], r[i] 9 | } 10 | return string(r) 11 | } 12 | -------------------------------------------------------------------------------- /67_stringutil/reverse_test.go: -------------------------------------------------------------------------------- 1 | package stringutil 2 | 3 | import "testing" 4 | 5 | func TestReverse(t *testing.T) { 6 | for _, c := range []struct { 7 | in, want string 8 | }{ 9 | {"Hello, world", "dlrow ,olleH"}, 10 | {"Hello, 世界", "界世 ,olleH"}, 11 | {"", ""}, 12 | } { 13 | got := Reverse(c.in) 14 | if got != c.want { 15 | t.Errorf("Reverse(%q) == %q, want %q", c.in, got, c.want) 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /68_iota/fileSizes.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | ) 7 | 8 | // ByteSize used for file size 9 | type ByteSize float64 10 | 11 | // file sizes from small to large 12 | const ( 13 | _ = iota // ignore first value by assigning to blank identifier 14 | KB ByteSize = 1 << (10 * iota) // 1 << (10*1) 15 | MB // 1 << (10*2) 16 | GB // 1 << (10*3) 17 | TB // 1 << (10*4) 18 | PB // 1 << (10*5) 19 | EB // 1 << (10*6) 20 | ZB // 1 << (10*7) 21 | YB // 1 << (10*8) 22 | ) 23 | 24 | func (s ByteSize) String() string { 25 | return strconv.FormatFloat(float64(s), 'f', -1, 64) + " bytes" 26 | } 27 | 28 | func main() { 29 | fmt.Println(KB) 30 | fmt.Println(MB) 31 | fmt.Println(GB) 32 | fmt.Println(PB) 33 | fmt.Println(EB) 34 | fmt.Println(ZB) 35 | fmt.Println(YB) 36 | } 37 | -------------------------------------------------------------------------------- /68_iota/seasons.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | ) 7 | 8 | // Season used for season of the year 9 | type Season int 10 | 11 | // Seasons of the year 12 | const ( 13 | Spring Season = iota 14 | Summer 15 | Autumn 16 | Winter 17 | ) 18 | 19 | func (s Season) String() string { 20 | lang := os.Getenv("LANG") 21 | switch lang { 22 | case "sp": 23 | return [...]string{"vesna", "leto", "osen'", "zima"}[s] 24 | case "en": 25 | return [...]string{"spring", "summer", "autumn", "winner"}[s] 26 | default: 27 | return [...]string{"spring", "summer", "autumn", "winner"}[s] 28 | } 29 | } 30 | 31 | func main() { 32 | os.Setenv("LANG", "en") 33 | 34 | fmt.Println(Spring) 35 | fmt.Println(Summer) 36 | fmt.Println(Autumn) 37 | fmt.Println(Winter) 38 | } 39 | 40 | // https://programming.guide/go/iota.html 41 | -------------------------------------------------------------------------------- /68_iota/weekdays.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | // Weekday has underlying type iota 8 | type Weekday int 9 | 10 | // Days of the week 11 | const ( 12 | Sun Weekday = iota 13 | Mon 14 | Tue 15 | Wed 16 | Thu 17 | Fri 18 | Sat 19 | ) 20 | 21 | func (day Weekday) String() string { 22 | return [...]string{"Sunday", "Monday", "Tue'", "Wed", "Thursday", "Friday", "Saturday"}[day] 23 | } 24 | 25 | // Weekend is it? 26 | func (day Weekday) Weekend() bool { 27 | switch day { 28 | case Sun, Sat: 29 | return true 30 | default: 31 | return false 32 | } 33 | } 34 | 35 | func main() { 36 | fmt.Println(Sun) 37 | fmt.Println(Mon) 38 | fmt.Println(Wed, Wed.Weekend()) 39 | fmt.Println(Sat, Sat.Weekend()) 40 | fmt.Println(Sun, Sun.Weekend()) 41 | fmt.Println(Mon, Mon.Weekend()) 42 | fmt.Println(Fri, Fri.Weekend()) 43 | } 44 | -------------------------------------------------------------------------------- /69_JSON/read_many_objects.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "fmt" 7 | "io" 8 | ) 9 | 10 | var j = []byte(` 11 | {"a":1} 12 | {"a":2} 13 | {"a":3} 14 | `) 15 | 16 | func main() { 17 | dec := json.NewDecoder(bytes.NewBuffer(j)) 18 | 19 | for { 20 | 21 | var v interface{} 22 | err := dec.Decode(&v) 23 | if err == io.EOF { 24 | break 25 | } else if err != nil { 26 | fmt.Println(err) 27 | } 28 | 29 | fmt.Println(v) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Zelenko 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. --------------------------------------------------------------------------------