├── go.sum ├── go.mod ├── static ├── favicon.ico ├── screenshot.png └── index.html ├── test_browser.sh ├── design ├── figlayout.fig ├── figlayout.png ├── y.html ├── x.html └── main.css ├── app ├── collections.go ├── flowControl.go ├── async.go ├── app_types.go ├── regex.go ├── recursion.go ├── binary.go ├── strings.go ├── methods.go ├── functions.go ├── collections_test.go ├── flowControl_test.go ├── operators.go ├── async_test.go ├── test_util.go ├── slices.go ├── binary_test.go ├── functions_test.go ├── recursion_test.go ├── methods_test.go ├── regex_test.go ├── strings_test.go ├── operators_test.go └── slices_test.go ├── test_browser.cmd ├── .gitignore ├── .vscode └── launch.json ├── .github └── workflows │ └── go.yml ├── test_all.sh ├── LICENSE ├── test_all.cmd ├── lessons.md ├── test_all.go ├── main.go ├── README.md └── parse.go /go.sum: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module dmh2000.xyz/goassessment 2 | 3 | go 1.18 4 | -------------------------------------------------------------------------------- /static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmh2000/go_assessment/HEAD/static/favicon.ico -------------------------------------------------------------------------------- /test_browser.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # to specify port, use 'go run . -port=8081' 3 | go run . 4 | -------------------------------------------------------------------------------- /design/figlayout.fig: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmh2000/go_assessment/HEAD/design/figlayout.fig -------------------------------------------------------------------------------- /design/figlayout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmh2000/go_assessment/HEAD/design/figlayout.png -------------------------------------------------------------------------------- /static/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmh2000/go_assessment/HEAD/static/screenshot.png -------------------------------------------------------------------------------- /app/collections.go: -------------------------------------------------------------------------------- 1 | package goassessment 2 | 3 | func MakeMap(keys []interface{}, values []interface{}) map[interface{}]interface{} { 4 | m := make(map[interface{}]interface{}) 5 | 6 | return m 7 | } 8 | 9 | func MakeList(data []interface{}) LinkedList { 10 | var list LinkedList 11 | 12 | return list 13 | } 14 | -------------------------------------------------------------------------------- /test_browser.cmd: -------------------------------------------------------------------------------- 1 | @rem start the test web server 2 | @rem on Windows, 'go run' can conflict with some antivirus, so 3 | @rem this script will build the .exe first, then run it. 4 | @rem that seems to work around some of the antivirus tools 5 | @rem build step 6 | go build . 7 | @rem to specify a port, change this to 'goassessment.exe -port 8081' 8 | goassessment.exe 9 | -------------------------------------------------------------------------------- /app/flowControl.go: -------------------------------------------------------------------------------- 1 | package goassessment 2 | 3 | // write a function that receives a number as its argument; 4 | // if the number is divisible by 3, the function should return 'fizz'; 5 | // if the number is divisible by 5, the function should return 'buzz'; 6 | // if the number is divisible by 3 and 5, the function should return 7 | // 'fizzbuzz'; 8 | // 9 | // otherwise the function should return the number as a string 10 | func fizzBuzz(num int) string { 11 | return "" 12 | } 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, built with `go test -c` 9 | *.test 10 | 11 | 12 | # Output of the go coverage tool, specifically when used with LiteIDE 13 | *.out 14 | 15 | # Dependency directories (remove the comment below to include it) 16 | # vendor/ 17 | 18 | # miscellaneous files to ignore 19 | js-assessment 20 | static/bootstrap-4.5.0-dist 21 | solutions 22 | __debug_bin 23 | goassessment 24 | results.txt 25 | -------------------------------------------------------------------------------- /app/async.go: -------------------------------------------------------------------------------- 1 | package goassessment 2 | 3 | /** 4 | * Write a function, delayedCount, that takes two arguments: 5 | * a send channel 'c' and a receive channel 'q'. 6 | * The function is called within a goroutine. 7 | * The function should send the values 0 .. 4 on the send channel, 8 | * with a delay of 10 milliseconds or greater before sending each value. 9 | * When the function receives a message on the 'q' channel it should 10 | * send a final value of 10 then return 11 | */ 12 | func delayedCount(c chan int, q chan int) { 13 | } 14 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Launch", 9 | "type": "go", 10 | "request": "launch", 11 | "mode": "auto", 12 | "program": "${fileDirname}", 13 | "env": {}, 14 | "args": [] 15 | } 16 | ] 17 | } -------------------------------------------------------------------------------- /.github/workflows/go.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a golang project 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go 3 | 4 | name: Go 5 | 6 | on: 7 | push: 8 | branches: [ "main", "collections" ] 9 | pull_request: 10 | branches: [ "main", "collections" ] 11 | 12 | jobs: 13 | 14 | build: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v3 18 | 19 | - name: Set up Go 20 | uses: actions/setup-go@v4 21 | with: 22 | go-version: '1.20' 23 | 24 | - name: Test 25 | run: ./test_all.sh 26 | -------------------------------------------------------------------------------- /app/app_types.go: -------------------------------------------------------------------------------- 1 | package goassessment 2 | 3 | // Person definition 4 | type Person struct { 5 | age int 6 | name string 7 | } 8 | 9 | // PersonSlice slice of 10 | type PersonSlice []Person 11 | 12 | // Employee subtype of Person 13 | type Employee struct { 14 | p Person 15 | id int 16 | } 17 | 18 | // Notifier interface 19 | type Notifier interface { 20 | notify() string 21 | } 22 | 23 | // Dir recursive definition of a file structure 24 | type Dir struct { 25 | name string 26 | files []string 27 | dirs []Dir 28 | } 29 | 30 | type LinkedListElement struct { 31 | next *LinkedListElement 32 | value interface{} 33 | } 34 | 35 | type LinkedList struct { 36 | head *LinkedListElement 37 | } 38 | -------------------------------------------------------------------------------- /app/regex.go: -------------------------------------------------------------------------------- 1 | package goassessment 2 | 3 | // write a function that checks if the string contains a decimal number 4 | func containsNumber(s string) bool { 5 | return false 6 | } 7 | 8 | // write a function that checks if the string ends with a vowel 9 | func endsWithVowel(s string) bool { 10 | return false 11 | } 12 | 13 | // write a function that captures and returns the first string of 3 decimal digits 14 | func captureThreeNumbers(s string) string { 15 | return "" 16 | } 17 | 18 | // write a function that checks if the string matches a specified pattern 19 | func matchesPattern(s string) bool { 20 | return false 21 | } 22 | 23 | // write a function that checks if the string is a correctly-formatted monetary amounts in USD 24 | func isUSD(s string) bool { 25 | return false 26 | } 27 | -------------------------------------------------------------------------------- /app/recursion.go: -------------------------------------------------------------------------------- 1 | package goassessment 2 | 3 | // write a function that returns a list of files starting 4 | // from a directory. if dirName == "" start from top level. 5 | // else start from specified directory 6 | func listFiles(data Dir, dirName string) []string { 7 | return nil 8 | } 9 | 10 | // wrote a function that returns all permutations of the input array 11 | // hint : https://www.geeksforgeeks.org/heaps-algorithm-for-generating-permutations/ 12 | func permute(arr []int) [][]int { 13 | return nil 14 | } 15 | 16 | // write a function that returns the fibonnaci number of n 17 | func fibonacci(n int) int { 18 | return -1 19 | } 20 | 21 | // write a function that returns an array of strings with all valid sets of n parens 22 | // hint : https://www.geeksforgeeks.org/print-all-combinations-of-balanced-parentheses/ 23 | func validParentheses(n int) []string { 24 | return nil 25 | } 26 | -------------------------------------------------------------------------------- /app/binary.go: -------------------------------------------------------------------------------- 1 | package goassessment 2 | 3 | // write a function that returns the 0 or 1 value at the specified bit position 4 | func valueAtbit(num int, bit int) int { 5 | return -1 6 | } 7 | 8 | // write a function that returns the base 10 value of the binary string 9 | func base10(n string) int { 10 | return -1 11 | } 12 | 13 | // write a function that returns the binary value of num as a string 14 | func convertToBinary(num int) string { 15 | return "" 16 | } 17 | 18 | // write a function that returns the bitwise OR of the input values 19 | func bitwiseOr(x int, y int, z int) int { 20 | return -1 21 | } 22 | 23 | // write a function that returns the bitwise AND of the input values 24 | func bitwiseAnd(x int, y int, z int) int { 25 | return -1 26 | } 27 | 28 | // write a function that returns the bitwise XOR of the input values 29 | func bitwiseXor(x int, y int, z int) int { 30 | return -1 31 | } 32 | -------------------------------------------------------------------------------- /app/strings.go: -------------------------------------------------------------------------------- 1 | package goassessment 2 | 3 | // write a function that composes a string from arguments 4 | func composeString(a string, b string) string { 5 | return "" 6 | } 7 | 8 | // write a function that returns a string from a byte array 9 | func fromBytes(b []byte) string { 10 | return "" 11 | } 12 | 13 | // write a function that splits a string into words 14 | func splitString(s string) []string { 15 | return nil 16 | } 17 | 18 | // write a function that converts a string to Title Case 19 | func titleString(s string) string { 20 | return "" 21 | } 22 | 23 | func runesFromString(s string) []rune { 24 | return nil 25 | } 26 | 27 | // write a function that reduces adjacent repeated characters 28 | func reduceString(s string, count int) string { 29 | return "" 30 | } 31 | 32 | // write a function that wraps lines at a given number of columns without breaking works 33 | func wordWrap(s string, column int) string { 34 | return "" 35 | } 36 | 37 | // write a function that reverses the characters in a string 38 | func reverseString(s string) string { 39 | return "" 40 | } 41 | -------------------------------------------------------------------------------- /app/methods.go: -------------------------------------------------------------------------------- 1 | package goassessment 2 | 3 | import "container/list" 4 | 5 | // fix the Sort interface for PersonSlice 6 | // fix the Heap interface for PersonSlice sorted by ascending age 7 | // fix the List interface for PersonSlice 8 | 9 | // Len ... 10 | func (p PersonSlice) Len() int { return len(p) } 11 | 12 | // Less ... 13 | func (p PersonSlice) Less(i int, j int) bool { 14 | return false 15 | } 16 | 17 | // Swap ... 18 | func (p PersonSlice) Swap(i int, j int) { 19 | 20 | } 21 | 22 | // Push ... 23 | func (p *PersonSlice) Push(x interface{}) { 24 | 25 | } 26 | 27 | // Pop ... 28 | func (p *PersonSlice) Pop() interface{} { 29 | return nil 30 | } 31 | 32 | // write a function that creates and populates a list 33 | func populateList(p PersonSlice) *list.List { 34 | var a *list.List 35 | return a 36 | } 37 | 38 | // write a function that sends a notification for different types 39 | func sendNotification(n Notifier) string { 40 | return "" 41 | } 42 | 43 | // write a function that returns an integer value from an interface{} 44 | func intFromInterface(i interface{}) int { 45 | return -1 46 | } 47 | -------------------------------------------------------------------------------- /test_all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | 4 | echo "Operators" 5 | go test -v ./app/operators*.go ./app/test_util.go ./app/app_types.go 6 | 7 | echo "Flow Control" 8 | go test -v ./app/flowControl*.go ./app/test_util.go ./app/app_types.go 9 | 10 | echo "Strings" 11 | go test -v ./app/strings*.go ./app/test_util.go ./app/app_types.go 12 | 13 | echo "Slices" 14 | go test -v ./app/slices*.go ./app/test_util.go ./app/app_types.go 15 | 16 | echo "Binary" 17 | go test -v ./app/binary*.go ./app/test_util.go ./app/app_types.go 18 | 19 | echo "Functions" 20 | go test -v ./app/functions*.go ./app/test_util.go ./app/app_types.go 21 | 22 | echo "Methods" 23 | go test -v ./app/method*.go ./app/test_util.go ./app/app_types.go 24 | 25 | echo "Collections" 26 | go test -v ./app/collections*.go ./app/test_util.go ./app/app_types.go 27 | 28 | echo "Recursion" 29 | go test -v ./app/recursion*.go ./app/test_util.go ./app/app_types.go 30 | 31 | echo "Regexp" 32 | go test -v ./app/regex*.go ./app/test_util.go ./app/app_types.go 33 | 34 | echo "Async" 35 | go test -v ./app/async*.go ./app/test_util.go ./app/app_types.go 36 | 37 | exit 0 -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 david howard 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. 22 | -------------------------------------------------------------------------------- /app/functions.go: -------------------------------------------------------------------------------- 1 | package goassessment 2 | 3 | // write a function that returns a function 4 | func fFunction(str string) func(string) string { 5 | return nil 6 | } 7 | 8 | // write a function that returns a slice of closures 9 | func fMakeClosures(fn func(x int) int, arr []int) []func() int { 10 | return nil 11 | } 12 | 13 | // write a function that implements a partial application 14 | func fPartial( 15 | fn func(a string, b string, c string) string, 16 | str1 string, 17 | str2 string, 18 | ) func(string) string { 19 | return nil 20 | } 21 | 22 | // write a function that creates a new array populated 23 | // with the result of calling the provided function 24 | func fMap(fn func(a int) int, arr []int) []int { 25 | return nil 26 | } 27 | 28 | // write a function that applies the reducer to a slice of integers 29 | func fReduce(fn func(acc int, val int) int, arr []int) int { 30 | return -1 31 | } 32 | 33 | // write a function that applies the filter to a slice of integers 34 | func fFilter(fn func(a int) bool, arr []int) []int { 35 | return nil 36 | } 37 | 38 | // write a function that handles a variadic argument 39 | func fVariadic(s ...int) string { 40 | return "" 41 | } 42 | -------------------------------------------------------------------------------- /app/collections_test.go: -------------------------------------------------------------------------------- 1 | package goassessment 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | // write a function that returns and empty map 8 | func TestCollectionMap(t *testing.T) { 9 | defer testPanic(t) // handle panics and syntax errors 10 | setTestInstance(t) // update test instance for logging 11 | 12 | keys := []interface{}{"a", "b", "c"} 13 | values := []interface{}{1, 2, 3} 14 | m := MakeMap(keys, values) 15 | if len(m) == 0 { 16 | t.Error("map is empty") 17 | } 18 | 19 | v, ok := m["a"] 20 | if !ok { 21 | t.Error("map does not contain key 'a'") 22 | } 23 | if v != 1 { 24 | t.Error("map['a'] is not 1") 25 | } 26 | 27 | v, ok = m["b"] 28 | if !ok { 29 | t.Error("map does not contain key 'b'") 30 | } 31 | if v != 2 { 32 | t.Error("map['b'] is not 2") 33 | } 34 | 35 | v, ok = m["c"] 36 | if !ok { 37 | t.Error("map does not contain key 'c'") 38 | } 39 | if v != 3 { 40 | t.Error("map['c'] is not 2") 41 | } 42 | } 43 | 44 | // write a function that returns a linked list supporting any type 45 | func TestCollectionLinkedList(t *testing.T) { 46 | defer testPanic(t) // handle panics and syntax errors 47 | setTestInstance(t) // update test instance for logging 48 | 49 | data := []interface{}{1, 2, 3, 4} 50 | list := MakeList(data) 51 | if list.head == nil { 52 | t.Error("list.head is nil") 53 | } 54 | 55 | node := list.head 56 | 57 | for _, v := range data { 58 | if node == nil { 59 | t.Error("node is nil") 60 | break 61 | } 62 | 63 | if node.value.(int) != v { 64 | t.Error("node.value is not", v) 65 | break 66 | } 67 | node = node.next 68 | } 69 | 70 | if node != nil { 71 | t.Error("node is not nil") 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /design/y.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |
5 |

Go-Assessment Test Results

6 |
7 |
progress 50%
8 |
passed 42
9 |
failed 15
10 |
11 |
12 |
Mon Dec 28 21:54:01 -0800 PST 2020 : ET 4.754 sec
13 |
14 |
15 | 16 | 17 |
18 |
Goal : You should be able to .......
19 |
FAIL
20 |
21 |
22 |
operator-test.go:15
23 |
this should be equal to 0
24 |
error
25 |
26 |
27 |
operator-test.go:19
28 |
this should be equal to 1
29 |
error
30 |
31 |
32 | 33 | 34 |
35 |
Goal : You should be able to .......
36 |
PASS
37 |
38 |
39 | 40 | 41 | -------------------------------------------------------------------------------- /app/flowControl_test.go: -------------------------------------------------------------------------------- 1 | package goassessment 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | // write a function that receives a number as its argument; 8 | // if the number is divisible by 3, the function should return 'fizz'; 9 | // if the number is divisible by 5, the function should return 'buzz'; 10 | // if the number is divisible by 3 and 5, the function should return 11 | // 'fizzbuzz'; 12 | // 13 | // otherwise the function should return the number as a string 14 | func TestFlowControl(t *testing.T) { 15 | defer testPanic(t) // handle panics and syntax errors // handle panics and syntax errors 16 | setTestInstance(t) // update test instance for logging 17 | 18 | t.Log("GOAL: you should be able to conditionally branch your code") 19 | 20 | var num int 21 | var s string 22 | 23 | // prime number 24 | num = 97 25 | 26 | s = fizzBuzz(2) 27 | if s != "2" { 28 | t.Error(shouldBe(s, "2")) 29 | } 30 | 31 | s = fizzBuzz(101) 32 | if s != "101" { 33 | t.Error(shouldBe(s, "101")) 34 | } 35 | 36 | s = fizzBuzz(3) 37 | if s != "fizz" { 38 | t.Error(shouldBe(s, "fizz")) 39 | } 40 | 41 | s = fizzBuzz(6) 42 | if s != "fizz" { 43 | t.Error(shouldBe(s, "fizz")) 44 | } 45 | 46 | s = fizzBuzz(num * 3) 47 | if s != "fizz" { 48 | t.Error(shouldBe(s, "fizz")) 49 | } 50 | 51 | s = fizzBuzz(5) 52 | if s != "buzz" { 53 | t.Error(shouldBe(s, "buzz")) 54 | } 55 | 56 | s = fizzBuzz(10) 57 | if s != "buzz" { 58 | t.Error(shouldBe(s, "buzz")) 59 | } 60 | 61 | s = fizzBuzz(num * 5) 62 | if s != "buzz" { 63 | t.Error(shouldBe(s, "buzz")) 64 | } 65 | 66 | s = fizzBuzz(15) 67 | if s != "fizzbuzz" { 68 | t.Error(shouldBe(s, "fizzbuzz")) 69 | } 70 | 71 | s = fizzBuzz(num * 3 * 5) 72 | if s != "fizzbuzz" { 73 | t.Error(shouldBe(s, "fizzbuzz")) 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /app/operators.go: -------------------------------------------------------------------------------- 1 | package goassessment 2 | 3 | // write a function that uses the addition operator 4 | func add(a int, b int) int { 5 | return -1 6 | } 7 | 8 | // write a function that uses the subtraction operator 9 | func subtract(a int, b int) int { 10 | return -1 11 | } 12 | 13 | // write a function that uses the multiplication operator 14 | func multiply(a int, b int) int { 15 | return -1 16 | } 17 | 18 | // write a function that uses the division operator 19 | func divide(a int, b int) int { 20 | return -1 21 | } 22 | 23 | // write a function that uses the remainder (integer modulo) operator 24 | func remainder(a int, b int) int { 25 | return -1 26 | } 27 | 28 | // write a function that uses the equal operator 29 | func equal(a int, b int) bool { 30 | return false 31 | } 32 | 33 | // write a function that uses the not equal operator 34 | func notEqual(a int, b int) bool { 35 | return false 36 | } 37 | 38 | // write a function that uses the less-than operator 39 | func lessThan(a int, b int) bool { 40 | return false 41 | } 42 | 43 | // write a function that uses the less-than or equal operator 44 | func lessThanEqual(a int, b int) bool { 45 | return false 46 | } 47 | 48 | // write a function that uses the greater-than operator 49 | func greaterThan(a int, b int) bool { 50 | return false 51 | } 52 | 53 | // write a function that uses the greater-than or equal operator 54 | func greaterThanEqual(a int, b int) bool { 55 | return false 56 | } 57 | 58 | // write a function that returns true if either argument is true 59 | func either(a bool, b bool) bool { 60 | return false 61 | } 62 | 63 | // write a function that returns true only if both arguments are true 64 | func both(a bool, b bool) bool { 65 | return false 66 | } 67 | 68 | // write a function that returns true only if both arguments are false 69 | func none(a bool, b bool) bool { 70 | return false 71 | } 72 | -------------------------------------------------------------------------------- /test_all.cmd: -------------------------------------------------------------------------------- 1 | @echo "Operators" ./app/app_types.go 1>> results.txt 2>&1 2 | go test -v ./app/operators.go ./app/operators_test.go ./app/test_util.go ./app/app_types.go 1>> results.txt 2>>&1 3 | @echo "Flow Control" >results.txt 4 | go test -v ./app/flowControl.go ./app/flowControl_test.go ./app/test_util.go ./app/app_types.go 1>> results.txt 2>&1 5 | @echo "Strings" ./app/app_types.go 1>> results.txt 2>&1 6 | go test -v ./app/strings.go ./app/strings_test.go ./app/test_util.go ./app/app_types.go 1>> results.txt 2>>&1 7 | @echo "Slices" ./app/app_types.go 1>> results.txt 2>&1 8 | go test -v ./app/slices.go ./app/slices_test.go ./app/test_util.go ./app/app_types.go 1>> results.txt 2>>&1 9 | @echo "Binary" ./app/app_types.go 1>> results.txt 2>&1 10 | go test -v ./app/binary.go ./app/binary_test.go ./app/test_util.go ./app/app_types.go 1>> results.txt 2>>&1 11 | @echo "Functions" ./app/app_types.go 1>> results.txt 2>&1 12 | go test -v ./app/functions.go ./app/functions_test.go ./app/test_util.go ./app/app_types.go 1>> results.txt 2>>&1 13 | @echo "Recursion" ./app/app_types.go 1>> results.txt 2>&1 14 | go test -v ./app/recursion.go ./app/recursion_test.go ./app/test_util.go ./app/app_types.go 1>> results.txt 2>>&1 15 | @echo "Methods" ./app/app_types.go 1>> results.txt 2>&1 16 | go test -v ./app/methods.go ./app/methods_test.go ./app/test_util.go ./app/app_types.go 1>> results.txt 2>>&1 17 | @echo "Regexp" ./app/app_types.go 1>> results.txt 2>&1 18 | go test -v ./app/regex.go ./app/regex_test.go ./app/test_util.go ./app/app_types.go 1>> results.txt 2>>&1 19 | @echo "Async" ./app/app_types.go 1>> results.txt 2>&1 20 | go test -v ./app/async.go ./app/async_test.go ./app/test_util.go ./app/app_types.go 1>> results.txt 2>>&1 21 | @echo "Collections" ./app/app_types.go 1>> results.txt 2>&1 22 | go test -v ./app/collections.go ./app/collections_test.go ./app/test_util.go ./app/app_types.go 1>> results.txt 2>>&1 23 | -------------------------------------------------------------------------------- /app/async_test.go: -------------------------------------------------------------------------------- 1 | package goassessment 2 | 3 | import ( 4 | "sync" 5 | "testing" 6 | "time" 7 | ) 8 | 9 | /** 10 | * Write a function, delayedCount, that takes two arguments: 11 | * a send channel 'c' and a receive channel 'q'. 12 | * The function is called within a goroutine. 13 | * The function should send the values 0 .. 4 on the send channel, 14 | * with a delay of 10 milliseconds or greater before sending each value. 15 | * When the function receives a message on the 'q' channel it should 16 | * send a final value of 10 then return 17 | */ 18 | 19 | func TestAsync(t *testing.T) { 20 | defer testPanic(t) // handle panics and syntax errors // handle panics and syntax errors 21 | setTestInstance(t) // update test instance for logging 22 | 23 | t.Log("GOAL: you should be able to send values to a channel with a delay") 24 | 25 | var c chan int 26 | var q chan int 27 | var wg sync.WaitGroup 28 | 29 | c = make(chan int) 30 | q = make(chan int, 2) 31 | 32 | wg.Add(2) 33 | 34 | go func() { 35 | var j int 36 | loop: 37 | for i := 0; i < 5; i++ { 38 | // record current time 39 | t0 := time.Now() 40 | 41 | // wait for response from go routine or timeout 42 | select { 43 | case j = <-c: 44 | if j != i { 45 | t.Error(shouldBe(j, i)) 46 | } 47 | case <-time.After(2000 * time.Millisecond): 48 | t.Error("select statement timed out") 49 | break loop 50 | } 51 | 52 | // compute time difference 53 | t1 := time.Now() 54 | d := t1.Sub(t0) 55 | if d.Milliseconds() < 10 { 56 | t.Error("delay of ", d.Milliseconds(), "should be greater than 10ms") 57 | } 58 | } 59 | // signal quit 60 | q <- 0 61 | 62 | // check final value 63 | select { 64 | case j = <-c: 65 | if j != 10 { 66 | t.Error(shouldBe(j, 10)) 67 | } 68 | case <-time.After(500 * time.Millisecond): 69 | t.Error("select statement timed out") 70 | } 71 | 72 | wg.Done() 73 | }() 74 | 75 | go func() { 76 | delayedCount(c, q) 77 | wg.Done() 78 | }() 79 | 80 | wg.Wait() 81 | } 82 | -------------------------------------------------------------------------------- /lessons.md: -------------------------------------------------------------------------------- 1 | ## Lessons Learned From A Browser Based Go Test Driver 2 | 3 | The following is not news to experienced Go developers but it was to me. 4 | 5 | I hadn't written a Go web server app before, so going in it seemed simple. Then 6 | things started to go wrong. I learned that the Go runtime supports a form a recovery 7 | that many other runtimes don't. 8 | 9 | 1. Defer-Recover is the best thing going for a server app 10 | - [read more about it here](https://blog.golang.org/defer-panic-and-recover) 11 | - something most conventional runtimes don't support 12 | - Go allows recovery from panics, and even syntax errors in tests 13 | - in a node.js server app,for example, the recovery strategy is typically to let the process die and have it auto restarted 14 | - in a Go program, you can use defer-recover to catch panics and possibly continue 15 | - for example, if one web handler is crashing because some resource is missing, you can do a deferred recovery, log something and potentially disable the handler, while letting the rest of the program continue 16 | - or, just do a comprehensive log and restart 17 | 2. Go native testing works as though tests are compiled at runtime 18 | - syntax errors don't show up until a test is run 19 | - with a syntax error, output will not be what you expect 20 | - using a deferred recovery you can continue and log information even after a syntax error in a test 21 | 3. all tests should probably have a deferred recovery procedure to catch panics 22 | - a panic in a test won't kill the whole test sequence, just that test. it will be marked Fail 23 | - with a deferred recovery you can log why the panic occurred instead of a cryptic fail message 24 | 4. a simple web server may not be so simple 25 | - see the rules for handler patterns in servemux doc 26 | - '/' will handle anything starting with '/' 27 | - longer patterns are checked first 28 | - chrome requests favicon.ico even if there is no link in the html 29 | - should have deferred recoveries to catch panics in handlers 30 | -------------------------------------------------------------------------------- /app/test_util.go: -------------------------------------------------------------------------------- 1 | package goassessment 2 | 3 | import ( 4 | "fmt" 5 | "path" 6 | "runtime" 7 | "testing" 8 | ) 9 | 10 | // test output helper 11 | func shouldBe(a interface{}, b interface{}) string { 12 | return fmt.Sprintf("%v should be %v\n", a, b) 13 | } 14 | 15 | // check if two slices are equal 16 | func testIntSliceEqual(a []int, b []int) bool { 17 | if len(a) != len(b) { 18 | return false 19 | } 20 | for i := 0; i < len(a); i++ { 21 | if a[i] != b[i] { 22 | return false 23 | } 24 | } 25 | 26 | return true 27 | 28 | } 29 | 30 | // return index of target or -1 if not found 31 | func testIndexOfStrings(a []string, target string) int { 32 | for i, v := range a { 33 | if v == target { 34 | return i 35 | } 36 | } 37 | return -1 38 | } 39 | 40 | // find index of slice of integers in 2d array 41 | func testIndexOfIntSlice(a [][]int, target []int) int { 42 | for i, v := range a { 43 | // different lengths 44 | if len(v) != len(target) { 45 | return -1 46 | } 47 | // equal values 48 | for j := 0; j < len(v); j++ { 49 | if target[j] == v[j] { 50 | return i 51 | } 52 | } 53 | } 54 | return -1 55 | } 56 | 57 | // catch a panic in a test 58 | // must be called with defer 59 | func testPanic(t *testing.T) { 60 | r := recover() 61 | if r != nil { 62 | _, _, line, ok := runtime.Caller(3) 63 | if ok { 64 | t.Errorf("panic in solution at line %v : %v", line, r) 65 | } else { 66 | t.Errorf("panic in solution %v", r) 67 | } 68 | } 69 | } 70 | 71 | // a bit of kludgery to make testing.T.Log available to the 72 | // app skeletons for debugging. this is to avoid having to 73 | // pass the testing.T instance to each app function under test 74 | // 75 | //lint:ignore U1000 this is used by the app skeletons 76 | var testUtilT *testing.T 77 | 78 | // save the test instance 79 | func setTestInstance(t *testing.T) { 80 | testUtilT = t 81 | } 82 | 83 | // print a string to the test log 84 | // 85 | //lint:ignore U1000 this is used by the app skeletons 86 | func testLog(s string) { 87 | _, file, line, ok := runtime.Caller(1) 88 | if testUtilT != nil && ok { 89 | testUtilT.Logf("%v:%v:%v", path.Base(file), line, s) 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /app/slices.go: -------------------------------------------------------------------------------- 1 | package goassessment 2 | 3 | // SLICES 4 | // For those functions that take a slice as input and return a slice, 5 | // you can either modify the input slice or make a copy for the return 6 | // the tests don't require that the input slice is not modified 7 | 8 | // write a function that returns the index of an item in a slice 9 | func indexOf(a []int, item int) int { 10 | return -1 11 | } 12 | 13 | // write a function that sums the values in a slice 14 | func sum(a []int) int { 15 | return -1 16 | } 17 | 18 | // write a function that removes all instances of a value from a slice 19 | func remove(a []int, item int) []int { 20 | return nil 21 | } 22 | 23 | // write a function that returns the value of the first element in a slice (wihtout removing it) 24 | func front(a []int) int { 25 | return -1 26 | } 27 | 28 | // write a function that returns the value of the last element in a slice (wihtout removing it) 29 | func back(a []int) int { 30 | return -1 31 | } 32 | 33 | // write a function that adds an item to the end of a slice 34 | func pushBack(a []int, item int) []int { 35 | return nil 36 | } 37 | 38 | // write a function that removes an item to the end of a slice 39 | func popBack(a []int) []int { 40 | return nil 41 | } 42 | 43 | // write a function that adds an item to the front of a slice 44 | func pushFront(a []int, item int) []int { 45 | return nil 46 | } 47 | 48 | // write a function that removes an item from the front of a slice 49 | func popFront(a []int) []int { 50 | return nil 51 | } 52 | 53 | // write a function that concatenates two slices 54 | func concat(a []int, b []int) []int { 55 | return nil 56 | } 57 | 58 | // write a function that adds an item to a slice at the specified index 59 | func insert(a []int, item int, index int) []int { 60 | return nil 61 | } 62 | 63 | // write a function that returns a count of matching items in a slice 64 | func count(a []int, item int) int { 65 | return -1 66 | } 67 | 68 | // write a function that finds duplicates in a slice 69 | func duplicates(a []int) []int { 70 | return nil 71 | } 72 | 73 | // write a function that squares all items in a slice 74 | func square(a []int) []int { 75 | return nil 76 | } 77 | 78 | // write a function that returns all the indices in a slice that matches an item 79 | func findAllOccurrences(a []int, item int) []int { 80 | return nil 81 | } 82 | -------------------------------------------------------------------------------- /test_all.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "os" 6 | "os/exec" 7 | "time" 8 | ) 9 | 10 | func runTest(title string, test string, f *os.File) []string { 11 | var b []byte 12 | var s []string 13 | var app string = "./app/" + test + ".go" 14 | var tst string = "./app/" + test + "_test.go" 15 | var utl string = "./app/test_util.go" 16 | var typ string = "./app/app_types.go" 17 | cmd := exec.Command("go", "test", "-v", app, tst, utl, typ) 18 | b, _ = cmd.CombinedOutput() 19 | 20 | // save to results.txt 21 | // ignore errors 22 | if f != nil { 23 | _, err := f.Write(b) 24 | if err != nil { 25 | log.Printf("can't write results of %v to results.txt", title) 26 | } 27 | } 28 | 29 | // store the title 30 | s = make([]string, 0) 31 | s = append(s, "@start "+test) 32 | s = append(s, title+" : "+time.Now().Format("15:04:05")) 33 | 34 | // parse out lines in the output 35 | t := "" 36 | for _, c := range b { 37 | if c == 10 { 38 | s = append(s, t) 39 | t = "" 40 | } else { 41 | t += string(c) 42 | } 43 | } 44 | s = append(s, t) 45 | 46 | s = append(s, "@end") 47 | 48 | return s 49 | } 50 | 51 | // test command arguments 52 | type testPair struct { 53 | title string 54 | prog string 55 | } 56 | 57 | // list of all tests to execute 58 | var tests []testPair = []testPair{ 59 | {"@Operators", "operators"}, 60 | {"@Flow Control", "flowControl"}, 61 | {"@Strings", "strings"}, 62 | {"@Slices", "slices"}, 63 | {"@Binary", "binary"}, 64 | {"@Functions", "functions"}, 65 | {"@Methods", "methods"}, 66 | {"@Collections", "collections"}, 67 | {"@Recursion", "recursion"}, 68 | {"@Regexp", "regex"}, 69 | {"@Async", "async"}, 70 | } 71 | 72 | // run tests, capture all output and return it as a string 73 | func runAllTests(now time.Time) [][]string { 74 | var s [][]string 75 | var t []string 76 | 77 | f, err := os.OpenFile("./results.txt", os.O_CREATE|os.O_WRONLY, 0644) 78 | if err != nil { 79 | log.Println("Can't Open results.txt for writing") 80 | f = nil 81 | } 82 | 83 | if f != nil { 84 | // output date/time stamp 85 | f.WriteString(now.Local().Format("Mon Jan 2 15:04:05 -0700 MST 2006") + "\n") 86 | } 87 | 88 | s = make([][]string, 0) 89 | for _, p := range tests { 90 | t = runTest(p.title, p.prog, f) 91 | s = append(s, t) 92 | } 93 | 94 | f.Close() 95 | 96 | return s 97 | } 98 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "html/template" 7 | "log" 8 | "net/http" 9 | "regexp" 10 | "time" 11 | ) 12 | 13 | // anything but / and /index.html 14 | func handle404(w http.ResponseWriter, r *http.Request) { 15 | log.Println("404:", r.RequestURI) 16 | w.WriteHeader(404) 17 | fmt.Fprint(w, "404 not found") 18 | } 19 | 20 | // something broke 21 | func handle500(w http.ResponseWriter, r *http.Request, err string) { 22 | log.Println(err) 23 | w.WriteHeader(500) 24 | fmt.Fprintf(w, "500 server error") 25 | } 26 | 27 | // page template 28 | type testPage struct { 29 | Body template.HTML 30 | } 31 | 32 | // execute tests and render the results as html 33 | func handleTests(w http.ResponseWriter, r *http.Request) { 34 | defer func() { 35 | rec := recover() 36 | if rec != nil { 37 | handle500(w, r, "error in handleTests") 38 | } 39 | }() 40 | 41 | // allow only / or /index.html 42 | var m bool 43 | m, _ = regexp.MatchString(`^/$|^/index.html$`, r.RequestURI) 44 | if !m { 45 | handle404(w, r) 46 | return 47 | } 48 | 49 | log.Println("req:", r.RequestURI) 50 | 51 | var tests [][]string 52 | var page testPage 53 | 54 | log.Println("Tests Started") 55 | 56 | // execute the tests 57 | t0 := time.Now() 58 | tests = runAllTests(t0) 59 | t1 := time.Now() 60 | // tests finished 61 | 62 | // elapsed time 63 | et := t1.Sub(t0) 64 | 65 | // print time for tests to execute 66 | log.Println("Tests Finished:", et) 67 | 68 | // compile the test results into a string 69 | timestamp := fmt.Sprintf("%s : ET %.3f sec", t0.Local().Format("Mon Jan 2 15:04:05 -0700 MST 2006"), et.Seconds()) 70 | 71 | // timestamp := t0.Local().Format("Mon Jan 2 15:04:05 -0700 MST 2006") + ": ET " + (t1.Sub(t0).Seconds()) 72 | page.Body = template.HTML(TestToHTML(timestamp, tests)) 73 | 74 | // create the template 75 | t, err := template.ParseFiles("static/index.html") 76 | if err != nil { 77 | handle500(w, r, err.Error()) 78 | return 79 | } 80 | 81 | // execute the template 82 | err = t.Execute(w, &page) 83 | if err != nil { 84 | log.Println(err) 85 | handle500(w, r, err.Error()) 86 | } 87 | } 88 | 89 | func main() { 90 | // get specified port 91 | port := flag.String("port", "8080", "http://ipaddr:port") 92 | flag.Parse() 93 | 94 | // handle the test 95 | http.HandleFunc("/index.html", handleTests) 96 | http.HandleFunc("/", handleTests) 97 | 98 | // handle static files 99 | // fs := http.FileServer(http.Dir("static/")) 100 | // http.Handle("/static/",http.StripPrefix("/static/",fs)) 101 | 102 | // run the server 103 | log.Println("listening on :", *port) 104 | log.Fatal(http.ListenAndServe(":"+*port, nil)) 105 | } 106 | -------------------------------------------------------------------------------- /app/binary_test.go: -------------------------------------------------------------------------------- 1 | package goassessment 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | // write a function that returns the 0 or 1 value at the specified bit position 8 | func TestValueAtBit(t *testing.T) { 9 | defer testPanic(t) // handle panics and syntax errors // handle panics and syntax errors 10 | setTestInstance(t) // update test instance for logging 11 | 12 | t.Log("GOAL: you should be able to find the value of a given bit") 13 | var bit int 14 | 15 | // first bit is at bit position 0 16 | bit = valueAtbit(1, 0) 17 | if bit != 1 { 18 | t.Error(shouldBe(bit, 1)) 19 | } 20 | 21 | bit = valueAtbit(128, 7) 22 | if bit != 1 { 23 | t.Error(shouldBe(bit, 1)) 24 | } 25 | 26 | bit = valueAtbit(65, 0) 27 | if bit != 1 { 28 | t.Error(shouldBe(bit, 0)) 29 | } 30 | 31 | bit = valueAtbit(65, 6) 32 | if bit != 1 { 33 | t.Error(shouldBe(bit, 1)) 34 | } 35 | 36 | bit = valueAtbit(128, 1) 37 | if bit != 0 { 38 | t.Error(shouldBe(bit, 0)) 39 | } 40 | 41 | } 42 | 43 | // write a function that returns the base 10 integer value of the binary string 44 | func TestBase10(t *testing.T) { 45 | defer testPanic(t) // handle panics and syntax errors // handle panics and syntax errors 46 | setTestInstance(t) // update test instance for logging 47 | 48 | t.Log("GOAL: you should be able to return the base10 representation of a binary string") 49 | val := base10("11000000") 50 | if val != 192 { 51 | t.Error(shouldBe(val, 192)) 52 | } 53 | } 54 | 55 | // write a function that converts the int value to a binary string 56 | func TestConvertoBinary(t *testing.T) { 57 | defer testPanic(t) // handle panics and syntax errors // handle panics and syntax errors 58 | setTestInstance(t) // update test instance for logging 59 | 60 | t.Log("GOAL: you should be able to convert an eight-bit number to a binary string") 61 | var bin string 62 | 63 | bin = convertToBinary(128) 64 | if bin != "10000000" { 65 | t.Error(shouldBe(bin, "10000000")) 66 | } 67 | 68 | bin = convertToBinary(65) 69 | if bin != "1000001" { 70 | t.Error(shouldBe(bin, "1000001")) 71 | } 72 | } 73 | 74 | // write a function that returns the bitwise OR of the input values 75 | func TestBitwiseOr(t *testing.T) { 76 | defer testPanic(t) // handle panics and syntax errors // handle panics and syntax errors 77 | setTestInstance(t) // update test instance for logging 78 | 79 | t.Log("GOAL: you should be able to use the bitwise OR operator") 80 | 81 | r := 770047 82 | x := bitwiseOr(0x12345, 0x33333, 0xabcde) 83 | if x != r { 84 | t.Error(shouldBe(x, r)) 85 | } 86 | } 87 | 88 | // write a function that returns the bitwise AND of the input values 89 | func TestBitwiseAnd(t *testing.T) { 90 | defer testPanic(t) // handle panics and syntax errors // handle panics and syntax errors 91 | setTestInstance(t) // update test instance for logging 92 | 93 | t.Log("GOAL: you should be able to use the bitwise AND operator") 94 | 95 | r := 8192 96 | x := bitwiseAnd(0x12345, 0x33333, 0xabcde) 97 | if x != r { 98 | t.Error(shouldBe(x, r)) 99 | } 100 | 101 | } 102 | 103 | // write a function that returns the bitwise XOR of the input values 104 | func TestBitwiseXor(t *testing.T) { 105 | defer testPanic(t) // handle panics and syntax errors // handle panics and syntax errors 106 | setTestInstance(t) // update test instance for logging 107 | 108 | t.Log("GOAL: you should be able to use the bitwise XOR operator") 109 | 110 | r := 568488 111 | x := bitwiseXor(0x12345, 0x33333, 0xabcde) 112 | if x != r { 113 | t.Error(shouldBe(x, r)) 114 | } 115 | 116 | } 117 | -------------------------------------------------------------------------------- /static/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Go Assessment 7 | 8 | 13 | 14 | 15 | 21 | 26 | 31 | 36 | 37 | 96 | 97 | 108 | 109 | 110 | 111 |
112 | 129 |
{{.Body}}
130 |
131 | 132 | 133 | -------------------------------------------------------------------------------- /app/functions_test.go: -------------------------------------------------------------------------------- 1 | package goassessment 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "testing" 7 | ) 8 | 9 | // write a function that returns a function 10 | func TestFunction(t *testing.T) { 11 | defer testPanic(t) // handle panics and syntax errors 12 | setTestInstance(t) // update test instance for logging 13 | 14 | t.Log("GOAL: you should be able to return a function from a function") 15 | var s string 16 | var r string 17 | 18 | f := fFunction("Hello") 19 | if f == nil { 20 | t.Error("fFunction returned nil") 21 | return 22 | } 23 | 24 | // check type of function 25 | q := fmt.Sprintf("%T", f) 26 | if q != "func(string) string" { 27 | t.Error(shouldBe(q, "func(string) string")) 28 | } 29 | 30 | // 31 | r = "Hello, world" 32 | s = f("world") 33 | if s != r { 34 | t.Error(shouldBe(s, r)) 35 | } 36 | 37 | f = fFunction("Hai") 38 | if f == nil { 39 | t.Error("fFunction returned nil") 40 | } 41 | 42 | r = "Hai, can i haz funxtion?" 43 | s = f("can i haz funxtion?") 44 | if s != r { 45 | t.Error(shouldBe(s, r)) 46 | } 47 | } 48 | 49 | // write a function that returns a slice of closures 50 | func TestClosures(t *testing.T) { 51 | defer testPanic(t) // handle panics and syntax errors 52 | setTestInstance(t) // update test instance for logging 53 | 54 | t.Log("GOAL: you should be able to use closures") 55 | 56 | arr := []int{rand.Int(), rand.Int(), rand.Int()} 57 | square := func(x int) int { return x * x } 58 | 59 | funcs := fMakeClosures(square, arr) 60 | if len(funcs) != len(arr) { 61 | t.Error(shouldBe(len(funcs), len(arr))) 62 | } 63 | 64 | for i, f := range funcs { 65 | u := f() 66 | v := square(arr[i]) 67 | if u != v { 68 | t.Error(shouldBe(u, v)) 69 | } 70 | } 71 | } 72 | 73 | // write a function that implements a partial application 74 | func TestPartial(t *testing.T) { 75 | defer testPanic(t) // handle panics and syntax errors 76 | setTestInstance(t) // update test instance for logging 77 | 78 | t.Log("GOAL: you should be able to create a 'partial' function") 79 | 80 | f := func(a string, b string, c string) string { 81 | return a + ", " + b + c 82 | } 83 | 84 | g := fPartial(f, "Hello", "Ellie") 85 | // check valid return 86 | if g == nil { 87 | t.Error("fPartial returned nil") 88 | return 89 | } 90 | 91 | // check type of function 92 | q := fmt.Sprintf("%T", g) 93 | if q != "func(string) string" { 94 | t.Error(shouldBe(q, "func(string) string")) 95 | } 96 | 97 | // invoke it 98 | s := g("!!!") 99 | 100 | // check function output 101 | r := "Hello, Ellie!!!" 102 | if s != r { 103 | t.Error(shouldBe(s, r)) 104 | } 105 | 106 | } 107 | 108 | // write a function that creates a new array populated 109 | // with the result of calling the provided function 110 | func TestMap(t *testing.T) { 111 | defer testPanic(t) // handle panics and syntax errors 112 | setTestInstance(t) // update test instance for logging 113 | 114 | t.Log("GOAL: you should be able to implement a MAP function") 115 | 116 | square := func(x int) int { return x * x } 117 | 118 | a := []int{1, 2, 3, 4, 5} 119 | b := []int{1, 4, 9, 16, 25} 120 | 121 | c := fMap(square, a) 122 | if len(c) != len(a) { 123 | t.Error(shouldBe(len(c), len(a))) 124 | } 125 | 126 | for i := 0; i < len(b); i++ { 127 | if c[i] != b[i] { 128 | t.Error(shouldBe(c[i], b[i])) 129 | } 130 | } 131 | } 132 | 133 | // write a function that applies the reducer to a slice of integers 134 | func TestReduce(t *testing.T) { 135 | defer testPanic(t) // handle panics and syntax errors 136 | setTestInstance(t) // update test instance for logging 137 | 138 | t.Log("GOAL: you should be able to implement a REDUCE function") 139 | 140 | sum := func(acc int, val int) int { 141 | acc += val 142 | return acc 143 | } 144 | 145 | a := []int{1, 2, 3, 4, 5} 146 | 147 | b := fReduce(sum, a) 148 | if b != 15 { 149 | t.Error(shouldBe(b, 15)) 150 | } 151 | } 152 | 153 | // write a function that applies the filter to a slice of integers 154 | func TestFilter(t *testing.T) { 155 | defer testPanic(t) // handle panics and syntax errors 156 | setTestInstance(t) // update test instance for logging 157 | 158 | t.Log("GOAL: you should be able to implement a FILTER function") 159 | 160 | // condition 161 | odd := func(v int) bool { return (v % 2) == 1 } 162 | 163 | a := []int{1, 2, 3, 4, 5} 164 | b := []int{1, 3, 5} 165 | 166 | c := fFilter(odd, a) 167 | if len(c) != len(b) { 168 | t.Error(shouldBe(len(c), len(b))) 169 | } 170 | 171 | for i := 0; i < len(b); i++ { 172 | if c[i] != b[i] { 173 | t.Error(shouldBe(c[i], b[i])) 174 | } 175 | } 176 | } 177 | 178 | // write a function that handles a variadic argument 179 | func TestVariadic(t *testing.T) { 180 | defer testPanic(t) // handle panics and syntax errors 181 | setTestInstance(t) // update test instance for logging 182 | 183 | t.Log("GOAL: you should be able to implement a variadic function") 184 | 185 | a := []int{1, 2, 3, 4, 5} 186 | 187 | s := fVariadic(a...) 188 | r := "1,2,3,4,5" 189 | if s != r { 190 | t.Error(shouldBe(s, r)) 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /app/recursion_test.go: -------------------------------------------------------------------------------- 1 | package goassessment 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | // defined in app_types.go 8 | // Dir recursive definition of a file structure 9 | // type Dir struct { 10 | // name string 11 | // files []string 12 | // dirs []Dir 13 | // } 14 | 15 | var fileData = Dir{ 16 | name: "app", 17 | files: []string{"index.html"}, 18 | dirs: []Dir{ 19 | { 20 | name: "js", 21 | files: []string{"main.js", "app.js", "misc.js"}, 22 | dirs: []Dir{ 23 | { 24 | name: "vendor", 25 | files: []string{"jquery.js", "underscore.js"}, 26 | }, 27 | { 28 | name: "css", 29 | files: []string{"reset.css", "main.css"}, 30 | dirs: []Dir{}, 31 | }, 32 | }, 33 | }, 34 | }, 35 | } 36 | 37 | // write a function that returns a list of files starting at the top level directory 38 | func TestListFiles(t *testing.T) { 39 | defer testPanic(t) // handle panics and syntax errors 40 | setTestInstance(t) // update test instance for logging 41 | 42 | t.Log("GOAL: you should be able to return a list of files starting at the top level directory") 43 | var index int 44 | 45 | // passing in empty string "" means list all files from the top level 46 | var result = listFiles(fileData, "") 47 | if len(result) != 8 { 48 | t.Error(shouldBe(len(result), 8)) 49 | } 50 | 51 | index = testIndexOfStrings(result, "index.html") 52 | if index < 0 { 53 | t.Error(index, "should be >= 0") 54 | } 55 | 56 | index = testIndexOfStrings(result, "main.js") 57 | if index < 0 { 58 | t.Error(index, "should be >= 0") 59 | } 60 | 61 | index = testIndexOfStrings(result, "notfound.js") 62 | if index > 0 { 63 | t.Error(shouldBe(index, -1)) 64 | } 65 | } 66 | 67 | // wrote a function that returns a list of all files starting at the named subdirectory 68 | func TestListDir(t *testing.T) { 69 | defer testPanic(t) // handle panics and syntax errors 70 | setTestInstance(t) // update test instance for logging 71 | 72 | t.Log("GOAL: you should be able to return a list of files starting at the named subdirectory") 73 | var index int 74 | 75 | var result = listFiles(fileData, "js") 76 | if len(result) != 7 { 77 | t.Error(shouldBe(len(result), 7)) 78 | } 79 | 80 | index = testIndexOfStrings(result, "main.js") 81 | if index < 0 { 82 | t.Error(index, "should be >= 0") 83 | } 84 | 85 | index = testIndexOfStrings(result, "index.html") 86 | if index > 0 { 87 | t.Error(shouldBe(index, -1)) 88 | } 89 | } 90 | 91 | var permData = []int{1, 2, 3, 4} 92 | 93 | var permutations = [][]int{ 94 | {1, 2, 3, 4}, 95 | {1, 2, 4, 3}, 96 | {1, 3, 2, 4}, 97 | {1, 3, 4, 2}, 98 | {1, 4, 2, 3}, 99 | {1, 4, 3, 2}, 100 | {2, 1, 3, 4}, 101 | {2, 1, 4, 3}, 102 | {2, 3, 1, 4}, 103 | {2, 3, 4, 1}, 104 | {2, 4, 1, 3}, 105 | {2, 4, 3, 1}, 106 | {3, 1, 2, 4}, 107 | {3, 1, 4, 2}, 108 | {3, 2, 1, 4}, 109 | {3, 2, 4, 1}, 110 | {3, 4, 1, 2}, 111 | {3, 4, 2, 1}, 112 | {4, 1, 2, 3}, 113 | {4, 1, 3, 2}, 114 | {4, 2, 1, 3}, 115 | {4, 2, 3, 1}, 116 | {4, 3, 1, 2}, 117 | {4, 3, 2, 1}, 118 | } 119 | 120 | // write a function that returns the fibonnaci number of n 121 | // Note : order of return values is arbitrary 122 | func TestPermute(t *testing.T) { 123 | defer testPanic(t) // handle panics and syntax errors 124 | setTestInstance(t) // update test instance for logging 125 | 126 | t.Log("GOAL: you should be able to return the permutations of an array") 127 | 128 | result := permute(permData) 129 | 130 | // length of answers should be the same 131 | if len(result) != len(permutations) { 132 | t.Error(shouldBe(len(result), len(permutations))) 133 | } 134 | 135 | // check for all permutations, order not required 136 | for _, target := range result { 137 | index := testIndexOfIntSlice(permutations, target) 138 | if index < 0 { 139 | t.Error("index of ", target, " should be >=0 ") 140 | } 141 | } 142 | } 143 | 144 | // write a function that returns the fibonnaci number of n 145 | func TestFibonacci(t *testing.T) { 146 | defer testPanic(t) // handle panics and syntax errors 147 | setTestInstance(t) // update test instance for logging 148 | 149 | t.Log("GOAL: you should be able to return the nth number in a fibonacci sequence") 150 | var fib int 151 | 152 | fib = fibonacci(2) 153 | if fib != 1 { 154 | t.Error(shouldBe(fib, 1)) 155 | } 156 | fib = fibonacci(6) 157 | if fib != 8 { 158 | t.Error(shouldBe(fib, 8)) 159 | } 160 | } 161 | 162 | // write a function that returns an array of strings with all valid sets of n parens 163 | func TestValidParens(t *testing.T) { 164 | defer testPanic(t) // handle panics and syntax errors 165 | setTestInstance(t) // update test instance for logging 166 | 167 | t.Log("GOAL: you should be able to return the set of all valid combinations of n pairs of parentheses.") 168 | 169 | r := []string{"((()))", "(()())", "(())()", "()(())", "()()()"} 170 | s := validParentheses(3) 171 | if len(s) != len(r) { 172 | t.Error(shouldBe(len(s), len(r))) 173 | } 174 | 175 | for i := 0; i < len(r); i++ { 176 | index := testIndexOfStrings(s, r[i]) 177 | if index < 0 { 178 | t.Error(s, "should contain", r[i]) 179 | } 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /app/methods_test.go: -------------------------------------------------------------------------------- 1 | package goassessment 2 | 3 | import ( 4 | "container/heap" 5 | "container/list" 6 | "fmt" 7 | "sort" 8 | "testing" 9 | ) 10 | 11 | // defined in app_types.go 12 | // type Person struct { 13 | // age int 14 | // name string 15 | // } 16 | 17 | // type PersonSlice []Person 18 | 19 | // type Employee struct { 20 | // p Person 21 | // id int 22 | // } 23 | 24 | // Sort : implement Sort for PersonSlice 25 | func TestMethodsSort(t *testing.T) { 26 | defer testPanic(t) // handle panics and syntax errors 27 | setTestInstance(t) // update test instance for logging 28 | 29 | t.Log("GOAL: you should be able to implement the Sort interface for a specified type") 30 | 31 | // unsorted 32 | p := PersonSlice{ 33 | {20, "January"}, {18, "April"}, {45, "June"}, {30, "August"}, 34 | } 35 | // sorted 36 | q := PersonSlice{ 37 | {18, "April"}, {20, "January"}, {30, "August"}, {45, "June"}, 38 | } 39 | 40 | // ========================================= 41 | // fix the sort implementation in methods.go 42 | // sort by age 43 | // ========================================= 44 | sort.Sort(p) 45 | 46 | for i := 0; i < len(p); i++ { 47 | if p[i] != q[i] { 48 | t.Error(shouldBe(p[i], q[i])) 49 | } 50 | } 51 | } 52 | 53 | // fix the Heap interface for PersonSlice sorted by ascending age 54 | func TestMethodsHeap(t *testing.T) { 55 | defer testPanic(t) // handle panics and syntax errors 56 | setTestInstance(t) // update test instance for logging 57 | 58 | t.Log("GOAL: you should be able to implement the Heap interface for a specified type") 59 | 60 | p := PersonSlice{ 61 | {20, "January"}, {18, "April"}, {45, "June"}, {30, "August"}, 62 | } 63 | q := PersonSlice{ 64 | {18, "April"}, {20, "January"}, {30, "August"}, {45, "June"}, 65 | } 66 | 67 | // =================================================== 68 | // fix the container/heap implementation in methods.go 69 | // sort by age ascending 70 | // ==================================================== 71 | // init the heap 72 | h := &PersonSlice{} 73 | heap.Init(h) 74 | 75 | // load the heap 76 | for i := 0; i < len(p); i++ { 77 | heap.Push(h, p[i]) 78 | } 79 | 80 | // pop in ascending order by age 81 | for i := 0; i < len(q); i++ { 82 | r := heap.Pop(h) 83 | if r == nil { 84 | t.Error("heap should not be empty") 85 | return 86 | } 87 | if r.(Person).age != q[i].age { 88 | t.Error(shouldBe(r, q[i])) 89 | } 90 | } 91 | 92 | // should be empty 93 | if h.Len() > 0 { 94 | t.Error("heap should be empty") 95 | } 96 | } 97 | 98 | // write a function that creates and populates a list 99 | func TestMethodsList(t *testing.T) { 100 | defer testPanic(t) // handle panics and syntax errors 101 | setTestInstance(t) // update test instance for logging 102 | 103 | t.Log("GOAL: you should be able to create and populate a list") 104 | var p *list.List 105 | var e *list.Element 106 | 107 | q := PersonSlice{ 108 | {18, "April"}, {20, "January"}, {30, "August"}, {45, "June"}, 109 | } 110 | 111 | // populate a list in order of increasing age 112 | p = populateList(q) 113 | if p == nil { 114 | t.Error("should return a list") 115 | return 116 | } 117 | 118 | e = p.Front() 119 | i := 0 120 | for e != nil { 121 | if i >= len(q) { 122 | t.Error("list is too long") 123 | } 124 | if e.Value.(Person).name != q[i].name { 125 | t.Error(shouldBe(e.Value.(Person), q[i])) 126 | } 127 | i++ 128 | e = e.Next() 129 | } 130 | } 131 | 132 | // defined in app_types.go 133 | // Notifier interface 134 | // type Notifier interface { 135 | // notify() string 136 | // } 137 | 138 | func (p Person) notify() string { 139 | return fmt.Sprintf("new mail for %s", p.name) 140 | } 141 | 142 | func (e Employee) notify() string { 143 | return fmt.Sprintf("new mail for %v:%s", e.id, e.p.name) 144 | } 145 | 146 | func TestMethodsNotify(t *testing.T) { 147 | defer testPanic(t) // handle panics and syntax errors 148 | setTestInstance(t) // update test instance for logging 149 | 150 | t.Log("GOAL: you should be able to use an interface with different types") 151 | var s string 152 | var r string 153 | 154 | p := Person{name: "October", age: 99} 155 | e := Employee{p: Person{name: "September", age: 31}, id: 12345} 156 | 157 | // ========================= 158 | // your function 159 | s = sendNotification(e) 160 | r = "new mail for 12345:September" 161 | if s != r { 162 | t.Error(shouldBe(s, r)) 163 | } 164 | 165 | // ========================= 166 | // your function 167 | s = sendNotification(p) 168 | r = "new mail for October" 169 | if s != r { 170 | t.Error(shouldBe(s, r)) 171 | } 172 | } 173 | 174 | // write a function that returns an integer value from an interface{} 175 | func TestIntFromInterface(t *testing.T) { 176 | defer testPanic(t) // handle panics and syntax errors 177 | setTestInstance(t) // update test instance for logging 178 | 179 | t.Log("GOAL: you shoud be able to get a value from an interface") 180 | var x interface{} 181 | var i int 182 | var r int 183 | 184 | x = 5 185 | r = 5 186 | i = intFromInterface(x) 187 | if i != r { 188 | t.Error(shouldBe(i, r)) 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /app/regex_test.go: -------------------------------------------------------------------------------- 1 | package goassessment 2 | 3 | import "testing" 4 | 5 | // write a function that checks if the string contains a decimal number 6 | func TestContainsNumber(t *testing.T) { 7 | defer testPanic(t) // handle panics and syntax errors 8 | setTestInstance(t) // update test instance for logging 9 | 10 | t.Log("GOAL: you should be able to detect a number in a string") 11 | var b bool 12 | 13 | b = containsNumber("abc123") 14 | if !b { 15 | t.Error(shouldBe(b, true)) 16 | } 17 | 18 | b = containsNumber("abc") 19 | if b { 20 | t.Error(shouldBe(b, false)) 21 | } 22 | } 23 | 24 | // write a function that checks if the string ends with a vowel 25 | func TestEndsWithVowel(t *testing.T) { 26 | defer testPanic(t) // handle panics and syntax errors 27 | setTestInstance(t) // update test instance for logging 28 | 29 | t.Log("GOAL: you should be able to determine whether a string ends with a vowel (aeiou)") 30 | var b bool 31 | 32 | b = endsWithVowel("cats") 33 | if b { 34 | t.Error(shouldBe(b, false)) 35 | } 36 | 37 | b = endsWithVowel("gorilla") 38 | if !b { 39 | t.Error(shouldBe(b, true)) 40 | } 41 | 42 | b = endsWithVowel("I KNOW KUNG FU") 43 | if !b { 44 | t.Error(shouldBe(b, true)) 45 | } 46 | } 47 | 48 | // write a function that captures and returns the first string of 3 decimal digits 49 | func TestCaptureThreeNumbers(t *testing.T) { 50 | defer testPanic(t) // handle panics and syntax errors 51 | setTestInstance(t) // update test instance for logging 52 | 53 | t.Log("GOAL: you should be able to capture the first series of three numbers") 54 | var s string 55 | var r string 56 | 57 | s = "abc123" 58 | r = "123" 59 | s = captureThreeNumbers(s) 60 | if s != r { 61 | t.Error(shouldBe(s, r)) 62 | } 63 | 64 | s = "9876543" 65 | r = "987" 66 | s = captureThreeNumbers(s) 67 | if s != r { 68 | t.Error(shouldBe(s, r)) 69 | } 70 | 71 | s = "abcdef" 72 | r = "" 73 | s = captureThreeNumbers(s) 74 | if s != r { 75 | t.Error(shouldBe(s, r)) 76 | } 77 | 78 | s = "12ab12ab" 79 | r = "" 80 | s = captureThreeNumbers(s) 81 | if s != r { 82 | t.Error(shouldBe(s, r)) 83 | } 84 | } 85 | 86 | // write a function that checks if the string matches a specified pattern 87 | func TestMatchesPattern(t *testing.T) { 88 | defer testPanic(t) // handle panics and syntax errors 89 | setTestInstance(t) // update test instance for logging 90 | 91 | t.Log("GOAL: you should be able to determine whether a string matches a pattern") 92 | // the pattern is XXX-XXX-XXXX where all X"s are digits 93 | var b bool 94 | 95 | b = matchesPattern("800-555-1212") 96 | if !b { 97 | t.Error(shouldBe(b, true)) 98 | } 99 | 100 | b = matchesPattern("451-933-7899") 101 | if !b { 102 | t.Error(shouldBe(b, true)) 103 | } 104 | 105 | b = matchesPattern("33-444-5555") 106 | if b { 107 | t.Error(shouldBe(b, false)) 108 | } 109 | 110 | b = matchesPattern("abc-def-hijk") 111 | if b { 112 | t.Error(shouldBe(b, false)) 113 | } 114 | 115 | b = matchesPattern("1800-555-1212") 116 | if b { 117 | t.Error(shouldBe(b, false)) 118 | } 119 | 120 | b = matchesPattern("800-555-12121") 121 | if b { 122 | t.Error(shouldBe(b, false)) 123 | } 124 | 125 | b = matchesPattern("800-5555-1212") 126 | if b { 127 | t.Error(shouldBe(b, false)) 128 | } 129 | 130 | b = matchesPattern("800-55-1212") 131 | if b { 132 | t.Error(shouldBe(b, false)) 133 | } 134 | } 135 | 136 | // write a function that checks if the string is a correctly-formatted monetary amounts in USD 137 | func TestIsUSD(t *testing.T) { 138 | defer testPanic(t) // handle panics and syntax errors 139 | setTestInstance(t) // update test instance for logging 140 | 141 | t.Log("GOAL: you should be able to detect correctly-formatted monetary amounts in USD") 142 | var b bool 143 | // TRUE 144 | 145 | b = isUSD("$1") 146 | if !b { 147 | t.Error(shouldBe(b, true)) 148 | } 149 | 150 | b = isUSD("$12") 151 | if !b { 152 | t.Error(shouldBe(b, true)) 153 | } 154 | 155 | b = isUSD("$123") 156 | if !b { 157 | t.Error(shouldBe(b, true)) 158 | } 159 | 160 | b = isUSD("$1234") 161 | if b { 162 | t.Error(shouldBe(b, false)) 163 | } 164 | 165 | b = isUSD("$132.03") 166 | if !b { 167 | t.Error(shouldBe(b, true)) 168 | } 169 | 170 | b = isUSD("$32.03") 171 | if !b { 172 | t.Error(shouldBe(b, true)) 173 | } 174 | 175 | b = isUSD("$2.03") 176 | if !b { 177 | t.Error(shouldBe(b, true)) 178 | } 179 | 180 | b = isUSD("$1,023,032.03") 181 | if !b { 182 | t.Error(shouldBe(b, true)) 183 | } 184 | 185 | b = isUSD("$20,933,209.93") 186 | if !b { 187 | t.Error(shouldBe(b, true)) 188 | } 189 | 190 | b = isUSD("$20,933,209") 191 | if !b { 192 | t.Error(shouldBe(b, true)) 193 | } 194 | 195 | b = isUSD("$459,049,393.21") 196 | if !b { 197 | t.Error(shouldBe(b, true)) 198 | } 199 | 200 | // FALSE 201 | b = isUSD("34,344.34") 202 | if b { 203 | t.Error(shouldBe(b, false)) 204 | } 205 | 206 | b = isUSD("$,344.34") 207 | if b { 208 | t.Error(shouldBe(b, false)) 209 | } 210 | 211 | if b { 212 | t.Error(shouldBe(b, false)) 213 | } 214 | 215 | if b { 216 | t.Error(shouldBe(b, false)) 217 | } 218 | 219 | b = isUSD("$34,344.3") 220 | if b { 221 | t.Error(shouldBe(b, false)) 222 | } 223 | 224 | b = isUSD("$34,344.344") 225 | if b { 226 | t.Error(shouldBe(b, false)) 227 | } 228 | 229 | b = isUSD("$34,344_34") 230 | if b { 231 | t.Error(shouldBe(b, false)) 232 | } 233 | 234 | b = isUSD("$3,432,12.12") 235 | if b { 236 | t.Error(shouldBe(b, false)) 237 | } 238 | 239 | b = isUSD("$3,432,1,034.12") 240 | if b { 241 | t.Error(shouldBe(b, false)) 242 | } 243 | 244 | b = isUSD("4$3,432,034.12") 245 | if b { 246 | t.Error(shouldBe(b, false)) 247 | } 248 | 249 | b = isUSD("$2.03.45") 250 | if b { 251 | t.Error(shouldBe(b, false)) 252 | } 253 | } 254 | -------------------------------------------------------------------------------- /app/strings_test.go: -------------------------------------------------------------------------------- 1 | package goassessment 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | // write a function that composes a string from arguments 8 | func TestStringCompose(t *testing.T) { 9 | defer testPanic(t) // handle panics and syntax errors 10 | setTestInstance(t) // update test instance for logging 11 | 12 | t.Log("GOAL: you should be able to compose a string from arguments") 13 | var s string 14 | var r string 15 | s = composeString("Hello", "World") 16 | r = "Hello, World\n" 17 | 18 | if s != r { 19 | t.Error(shouldBe(s, r)) 20 | } 21 | } 22 | 23 | // write a function that returns a string from a byte array 24 | func TestStringFromBytes(t *testing.T) { 25 | defer testPanic(t) // handle panics and syntax errors 26 | setTestInstance(t) // update test instance for logging 27 | 28 | t.Log("GOAL: you should be able to convert a byte array to a string") 29 | 30 | b := []byte{72, 101, 108, 108, 111, 44, 32, 87, 111, 114, 108, 100, 10} 31 | s := fromBytes(b) 32 | r := "Hello, World\n" 33 | 34 | if s != r { 35 | t.Error(shouldBe(s, r)) 36 | } 37 | } 38 | 39 | // write a function that takes a string and returns an array of runes 40 | func TestRunes(t *testing.T) { 41 | defer testPanic(t) // handle panics and syntax errors 42 | setTestInstance(t) // update test instance for logging 43 | 44 | t.Log("GOAL: you should be able to decompose a UTF-8 string into an array of runes") 45 | var s string 46 | var r []rune 47 | var u []rune 48 | 49 | s = "✋ 👍 👎 ✊" 50 | u = []rune{9995, 32, 128077, 32, 128078, 32, 9994} 51 | r = runesFromString(s) 52 | 53 | // are they the same length 54 | if len(u) != len(r) { 55 | t.Error(shouldBe(len(u), len(r))) 56 | return 57 | } 58 | 59 | // are they equal 60 | b := true 61 | for i := 0; i < len(u); i++ { 62 | if r[i] != u[i] { 63 | b = false 64 | break 65 | } 66 | } 67 | 68 | if !b { 69 | t.Error(shouldBe(r, u)) 70 | } 71 | } 72 | 73 | // write a function that splits a string into words 74 | func TestSplitString(t *testing.T) { 75 | defer testPanic(t) // handle panics and syntax errors 76 | setTestInstance(t) // update test instance for logging 77 | 78 | t.Log("GOAL: you should be able to split a string into words") 79 | var s string 80 | var r []string 81 | var u []string 82 | s = "Hello, World" 83 | u = []string{"Hello", "World"} 84 | 85 | r = splitString(s) 86 | 87 | // check length equal 88 | if len(r) != len(u) { 89 | t.Error(shouldBe(len(r), len(u))) 90 | return 91 | } 92 | 93 | // check words 94 | for i := 0; i < len(u); i++ { 95 | if u[i] != r[i] { 96 | t.Error(shouldBe(u, r)) 97 | } 98 | } 99 | } 100 | 101 | // write a function that converts a string to Title Case 102 | func TestTitleCase(t *testing.T) { 103 | defer testPanic(t) // handle panics and syntax errors 104 | setTestInstance(t) // update test instance for logging 105 | 106 | t.Log("GOAL: you should be able to convert a string to title case") 107 | var s string 108 | var r string 109 | var u string 110 | s = "this is the title" 111 | u = "This Is The Title" 112 | 113 | r = titleString(s) 114 | 115 | // check length equal 116 | if r != u { 117 | t.Error(shouldBe(r, u)) 118 | } 119 | } 120 | 121 | // write a function that reduces repeated characters 122 | func TestReduceString(t *testing.T) { 123 | defer testPanic(t) // handle panics and syntax errors 124 | setTestInstance(t) // update test instance for logging 125 | 126 | t.Log("GOAL: you should be able to reduce adjacent repeated characters to a desired minimum") 127 | var s string 128 | var r string 129 | 130 | s = "aaaabbbb" 131 | r = "aabb" 132 | s = reduceString(s, 2) 133 | if s != r { 134 | t.Error(shouldBe(s, r)) 135 | } 136 | 137 | s = "xaaabbbb" 138 | r = "xaabb" 139 | s = reduceString(s, 2) 140 | if s != r { 141 | t.Error(shouldBe(s, r)) 142 | } 143 | 144 | s = "aaaabbbb" 145 | r = "ab" 146 | s = reduceString(s, 1) 147 | if s != r { 148 | t.Error(shouldBe(s, r)) 149 | } 150 | 151 | s = "aaxxxaabbbb" 152 | r = "aaxxaabb" 153 | s = reduceString(s, 2) 154 | if s != r { 155 | t.Error(shouldBe(s, r)) 156 | } 157 | 158 | s = "aaxxxaabbbb" 159 | r = "axab" 160 | s = reduceString(s, 1) 161 | if s != r { 162 | t.Error(shouldBe(s, r)) 163 | } 164 | } 165 | 166 | // write a function that wraps lines at a given number of columns without breaking works 167 | func TestWordWrap(t *testing.T) { 168 | defer testPanic(t) // handle panics and syntax errors 169 | setTestInstance(t) // update test instance for logging 170 | 171 | t.Log("GOAL: you should be able to wrap lines at a given number of columns, without breaking words") 172 | // !!! use underscore to indicate where a wrap would occur 173 | 174 | column := 5 175 | s := "abcdef abcde abc def" 176 | r := "abcdef_abcde_abc_def" 177 | s = wordWrap(s, column) 178 | if s != r { 179 | t.Error(shouldBe(s, r)) 180 | } 181 | 182 | s = "abc abc abc" 183 | r = "abc_abc_abc" 184 | s = wordWrap(s, column) 185 | if s != r { 186 | t.Error(shouldBe(s, r)) 187 | } 188 | s = "a b c def" 189 | r = "a b c_def" 190 | 191 | s = wordWrap(s, column) 192 | if s != r { 193 | t.Error(shouldBe(s, r)) 194 | } 195 | 196 | } 197 | 198 | // write a function that reverses the characters in a string 199 | func TestReverseString(t *testing.T) { 200 | defer testPanic(t) // handle panics and syntax errors 201 | setTestInstance(t) // update test instance for logging 202 | 203 | t.Log("GOAL: you should be able to reverse the characters in a string") 204 | var s string 205 | var r string 206 | 207 | s = "abc" 208 | r = "cba" 209 | s = reverseString(s) 210 | if s != r { 211 | t.Error(shouldBe(s, r)) 212 | } 213 | 214 | s = "i am a string of characters" 215 | r = "sretcarahc fo gnirts a ma i" 216 | s = reverseString(s) 217 | if s != r { 218 | t.Error(shouldBe(s, r)) 219 | } 220 | 221 | } 222 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # go-assessment 2 | 3 |

4 | 5 |

6 | 7 | **Your Job Is To Make The Tests Pass!** 8 | 9 | ### What is this? 10 | 11 | This is a tool for assessing or practicing beginner level programming in Golang. It is [inspired by Rebecca Murphey's js-assessment](https://github.com/rmurphey/js-assessment) 12 | 13 | A while back I tried out Murphey's js-assessment and found it to be a valuable tool for refreshing my javascript capability when I 14 | had not written any JavaScript for a few months. I figured a similar tool for Go might be useful 15 | for the same reason. 16 | 17 | This tool leads the user through a series of Go implementation exercises from easy to medium. 18 | It's not meant to be a leetcode challenge. The point is to exercise your skill with some basic syntax and semantics of Go. 19 | Most of the tests and implementations are straightforward. A few are harder, require a bit of 20 | algorithm knowledge or the ability to look up a solution. If you have gone through the 21 | official golang tutorial you will know enough to make most of the tests pass. For the rest 22 | go ahead and look up a solution if you need to. Feel free to use go standard libraries. 23 | No need to reinvent the wheel. 24 | 25 | This tool relies on Test Driven Development using the 26 | [native Go test framework](https://golang.org/pkg/testing/). The ./app directory 27 | contains a set of test files (app/_topic_\_test.go) and a corresponding app skeleton file (app/_topic_.go) with 28 | the required function definitions but missing the implementations. Treat the _topic_\_test.go files 29 | as the specifications for the function skeletons. The goal is to provide the implementations in the 30 | skeleton files to pass the tests. If the tests are not passing, dig into the _topic_\_test.go files 31 | to figure out what the requirement is, then fix the skeleton file so the tests pass. 32 | You are done when all tests pass. You should not have to modify anything in the _topic_\_test.go files, 33 | only the _topic_.go skeleton files (unless the tests have a bug in which case feel free to report it). 34 | 35 | - if you are stuck, don't hesitate to get help. Look it up! 36 | - if you have a compile error in a function under test (inside one of the _topic_.go files) it will terminate the tests for that topic. You will (probably) get an error message describing where and what the compile error is. 37 | 38 | The tests are ordered (more or less) by increasing difficulty. The topics covered include 39 | 40 | - Operators 41 | - Flow Control 42 | - Strings 43 | - Slices 44 | - Binary 45 | - Functions 46 | - Recursion 47 | - Methods 48 | - Collections 49 | - Regexp 50 | - Async 51 | 52 | Here's how to work this: 53 | 54 | 1. Set up Go 55 | 2. Clone or fork this repo 56 | 3. Start the browser based test framework (test_browser.sh or test_browser.cmd). Open a browser to the host:port (:8080 by default) 57 | 4. Refresh the page to run the tests 58 | 5. Update the skeleton files in ./app 59 | 6. When all tests pass you are done 60 | 61 | #### Running the Tests 62 | 63 | To run the tests and see their results you have some choices. 64 | 65 | 1. From a web browser : **best** 66 | - the tool includes a web server implementation that will run the tests and display the results for you. 67 | - in the root of the repo, run './test_browser.sh' (or 'test_browser.cmd' on Windows. see the issue regarding Windows Antivirus if you have problems) and connect to the hostip:8080 with a browser. You will get a display of all the test results. 68 | - after editing skeleton files, you can update the test results by refreshing the web page. this will rerun the tests and update the results. 69 | - you don't need to restart the web server when you change a function under test. just refresh the page. If you modify a _topic_\_test.go file, you would need to restart the server. 70 | - the browser tool needs to be connected to the internet because it uses Bootstrap from a CDN. If you want to run locally you can download the required bootstrap files and modify './static/index.html' to point to their local copies. 71 | - You can change the port number in './main.go' or in the startup scripts. 72 | 2. From the Shell 73 | - run a shell script that runs all the tests and writes the output to 'results.txt' 74 | - for Linux or Mac, the script is './test_all.sh' 75 | - for Windows, the script is 'test_all.cmd' 76 | - if your tests and other go programs build slowly on Windows, its probably due to Windows Defender or other antivirus 77 | - you can run individual test files using 'go test...' 78 | - example for the strings test 79 | - \[linux/macos\]: 'go test -v ./app/strings\*.go ./app/test_util.go ./app/app_types.go' 80 | - \[windows\]: 'go test -v ./app/strings.go ./app/strings_test.go ./app/test_util.go ./app/app_types.go' 81 | 82 | #### Debugging the functions under test 83 | 84 | 1. Visual Studio Code (Or other debugger with similar capability) 85 | 86 | Visual Studio Code set up for Go programming provides the capability to run individual tests and use breakpoints and other debugger functions. 87 | 88 | With this setup, you can run individual tests within the _topic_\_test.go functions. VS Code will superimpose buttons 89 | at the top of each test to let you run or debug the test function. This allows you to step into the actual function 90 | under test and observe it. You should never have to change anything in the _topic_\_test.go function itself. 91 | 92 | This is independent of whether or not the browser test setup is running. You can do both at the same time. If you 93 | are viewing the browser based test output while editing with VS Code and you need to debug a specific test, you can 94 | use the VS Code test debug function and still update results with a browser refresh 95 | 96 | 2. Logging output in a function under test 97 | 98 | If you want to debug using printouts from within a function under test, the test*util.go file provides the \_testLog(s string)* function. 99 | You can print output using _testLog_ from within a function in an app skeleton file. Due to the way the golang testing system works, the output from these logs may come after the results for that test are printed. The log output specifies the file and line number of where the testLog was called. 100 | 101 | #### Go Modules 102 | 103 | This code is set up to be using Modules rather than GOPATH. As it is, it does not import or use any modules besides standard Go libraries. You could probably fix it to use GOPATH if you require that. 104 | -------------------------------------------------------------------------------- /parse.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "regexp" 6 | "strings" 7 | ) 8 | 9 | // results of a single test 10 | type testResults struct { 11 | pass int 12 | fail int 13 | html []string 14 | } 15 | 16 | func parseTestLine(line string, ti *testResults) { 17 | var matched bool 18 | var err error 19 | var r *regexp.Regexp 20 | var s []string 21 | 22 | // =================================================================== 23 | // find matches to the line format and output the corresponding HTML 24 | // =================================================================== 25 | 26 | // @start 27 | r, err = regexp.Compile(`@start (.+)`) 28 | s = r.FindStringSubmatch(line) 29 | if err != nil { 30 | panic(err) 31 | } 32 | if len(s) >= 2 { 33 | h := []string{ 34 | `

`, 37 | } 38 | ti.html = append(ti.html, strings.Join(h, "")) 39 | return 40 | } 41 | 42 | // @end 43 | matched, err = regexp.MatchString(`@end`, line) 44 | if err != nil { 45 | panic(err) 46 | } 47 | if matched { 48 | h := []string{ 49 | `
`, 50 | } 51 | ti.html = append(ti.html, strings.Join(h, "")) 52 | return 53 | } 54 | 55 | // Test Category 56 | r, err = regexp.Compile(`@(.+)`) 57 | s = r.FindStringSubmatch(line) 58 | if err != nil { 59 | panic(err) 60 | } 61 | if len(s) >= 2 { 62 | h := catHeader(s[1]) 63 | ti.html = append(ti.html, h) 64 | return 65 | } 66 | 67 | matched, err = regexp.MatchString(`=== RUN`, line) 68 | if err != nil { 69 | panic(err) 70 | } 71 | if matched { 72 | // don't print the === RUN output 73 | return 74 | } 75 | 76 | // individual test passsed 77 | matched, err = regexp.MatchString(`--- PASS`, line) 78 | if err != nil { 79 | panic(err) 80 | } 81 | if matched { 82 | ti.pass++ 83 | ti.html = append(ti.html, testPass(line)) 84 | return 85 | } 86 | 87 | // individual test failed 88 | matched, err = regexp.MatchString(`--- FAIL`, line) 89 | if err != nil { 90 | panic(err) 91 | } 92 | if matched { 93 | ti.fail++ 94 | ti.html = append(ti.html, testFail(line)) 95 | return 96 | } 97 | 98 | // test goal 99 | matched, err = regexp.MatchString(`.*GOAL*`, line) 100 | if err != nil { 101 | panic(err) 102 | } 103 | if matched { 104 | ti.html = append(ti.html, testGoal(line)) 105 | return 106 | } 107 | 108 | matched, err = regexp.MatchString(` .+_test`, line) 109 | if err != nil { 110 | panic(err) 111 | } 112 | if matched { 113 | ti.html = append(ti.html, testInfo(line)) 114 | return 115 | } 116 | 117 | matched, err = regexp.MatchString(` test_util.go`, line) 118 | if err != nil { 119 | panic(err) 120 | } 121 | if matched { 122 | ti.html = append(ti.html, testInfo(line)) 123 | return 124 | } 125 | 126 | matched, err = regexp.MatchString(`^ok|^PASS`, line) 127 | if err != nil { 128 | panic(err) 129 | } 130 | if matched { 131 | return 132 | } 133 | 134 | /* example output if tests did not compile properly 135 | # command-line-arguments [command-line-arguments.test] 136 | app/strings_test.go:4:2: imported and not used: "log" 137 | FAIL command-line-arguments [build failed] 138 | FAIL 139 | */ 140 | matched, err = regexp.MatchString(`^app/.*\.go`, line) 141 | if err != nil { 142 | panic(err) 143 | } 144 | if matched { 145 | ti.fail++ 146 | ti.html = append(ti.html, fmt.Sprintf("
compile failed : %s
", line)) 147 | } 148 | } 149 | 150 | // statistics 151 | func statHeader(pass int, fail int, timestamp string) string { 152 | 153 | header := make([]string, 6) 154 | 155 | // create the pass/fail stats 156 | var percent float64 157 | if fail == 0 { 158 | percent = 1.0 159 | } else { 160 | percent = (float64(pass) / float64(pass+fail)) + 0.005 161 | } 162 | 163 | header[0] = `
` 164 | header[1] = `
165 | Go-Assessment 166 |
167 |
168 | 169 |
` 170 | header[2] = fmt.Sprintf("
progress %.0f%%
", percent*100.0) 171 | header[3] = fmt.Sprintf(`
passed %2d
`, pass) 172 | header[4] = fmt.Sprintf(`
failed %2d
`, fail) 173 | 174 | header[5] = fmt.Sprintf(`
%s
`, timestamp) 175 | 176 | return strings.Join(header, "") 177 | } 178 | 179 | // category header 180 | func catHeader(category string) string { 181 | 182 | // ` ▲ ` 183 | return fmt.Sprintf(`
184 |
185 |
%s
186 |
187 |
`, category) 188 | } 189 | 190 | // individual test passed 191 | func testPass(name string) string { 192 | return fmt.Sprintf(`
193 |
%s
194 |
PASS
195 |
`, name[9:]) 196 | } 197 | 198 | func testFail(name string) string { 199 | return fmt.Sprintf(`
200 |
%s
201 |
FAIL
202 |
`, name[9:]) 203 | } 204 | 205 | // individual test goal 206 | func testGoal(line string) string { 207 | 208 | index := strings.Index(line, "GOAL") 209 | location := line[0:index] 210 | goal := line[index+5:] 211 | 212 | return fmt.Sprintf(`
213 |
%s
214 |
%s
215 |
`, location, goal) 216 | } 217 | 218 | // individual test info (line where it failed) 219 | func testInfo(line string) string { 220 | index := strings.LastIndex(line, ":") 221 | location := line[0:index] 222 | info := line[index+1:] 223 | 224 | return fmt.Sprintf(`
225 |
%s
226 |
%s
227 |
`, location, info) 228 | 229 | // return fmt.Sprintf(`
%s
`,info) 230 | } 231 | 232 | // TestToHTML : convert array of test results to html content 233 | func TestToHTML(timestamp string, results [][]string) string { 234 | var ti testResults 235 | 236 | // for each line in the test results 237 | for i := 0; i < len(results); i++ { 238 | // transform line to HTML 239 | for _, v := range results[i] { 240 | parseTestLine(v, &ti) 241 | } 242 | } 243 | 244 | // return the body as a string 245 | return statHeader(ti.pass, ti.fail, timestamp) + strings.Join(ti.html, "") 246 | } 247 | -------------------------------------------------------------------------------- /design/x.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Go Assessment 7 | 8 | 13 | 14 | 15 | 21 | 26 | 31 | 36 | 37 | 130 | 131 | 132 | 133 |
134 | 150 |
151 |
152 |
153 |

Go-Assessment Test Results

154 |
155 |
progress 50%
156 |
passed 42
157 |
failed 15
158 |
159 |
160 |
Mon Dec 28 21:54:01 -0800 PST 2020 : ET 4.754 sec
161 |
162 |
163 | 164 |
165 |
Goal : You should be able to .......
166 |
FAIL
167 |
168 |
169 |
operator-test.go:15
170 |
this should be equal to 0
171 |
error
172 |
173 |
174 |
operator-test.go:19
175 |
this should be equal to 1
176 |
error
177 |
178 |
179 | 180 | 181 |
182 |
Goal : You should be able to .......
183 |
PASS
184 |
185 |
186 |
187 |
188 | 189 | 190 | -------------------------------------------------------------------------------- /app/operators_test.go: -------------------------------------------------------------------------------- 1 | package goassessment 2 | 3 | import "testing" 4 | 5 | // ARITHMETIC OPERATORS ON INTEGERS 6 | 7 | // write a function that returns the sum of two values 8 | func TestIntegerSum(t *testing.T) { 9 | defer testPanic(t) // handle panics and syntax errors 10 | setTestInstance(t) // update test instance for logging 11 | var a int 12 | var b int 13 | var r int 14 | 15 | t.Log("GOAL: you should be able to work with addition operator") 16 | a = 6 17 | b = 2 18 | r = add(a, b) 19 | if r != 8 { 20 | t.Error(shouldBe(r, 8)) 21 | } 22 | } 23 | 24 | // write a function that returns the subtract between two values 25 | func TestIntegerDifference(t *testing.T) { 26 | defer testPanic(t) // handle panics and syntax errors 27 | setTestInstance(t) // update test instance for logging 28 | var a int 29 | var b int 30 | var r int 31 | 32 | t.Log("GOAL: you should be able to work with the subtraction operator") 33 | a = 6 34 | b = 2 35 | r = subtract(a, b) 36 | if r != 4 { 37 | t.Error(shouldBe(r, 4)) 38 | } 39 | } 40 | 41 | // write a function that returns a value equal to the multiply of two values 42 | func TestIntegerProduct(t *testing.T) { 43 | defer testPanic(t) // handle panics and syntax errors 44 | setTestInstance(t) // update test instance for logging 45 | var a int 46 | var b int 47 | var r int 48 | 49 | t.Log("GOAL: you should be able to work with the multiplication operator") 50 | a = 6 51 | b = 2 52 | r = multiply(a, b) 53 | if r != 12 { 54 | t.Error(shouldBe(r, 12)) 55 | } 56 | } 57 | 58 | // write a function that returns a value equal to the divide of two values 59 | func TestIntegerQuotient(t *testing.T) { 60 | defer testPanic(t) // handle panics and syntax errors 61 | setTestInstance(t) // update test instance for logging 62 | var a int 63 | var b int 64 | var r int 65 | 66 | t.Log("GOAL: you should be able to work with the division operator") 67 | a = 6 68 | b = 2 69 | r = divide(a, b) 70 | if r != 3 { 71 | t.Error(shouldBe(r, 3)) 72 | } 73 | 74 | a = 7 75 | b = 2 76 | r = divide(a, b) 77 | if r != 3 { 78 | t.Error(shouldBe(r, 3)) 79 | } 80 | } 81 | 82 | // write a function that returns a value equal to the remainder of two values 83 | func TestIntegerRemainder(t *testing.T) { 84 | defer testPanic(t) // handle panics and syntax errors 85 | setTestInstance(t) // update test instance for logging 86 | var a int 87 | var b int 88 | var r int 89 | 90 | t.Log("GOAL: you should be able to work with the remainder (modulo) operator") 91 | a = 7 92 | b = 2 93 | r = remainder(a, b) 94 | if r != 1 { 95 | t.Error(shouldBe(r, 1)) 96 | } 97 | 98 | a = 6 99 | b = 2 100 | r = remainder(a, b) 101 | if r != 0 { 102 | t.Error(shouldBe(r, 0)) 103 | } 104 | } 105 | 106 | // COMPARISON OPERATORS 107 | // write a function that returns true or false if two values are equal 108 | func TestEqual(t *testing.T) { 109 | defer testPanic(t) // handle panics and syntax errors 110 | setTestInstance(t) // update test instance for logging 111 | var a int 112 | var b int 113 | var r bool 114 | 115 | t.Log("GOAL: you should be able to work with the equal operator") 116 | a = 7 117 | b = 2 118 | r = equal(a, b) 119 | if r { 120 | t.Error(shouldBe(r, false)) 121 | } 122 | a = 2 123 | b = 2 124 | r = equal(a, b) 125 | if !r { 126 | t.Error(shouldBe(r, true)) 127 | } 128 | } 129 | 130 | // write a function that returns true or false if two values are not equal 131 | func TestNotEqual(t *testing.T) { 132 | defer testPanic(t) // handle panics and syntax errors 133 | setTestInstance(t) // update test instance for logging 134 | var a int 135 | var b int 136 | var r bool 137 | 138 | t.Log("GOAL: you should be able to work with the not equal operator") 139 | a = 7 140 | b = 2 141 | r = notEqual(a, b) 142 | if !r { 143 | t.Error(shouldBe(r, true)) 144 | } 145 | a = 2 146 | b = 2 147 | r = notEqual(a, b) 148 | if r { 149 | t.Error(shouldBe(r, false)) 150 | } 151 | } 152 | 153 | // write a function that returns true or false if one value is less than the other one 154 | func TestLessThan(t *testing.T) { 155 | defer testPanic(t) // handle panics and syntax errors 156 | setTestInstance(t) // update test instance for logging 157 | var a int 158 | var b int 159 | var r bool 160 | 161 | t.Log("GOAL: you should be able to work with the less than operator") 162 | a = 7 163 | b = 2 164 | r = lessThan(a, b) 165 | if r { 166 | t.Error(shouldBe(r, false)) 167 | } 168 | a = 2 169 | b = 7 170 | r = lessThan(a, b) 171 | if !r { 172 | t.Error(shouldBe(r, true)) 173 | } 174 | } 175 | 176 | // write a function that returns true or false if one value is less than or equal to the other one 177 | func TestLessThanEqual(t *testing.T) { 178 | defer testPanic(t) // handle panics and syntax errors 179 | setTestInstance(t) // update test instance for logging 180 | var a int 181 | var b int 182 | var r bool 183 | 184 | t.Log("GOAL: you should be able to work with the less than or equal than operator") 185 | a = 7 186 | b = 2 187 | r = lessThanEqual(a, b) 188 | if r { 189 | t.Error(shouldBe(r, false)) 190 | } 191 | a = 2 192 | b = 7 193 | r = lessThanEqual(a, b) 194 | if !r { 195 | t.Error(shouldBe(r, true)) 196 | } 197 | 198 | a = 2 199 | b = 2 200 | r = lessThanEqual(a, b) 201 | if !r { 202 | t.Error(shouldBe(r, true)) 203 | } 204 | } 205 | 206 | // write a function that returns true or false if one value is greater than the other one 207 | func TestGreaterThan(t *testing.T) { 208 | defer testPanic(t) // handle panics and syntax errors 209 | setTestInstance(t) // update test instance for logging 210 | var a int 211 | var b int 212 | var r bool 213 | 214 | t.Log("GOAL: you should be able to work with the greater than operator") 215 | a = 7 216 | b = 2 217 | r = greaterThan(a, b) 218 | if !r { 219 | t.Error(shouldBe(r, true)) 220 | } 221 | a = 2 222 | b = 7 223 | r = greaterThan(a, b) 224 | if r { 225 | t.Error(shouldBe(r, false)) 226 | } 227 | } 228 | 229 | // write a function that returns true or false if one value is greater than or equal to the other one 230 | func TestGreaterThanEqual(t *testing.T) { 231 | defer testPanic(t) // handle panics and syntax errors 232 | setTestInstance(t) // update test instance for logging 233 | var a int 234 | var b int 235 | var r bool 236 | 237 | t.Log("GOAL: you should be able to work with the greater than or equal operator") 238 | a = 7 239 | b = 2 240 | r = greaterThanEqual(a, b) 241 | if !r { 242 | t.Error(shouldBe(r, true)) 243 | } 244 | a = 2 245 | b = 7 246 | r = greaterThanEqual(a, b) 247 | if r { 248 | t.Error(shouldBe(r, false)) 249 | } 250 | 251 | a = 2 252 | b = 2 253 | r = greaterThanEqual(a, b) 254 | if !r { 255 | t.Error(shouldBe(r, true)) 256 | } 257 | } 258 | 259 | // LOGICAL OPERATORS 260 | 261 | // write a function that returns true if either argument is true 262 | func TestLogicalOr(t *testing.T) { 263 | defer testPanic(t) // handle panics and syntax errors 264 | setTestInstance(t) // update test instance for logging 265 | 266 | t.Log("GOAL: you should be able to work with logical or") 267 | var b bool 268 | 269 | b = either(false, true) 270 | if !b { 271 | t.Error(shouldBe(b, true)) 272 | } 273 | 274 | b = either(true, false) 275 | if !b { 276 | t.Error(shouldBe(b, true)) 277 | } 278 | 279 | b = either(true, true) 280 | if !b { 281 | t.Error(shouldBe(b, true)) 282 | } 283 | 284 | b = either(false, false) 285 | if b { 286 | t.Error(shouldBe(b, false)) 287 | } 288 | } 289 | 290 | // write a function that returns true only if both arguments are true 291 | func TestLogicalAnd(t *testing.T) { 292 | defer testPanic(t) // handle panics and syntax errors 293 | setTestInstance(t) // update test instance for logging 294 | 295 | t.Log("GOAL: you should be able to work with logical and") 296 | var b bool 297 | 298 | b = both(false, true) 299 | if b { 300 | t.Error(shouldBe(b, false)) 301 | } 302 | 303 | b = both(true, false) 304 | if b { 305 | t.Error(shouldBe(b, false)) 306 | } 307 | 308 | b = both(true, true) 309 | if !b { 310 | t.Error(shouldBe(b, true)) 311 | } 312 | 313 | b = both(false, false) 314 | if b { 315 | t.Error(shouldBe(b, false)) 316 | } 317 | } 318 | 319 | // write a function that returns true only if both arguments are false 320 | func TestLogicalNot(t *testing.T) { 321 | defer testPanic(t) // handle panics and syntax errors 322 | setTestInstance(t) // update test instance for logging 323 | 324 | t.Log("GOAL: you should be able to work with logical not") 325 | var b bool 326 | 327 | b = none(false, true) 328 | if b { 329 | t.Error(shouldBe(b, false)) 330 | } 331 | 332 | b = none(true, false) 333 | if b { 334 | t.Error(shouldBe(b, false)) 335 | } 336 | 337 | b = none(true, true) 338 | if b { 339 | t.Error(shouldBe(b, false)) 340 | } 341 | 342 | b = none(false, false) 343 | if !b { 344 | t.Error(shouldBe(b, true)) 345 | } 346 | } 347 | -------------------------------------------------------------------------------- /app/slices_test.go: -------------------------------------------------------------------------------- 1 | package goassessment 2 | 3 | import ( 4 | "sort" 5 | "testing" 6 | ) 7 | 8 | // write a function that retursns the index of an item in a slice 9 | func TestIndexOf(t *testing.T) { 10 | defer testPanic(t) // handle panics and syntax errors // handle panics and syntax errors 11 | setTestInstance(t) // update test instance for logging 12 | 13 | t.Log("GOAL: you should be able to determine the location of an item in a slice") 14 | 15 | a := []int{1, 2, 3, 4} 16 | 17 | index := indexOf(a, 3) 18 | 19 | if index != 2 { 20 | t.Error(shouldBe(index, 2)) 21 | } 22 | index = indexOf(a, 5) 23 | if index != -1 { 24 | t.Error(shouldBe(index, -1)) 25 | } 26 | } 27 | 28 | // write a function that sums the values in a slice 29 | func TestSum(t *testing.T) { 30 | defer testPanic(t) // handle panics and syntax errors 31 | setTestInstance(t) // update test instance for logging 32 | 33 | t.Log("GOAL: you should be able to sum the items of a slice") 34 | 35 | a := []int{1, 2, 3, 4} 36 | 37 | v := sum(a) 38 | 39 | if v != 10 { 40 | t.Error(shouldBe(v, 10)) 41 | } 42 | } 43 | 44 | // write a function that removes all instances of a value from a slice 45 | func TestRemove(t *testing.T) { 46 | defer testPanic(t) // handle panics and syntax errors 47 | setTestInstance(t) // update test instance for logging 48 | 49 | t.Log("GOAL: you should be able to remove all instances of a value from a slice") 50 | 51 | a := []int{1, 2, 3, 4, 2, 2} 52 | b := []int{1, 3, 4} 53 | 54 | a = remove(a, 2) 55 | if len(a) != len(b) { 56 | t.Error(shouldBe(len(a), len(b))) 57 | } 58 | if !testIntSliceEqual(a, b) { 59 | t.Error(shouldBe(a, b)) 60 | } 61 | } 62 | 63 | // write a function that returns the value of the first element in a slice (wihtout removing it) 64 | func TestFront(t *testing.T) { 65 | defer testPanic(t) // handle panics and syntax errors 66 | setTestInstance(t) // update test instance for logging 67 | 68 | t.Log("GOAL: you should be able to get the value of the first element of a slice") 69 | 70 | a := []int{1, 2, 3, 4} 71 | 72 | v := front(a) 73 | 74 | if v != 1 { 75 | t.Error(shouldBe(v, 1)) 76 | } 77 | } 78 | 79 | // write a function that returns the value of the last element in a slice (wihtout removing it) 80 | func TestBack(t *testing.T) { 81 | defer testPanic(t) // handle panics and syntax errors 82 | setTestInstance(t) // update test instance for logging 83 | 84 | t.Log("GOAL: you should be able to get the value of the last element of a slice") 85 | 86 | a := []int{1, 2, 3, 4} 87 | 88 | v := back(a) 89 | 90 | if v != 4 { 91 | t.Error(shouldBe(v, 1)) 92 | } 93 | } 94 | 95 | // write a function that adds an item to the end of a slice 96 | func TestPushBack(t *testing.T) { 97 | defer testPanic(t) // handle panics and syntax errors 98 | setTestInstance(t) // update test instance for logging 99 | 100 | t.Log("GOAL: you should be able to add an item to the end of a slice") 101 | 102 | a := []int{1, 2, 3, 4} 103 | b := []int{1, 2, 3, 4, 2} 104 | 105 | a = pushBack(a, 2) 106 | if len(a) != len(b) { 107 | t.Error(shouldBe(len(a), len(b))) 108 | } 109 | if !testIntSliceEqual(a, b) { 110 | t.Error(shouldBe(a, b)) 111 | } 112 | } 113 | 114 | // write a function that removes an item to the end of a slice 115 | func TestPopBack(t *testing.T) { 116 | defer testPanic(t) // handle panics and syntax errors 117 | setTestInstance(t) // update test instance for logging 118 | 119 | t.Log("GOAL: you should be able to remove the last item of a slice") 120 | 121 | a := []int{1, 2, 3, 4} 122 | b := []int{1, 2, 3} 123 | 124 | a = popBack(a) 125 | if len(a) != len(b) { 126 | t.Error(shouldBe(len(a), len(b))) 127 | } 128 | if !testIntSliceEqual(a, b) { 129 | t.Error(shouldBe(a, b)) 130 | } 131 | } 132 | 133 | // write a function that adds an item to the front of a slice 134 | func TestPushFront(t *testing.T) { 135 | defer testPanic(t) // handle panics and syntax errors 136 | setTestInstance(t) // update test instance for logging 137 | 138 | t.Log("GOAL: you should be able to add an item to the front of a slice") 139 | 140 | a := []int{1, 2, 3, 4} 141 | b := []int{2, 1, 2, 3, 4} 142 | 143 | a = pushFront(a, 2) 144 | if len(a) != len(b) { 145 | t.Error(shouldBe(len(a), len(b))) 146 | } 147 | if !testIntSliceEqual(a, b) { 148 | t.Error(shouldBe(a, b)) 149 | } 150 | 151 | } 152 | 153 | // write a function that removes an item from the front of a slice 154 | func TestPopFront(t *testing.T) { 155 | defer testPanic(t) // handle panics and syntax errors 156 | setTestInstance(t) // update test instance for logging 157 | 158 | t.Log("GOAL: you should be able to remove the first item of a slice") 159 | 160 | a := []int{1, 2, 3, 4} 161 | b := []int{2, 3, 4} 162 | 163 | a = popFront(a) 164 | if len(a) != len(b) { 165 | t.Error(shouldBe(len(a), len(b))) 166 | } 167 | if !testIntSliceEqual(a, b) { 168 | t.Error(shouldBe(a, b)) 169 | } 170 | } 171 | 172 | // write a function that concatenates two slices 173 | func TestConcat(t *testing.T) { 174 | defer testPanic(t) // handle panics and syntax errors 175 | setTestInstance(t) // update test instance for logging 176 | 177 | t.Log("GOAL: you should be able to join together two slices") 178 | a := []int{1, 2, 3, 4} 179 | b := []int{5, 6, 7, 8} 180 | c := []int{1, 2, 3, 4, 5, 6, 7, 8} 181 | 182 | a = concat(a, b) 183 | 184 | if len(a) != len(c) { 185 | t.Error(shouldBe(len(a), len(c))) 186 | } 187 | if !testIntSliceEqual(a, c) { 188 | t.Error(shouldBe(a, c)) 189 | } 190 | } 191 | 192 | // write a function that adds an item to a slice at the specified index 193 | func TestInsert(t *testing.T) { 194 | defer testPanic(t) // handle panics and syntax errors 195 | setTestInstance(t) // update test instance for logging 196 | 197 | t.Log("GOAL: you should be able to add an item anywhere in a slice") 198 | 199 | a := []int{1, 2, 3, 4} 200 | 201 | a = insert(a, 5, 2) 202 | 203 | b := []int{1, 2, 5, 3, 4} 204 | if len(a) != len(b) { 205 | t.Error(shouldBe(len(a), len(b))) 206 | } 207 | if !testIntSliceEqual(a, b) { 208 | t.Error(shouldBe(a, b)) 209 | } 210 | 211 | // insert at front 212 | a = []int{1} 213 | b = []int{5, 1} 214 | a = insert(a, 5, 0) 215 | if len(a) != len(b) { 216 | t.Error(shouldBe(len(a), len(b))) 217 | } 218 | if !testIntSliceEqual(a, b) { 219 | t.Error(shouldBe(a, b)) 220 | } 221 | 222 | // insert at back 223 | a = []int{1} 224 | b = []int{1, 5} 225 | a = insert(a, 5, 1) 226 | if len(a) != len(b) { 227 | t.Error(shouldBe(len(a), len(b))) 228 | } 229 | if !testIntSliceEqual(a, b) { 230 | t.Error(shouldBe(a, b)) 231 | } 232 | 233 | // if index > length of slice, append to end 234 | a = []int{} 235 | b = []int{5} 236 | a = insert(a, 5, 2) 237 | if len(a) != len(b) { 238 | t.Error(shouldBe(len(a), len(b))) 239 | } 240 | if !testIntSliceEqual(a, b) { 241 | t.Error(shouldBe(a, b)) 242 | } 243 | } 244 | 245 | // write a function that returns a count of matching items in a slice 246 | func TestCount(t *testing.T) { 247 | defer testPanic(t) // handle panics and syntax errors 248 | setTestInstance(t) // update test instance for logging 249 | 250 | t.Log("GOAL: you should be able to count the occurrences of an item in a slice") 251 | 252 | a := []int{1, 4, 2, 3, 4, 4} 253 | 254 | v := count(a, 4) 255 | 256 | if v != 3 { 257 | t.Error(shouldBe(v, 3)) 258 | } 259 | } 260 | 261 | // write a function that finds duplicates in a slice 262 | func TestDuplicates(t *testing.T) { 263 | defer testPanic(t) // handle panics and syntax errors 264 | setTestInstance(t) // update test instance for logging 265 | 266 | t.Log("GOAL: you should be able to find duplicates in a slice") 267 | 268 | a := []int{1, 2, 4, 4, 3, 3, 1, 5, 3} 269 | 270 | a = duplicates(a) 271 | 272 | sort.IntSlice(a).Sort() 273 | b := []int{1, 3, 4} 274 | if len(a) != len(b) { 275 | t.Error(shouldBe(len(a), len(b))) 276 | } 277 | if !testIntSliceEqual(a, b) { 278 | t.Error(shouldBe(a, b)) 279 | } 280 | } 281 | 282 | // write a function that sqaures all items in a slice 283 | func TestSquare(t *testing.T) { 284 | defer testPanic(t) // handle panics and syntax errors 285 | setTestInstance(t) // update test instance for logging 286 | 287 | t.Log("GOAL: you should be able to square each number in a slice") 288 | 289 | a := []int{1, 2, 3, 4} 290 | b := []int{1, 4, 9, 16} 291 | 292 | a = square(a) 293 | if !testIntSliceEqual(a, b) { 294 | t.Error(shouldBe(a, b)) 295 | } 296 | } 297 | 298 | // write a function that returns all the indices in a slice that matches an item 299 | func TestFindAllOccurrences(t *testing.T) { 300 | defer testPanic(t) // handle panics and syntax errors 301 | setTestInstance(t) // update test instance for logging 302 | 303 | t.Log("GOAL: you should be able to find all occurrences of an item in an array and return their indices") 304 | 305 | a := []int{1, 2, 3, 4, 5, 6, 1, 7} 306 | b := []int{0, 6} 307 | 308 | a = findAllOccurrences(a, 1) 309 | if !testIntSliceEqual(a, b) { 310 | t.Error(shouldBe(a, b)) 311 | } 312 | } 313 | -------------------------------------------------------------------------------- /design/main.css: -------------------------------------------------------------------------------- 1 | * { 2 | overflow-x: hidden; 3 | padding: 0px !important; 4 | margin: 0px !important; 5 | } 6 | .v10_826 { 7 | width: 100%; 8 | height: 1024px; 9 | background: rgba(255,255,255,1); 10 | opacity: 1; 11 | position: relative; 12 | top: 0px; 13 | left: 0px; 14 | border-top-left-radius: 20px; 15 | border-top-right-radius: 20px; 16 | border-bottom-left-radius: 20px; 17 | border-bottom-right-radius: 20px; 18 | box-shadow: 100px 0px 160px rgba(0, 0, 0, 0.25); 19 | overflow: hidden; 20 | } 21 | .v10_827 { 22 | width: 100%; 23 | height: 64px; 24 | background: rgba(76,96,135,1); 25 | opacity: 1; 26 | position: absolute; 27 | top: 218px; 28 | left: 0px; 29 | overflow: hidden; 30 | } 31 | .v10_828 { 32 | width: 10px; 33 | height: 3px; 34 | background: rgba(108,103,119,1); 35 | opacity: 1; 36 | position: absolute; 37 | top: 2395px; 38 | left: 679px; 39 | } 40 | .v10_829 { 41 | width: 10px; 42 | height: 2px; 43 | background: rgba(40,37,51,1); 44 | opacity: 0.5600000023841858; 45 | position: absolute; 46 | top: 2396px; 47 | left: 679px; 48 | } 49 | .v10_830 { 50 | width: 3px; 51 | height: 2px; 52 | background: rgba(108,103,119,1); 53 | opacity: 1; 54 | position: absolute; 55 | top: 2395px; 56 | left: 678px; 57 | } 58 | .v10_831 { 59 | width: 2px; 60 | height: 0px; 61 | background: rgba(108,103,119,1); 62 | opacity: 1; 63 | position: absolute; 64 | top: 2395px; 65 | left: 676px; 66 | } 67 | .v10_832 { 68 | width: 5px; 69 | height: 2px; 70 | background: rgba(40,37,51,1); 71 | opacity: 0.5600000023841858; 72 | position: absolute; 73 | top: 2395px; 74 | left: 676px; 75 | } 76 | .v10_833 { 77 | width: 114px; 78 | height: 10px; 79 | background: url("../images/v10_833.png"); 80 | background-repeat: no-repeat; 81 | background-position: center center; 82 | background-size: cover; 83 | opacity: 1; 84 | position: absolute; 85 | top: 2425px; 86 | left: 647px; 87 | overflow: hidden; 88 | } 89 | .v10_834 { 90 | width: 114px; 91 | height: 10px; 92 | background: rgba(92,88,104,1); 93 | opacity: 1; 94 | position: absolute; 95 | top: 0px; 96 | left: 0px; 97 | } 98 | .v10_835 { 99 | width: 35px; 100 | height: 5px; 101 | background: rgba(86,56,7,1); 102 | opacity: 1; 103 | position: absolute; 104 | top: 2425px; 105 | left: 685px; 106 | } 107 | .v10_836 { 108 | width: 54px; 109 | height: 16px; 110 | background: rgba(232,133,15,1); 111 | opacity: 1; 112 | position: absolute; 113 | top: 2411px; 114 | left: 676px; 115 | } 116 | .v10_837 { 117 | width: 36px; 118 | height: 11px; 119 | background: rgba(249,189,125,1); 120 | opacity: 0.38999998569488525; 121 | position: absolute; 122 | top: 2411px; 123 | left: 694px; 124 | } 125 | .v10_838 { 126 | width: 39px; 127 | height: 16px; 128 | background: rgba(232,133,15,1); 129 | opacity: 0.5600000023841858; 130 | position: absolute; 131 | top: 2411px; 132 | left: 676px; 133 | } 134 | .v10_839 { 135 | width: 33px; 136 | height: 10px; 137 | background: url("../images/v10_839.png"); 138 | background-repeat: no-repeat; 139 | background-position: center center; 140 | background-size: cover; 141 | opacity: 1; 142 | position: absolute; 143 | top: 2402px; 144 | left: 686px; 145 | overflow: hidden; 146 | } 147 | .v10_840 { 148 | width: 33px; 149 | height: 10px; 150 | background: rgba(232,133,15,1); 151 | opacity: 1; 152 | position: absolute; 153 | top: 0px; 154 | left: 0px; 155 | } 156 | .v10_841 { 157 | width: 30px; 158 | height: 10px; 159 | background: rgba(232,133,15,1); 160 | opacity: 1; 161 | position: absolute; 162 | top: 2402px; 163 | left: 686px; 164 | } 165 | .v10_842 { 166 | width: 32px; 167 | height: 24px; 168 | background: url("../images/v10_842.png"); 169 | background-repeat: no-repeat; 170 | background-position: center center; 171 | background-size: cover; 172 | opacity: 1; 173 | position: absolute; 174 | top: 2400px; 175 | left: 687px; 176 | overflow: hidden; 177 | } 178 | .v10_843 { 179 | width: 2px; 180 | height: 20px; 181 | background: rgba(82,77,91,1); 182 | opacity: 0.6299999952316284; 183 | position: absolute; 184 | top: 3px; 185 | left: 15px; 186 | } 187 | .v10_844 { 188 | width: 32px; 189 | height: 4px; 190 | background: rgba(82,77,91,1); 191 | opacity: 1; 192 | position: absolute; 193 | top: 0px; 194 | left: 0px; 195 | } 196 | .v10_845 { 197 | width: 29px; 198 | height: 24px; 199 | background: url("../images/v10_845.png"); 200 | background-repeat: no-repeat; 201 | background-position: center center; 202 | background-size: cover; 203 | opacity: 1; 204 | position: absolute; 205 | top: 2379px; 206 | left: 688px; 207 | overflow: hidden; 208 | } 209 | .v10_846 { 210 | width: 29px; 211 | height: 9px; 212 | background: rgba(108,103,119,1); 213 | opacity: 1; 214 | position: absolute; 215 | top: 14px; 216 | left: 0px; 217 | } 218 | .v10_847 { 219 | width: 20px; 220 | height: 9px; 221 | background: rgba(82,77,91,1); 222 | opacity: 1; 223 | position: absolute; 224 | top: 5px; 225 | left: 4px; 226 | } 227 | .v10_848 { 228 | width: 20px; 229 | height: 6px; 230 | background: url("../images/v10_848.png"); 231 | background-repeat: no-repeat; 232 | background-position: center center; 233 | background-size: cover; 234 | opacity: 1; 235 | position: absolute; 236 | top: 0px; 237 | left: 4px; 238 | overflow: hidden; 239 | } 240 | .v10_849 { 241 | width: 20px; 242 | height: 6px; 243 | background: rgba(40,37,51,1); 244 | opacity: 1; 245 | position: absolute; 246 | top: 0px; 247 | left: 0px; 248 | } 249 | .v10_850 { 250 | width: 13px; 251 | height: 24px; 252 | background: rgba(40,37,51,1); 253 | opacity: 0.5600000023841858; 254 | position: absolute; 255 | top: 0px; 256 | left: 0px; 257 | } 258 | .v10_851 { 259 | width: 63px; 260 | height: 8px; 261 | background: url("../images/v10_851.png"); 262 | background-repeat: no-repeat; 263 | background-position: center center; 264 | background-size: cover; 265 | opacity: 1; 266 | position: absolute; 267 | top: 2372px; 268 | left: 671px; 269 | overflow: hidden; 270 | } 271 | .v10_852 { 272 | width: 63px; 273 | height: 8px; 274 | background: url("../images/v10_852.png"); 275 | background-repeat: no-repeat; 276 | background-position: center center; 277 | background-size: cover; 278 | opacity: 1; 279 | position: absolute; 280 | top: 0px; 281 | left: 0px; 282 | overflow: hidden; 283 | } 284 | .v10_853 { 285 | width: 63px; 286 | height: 5px; 287 | background: rgba(121,117,130,1); 288 | opacity: 1; 289 | position: absolute; 290 | top: 3px; 291 | left: 0px; 292 | } 293 | .v10_854 { 294 | width: 44px; 295 | height: 5px; 296 | background: rgba(82,77,91,1); 297 | opacity: 0.38999998569488525; 298 | position: absolute; 299 | top: 3px; 300 | left: 0px; 301 | } 302 | .v10_855 { 303 | width: 63px; 304 | height: 6px; 305 | background: rgba(142,133,168,1); 306 | opacity: 1; 307 | position: absolute; 308 | top: 0px; 309 | left: 0px; 310 | } 311 | .v10_856 { 312 | width: 63px; 313 | height: 3px; 314 | background: rgba(217,211,244,1); 315 | opacity: 1; 316 | position: absolute; 317 | top: 3px; 318 | left: 0px; 319 | } 320 | .v10_857 { 321 | width: 14px; 322 | height: 4px; 323 | background: url("../images/v10_857.png"); 324 | background-repeat: no-repeat; 325 | background-position: center center; 326 | background-size: cover; 327 | opacity: 1; 328 | position: absolute; 329 | top: 2372px; 330 | left: 696px; 331 | overflow: hidden; 332 | } 333 | .v10_858 { 334 | width: 14px; 335 | height: 4px; 336 | background: rgba(61,58,68,1); 337 | opacity: 1; 338 | position: absolute; 339 | top: 0px; 340 | left: 0px; 341 | } 342 | .v10_859 { 343 | width: 13px; 344 | height: 3px; 345 | background: rgba(82,77,91,1); 346 | opacity: 1; 347 | position: absolute; 348 | top: 2369px; 349 | left: 696px; 350 | } 351 | .v10_860 { 352 | width: 19px; 353 | height: 3px; 354 | background: rgba(61,58,68,1); 355 | opacity: 1; 356 | position: absolute; 357 | top: 2367px; 358 | left: 693px; 359 | } 360 | .v10_861 { 361 | width: 24px; 362 | height: 1px; 363 | background: rgba(40,37,51,1); 364 | opacity: 1; 365 | position: absolute; 366 | top: 2367px; 367 | left: 691px; 368 | } 369 | .v10_862 { 370 | width: 30px; 371 | height: 6px; 372 | background: rgba(82,77,91,1); 373 | opacity: 1; 374 | position: absolute; 375 | top: 2362px; 376 | left: 688px; 377 | } 378 | .v10_863 { 379 | width: 16px; 380 | height: 5px; 381 | background: rgba(86,56,7,1); 382 | opacity: 1; 383 | position: absolute; 384 | top: 2393px; 385 | left: 715px; 386 | } 387 | .v10_864 { 388 | width: 7px; 389 | height: 2px; 390 | background: rgba(124,87,33,1); 391 | opacity: 1; 392 | position: absolute; 393 | top: 2393px; 394 | left: 726px; 395 | } 396 | .v10_865 { 397 | width: 30px; 398 | height: 4px; 399 | background: url("../images/v10_865.png"); 400 | background-repeat: no-repeat; 401 | background-position: center center; 402 | background-size: cover; 403 | opacity: 1; 404 | position: absolute; 405 | top: 2430px; 406 | left: 707px; 407 | overflow: hidden; 408 | } 409 | .v10_866 { 410 | width: 13px; 411 | height: 2px; 412 | background: rgba(86,56,7,1); 413 | opacity: 1; 414 | position: absolute; 415 | top: 0px; 416 | left: 16px; 417 | } 418 | .v10_867 { 419 | width: 4px; 420 | height: 2px; 421 | background: rgba(124,87,33,1); 422 | opacity: 1; 423 | position: absolute; 424 | top: 0px; 425 | left: 14px; 426 | } 427 | .v10_868 { 428 | width: 4px; 429 | height: 2px; 430 | background: rgba(124,87,33,1); 431 | opacity: 1; 432 | position: absolute; 433 | top: 0px; 434 | left: 10px; 435 | } 436 | .v10_869 { 437 | width: 4px; 438 | height: 2px; 439 | background: rgba(124,87,33,1); 440 | opacity: 1; 441 | position: absolute; 442 | top: 1px; 443 | left: 7px; 444 | } 445 | .v10_870 { 446 | width: 4px; 447 | height: 2px; 448 | background: rgba(124,87,33,1); 449 | opacity: 1; 450 | position: absolute; 451 | top: 1px; 452 | left: 3px; 453 | } 454 | .v10_871 { 455 | width: 4px; 456 | height: 2px; 457 | background: rgba(124,87,33,1); 458 | opacity: 1; 459 | position: absolute; 460 | top: 2px; 461 | left: 0px; 462 | } 463 | .v10_872 { 464 | width: 123px; 465 | height: 50px; 466 | background: rgba(108,103,119,1); 467 | opacity: 1; 468 | position: absolute; 469 | top: 2385px; 470 | left: 645px; 471 | } 472 | .v10_873 { 473 | width: 13px; 474 | height: 3px; 475 | background: rgba(185,184,193,1); 476 | opacity: 0.6899999976158142; 477 | position: absolute; 478 | top: 2364px; 479 | left: 703px; 480 | } 481 | .v10_874 { 482 | width: 13px; 483 | height: 3px; 484 | background: rgba(185,184,193,1); 485 | opacity: 0.6899999976158142; 486 | position: absolute; 487 | top: 2399px; 488 | left: 702px; 489 | } 490 | .v10_875 { 491 | width: 9px; 492 | height: 0px; 493 | background: rgba(185,184,193,1); 494 | opacity: 0.6899999976158142; 495 | position: absolute; 496 | top: 2371px; 497 | left: 700px; 498 | } 499 | .v10_876 { 500 | width: 23px; 501 | height: 13px; 502 | background: rgba(82,77,91,1); 503 | opacity: 0.6899999976158142; 504 | position: absolute; 505 | top: 2363px; 506 | left: 679px; 507 | } 508 | .v10_877 { 509 | height: 0px; 510 | background: rgba(154,143,170,1); 511 | opacity: 1; 512 | position: absolute; 513 | top: 2363px; 514 | left: 716px; 515 | } 516 | .v10_878 { 517 | width: 26px; 518 | height: 2px; 519 | background: rgba(154,143,170,1); 520 | opacity: 1; 521 | position: absolute; 522 | top: 2361px; 523 | left: 690px; 524 | } 525 | .v10_879 { 526 | width: 24px; 527 | height: 2px; 528 | background: rgba(82,77,91,1); 529 | opacity: 1; 530 | position: absolute; 531 | top: 2361px; 532 | left: 691px; 533 | } 534 | .v10_880 { 535 | width: 26px; 536 | height: 1px; 537 | background: url("../images/v10_880.png"); 538 | background-repeat: no-repeat; 539 | background-position: center center; 540 | background-size: cover; 541 | opacity: 1; 542 | position: absolute; 543 | top: 2363px; 544 | left: 690px; 545 | overflow: hidden; 546 | } 547 | .v10_881 { 548 | width: 26px; 549 | height: 1px; 550 | background: rgba(0,0,0,1); 551 | opacity: 1; 552 | position: absolute; 553 | top: 0px; 554 | left: 0px; 555 | } 556 | .v10_882 { 557 | width: 10px; 558 | height: 2px; 559 | background: rgba(82,77,91,1); 560 | opacity: 0.4099999964237213; 561 | position: absolute; 562 | top: 2362px; 563 | left: 704px; 564 | } 565 | .v10_883 { 566 | width: 4px; 567 | height: 2px; 568 | background: rgba(135,133,142,1); 569 | opacity: 1; 570 | position: absolute; 571 | top: 2362px; 572 | left: 694px; 573 | } 574 | .v10_884 { 575 | width: 4px; 576 | height: 0px; 577 | background: rgba(154,154,183,1); 578 | opacity: 1; 579 | position: absolute; 580 | top: 2364px; 581 | left: 707px; 582 | } 583 | .v10_885 { 584 | width: 4px; 585 | height: 2px; 586 | background: rgba(82,77,91,1); 587 | opacity: 1; 588 | position: absolute; 589 | top: 2373px; 590 | left: 705px; 591 | } 592 | .v10_886 { 593 | width: 30px; 594 | height: 2px; 595 | background: rgba(185,184,193,1); 596 | opacity: 0.6899999976158142; 597 | position: absolute; 598 | top: 2375px; 599 | left: 701px; 600 | } 601 | .v10_887 { 602 | width: 6px; 603 | height: 1px; 604 | background: rgba(121,117,130,1); 605 | opacity: 0.46000000834465027; 606 | position: absolute; 607 | top: 2381px; 608 | left: 704px; 609 | } 610 | .v10_888 { 611 | width: 8px; 612 | height: 6px; 613 | background: rgba(198,193,211,1); 614 | opacity: 0.7799999713897705; 615 | position: absolute; 616 | top: 2386px; 617 | left: 703px; 618 | } 619 | .v10_889 { 620 | width: 17px; 621 | height: 5px; 622 | background: rgba(86,56,7,1); 623 | opacity: 1; 624 | position: absolute; 625 | top: 2393px; 626 | left: 714px; 627 | } 628 | .v10_890 { 629 | width: 7px; 630 | height: 2px; 631 | background: rgba(124,87,33,1); 632 | opacity: 1; 633 | position: absolute; 634 | top: 2393px; 635 | left: 726px; 636 | } 637 | .v10_891 { 638 | width: 12px; 639 | height: 4px; 640 | background: rgba(86,56,7,1); 641 | opacity: 1; 642 | position: absolute; 643 | top: 2390px; 644 | left: 729px; 645 | } 646 | .v10_892 { 647 | width: 5px; 648 | height: 2px; 649 | background: rgba(124,87,33,1); 650 | opacity: 1; 651 | position: absolute; 652 | top: 2389px; 653 | left: 737px; 654 | } 655 | .v10_893 { 656 | width: 5px; 657 | height: 2px; 658 | background: rgba(124,87,33,1); 659 | opacity: 1; 660 | position: absolute; 661 | top: 2388px; 662 | left: 740px; 663 | } 664 | .v10_894 { 665 | width: 5px; 666 | height: 2px; 667 | background: rgba(124,87,33,1); 668 | opacity: 1; 669 | position: absolute; 670 | top: 2387px; 671 | left: 743px; 672 | } 673 | .v10_895 { 674 | width: 24px; 675 | height: 13px; 676 | background: rgba(185,184,193,1); 677 | opacity: 0.6899999976158142; 678 | position: absolute; 679 | top: 2413px; 680 | left: 702px; 681 | } 682 | .v10_896 { 683 | width: 10px; 684 | height: 1px; 685 | background: rgba(185,184,193,1); 686 | opacity: 0.6899999976158142; 687 | position: absolute; 688 | top: 2430px; 689 | left: 726px; 690 | } 691 | .v10_897 { 692 | width: 2px; 693 | height: 1px; 694 | background: rgba(185,184,193,1); 695 | opacity: 0.6899999976158142; 696 | position: absolute; 697 | top: 2430px; 698 | left: 722px; 699 | } 700 | .v10_898 { 701 | width: 2px; 702 | height: 1px; 703 | background: rgba(185,184,193,1); 704 | opacity: 0.6899999976158142; 705 | position: absolute; 706 | top: 2431px; 707 | left: 718px; 708 | } 709 | .v10_899 { 710 | width: 2px; 711 | height: 1px; 712 | background: rgba(185,184,193,1); 713 | opacity: 0.6899999976158142; 714 | position: absolute; 715 | top: 2431px; 716 | left: 715px; 717 | } 718 | .v10_900 { 719 | width: 2px; 720 | height: 1px; 721 | background: rgba(185,184,193,1); 722 | opacity: 0.6899999976158142; 723 | position: absolute; 724 | top: 2432px; 725 | left: 711px; 726 | } 727 | .v10_901 { 728 | width: 2px; 729 | height: 1px; 730 | background: rgba(185,184,193,1); 731 | opacity: 0.6899999976158142; 732 | position: absolute; 733 | top: 2432px; 734 | left: 708px; 735 | } 736 | .v10_902 { 737 | width: 5px; 738 | height: 2px; 739 | background: rgba(52,49,61,1); 740 | opacity: 1; 741 | position: absolute; 742 | top: 2432px; 743 | left: 704px; 744 | } 745 | .v10_903 { 746 | width: 2px; 747 | height: 0px; 748 | background: rgba(185,184,193,1); 749 | opacity: 0.6899999976158142; 750 | position: absolute; 751 | top: 2433px; 752 | left: 705px; 753 | } 754 | .v10_904 { 755 | width: 27px; 756 | height: 3px; 757 | background: rgba(40,37,51,1); 758 | opacity: 0.5600000023841858; 759 | position: absolute; 760 | top: 2427px; 761 | left: 685px; 762 | } 763 | .v10_905 { 764 | width: 10px; 765 | height: 3px; 766 | background: rgba(255,192,3,1); 767 | opacity: 1; 768 | position: absolute; 769 | top: 3952px; 770 | left: 1709px; 771 | } 772 | .v10_906 { 773 | width: 10px; 774 | height: 2px; 775 | background: rgba(255,166,0,1); 776 | opacity: 0.5600000023841858; 777 | position: absolute; 778 | top: 3954px; 779 | left: 1709px; 780 | } 781 | .v10_907 { 782 | width: 3px; 783 | height: 2px; 784 | background: rgba(108,103,119,1); 785 | opacity: 1; 786 | position: absolute; 787 | top: 3952px; 788 | left: 1708px; 789 | } 790 | .v10_908 { 791 | width: 2px; 792 | height: 0px; 793 | background: rgba(108,103,119,1); 794 | opacity: 1; 795 | position: absolute; 796 | top: 3953px; 797 | left: 1706px; 798 | } 799 | .v10_909 { 800 | width: 5px; 801 | height: 2px; 802 | background: rgba(189,37,36,1); 803 | opacity: 0.5600000023841858; 804 | position: absolute; 805 | top: 3952px; 806 | left: 1706px; 807 | } 808 | .v10_910 { 809 | width: 114px; 810 | height: 10px; 811 | background: url("../images/v10_910.png"); 812 | background-repeat: no-repeat; 813 | background-position: center center; 814 | background-size: cover; 815 | opacity: 1; 816 | position: absolute; 817 | top: 3983px; 818 | left: 1677px; 819 | overflow: hidden; 820 | } 821 | .v10_911 { 822 | width: 114px; 823 | height: 10px; 824 | background: rgba(92,88,104,1); 825 | opacity: 1; 826 | position: absolute; 827 | top: 0px; 828 | left: 0px; 829 | } 830 | .v10_912 { 831 | width: 35px; 832 | height: 5px; 833 | background: rgba(86,56,7,1); 834 | opacity: 1; 835 | position: absolute; 836 | top: 3983px; 837 | left: 1715px; 838 | } 839 | .v10_913 { 840 | width: 54px; 841 | height: 16px; 842 | background: rgba(232,133,15,1); 843 | opacity: 1; 844 | position: absolute; 845 | top: 3969px; 846 | left: 1706px; 847 | } 848 | .v10_914 { 849 | width: 36px; 850 | height: 11px; 851 | background: rgba(249,189,125,1); 852 | opacity: 0.38999998569488525; 853 | position: absolute; 854 | top: 3969px; 855 | left: 1724px; 856 | } 857 | .v10_915 { 858 | width: 39px; 859 | height: 16px; 860 | background: rgba(189,37,36,1); 861 | opacity: 0.5600000023841858; 862 | position: absolute; 863 | top: 3969px; 864 | left: 1706px; 865 | } 866 | .v10_916 { 867 | width: 33px; 868 | height: 10px; 869 | background: url("../images/v10_916.png"); 870 | background-repeat: no-repeat; 871 | background-position: center center; 872 | background-size: cover; 873 | opacity: 1; 874 | position: absolute; 875 | top: 3960px; 876 | left: 1716px; 877 | overflow: hidden; 878 | } 879 | .v10_917 { 880 | width: 33px; 881 | height: 10px; 882 | background: rgba(235,58,52,1); 883 | opacity: 1; 884 | position: absolute; 885 | top: 0px; 886 | left: 0px; 887 | } 888 | .v10_918 { 889 | width: 30px; 890 | height: 10px; 891 | background: rgba(189,37,36,1); 892 | opacity: 1; 893 | position: absolute; 894 | top: 3960px; 895 | left: 1716px; 896 | } 897 | .v10_919 { 898 | width: 32px; 899 | height: 4px; 900 | background: url("../images/v10_919.png"); 901 | background-repeat: no-repeat; 902 | background-position: center center; 903 | background-size: cover; 904 | opacity: 1; 905 | position: absolute; 906 | top: 3958px; 907 | left: 1717px; 908 | overflow: hidden; 909 | } 910 | .v10_920 { 911 | width: 32px; 912 | height: 4px; 913 | background: rgba(82,77,91,1); 914 | opacity: 1; 915 | position: absolute; 916 | top: 0px; 917 | left: 0px; 918 | } 919 | .v10_921 { 920 | width: 29px; 921 | height: 24px; 922 | background: url("../images/v10_921.png"); 923 | background-repeat: no-repeat; 924 | background-position: center center; 925 | background-size: cover; 926 | opacity: 1; 927 | position: absolute; 928 | top: 3936px; 929 | left: 1718px; 930 | overflow: hidden; 931 | } 932 | .v10_922 { 933 | width: 29px; 934 | height: 9px; 935 | background: rgba(255,192,3,1); 936 | opacity: 1; 937 | position: absolute; 938 | top: 14px; 939 | left: 0px; 940 | } 941 | .v10_923 { 942 | width: 20px; 943 | height: 9px; 944 | background: rgba(255,192,3,1); 945 | opacity: 1; 946 | position: absolute; 947 | top: 5px; 948 | left: 4px; 949 | } 950 | .v10_924 { 951 | width: 20px; 952 | height: 6px; 953 | background: url("../images/v10_924.png"); 954 | background-repeat: no-repeat; 955 | background-position: center center; 956 | background-size: cover; 957 | opacity: 1; 958 | position: absolute; 959 | top: 0px; 960 | left: 4px; 961 | overflow: hidden; 962 | } 963 | .v10_925 { 964 | width: 20px; 965 | height: 6px; 966 | background: rgba(255,166,0,1); 967 | opacity: 1; 968 | position: absolute; 969 | top: 0px; 970 | left: 0px; 971 | } 972 | .v10_926 { 973 | width: 13px; 974 | height: 24px; 975 | background: rgba(255,166,0,1); 976 | opacity: 0.5600000023841858; 977 | position: absolute; 978 | top: 0px; 979 | left: 0px; 980 | } 981 | .v10_927 { 982 | width: 63px; 983 | height: 8px; 984 | background: url("../images/v10_927.png"); 985 | background-repeat: no-repeat; 986 | background-position: center center; 987 | background-size: cover; 988 | opacity: 1; 989 | position: absolute; 990 | top: 3930px; 991 | left: 1701px; 992 | overflow: hidden; 993 | } 994 | .v10_928 { 995 | width: 63px; 996 | height: 8px; 997 | background: url("../images/v10_928.png"); 998 | background-repeat: no-repeat; 999 | background-position: center center; 1000 | background-size: cover; 1001 | opacity: 1; 1002 | position: absolute; 1003 | top: 0px; 1004 | left: 0px; 1005 | overflow: hidden; 1006 | } 1007 | .v10_929 { 1008 | width: 63px; 1009 | height: 5px; 1010 | background: rgba(255,166,0,1); 1011 | opacity: 1; 1012 | position: absolute; 1013 | top: 3px; 1014 | left: 0px; 1015 | } 1016 | .v10_930 { 1017 | width: 44px; 1018 | height: 5px; 1019 | background: rgba(255,166,0,1); 1020 | opacity: 0.38999998569488525; 1021 | position: absolute; 1022 | top: 3px; 1023 | left: 0px; 1024 | } 1025 | .v10_931 { 1026 | width: 63px; 1027 | height: 6px; 1028 | background: rgba(255,192,3,1); 1029 | opacity: 1; 1030 | position: absolute; 1031 | top: 0px; 1032 | left: 0px; 1033 | } 1034 | .v10_932 { 1035 | width: 63px; 1036 | height: 3px; 1037 | background: rgba(227,157,0,1); 1038 | opacity: 1; 1039 | position: absolute; 1040 | top: 3px; 1041 | left: 0px; 1042 | } 1043 | .v10_933 { 1044 | width: 14px; 1045 | height: 4px; 1046 | background: url("../images/v10_933.png"); 1047 | background-repeat: no-repeat; 1048 | background-position: center center; 1049 | background-size: cover; 1050 | opacity: 1; 1051 | position: absolute; 1052 | top: 3929px; 1053 | left: 1726px; 1054 | overflow: hidden; 1055 | } 1056 | .v10_934 { 1057 | width: 14px; 1058 | height: 4px; 1059 | background: rgba(189,37,36,1); 1060 | opacity: 1; 1061 | position: absolute; 1062 | top: 0px; 1063 | left: 0px; 1064 | } 1065 | .v10_935 { 1066 | width: 13px; 1067 | height: 3px; 1068 | background: rgba(235,58,52,1); 1069 | opacity: 1; 1070 | position: absolute; 1071 | top: 3927px; 1072 | left: 1726px; 1073 | } 1074 | .v10_936 { 1075 | width: 19px; 1076 | height: 3px; 1077 | background: rgba(189,37,36,1); 1078 | opacity: 1; 1079 | position: absolute; 1080 | top: 3925px; 1081 | left: 1723px; 1082 | } 1083 | .v10_937 { 1084 | width: 24px; 1085 | height: 1px; 1086 | background: rgba(189,37,36,1); 1087 | opacity: 1; 1088 | position: absolute; 1089 | top: 3925px; 1090 | left: 1721px; 1091 | } 1092 | .v10_938 { 1093 | width: 30px; 1094 | height: 6px; 1095 | background: rgba(115,12,8,1); 1096 | opacity: 1; 1097 | position: absolute; 1098 | top: 3920px; 1099 | left: 1718px; 1100 | } 1101 | .v10_939 { 1102 | width: 16px; 1103 | height: 5px; 1104 | background: rgba(86,56,7,1); 1105 | opacity: 1; 1106 | position: absolute; 1107 | top: 3951px; 1108 | left: 1745px; 1109 | } 1110 | .v10_940 { 1111 | width: 7px; 1112 | height: 2px; 1113 | background: rgba(124,87,33,1); 1114 | opacity: 1; 1115 | position: absolute; 1116 | top: 3951px; 1117 | left: 1756px; 1118 | } 1119 | .v10_941 { 1120 | width: 30px; 1121 | height: 4px; 1122 | background: url("../images/v10_941.png"); 1123 | background-repeat: no-repeat; 1124 | background-position: center center; 1125 | background-size: cover; 1126 | opacity: 1; 1127 | position: absolute; 1128 | top: 3988px; 1129 | left: 1737px; 1130 | overflow: hidden; 1131 | } 1132 | .v10_942 { 1133 | width: 13px; 1134 | height: 2px; 1135 | background: rgba(86,56,7,1); 1136 | opacity: 1; 1137 | position: absolute; 1138 | top: 0px; 1139 | left: 16px; 1140 | } 1141 | .v10_943 { 1142 | width: 4px; 1143 | height: 2px; 1144 | background: rgba(124,87,33,1); 1145 | opacity: 1; 1146 | position: absolute; 1147 | top: 0px; 1148 | left: 14px; 1149 | } 1150 | .v10_944 { 1151 | width: 4px; 1152 | height: 2px; 1153 | background: rgba(124,87,33,1); 1154 | opacity: 1; 1155 | position: absolute; 1156 | top: 0px; 1157 | left: 10px; 1158 | } 1159 | .v10_945 { 1160 | width: 4px; 1161 | height: 2px; 1162 | background: rgba(124,87,33,1); 1163 | opacity: 1; 1164 | position: absolute; 1165 | top: 1px; 1166 | left: 7px; 1167 | } 1168 | .v10_946 { 1169 | width: 4px; 1170 | height: 2px; 1171 | background: rgba(124,87,33,1); 1172 | opacity: 1; 1173 | position: absolute; 1174 | top: 1px; 1175 | left: 3px; 1176 | } 1177 | .v10_947 { 1178 | width: 4px; 1179 | height: 2px; 1180 | background: rgba(124,87,33,1); 1181 | opacity: 1; 1182 | position: absolute; 1183 | top: 2px; 1184 | left: 0px; 1185 | } 1186 | .v10_948 { 1187 | width: 123px; 1188 | height: 50px; 1189 | background: rgba(108,103,119,1); 1190 | opacity: 1; 1191 | position: absolute; 1192 | top: 3943px; 1193 | left: 1675px; 1194 | } 1195 | .v10_949 { 1196 | width: 13px; 1197 | height: 3px; 1198 | background: rgba(189,37,36,1); 1199 | opacity: 0.6899999976158142; 1200 | position: absolute; 1201 | top: 3922px; 1202 | left: 1733px; 1203 | } 1204 | .v10_950 { 1205 | width: 9px; 1206 | height: 0px; 1207 | background: rgba(235,58,52,1); 1208 | opacity: 0.6899999976158142; 1209 | position: absolute; 1210 | top: 3929px; 1211 | left: 1730px; 1212 | } 1213 | .v10_951 { 1214 | width: 23px; 1215 | height: 13px; 1216 | background: rgba(241,107,81,1); 1217 | opacity: 0.6899999976158142; 1218 | position: absolute; 1219 | top: 3920px; 1220 | left: 1709px; 1221 | } 1222 | .v10_952 { 1223 | height: 0px; 1224 | background: rgba(154,143,170,1); 1225 | opacity: 1; 1226 | position: absolute; 1227 | top: 3921px; 1228 | left: 1746px; 1229 | } 1230 | .v10_953 { 1231 | width: 26px; 1232 | height: 2px; 1233 | background: rgba(154,143,170,1); 1234 | opacity: 1; 1235 | position: absolute; 1236 | top: 3919px; 1237 | left: 1720px; 1238 | } 1239 | .v10_954 { 1240 | width: 24px; 1241 | height: 2px; 1242 | background: rgba(82,77,91,1); 1243 | opacity: 1; 1244 | position: absolute; 1245 | top: 3919px; 1246 | left: 1721px; 1247 | } 1248 | .v10_955 { 1249 | width: 26px; 1250 | height: 1px; 1251 | background: url("../images/v10_955.png"); 1252 | background-repeat: no-repeat; 1253 | background-position: center center; 1254 | background-size: cover; 1255 | opacity: 1; 1256 | position: absolute; 1257 | top: 3921px; 1258 | left: 1720px; 1259 | overflow: hidden; 1260 | } 1261 | .v10_956 { 1262 | width: 26px; 1263 | height: 1px; 1264 | background: rgba(0,0,0,1); 1265 | opacity: 1; 1266 | position: absolute; 1267 | top: 0px; 1268 | left: 0px; 1269 | } 1270 | .v10_957 { 1271 | width: 10px; 1272 | height: 2px; 1273 | background: rgba(82,77,91,1); 1274 | opacity: 0.4099999964237213; 1275 | position: absolute; 1276 | top: 3919px; 1277 | left: 1734px; 1278 | } 1279 | .v10_958 { 1280 | width: 4px; 1281 | height: 2px; 1282 | background: rgba(135,133,142,1); 1283 | opacity: 1; 1284 | position: absolute; 1285 | top: 3919px; 1286 | left: 1724px; 1287 | } 1288 | .v10_959 { 1289 | width: 4px; 1290 | height: 0px; 1291 | background: rgba(154,154,183,1); 1292 | opacity: 1; 1293 | position: absolute; 1294 | top: 3922px; 1295 | left: 1737px; 1296 | } 1297 | .v10_960 { 1298 | width: 4px; 1299 | height: 2px; 1300 | background: rgba(235,58,52,1); 1301 | opacity: 1; 1302 | position: absolute; 1303 | top: 3930px; 1304 | left: 1735px; 1305 | } 1306 | .v10_961 { 1307 | width: 30px; 1308 | height: 2px; 1309 | background: rgba(255,203,31,1); 1310 | opacity: 0.6899999976158142; 1311 | position: absolute; 1312 | top: 3932px; 1313 | left: 1731px; 1314 | } 1315 | .v10_962 { 1316 | width: 6px; 1317 | height: 1px; 1318 | background: rgba(255,203,31,1); 1319 | opacity: 0.46000000834465027; 1320 | position: absolute; 1321 | top: 3939px; 1322 | left: 1734px; 1323 | } 1324 | .v10_963 { 1325 | width: 8px; 1326 | height: 6px; 1327 | background: rgba(255,207,39,1); 1328 | opacity: 0.7799999713897705; 1329 | position: absolute; 1330 | top: 3944px; 1331 | left: 1733px; 1332 | } 1333 | .v10_964 { 1334 | width: 17px; 1335 | height: 5px; 1336 | background: rgba(86,56,7,1); 1337 | opacity: 1; 1338 | position: absolute; 1339 | top: 3951px; 1340 | left: 1744px; 1341 | } 1342 | .v10_965 { 1343 | width: 7px; 1344 | height: 2px; 1345 | background: rgba(124,87,33,1); 1346 | opacity: 1; 1347 | position: absolute; 1348 | top: 3951px; 1349 | left: 1756px; 1350 | } 1351 | .v10_966 { 1352 | width: 12px; 1353 | height: 4px; 1354 | background: rgba(86,56,7,1); 1355 | opacity: 1; 1356 | position: absolute; 1357 | top: 3948px; 1358 | left: 1759px; 1359 | } 1360 | .v10_967 { 1361 | width: 5px; 1362 | height: 2px; 1363 | background: rgba(124,87,33,1); 1364 | opacity: 1; 1365 | position: absolute; 1366 | top: 3947px; 1367 | left: 1767px; 1368 | } 1369 | .v10_968 { 1370 | width: 5px; 1371 | height: 2px; 1372 | background: rgba(124,87,33,1); 1373 | opacity: 1; 1374 | position: absolute; 1375 | top: 3946px; 1376 | left: 1770px; 1377 | } 1378 | .v10_969 { 1379 | width: 5px; 1380 | height: 2px; 1381 | background: rgba(124,87,33,1); 1382 | opacity: 1; 1383 | position: absolute; 1384 | top: 3945px; 1385 | left: 1773px; 1386 | } 1387 | .v10_970 { 1388 | width: 24px; 1389 | height: 13px; 1390 | background: rgba(185,184,193,1); 1391 | opacity: 0.6899999976158142; 1392 | position: absolute; 1393 | top: 3971px; 1394 | left: 1732px; 1395 | } 1396 | .v10_971 { 1397 | width: 10px; 1398 | height: 1px; 1399 | background: rgba(185,184,193,1); 1400 | opacity: 0.6899999976158142; 1401 | position: absolute; 1402 | top: 3988px; 1403 | left: 1756px; 1404 | } 1405 | .v10_972 { 1406 | width: 2px; 1407 | height: 1px; 1408 | background: rgba(185,184,193,1); 1409 | opacity: 0.6899999976158142; 1410 | position: absolute; 1411 | top: 3988px; 1412 | left: 1752px; 1413 | } 1414 | .v10_973 { 1415 | width: 2px; 1416 | height: 1px; 1417 | background: rgba(185,184,193,1); 1418 | opacity: 0.6899999976158142; 1419 | position: absolute; 1420 | top: 3989px; 1421 | left: 1748px; 1422 | } 1423 | .v10_974 { 1424 | width: 2px; 1425 | height: 1px; 1426 | background: rgba(185,184,193,1); 1427 | opacity: 0.6899999976158142; 1428 | position: absolute; 1429 | top: 3989px; 1430 | left: 1745px; 1431 | } 1432 | .v10_975 { 1433 | width: 2px; 1434 | height: 1px; 1435 | background: rgba(185,184,193,1); 1436 | opacity: 0.6899999976158142; 1437 | position: absolute; 1438 | top: 3989px; 1439 | left: 1741px; 1440 | } 1441 | .v10_976 { 1442 | width: 2px; 1443 | height: 1px; 1444 | background: rgba(185,184,193,1); 1445 | opacity: 0.6899999976158142; 1446 | position: absolute; 1447 | top: 3990px; 1448 | left: 1738px; 1449 | } 1450 | .v10_977 { 1451 | width: 5px; 1452 | height: 2px; 1453 | background: rgba(52,49,61,1); 1454 | opacity: 1; 1455 | position: absolute; 1456 | top: 3990px; 1457 | left: 1734px; 1458 | } 1459 | .v10_978 { 1460 | width: 2px; 1461 | height: 0px; 1462 | background: rgba(185,184,193,1); 1463 | opacity: 0.6899999976158142; 1464 | position: absolute; 1465 | top: 3990px; 1466 | left: 1735px; 1467 | } 1468 | .v10_979 { 1469 | width: 27px; 1470 | height: 3px; 1471 | background: rgba(40,37,51,1); 1472 | opacity: 0.5600000023841858; 1473 | position: absolute; 1474 | top: 3985px; 1475 | left: 1715px; 1476 | } 1477 | .v10_980 { 1478 | background: url("../images/v10_980.png"); 1479 | background-repeat: no-repeat; 1480 | background-position: center center; 1481 | background-size: cover; 1482 | opacity: 1; 1483 | position: absolute; 1484 | top: 627px; 1485 | left: 765px; 1486 | overflow: hidden; 1487 | } 1488 | .v10_981 { 1489 | width: 100%; 1490 | height: 72px; 1491 | background: rgba(30,38,54,1); 1492 | opacity: 1; 1493 | position: relative; 1494 | top: 0px; 1495 | left: 0px; 1496 | box-shadow: 0px 4px 20px rgba(0, 0, 0, 0.05000000074505806); 1497 | overflow: hidden; 1498 | } 1499 | .v10_982 { 1500 | width: 721px; 1501 | height: 24px; 1502 | background: url("../images/v10_982.png"); 1503 | background-repeat: no-repeat; 1504 | background-position: center center; 1505 | background-size: cover; 1506 | opacity: 1; 1507 | position: absolute; 1508 | top: 24px; 1509 | left: 360px; 1510 | overflow: hidden; 1511 | } 1512 | .v10_983 { 1513 | width: 721px; 1514 | height: 24px; 1515 | background: url("../images/v10_983.png"); 1516 | background-repeat: no-repeat; 1517 | background-position: center center; 1518 | background-size: cover; 1519 | opacity: 1; 1520 | position: relative; 1521 | top: 0px; 1522 | left: 0px; 1523 | overflow: hidden; 1524 | } 1525 | .v10_984 { 1526 | width: 42px; 1527 | color: rgba(255,255,255,1); 1528 | position: relative; 1529 | top: 0px; 1530 | left: 0px; 1531 | font-family: Poppins; 1532 | font-weight: Medium; 1533 | font-size: 16px; 1534 | opacity: 1; 1535 | text-align: left; 1536 | } 1537 | .v10_985 { 1538 | width: 36px; 1539 | color: rgba(255,255,255,1); 1540 | position: absolute; 1541 | top: 0px; 1542 | left: 73px; 1543 | font-family: Poppins; 1544 | font-weight: Medium; 1545 | font-size: 16px; 1546 | opacity: 1; 1547 | text-align: left; 1548 | } 1549 | .v10_986 { 1550 | width: 47px; 1551 | color: rgba(255,255,255,1); 1552 | position: absolute; 1553 | top: 0px; 1554 | left: 141px; 1555 | font-family: Poppins; 1556 | font-weight: Medium; 1557 | font-size: 16px; 1558 | opacity: 1; 1559 | text-align: left; 1560 | } 1561 | .v10_987 { 1562 | width: 51px; 1563 | color: rgba(255,255,255,1); 1564 | position: absolute; 1565 | top: 0px; 1566 | left: 218px; 1567 | font-family: Poppins; 1568 | font-weight: Medium; 1569 | font-size: 16px; 1570 | opacity: 1; 1571 | text-align: left; 1572 | } 1573 | .v10_988 { 1574 | width: 56px; 1575 | color: rgba(255,255,255,1); 1576 | position: absolute; 1577 | top: 0px; 1578 | left: 299px; 1579 | font-family: Poppins; 1580 | font-weight: Medium; 1581 | font-size: 16px; 1582 | opacity: 1; 1583 | text-align: left; 1584 | } 1585 | .v10_989 { 1586 | width: 78px; 1587 | color: rgba(255,255,255,1); 1588 | position: absolute; 1589 | top: 0px; 1590 | left: 384px; 1591 | font-family: Poppins; 1592 | font-weight: Medium; 1593 | font-size: 16px; 1594 | opacity: 1; 1595 | text-align: left; 1596 | } 1597 | .v10_990 { 1598 | width: 70px; 1599 | color: rgba(255,255,255,1); 1600 | position: absolute; 1601 | top: 0px; 1602 | left: 489px; 1603 | font-family: Poppins; 1604 | font-weight: Medium; 1605 | font-size: 16px; 1606 | opacity: 1; 1607 | text-align: left; 1608 | } 1609 | .v10_991 { 1610 | width: 56px; 1611 | color: rgba(255,255,255,1); 1612 | position: absolute; 1613 | top: 0px; 1614 | left: 587px; 1615 | font-family: Poppins; 1616 | font-weight: Medium; 1617 | font-size: 16px; 1618 | opacity: 1; 1619 | text-align: left; 1620 | } 1621 | .v10_992 { 1622 | width: 49px; 1623 | color: rgba(255,255,255,1); 1624 | position: absolute; 1625 | top: 0px; 1626 | left: 672px; 1627 | font-family: Poppins; 1628 | font-weight: Medium; 1629 | font-size: 16px; 1630 | opacity: 1; 1631 | text-align: left; 1632 | } 1633 | .v10_993 { 1634 | width: 505px; 1635 | height: 50px; 1636 | background: url("../images/v10_993.png"); 1637 | background-repeat: no-repeat; 1638 | background-position: center center; 1639 | background-size: cover; 1640 | opacity: 1; 1641 | position: absolute; 1642 | top: 108px; 1643 | left: 828px; 1644 | overflow: hidden; 1645 | } 1646 | .v10_994 { 1647 | width: 158px; 1648 | height: 50px; 1649 | background: rgba(59,84,255,1); 1650 | opacity: 1; 1651 | position: relative; 1652 | top: 0px; 1653 | left: 0px; 1654 | border-top-left-radius: 25px; 1655 | border-top-right-radius: 25px; 1656 | border-bottom-left-radius: 25px; 1657 | border-bottom-right-radius: 25px; 1658 | overflow: hidden; 1659 | } 1660 | .v10_995 { 1661 | width: 158px; 1662 | height: 50px; 1663 | background: rgba(62,210,62,1); 1664 | opacity: 1; 1665 | position: absolute; 1666 | top: 0px; 1667 | left: 179px; 1668 | border-top-left-radius: 25px; 1669 | border-top-right-radius: 25px; 1670 | border-bottom-left-radius: 25px; 1671 | border-bottom-right-radius: 25px; 1672 | overflow: hidden; 1673 | } 1674 | .v10_996 { 1675 | width: 158px; 1676 | height: 50px; 1677 | background: rgba(214,45,45,1); 1678 | opacity: 1; 1679 | position: absolute; 1680 | top: 0px; 1681 | left: 347px; 1682 | border-top-left-radius: 25px; 1683 | border-top-right-radius: 25px; 1684 | border-bottom-left-radius: 25px; 1685 | border-bottom-right-radius: 25px; 1686 | overflow: hidden; 1687 | } 1688 | .v10_997 { 1689 | width: 97px; 1690 | color: rgba(255,255,255,1); 1691 | position: absolute; 1692 | top: 13px; 1693 | left: 30px; 1694 | font-family: Poppins; 1695 | font-weight: Medium; 1696 | font-size: 16px; 1697 | opacity: 1; 1698 | text-align: left; 1699 | } 1700 | .v10_998 { 1701 | width: 68px; 1702 | color: rgba(255,255,255,1); 1703 | position: absolute; 1704 | top: 13px; 1705 | left: 224px; 1706 | font-family: Poppins; 1707 | font-weight: Medium; 1708 | font-size: 16px; 1709 | opacity: 1; 1710 | text-align: left; 1711 | } 1712 | .v10_999 { 1713 | width: 76px; 1714 | color: rgba(255,255,255,1); 1715 | position: absolute; 1716 | top: 13px; 1717 | left: 388px; 1718 | font-family: Poppins; 1719 | font-weight: Medium; 1720 | font-size: 16px; 1721 | opacity: 1; 1722 | text-align: left; 1723 | } 1724 | .v10_1000 { 1725 | width: 392px; 1726 | height: 21px; 1727 | background: url("../images/v10_1000.png"); 1728 | background-repeat: no-repeat; 1729 | background-position: center center; 1730 | background-size: cover; 1731 | opacity: 1; 1732 | position: absolute; 1733 | top: 180px; 1734 | left: 941px; 1735 | overflow: hidden; 1736 | } 1737 | .v10_1001 { 1738 | width: 32px; 1739 | color: rgba(0,0,0,1); 1740 | position: relative; 1741 | top: 0px; 1742 | left: 0px; 1743 | font-family: Poppins; 1744 | font-weight: Regular; 1745 | font-size: 14px; 1746 | opacity: 1; 1747 | text-align: left; 1748 | } 1749 | .v10_1002 { 1750 | width: 45px; 1751 | color: rgba(0,0,0,1); 1752 | position: absolute; 1753 | top: 0px; 1754 | left: 44px; 1755 | font-family: Poppins; 1756 | font-weight: Regular; 1757 | font-size: 14px; 1758 | opacity: 1; 1759 | text-align: left; 1760 | } 1761 | .v10_1003 { 1762 | width: 54px; 1763 | color: rgba(0,0,0,1); 1764 | position: absolute; 1765 | top: 0px; 1766 | left: 101px; 1767 | font-family: Poppins; 1768 | font-weight: Regular; 1769 | font-size: 14px; 1770 | opacity: 1; 1771 | text-align: left; 1772 | } 1773 | .v10_1004 { 1774 | width: 147px; 1775 | color: rgba(0,0,0,1); 1776 | position: absolute; 1777 | top: 0px; 1778 | left: 167px; 1779 | font-size: 14px; 1780 | opacity: 1; 1781 | text-align: left; 1782 | } 1783 | .v10_1005 { 1784 | width: 66px; 1785 | color: rgba(0,0,0,1); 1786 | position: absolute; 1787 | top: 0px; 1788 | left: 326px; 1789 | font-family: Poppins; 1790 | font-weight: Regular; 1791 | font-size: 14px; 1792 | opacity: 1; 1793 | text-align: left; 1794 | } 1795 | .name { 1796 | color: #fff; 1797 | } 1798 | .name { 1799 | color: #fff; 1800 | } 1801 | .name { 1802 | color: #fff; 1803 | } 1804 | .name { 1805 | color: #fff; 1806 | } 1807 | .name { 1808 | color: #fff; 1809 | } 1810 | .name { 1811 | color: #fff; 1812 | } 1813 | .name { 1814 | color: #fff; 1815 | } 1816 | .name { 1817 | color: #fff; 1818 | } 1819 | .name { 1820 | color: #fff; 1821 | } 1822 | .name { 1823 | color: #fff; 1824 | } 1825 | .name { 1826 | color: #fff; 1827 | } 1828 | .name { 1829 | color: #fff; 1830 | } 1831 | .name { 1832 | color: #fff; 1833 | } 1834 | .v10_1019 { 1835 | width: 100%; 1836 | height: 715px; 1837 | background: url("../images/v10_1019.png"); 1838 | background-repeat: no-repeat; 1839 | background-position: center center; 1840 | background-size: cover; 1841 | opacity: 1; 1842 | position: absolute; 1843 | top: 240px; 1844 | left: 144px; 1845 | overflow: hidden; 1846 | } 1847 | .v10_1020 { 1848 | width: 352px; 1849 | height: 714px; 1850 | background: url("../images/v10_1020.png"); 1851 | background-repeat: no-repeat; 1852 | background-position: center center; 1853 | background-size: cover; 1854 | opacity: 1; 1855 | position: absolute; 1856 | top: 0px; 1857 | left: 552px; 1858 | overflow: hidden; 1859 | } 1860 | .v10_1021 { 1861 | width: 352px; 1862 | height: 714px; 1863 | background: url("../images/v10_1021.png"); 1864 | background-repeat: no-repeat; 1865 | background-position: center center; 1866 | background-size: cover; 1867 | opacity: 1; 1868 | position: relative; 1869 | top: 0px; 1870 | left: 0px; 1871 | overflow: hidden; 1872 | } 1873 | .v10_1022 { 1874 | width: 352px; 1875 | color: rgba(63,61,61,1); 1876 | position: absolute; 1877 | top: 60px; 1878 | left: 0px; 1879 | font-family: Poppins; 1880 | font-weight: Medium; 1881 | font-size: 14px; 1882 | opacity: 1; 1883 | text-align: left; 1884 | } 1885 | .v10_1023 { 1886 | width: 352px; 1887 | color: rgba(63,61,61,1); 1888 | position: absolute; 1889 | top: 117px; 1890 | left: 0px; 1891 | font-family: Poppins; 1892 | font-weight: Medium; 1893 | font-size: 14px; 1894 | opacity: 1; 1895 | text-align: left; 1896 | } 1897 | .v10_1024 { 1898 | width: 352px; 1899 | color: rgba(63,61,61,1); 1900 | position: absolute; 1901 | top: 174px; 1902 | left: 0px; 1903 | font-family: Poppins; 1904 | font-weight: Medium; 1905 | font-size: 14px; 1906 | opacity: 1; 1907 | text-align: left; 1908 | } 1909 | .v10_1025 { 1910 | width: 352px; 1911 | color: rgba(63,61,61,1); 1912 | position: absolute; 1913 | top: 231px; 1914 | left: 0px; 1915 | font-family: Poppins; 1916 | font-weight: Medium; 1917 | font-size: 14px; 1918 | opacity: 1; 1919 | text-align: left; 1920 | } 1921 | .v10_1026 { 1922 | width: 352px; 1923 | color: rgba(63,61,61,1); 1924 | position: absolute; 1925 | top: 288px; 1926 | left: 0px; 1927 | font-family: Poppins; 1928 | font-weight: Medium; 1929 | font-size: 14px; 1930 | opacity: 1; 1931 | text-align: left; 1932 | } 1933 | .v10_1027 { 1934 | width: 352px; 1935 | color: rgba(63,61,61,1); 1936 | position: absolute; 1937 | top: 348px; 1938 | left: 0px; 1939 | font-family: Poppins; 1940 | font-weight: Medium; 1941 | font-size: 14px; 1942 | opacity: 1; 1943 | text-align: left; 1944 | } 1945 | .v10_1028 { 1946 | width: 352px; 1947 | color: rgba(63,61,61,1); 1948 | position: absolute; 1949 | top: 408px; 1950 | left: 0px; 1951 | font-family: Poppins; 1952 | font-weight: Medium; 1953 | font-size: 14px; 1954 | opacity: 1; 1955 | text-align: left; 1956 | } 1957 | .v10_1029 { 1958 | width: 352px; 1959 | color: rgba(63,61,61,1); 1960 | position: absolute; 1961 | top: 465px; 1962 | left: 0px; 1963 | font-family: Poppins; 1964 | font-weight: Medium; 1965 | font-size: 14px; 1966 | opacity: 1; 1967 | text-align: left; 1968 | } 1969 | .v10_1030 { 1970 | width: 352px; 1971 | color: rgba(63,61,61,1); 1972 | position: absolute; 1973 | top: 522px; 1974 | left: 0px; 1975 | font-family: Poppins; 1976 | font-weight: Medium; 1977 | font-size: 14px; 1978 | opacity: 1; 1979 | text-align: left; 1980 | } 1981 | .v10_1031 { 1982 | width: 352px; 1983 | color: rgba(63,61,61,1); 1984 | position: absolute; 1985 | top: 579px; 1986 | left: 0px; 1987 | font-family: Poppins; 1988 | font-weight: Medium; 1989 | font-size: 14px; 1990 | opacity: 1; 1991 | text-align: left; 1992 | } 1993 | .v10_1032 { 1994 | width: 352px; 1995 | color: rgba(63,61,61,1); 1996 | position: absolute; 1997 | top: 636px; 1998 | left: 0px; 1999 | font-family: Poppins; 2000 | font-weight: Medium; 2001 | font-size: 14px; 2002 | opacity: 1; 2003 | text-align: left; 2004 | } 2005 | .v10_1033 { 2006 | width: 352px; 2007 | color: rgba(63,61,61,1); 2008 | position: absolute; 2009 | top: 693px; 2010 | left: 0px; 2011 | font-family: Poppins; 2012 | font-weight: Medium; 2013 | font-size: 14px; 2014 | opacity: 1; 2015 | text-align: left; 2016 | } 2017 | .v10_1034 { 2018 | width: 46px; 2019 | color: rgba(255,255,255,1); 2020 | position: absolute; 2021 | top: 0px; 2022 | left: 153px; 2023 | font-family: Poppins; 2024 | font-weight: SemiBold; 2025 | font-size: 14px; 2026 | opacity: 1; 2027 | text-align: left; 2028 | } 2029 | .v10_1035 { 2030 | width: 65px; 2031 | height: 714px; 2032 | background: url("../images/v10_1035.png"); 2033 | background-repeat: no-repeat; 2034 | background-position: center center; 2035 | background-size: cover; 2036 | opacity: 1; 2037 | position: absolute; 2038 | top: 0px; 2039 | left: 1088px; 2040 | overflow: hidden; 2041 | } 2042 | .v10_1036 { 2043 | width: 33px; 2044 | color: rgba(0,128,0,1); 2045 | position: absolute; 2046 | top: 60px; 2047 | left: 16px; 2048 | font-family: Poppins; 2049 | font-weight: Medium; 2050 | font-size: 14px; 2051 | opacity: 1; 2052 | text-align: left; 2053 | } 2054 | .v10_1037 { 2055 | width: 25px; 2056 | color: rgba(255,0,0,1); 2057 | position: absolute; 2058 | top: 117px; 2059 | left: 20px; 2060 | font-family: Poppins; 2061 | font-weight: Medium; 2062 | font-size: 14px; 2063 | opacity: 1; 2064 | text-align: left; 2065 | } 2066 | .v10_1038 { 2067 | width: 25px; 2068 | color: rgba(255,0,0,1); 2069 | position: absolute; 2070 | top: 174px; 2071 | left: 20px; 2072 | font-family: Poppins; 2073 | font-weight: Medium; 2074 | font-size: 14px; 2075 | opacity: 1; 2076 | text-align: left; 2077 | } 2078 | .v10_1039 { 2079 | width: 25px; 2080 | color: rgba(255,0,0,1); 2081 | position: absolute; 2082 | top: 231px; 2083 | left: 20px; 2084 | font-family: Poppins; 2085 | font-weight: Medium; 2086 | font-size: 14px; 2087 | opacity: 1; 2088 | text-align: left; 2089 | } 2090 | .v10_1040 { 2091 | width: 25px; 2092 | color: rgba(255,0,0,1); 2093 | position: absolute; 2094 | top: 288px; 2095 | left: 20px; 2096 | font-family: Poppins; 2097 | font-weight: Medium; 2098 | font-size: 14px; 2099 | opacity: 1; 2100 | text-align: left; 2101 | } 2102 | .v10_1041 { 2103 | width: 25px; 2104 | color: rgba(255,0,0,1); 2105 | position: absolute; 2106 | top: 348px; 2107 | left: 20px; 2108 | font-family: Poppins; 2109 | font-weight: Medium; 2110 | font-size: 14px; 2111 | opacity: 1; 2112 | text-align: left; 2113 | } 2114 | .v10_1042 { 2115 | width: 25px; 2116 | color: rgba(255,0,0,1); 2117 | position: absolute; 2118 | top: 408px; 2119 | left: 20px; 2120 | font-family: Poppins; 2121 | font-weight: Medium; 2122 | font-size: 14px; 2123 | opacity: 1; 2124 | text-align: left; 2125 | } 2126 | .v10_1043 { 2127 | width: 25px; 2128 | color: rgba(255,0,0,1); 2129 | position: absolute; 2130 | top: 465px; 2131 | left: 20px; 2132 | font-family: Poppins; 2133 | font-weight: Medium; 2134 | font-size: 14px; 2135 | opacity: 1; 2136 | text-align: left; 2137 | } 2138 | .v10_1044 { 2139 | width: 25px; 2140 | color: rgba(255,0,0,1); 2141 | position: absolute; 2142 | top: 522px; 2143 | left: 20px; 2144 | font-family: Poppins; 2145 | font-weight: Medium; 2146 | font-size: 14px; 2147 | opacity: 1; 2148 | text-align: left; 2149 | } 2150 | .v10_1045 { 2151 | width: 25px; 2152 | color: rgba(255,0,0,1); 2153 | position: absolute; 2154 | top: 579px; 2155 | left: 20px; 2156 | font-family: Poppins; 2157 | font-weight: Medium; 2158 | font-size: 14px; 2159 | opacity: 1; 2160 | text-align: left; 2161 | } 2162 | .v10_1046 { 2163 | width: 25px; 2164 | color: rgba(255,0,0,1); 2165 | position: absolute; 2166 | top: 636px; 2167 | left: 20px; 2168 | font-family: Poppins; 2169 | font-weight: Medium; 2170 | font-size: 14px; 2171 | opacity: 1; 2172 | text-align: left; 2173 | } 2174 | .v10_1047 { 2175 | width: 25px; 2176 | color: rgba(255,0,0,1); 2177 | position: absolute; 2178 | top: 693px; 2179 | left: 20px; 2180 | font-family: Poppins; 2181 | font-weight: Medium; 2182 | font-size: 14px; 2183 | opacity: 1; 2184 | text-align: left; 2185 | } 2186 | .v10_1048 { 2187 | width: 65px; 2188 | color: rgba(255,255,255,1); 2189 | position: relative; 2190 | top: 0px; 2191 | left: 0px; 2192 | font-family: Poppins; 2193 | font-weight: SemiBold; 2194 | font-size: 14px; 2195 | opacity: 1; 2196 | text-align: left; 2197 | } 2198 | .v10_1049 { 2199 | width: 34px; 2200 | height: 715px; 2201 | background: url("../images/v10_1049.png"); 2202 | background-repeat: no-repeat; 2203 | background-position: center center; 2204 | background-size: cover; 2205 | opacity: 1; 2206 | position: absolute; 2207 | top: 0px; 2208 | left: 334px; 2209 | overflow: hidden; 2210 | } 2211 | .v10_1050 { 2212 | width: 33px; 2213 | color: rgba(0,128,0,1); 2214 | position: absolute; 2215 | top: 60px; 2216 | left: 0px; 2217 | font-family: Poppins; 2218 | font-weight: Medium; 2219 | font-size: 14px; 2220 | opacity: 1; 2221 | text-align: left; 2222 | } 2223 | .v10_1051 { 2224 | width: 15px; 2225 | color: rgba(255,0,0,1); 2226 | position: absolute; 2227 | top: 116px; 2228 | left: 0px; 2229 | font-family: Poppins; 2230 | font-weight: Bold; 2231 | font-size: 15px; 2232 | opacity: 1; 2233 | text-align: left; 2234 | } 2235 | .v10_1052 { 2236 | width: 15px; 2237 | color: rgba(255,0,0,1); 2238 | position: absolute; 2239 | top: 173px; 2240 | left: 0px; 2241 | font-family: Poppins; 2242 | font-weight: Bold; 2243 | font-size: 15px; 2244 | opacity: 1; 2245 | text-align: left; 2246 | } 2247 | .v10_1053 { 2248 | width: 15px; 2249 | color: rgba(255,0,0,1); 2250 | position: absolute; 2251 | top: 230px; 2252 | left: 0px; 2253 | font-family: Poppins; 2254 | font-weight: Bold; 2255 | font-size: 15px; 2256 | opacity: 1; 2257 | text-align: left; 2258 | } 2259 | .v10_1054 { 2260 | width: 15px; 2261 | color: rgba(255,0,0,1); 2262 | position: absolute; 2263 | top: 287px; 2264 | left: 0px; 2265 | font-family: Poppins; 2266 | font-weight: Bold; 2267 | font-size: 15px; 2268 | opacity: 1; 2269 | text-align: left; 2270 | } 2271 | .v10_1055 { 2272 | width: 15px; 2273 | color: rgba(255,0,0,1); 2274 | position: absolute; 2275 | top: 347px; 2276 | left: 0px; 2277 | font-family: Poppins; 2278 | font-weight: Bold; 2279 | font-size: 15px; 2280 | opacity: 1; 2281 | text-align: left; 2282 | } 2283 | .v10_1056 { 2284 | width: 15px; 2285 | color: rgba(255,0,0,1); 2286 | position: absolute; 2287 | top: 407px; 2288 | left: 0px; 2289 | font-family: Poppins; 2290 | font-weight: Bold; 2291 | font-size: 15px; 2292 | opacity: 1; 2293 | text-align: left; 2294 | } 2295 | .v10_1057 { 2296 | width: 15px; 2297 | color: rgba(255,0,0,1); 2298 | position: absolute; 2299 | top: 464px; 2300 | left: 0px; 2301 | font-family: Poppins; 2302 | font-weight: Bold; 2303 | font-size: 15px; 2304 | opacity: 1; 2305 | text-align: left; 2306 | } 2307 | .v10_1058 { 2308 | width: 15px; 2309 | color: rgba(255,0,0,1); 2310 | position: absolute; 2311 | top: 521px; 2312 | left: 0px; 2313 | font-family: Poppins; 2314 | font-weight: Bold; 2315 | font-size: 15px; 2316 | opacity: 1; 2317 | text-align: left; 2318 | } 2319 | .v10_1059 { 2320 | width: 15px; 2321 | color: rgba(255,0,0,1); 2322 | position: absolute; 2323 | top: 578px; 2324 | left: 0px; 2325 | font-family: Poppins; 2326 | font-weight: Bold; 2327 | font-size: 15px; 2328 | opacity: 1; 2329 | text-align: left; 2330 | } 2331 | .v10_1060 { 2332 | width: 15px; 2333 | color: rgba(255,0,0,1); 2334 | position: absolute; 2335 | top: 635px; 2336 | left: 0px; 2337 | font-family: Poppins; 2338 | font-weight: Bold; 2339 | font-size: 15px; 2340 | opacity: 1; 2341 | text-align: left; 2342 | } 2343 | .v10_1061 { 2344 | width: 15px; 2345 | color: rgba(255,0,0,1); 2346 | position: absolute; 2347 | top: 692px; 2348 | left: 0px; 2349 | font-family: Poppins; 2350 | font-weight: Bold; 2351 | font-size: 15px; 2352 | opacity: 1; 2353 | text-align: left; 2354 | } 2355 | .v10_1062 { 2356 | width: 34px; 2357 | color: rgba(255,255,255,1); 2358 | position: relative; 2359 | top: 0px; 2360 | left: 0px; 2361 | font-family: Poppins; 2362 | font-weight: SemiBold; 2363 | font-size: 14px; 2364 | opacity: 1; 2365 | text-align: left; 2366 | } 2367 | .v10_1063 { 2368 | width: 146px; 2369 | height: 714px; 2370 | background: url("../images/v10_1063.png"); 2371 | background-repeat: no-repeat; 2372 | background-position: center center; 2373 | background-size: cover; 2374 | opacity: 1; 2375 | position: relative; 2376 | top: 0px; 2377 | left: 0px; 2378 | overflow: hidden; 2379 | } 2380 | .v10_1064 { 2381 | width: 146px; 2382 | color: rgba(56,53,53,1); 2383 | position: absolute; 2384 | top: 60px; 2385 | left: 0px; 2386 | font-family: Poppins; 2387 | font-weight: Medium; 2388 | font-size: 14px; 2389 | opacity: 1; 2390 | text-align: left; 2391 | } 2392 | .v10_1065 { 2393 | width: 146px; 2394 | color: rgba(56,53,53,1); 2395 | position: absolute; 2396 | top: 117px; 2397 | left: 0px; 2398 | font-family: Poppins; 2399 | font-weight: Medium; 2400 | font-size: 14px; 2401 | opacity: 1; 2402 | text-align: left; 2403 | } 2404 | .v10_1066 { 2405 | width: 146px; 2406 | color: rgba(56,53,53,1); 2407 | position: absolute; 2408 | top: 174px; 2409 | left: 0px; 2410 | font-family: Poppins; 2411 | font-weight: Medium; 2412 | font-size: 14px; 2413 | opacity: 1; 2414 | text-align: left; 2415 | } 2416 | .v10_1067 { 2417 | width: 146px; 2418 | color: rgba(56,53,53,1); 2419 | position: absolute; 2420 | top: 231px; 2421 | left: 0px; 2422 | font-family: Poppins; 2423 | font-weight: Medium; 2424 | font-size: 14px; 2425 | opacity: 1; 2426 | text-align: left; 2427 | } 2428 | .v10_1068 { 2429 | width: 146px; 2430 | color: rgba(56,53,53,1); 2431 | position: absolute; 2432 | top: 288px; 2433 | left: 0px; 2434 | font-family: Poppins; 2435 | font-weight: Medium; 2436 | font-size: 14px; 2437 | opacity: 1; 2438 | text-align: left; 2439 | } 2440 | .v10_1069 { 2441 | width: 146px; 2442 | color: rgba(56,53,53,1); 2443 | position: absolute; 2444 | top: 348px; 2445 | left: 0px; 2446 | font-family: Poppins; 2447 | font-weight: Medium; 2448 | font-size: 14px; 2449 | opacity: 1; 2450 | text-align: left; 2451 | } 2452 | .v10_1070 { 2453 | width: 146px; 2454 | color: rgba(56,53,53,1); 2455 | position: absolute; 2456 | top: 408px; 2457 | left: 0px; 2458 | font-family: Poppins; 2459 | font-weight: Medium; 2460 | font-size: 14px; 2461 | opacity: 1; 2462 | text-align: left; 2463 | } 2464 | .v10_1071 { 2465 | width: 146px; 2466 | color: rgba(56,53,53,1); 2467 | position: absolute; 2468 | top: 465px; 2469 | left: 0px; 2470 | font-family: Poppins; 2471 | font-weight: Medium; 2472 | font-size: 14px; 2473 | opacity: 1; 2474 | text-align: left; 2475 | } 2476 | .v10_1072 { 2477 | width: 146px; 2478 | color: rgba(56,53,53,1); 2479 | position: absolute; 2480 | top: 522px; 2481 | left: 0px; 2482 | font-family: Poppins; 2483 | font-weight: Medium; 2484 | font-size: 14px; 2485 | opacity: 1; 2486 | text-align: left; 2487 | } 2488 | .v10_1073 { 2489 | width: 146px; 2490 | color: rgba(56,53,53,1); 2491 | position: absolute; 2492 | top: 579px; 2493 | left: 0px; 2494 | font-family: Poppins; 2495 | font-weight: Medium; 2496 | font-size: 14px; 2497 | opacity: 1; 2498 | text-align: left; 2499 | } 2500 | .v10_1074 { 2501 | width: 146px; 2502 | color: rgba(56,53,53,1); 2503 | position: absolute; 2504 | top: 636px; 2505 | left: 0px; 2506 | font-family: Poppins; 2507 | font-weight: Medium; 2508 | font-size: 14px; 2509 | opacity: 1; 2510 | text-align: left; 2511 | } 2512 | .v10_1075 { 2513 | width: 146px; 2514 | color: rgba(56,53,53,1); 2515 | position: absolute; 2516 | top: 693px; 2517 | left: 0px; 2518 | font-family: Poppins; 2519 | font-weight: Medium; 2520 | font-size: 14px; 2521 | opacity: 1; 2522 | text-align: left; 2523 | } 2524 | .v10_1076 { 2525 | width: 81px; 2526 | color: rgba(255,255,255,1); 2527 | position: relative; 2528 | top: 0px; 2529 | left: 0px; 2530 | font-family: Poppins; 2531 | font-weight: SemiBold; 2532 | font-size: 14px; 2533 | opacity: 1; 2534 | text-align: left; 2535 | } 2536 | .v10_1077 { 2537 | width: 393px; 2538 | height: 90px; 2539 | background: url("../images/v10_1077.png"); 2540 | background-repeat: no-repeat; 2541 | background-position: center center; 2542 | background-size: cover; 2543 | opacity: 1; 2544 | position: absolute; 2545 | top: 97px; 2546 | left: 104px; 2547 | overflow: hidden; 2548 | } 2549 | .v10_1078 { 2550 | width: 393px; 2551 | color: rgba(30,38,54,1); 2552 | position: relative; 2553 | top: 0px; 2554 | left: 0px; 2555 | font-family: Poppins; 2556 | font-weight: Bold; 2557 | font-size: 26px; 2558 | opacity: 1; 2559 | text-align: left; 2560 | } 2561 | .v10_1079 { 2562 | width: 241px; 2563 | height: 36px; 2564 | background: url("../images/v10_1079.png"); 2565 | background-repeat: no-repeat; 2566 | background-position: center center; 2567 | background-size: cover; 2568 | opacity: 1; 2569 | position: absolute; 2570 | top: 54px; 2571 | left: 0px; 2572 | overflow: hidden; 2573 | } 2574 | .v10_1080 { 2575 | width: 136px; 2576 | color: rgba(76,96,135,1); 2577 | position: relative; 2578 | top: 0px; 2579 | left: 0px; 2580 | font-family: Poppins; 2581 | font-weight: Medium; 2582 | font-size: 24px; 2583 | opacity: 1; 2584 | text-align: left; 2585 | } 2586 | .v10_1081 { 2587 | width: 97px; 2588 | color: rgba(76,96,135,1); 2589 | position: absolute; 2590 | top: 0px; 2591 | left: 143px; 2592 | font-family: Poppins; 2593 | font-weight: Medium; 2594 | font-size: 24px; 2595 | opacity: 1; 2596 | text-align: left; 2597 | } 2598 | --------------------------------------------------------------------------------