mirror of https://github.com/01-edu/public.git
Christopher Fremond
5 years ago
committed by
GitHub
374 changed files with 3754 additions and 901 deletions
@ -0,0 +1,119 @@ |
|||||||
|
## rc (restrictions checker) |
||||||
|
|
||||||
|
This program analyses a go source file and displays in standard output the imports, functions, array types and loops used without authorization. |
||||||
|
|
||||||
|
### By default: |
||||||
|
|
||||||
|
- NO imports and NO built-in functions are allowed. |
||||||
|
- NO casting is allowed either. |
||||||
|
- Only functions declared inside the source file are allowed. |
||||||
|
- All array types are allowed |
||||||
|
- Loops are allowed |
||||||
|
|
||||||
|
### Flags |
||||||
|
|
||||||
|
- Two flags are defined: |
||||||
|
- `--cast` allows casting to every built-in type. |
||||||
|
- `--no-for` prohibits the use of `for` loops in the program or function. |
||||||
|
- `--no-array`: |
||||||
|
- Prohibits all array types if no types are specified after the flag. |
||||||
|
Ex. |
||||||
|
```console |
||||||
|
_$ ./rc main.go fmt.* github.com/01-edu/z01.PrintRune len --no-array |
||||||
|
``` |
||||||
|
All array type in main.go will cause an error message. |
||||||
|
- Prohibits only the types specified after the flag |
||||||
|
Ex. |
||||||
|
```console |
||||||
|
_$ ./rc main.go fmt.* github.com/01-edu/z01.PrintRune len --no-array rune string |
||||||
|
``` |
||||||
|
Only array from the type rune and string are prohibit. All other array from built-in types are allowed |
||||||
|
|
||||||
|
### Arguments: |
||||||
|
|
||||||
|
- First Argument: |
||||||
|
|
||||||
|
The program must be executed passing the go source file to be analyze as the first argument |
||||||
|
|
||||||
|
- The remaining argument (from 2 to ...): |
||||||
|
|
||||||
|
Can be (without any particular order): |
||||||
|
|
||||||
|
- Allowed imports and functions from a package |
||||||
|
- `<package>.*` for full imports (all functions from that package are allowed) |
||||||
|
- `<package>`.`<function>` for partial imports (only the function is allowed) |
||||||
|
- `<package>`.`<function>#amout` for certain amounts (only certain amount os a function is allowed) |
||||||
|
- Ex: `fmt.*` (all functions from `fmt` are allowed), `github.com/01-edu/z01.PrintRune` (only `z01.PrintRune` is allowed), `append#2` (the only amount of `append`'s allowed is 2) |
||||||
|
- Allowed built-in functions |
||||||
|
- Use the name of the built-in function |
||||||
|
- Ex: `make`, `append`, `len`. |
||||||
|
- Allowed casting |
||||||
|
- by using the type of casting, ex: for allowing `string` casting, use `string` |
||||||
|
- Or use the flag `--cast`, to allow every type of casting |
||||||
|
|
||||||
|
- Import relative packages |
||||||
|
- Use the relative path |
||||||
|
- Ex: `../piscine`, `..`, `.` |
||||||
|
|
||||||
|
- Unallow for loops |
||||||
|
- Use the flags `--no-for`. |
||||||
|
- Note: remember to use it before the `--no-array` flag. |
||||||
|
- ex: |
||||||
|
```console |
||||||
|
_$ ./rc main.go fmt.* github.com/01-edu/z01.PrintRune len --no-array <...> --no-for |
||||||
|
``` |
||||||
|
the last line produces undesired behaviors. |
||||||
|
- Unallow literals |
||||||
|
- Use the flag `--no-lit="{PATTERN}"` |
||||||
|
- Note: `"{PATTERN}"` must be a valid RegExp. |
||||||
|
- ex: |
||||||
|
```console |
||||||
|
_$ ./rc main.go fmt.* github.com/01-edu/z01.PrintRune len --no-array --no-lit=[b-yB-Y] |
||||||
|
``` |
||||||
|
- Optional lasts arguments |
||||||
|
- The flag `--no-array` must be given as the last argument or to signal that all the arguments after are unallowed array types |
||||||
|
### Usage: |
||||||
|
|
||||||
|
- To allow the import of the whole `fmt` package, `z01.PrintRune` and the built-in functions len in the file `main.go` |
||||||
|
|
||||||
|
The imports must be writen exactly the way are writen inside the source code, example: |
||||||
|
|
||||||
|
```console |
||||||
|
_$ ./rc main.go fmt.* github.com/01-edu/z01.PrintRune len |
||||||
|
``` |
||||||
|
- More examples: |
||||||
|
|
||||||
|
- import "fmt" is allowed by executing |
||||||
|
```console |
||||||
|
_$ ./rc sourcefile.go fmt.* |
||||||
|
``` |
||||||
|
|
||||||
|
- import "go/parser" is allowed by executing |
||||||
|
```console |
||||||
|
_$ ./rc sourcefile.go go/parser.* |
||||||
|
``` |
||||||
|
|
||||||
|
- import "github.com/01-edu/z01" is allowed by executing |
||||||
|
```console |
||||||
|
./rc sourcefile.go github.com/01-edu/z01.* |
||||||
|
``` |
||||||
|
|
||||||
|
- import "../../../all/tests/go/solutions" is allowed by executing |
||||||
|
```console |
||||||
|
_$ ./rc sourcefile.go ../../../all/tests/go/solutions |
||||||
|
``` |
||||||
|
(no `.*` is needed, all the functions from this relative package are allowed) |
||||||
|
|
||||||
|
- allow all type of casting |
||||||
|
|
||||||
|
```console |
||||||
|
_$ ./rc sourcefile.go ../../../all/tests/go/solutions/ztail/ztail.go fmt.* github.com/01-edu/z01 os.* strconv.* make len append --cast |
||||||
|
``` |
||||||
|
- this will allow all type of casting in the file ztail.go |
||||||
|
|
||||||
|
- to allow just one type of casting |
||||||
|
|
||||||
|
```console |
||||||
|
_$ ./rc sourcefile.go ../../../all/tests/go/solutions/ztail/ztail.go fmt.* github.com/01-edu/z01 os.* strconv.* make len append rune |
||||||
|
``` |
||||||
|
- this will allow `rune`, but not `int8`, ..., `string`, `float32`, ... |
@ -0,0 +1,754 @@ |
|||||||
|
package main |
||||||
|
|
||||||
|
import ( |
||||||
|
"fmt" |
||||||
|
"go/ast" |
||||||
|
"go/parser" |
||||||
|
"go/token" |
||||||
|
"log" |
||||||
|
"os" |
||||||
|
"regexp" |
||||||
|
"strconv" |
||||||
|
"strings" |
||||||
|
) |
||||||
|
|
||||||
|
const ( |
||||||
|
identation = " " |
||||||
|
) |
||||||
|
|
||||||
|
var ( |
||||||
|
allowedImp map[string]map[string]bool // Map of the allowed imports
|
||||||
|
allowedFun map[string]bool // Map of the allowed built-in functions
|
||||||
|
// Is necessary an array to keep all the call instances.
|
||||||
|
callX []nodePos // Keeps the name of the called functions and the position in the file.
|
||||||
|
// A map is enough for function declarations because they are unique.
|
||||||
|
funcDeclPkg map[string]*funcBody // Keeps the name of the function associated to its body and its position in the file.
|
||||||
|
allArrayTypes = true |
||||||
|
arraysInstances []nodePos |
||||||
|
forStmts []nodePos |
||||||
|
basicLits []nodePos |
||||||
|
illegals []illegal |
||||||
|
notAllowedArrayT []string |
||||||
|
predeclaredTypes = []string{"bool", "byte", "complex64", "complex128", |
||||||
|
"error", "float32", "float64", "int", "int8", |
||||||
|
"int16", "int32", "int64", "rune", "string", |
||||||
|
"uint", "uint8", "uint16", "uint32", "uint64", |
||||||
|
"uintptr", |
||||||
|
} |
||||||
|
relativeImports []string |
||||||
|
importPkg map[string]*pkgFunc |
||||||
|
pkgName []string |
||||||
|
allImports map[string]bool |
||||||
|
openImports []string |
||||||
|
funcOccurrences map[string]int |
||||||
|
) |
||||||
|
|
||||||
|
//pkgFunc for all the functions of a given package
|
||||||
|
type pkgFunc struct { |
||||||
|
functions []string |
||||||
|
path string |
||||||
|
} |
||||||
|
|
||||||
|
type funcImp struct { |
||||||
|
pkg, fun string |
||||||
|
pos token.Pos |
||||||
|
} |
||||||
|
|
||||||
|
// All visitors
|
||||||
|
type callVisitor struct { |
||||||
|
Calls []string |
||||||
|
Fset *token.FileSet |
||||||
|
} |
||||||
|
|
||||||
|
type fileVisitor struct { |
||||||
|
funcDecl []string |
||||||
|
funcCalls []string |
||||||
|
selectExpr []string |
||||||
|
arrayType []nodePos |
||||||
|
Fset *token.FileSet |
||||||
|
} |
||||||
|
|
||||||
|
type pkgVisitor struct { |
||||||
|
Fset *token.FileSet |
||||||
|
} |
||||||
|
|
||||||
|
type impVisitor struct { |
||||||
|
Fset *token.FileSet |
||||||
|
relativeImports []string |
||||||
|
} |
||||||
|
|
||||||
|
// Get the position of the node in the file
|
||||||
|
type locate interface { |
||||||
|
getPos(ast.Node) string |
||||||
|
} |
||||||
|
|
||||||
|
func (i *impVisitor) getPos(n ast.Node) string { |
||||||
|
return i.Fset.Position(n.Pos()).String() |
||||||
|
} |
||||||
|
|
||||||
|
func (fv *fileVisitor) getPos(n ast.Node) string { |
||||||
|
return fv.Fset.Position(n.Pos()).String() |
||||||
|
} |
||||||
|
|
||||||
|
func (p *pkgVisitor) getPos(n ast.Node) string { |
||||||
|
return p.Fset.Position(n.Pos()).String() |
||||||
|
} |
||||||
|
func (c *callVisitor) getPos(n ast.Node) string { |
||||||
|
return c.Fset.Position(n.Pos()).String() |
||||||
|
} |
||||||
|
|
||||||
|
type illegal struct { |
||||||
|
T string |
||||||
|
Name string |
||||||
|
Pos string |
||||||
|
} |
||||||
|
|
||||||
|
func (i *illegal) String() string { |
||||||
|
return i.T + " " + i.Name + " " + i.Pos |
||||||
|
} |
||||||
|
|
||||||
|
func getPkgFunc(path string, fsetPkg *token.FileSet) { |
||||||
|
i := &impVisitor{Fset: fsetPkg} |
||||||
|
p := &pkgVisitor{Fset: fsetPkg} |
||||||
|
pkgs, err := parser.ParseDir(fsetPkg, path, nil, parser.AllErrors) |
||||||
|
|
||||||
|
if err != nil { |
||||||
|
fmt.Println(err.Error()) |
||||||
|
os.Exit(1) |
||||||
|
} |
||||||
|
|
||||||
|
for pkgname := range pkgs { |
||||||
|
pkg, _ := ast.NewPackage(fsetPkg, pkgs[pkgname].Files, nil, nil) |
||||||
|
pkgName = append(pkgName, pkgname) |
||||||
|
|
||||||
|
ast.Walk(i, pkg) |
||||||
|
ast.Walk(p, pkg) |
||||||
|
|
||||||
|
for _, v := range i.relativeImports { |
||||||
|
if isIn(v, openImports) { |
||||||
|
break |
||||||
|
} |
||||||
|
openImports = append(openImports, v) |
||||||
|
getPkgFunc(path+"/"+v, fsetPkg) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
//reformat from the data base
|
||||||
|
func splitArgs(args string) []string { |
||||||
|
result := strings.Split(args, " ") |
||||||
|
return result |
||||||
|
} |
||||||
|
|
||||||
|
func rightFile(args string) string { |
||||||
|
expectedFiles := splitArgs(args) |
||||||
|
|
||||||
|
for _, s := range expectedFiles { |
||||||
|
if strings.Contains(s, ".go") { |
||||||
|
return s |
||||||
|
} |
||||||
|
} |
||||||
|
return "" |
||||||
|
} |
||||||
|
|
||||||
|
func allowCastingAndImp(allowedImports []string) { |
||||||
|
casted := false |
||||||
|
for i, v := range allowedImports { |
||||||
|
casted = allow(v, casted) |
||||||
|
if v == "--no-array" { |
||||||
|
allArrayTypes = false |
||||||
|
notAllowedArrayT = append(notAllowedArrayT, allowedImports[i+1:]...) |
||||||
|
break |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
type flags struct { |
||||||
|
l struct { // flag for char or string literal
|
||||||
|
noLit bool // true -> unallows
|
||||||
|
pattern string // this pattern
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// TODO: treat all the flags in this function
|
||||||
|
// For now, only --no-lit="{PATTERN}"
|
||||||
|
func parseFlags(args []string) *flags { |
||||||
|
f := &flags{} |
||||||
|
for _, v := range args { |
||||||
|
var flag []string |
||||||
|
if strings.Contains(v, "=") { |
||||||
|
flag = strings.Split(v, "=") |
||||||
|
} |
||||||
|
if flag == nil { |
||||||
|
continue |
||||||
|
} |
||||||
|
if flag[0] == "--no-lit" { |
||||||
|
f.l.noLit = true |
||||||
|
f.l.pattern = flag[1] |
||||||
|
} |
||||||
|
} |
||||||
|
return f |
||||||
|
} |
||||||
|
|
||||||
|
func removeAmount(s string) string { |
||||||
|
strRm := strings.TrimFunc(s, func(c rune) bool { |
||||||
|
return c >= '0' && c <= '9' || c == '#' |
||||||
|
}) |
||||||
|
return strRm |
||||||
|
} |
||||||
|
|
||||||
|
//compares if the function is used a certain amount of times allowed
|
||||||
|
func allowedAmount(occurrences map[string]int, allowedImports []string) { |
||||||
|
function := "" |
||||||
|
funcSelector := "" |
||||||
|
for _, v := range allowedImports { |
||||||
|
//pkg in case it's a build in function and slice in case it's a selector function
|
||||||
|
pkg, slice := trimRelativeImport(v) |
||||||
|
if slice != nil { |
||||||
|
function = strings.Join(slice, ".") |
||||||
|
funcSelector = removeAmount(function) |
||||||
|
} else { |
||||||
|
function = pkg |
||||||
|
funcSelector = removeAmount(pkg) |
||||||
|
} |
||||||
|
if strings.ContainsAny(function, "#") { |
||||||
|
strNbr := strings.TrimPrefix(function, funcSelector+"#") |
||||||
|
nbr, err := strconv.Atoi(strNbr) |
||||||
|
if err != nil { |
||||||
|
log.Panic(err) |
||||||
|
} |
||||||
|
if occurrences[funcSelector] > nbr { |
||||||
|
illegals = append(illegals, illegal{ |
||||||
|
T: "illegal-amount", |
||||||
|
Name: funcSelector + " allowed count " + strNbr + " your count " + strconv.Itoa(occurrences[funcSelector]), |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func main() { |
||||||
|
if len(os.Args) < 2 { |
||||||
|
fmt.Println("No file or directory") |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
var allowedImports []string |
||||||
|
|
||||||
|
if len(os.Args) > 2 { |
||||||
|
allowedImports = splitArgs(os.Args[2]) |
||||||
|
} |
||||||
|
|
||||||
|
allowCastingAndImp(allowedImports) |
||||||
|
flag := parseFlags(allowedImports) |
||||||
|
|
||||||
|
filename := strings.TrimSpace(rightFile(os.Args[1])) |
||||||
|
split := strings.Split(filename, "/") |
||||||
|
path := strings.Join(split[:len(split)-1], "/") |
||||||
|
|
||||||
|
if path == "" { |
||||||
|
path = "." |
||||||
|
} |
||||||
|
|
||||||
|
fsetFile := token.NewFileSet() |
||||||
|
fsetPkg := token.NewFileSet() |
||||||
|
|
||||||
|
fmt.Println("Parsing") |
||||||
|
file, err := parser.ParseFile(fsetFile, filename, nil, parser.AllErrors) |
||||||
|
|
||||||
|
if err != nil { |
||||||
|
fmt.Println(err.Error()) |
||||||
|
os.Exit(1) |
||||||
|
} |
||||||
|
|
||||||
|
// Get all the name of all functions declared in the file
|
||||||
|
w := &fileVisitor{Fset: fsetFile} |
||||||
|
ast.Walk(w, file) |
||||||
|
getPkgFunc(path, fsetPkg) |
||||||
|
|
||||||
|
for _, v := range w.funcDecl { |
||||||
|
isFuncAllowed(v, fsetPkg) |
||||||
|
} |
||||||
|
|
||||||
|
// TODO: Parsing the arguments for the --max-occurrences flag
|
||||||
|
allowedAmount(funcOccurrences, allowedImports) |
||||||
|
|
||||||
|
if flag != nil { |
||||||
|
flag.unallowLits() |
||||||
|
} |
||||||
|
|
||||||
|
analyzeArrayT() |
||||||
|
analyzeForStmt(allowedImports) |
||||||
|
|
||||||
|
fmt.Println(identation + "OK") |
||||||
|
|
||||||
|
fmt.Println("Cheating") |
||||||
|
|
||||||
|
if len(illegals) > 0 { |
||||||
|
for _, i := range illegals { |
||||||
|
fmt.Println(identation + i.String()) |
||||||
|
} |
||||||
|
os.Exit(1) |
||||||
|
} else { |
||||||
|
fmt.Println(identation + "OK") |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func (f flags) unallowLits() { |
||||||
|
if f.l.noLit { |
||||||
|
for _, v := range basicLits { |
||||||
|
if !f.isLitAllowed(v.name) { |
||||||
|
illegals = append(illegals, illegal{ |
||||||
|
T: "illegal-literal", |
||||||
|
Name: v.name, |
||||||
|
Pos: v.position, |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func (f flags) isLitAllowed(s string) bool { |
||||||
|
matched, err := regexp.Match(f.l.pattern, []byte(s)) |
||||||
|
|
||||||
|
if err != nil { |
||||||
|
return true |
||||||
|
} |
||||||
|
|
||||||
|
return !matched |
||||||
|
} |
||||||
|
|
||||||
|
func analyzeForStmt(args []string) { |
||||||
|
if isIn("--no-for", args) { |
||||||
|
for _, v := range forStmts { |
||||||
|
illegals = append(illegals, illegal{ |
||||||
|
T: "illegal-loop", |
||||||
|
Name: v.name, |
||||||
|
Pos: v.position, |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func analyzeArrayT() { |
||||||
|
if !allArrayTypes { |
||||||
|
l := len(notAllowedArrayT) |
||||||
|
for _, v := range arraysInstances { |
||||||
|
if l == 0 || |
||||||
|
isIn(v.name, notAllowedArrayT) { |
||||||
|
illegals = append(illegals, illegal{ |
||||||
|
T: "illegal-array-type", |
||||||
|
Name: v.name, |
||||||
|
Pos: v.position, |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func allow(s string, casted bool) bool { |
||||||
|
if strings.ContainsRune(s, '.') { |
||||||
|
allowImport(s) |
||||||
|
} else { |
||||||
|
if allowedFun == nil { |
||||||
|
allowedFun = make(map[string]bool) |
||||||
|
} |
||||||
|
if strings.ContainsAny(s, "#") { |
||||||
|
s = removeAmount(s) |
||||||
|
} |
||||||
|
allowedFun[s] = true |
||||||
|
} |
||||||
|
|
||||||
|
if s == "--cast" && !casted { |
||||||
|
for _, v := range predeclaredTypes { |
||||||
|
allow(v, false) |
||||||
|
} |
||||||
|
return true |
||||||
|
} |
||||||
|
return casted |
||||||
|
} |
||||||
|
|
||||||
|
// Returns true if the string matches the format of a relative import
|
||||||
|
func isRelativeImport(s string) bool { |
||||||
|
relativeImport, _ := regexp.MatchString(`\.\.\\??`, s) |
||||||
|
return relativeImport |
||||||
|
} |
||||||
|
|
||||||
|
// Returns true if the string represents an import package
|
||||||
|
// i.e and expresion like <lib>.<function>
|
||||||
|
func isImport(s string) bool { |
||||||
|
matched, _ := regexp.MatchString(`.\..`, s) |
||||||
|
return matched |
||||||
|
} |
||||||
|
|
||||||
|
func trimRelativeImport(str string) (string, []string) { |
||||||
|
var pkg string |
||||||
|
var slice []string |
||||||
|
if isImport(str) && !isRelativeImport(str) { |
||||||
|
splited := strings.Split(str, "/") |
||||||
|
slice = strings.Split(splited[len(splited)-1], ".") |
||||||
|
splited[len(splited)-1] = slice[0] |
||||||
|
pkg = strings.Join(splited, "/") |
||||||
|
|
||||||
|
if allowedImp[slice[0]] == nil { |
||||||
|
allowedImp[slice[0]] = make(map[string]bool) |
||||||
|
} |
||||||
|
fn := slice[len(slice)-1] |
||||||
|
allowedImp[slice[0]][fn] = true |
||||||
|
} else { |
||||||
|
pkg = str |
||||||
|
} |
||||||
|
return pkg, slice |
||||||
|
} |
||||||
|
|
||||||
|
func allowImport(s string) { |
||||||
|
if allowedImp == nil { |
||||||
|
allowedImp = make(map[string]map[string]bool) |
||||||
|
} |
||||||
|
if allImports == nil { |
||||||
|
allImports = make(map[string]bool) |
||||||
|
} |
||||||
|
|
||||||
|
pkg, slice := trimRelativeImport(s) |
||||||
|
|
||||||
|
allImports[pkg] = true |
||||||
|
|
||||||
|
fn := "*" |
||||||
|
if len(slice) > 1 { |
||||||
|
fn = removeAmount(slice[1]) |
||||||
|
} |
||||||
|
|
||||||
|
if allowedImp[pkg] == nil { |
||||||
|
allowedImp[pkg] = make(map[string]bool) |
||||||
|
} |
||||||
|
allowedImp[pkg][fn] = true |
||||||
|
} |
||||||
|
|
||||||
|
func addToIllegals(funcname string) { |
||||||
|
for _, v := range callX { |
||||||
|
if v.name == funcname { |
||||||
|
pos := v.position |
||||||
|
setIllegal("illegal-call", v.name, pos) |
||||||
|
} |
||||||
|
} |
||||||
|
if funcDeclPkg[funcname] != nil { |
||||||
|
pos := funcDeclPkg[funcname].position |
||||||
|
setIllegal("illegal-call", funcname, pos) |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// First ignoring the imported functions
|
||||||
|
func isFuncAllowed(funcname string, fset *token.FileSet) bool { |
||||||
|
if allowedFun[funcname] { |
||||||
|
return true |
||||||
|
} |
||||||
|
|
||||||
|
if !isFuncDeclIn(funcname, funcDeclPkg) { |
||||||
|
addToIllegals(funcname) |
||||||
|
return false |
||||||
|
} |
||||||
|
bodyf := funcDeclPkg[funcname].body |
||||||
|
|
||||||
|
if bodyf == nil { |
||||||
|
addToIllegals(funcname) |
||||||
|
fmt.Println("Body is nil") |
||||||
|
return false |
||||||
|
} |
||||||
|
c := &callVisitor{Fset: fset} |
||||||
|
ast.Walk(c, bodyf) |
||||||
|
|
||||||
|
res := true |
||||||
|
|
||||||
|
for _, v := range c.Calls { |
||||||
|
if v == funcname { |
||||||
|
continue |
||||||
|
} |
||||||
|
allowed := isFuncAllowed(v, fset) |
||||||
|
if !allowed { |
||||||
|
addToIllegals(funcname) |
||||||
|
for _, v := range c.Calls { |
||||||
|
if v == funcname { |
||||||
|
continue |
||||||
|
} |
||||||
|
allowed := isFuncAllowed(v, fset) |
||||||
|
if !allowed { |
||||||
|
addToIllegals(funcname) |
||||||
|
} |
||||||
|
res = res && allowed |
||||||
|
} |
||||||
|
} |
||||||
|
res = res && allowed |
||||||
|
} |
||||||
|
return res |
||||||
|
} |
||||||
|
|
||||||
|
func isFuncDeclIn(funcname string, fundecl map[string]*funcBody) bool { |
||||||
|
return fundecl[funcname] != nil |
||||||
|
} |
||||||
|
|
||||||
|
func isFuncCallIn(funcname string, funP []nodePos) bool { |
||||||
|
for _, v := range funP { |
||||||
|
if v.name == funcname { |
||||||
|
return true |
||||||
|
} |
||||||
|
} |
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
func isIn(s string, slc []string) bool { |
||||||
|
for _, v := range slc { |
||||||
|
if s == v { |
||||||
|
return true |
||||||
|
} |
||||||
|
} |
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
// Keeps the positions of each function call and declaration
|
||||||
|
type funcBody struct { |
||||||
|
position string |
||||||
|
body *ast.BlockStmt |
||||||
|
} |
||||||
|
|
||||||
|
type nodePos struct { |
||||||
|
position string |
||||||
|
name string |
||||||
|
} |
||||||
|
|
||||||
|
func (fv *fileVisitor) Visit(n ast.Node) ast.Visitor { |
||||||
|
fv.checkImport(n) |
||||||
|
if ide, ok := n.(*ast.CallExpr); ok { |
||||||
|
if opt, ok := ide.Fun.(*ast.Ident); ok { |
||||||
|
fv.funcCalls = append(fv.funcCalls, opt.Name) |
||||||
|
newFun := nodePos{position: fv.getPos(n), name: opt.Name} |
||||||
|
callX = append(callX, newFun) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if expr, ok := n.(*ast.SelectorExpr); ok { |
||||||
|
if x, ok := expr.X.(*ast.Ident); ok { |
||||||
|
fv.selectExpr = append(fv.selectExpr, x.Name+"."+expr.Sel.Name) |
||||||
|
|
||||||
|
//saves the function in to the map, from the package
|
||||||
|
if importPkg[x.Name] != nil { |
||||||
|
importPkg[x.Name].functions = append(importPkg[x.Name].functions, x.Name+"."+expr.Sel.Name) |
||||||
|
} |
||||||
|
if funcOccurrences == nil { |
||||||
|
funcOccurrences = make(map[string]int) |
||||||
|
} |
||||||
|
funcOccurrences[x.Name+"."+expr.Sel.Name]++ |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if ex, ok := n.(*ast.ArrayType); ok { |
||||||
|
if op, ok := ex.Elt.(*ast.Ident); ok { |
||||||
|
fv.arrayType = append(fv.arrayType, nodePos{ |
||||||
|
name: op.Name, |
||||||
|
position: fv.getPos(n), |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
if exp, ok := n.(*ast.FuncDecl); ok { |
||||||
|
fv.funcDecl = append(fv.funcDecl, exp.Name.Name) |
||||||
|
for _, v := range exp.Type.Params.List { |
||||||
|
if _, ok := v.Type.(*ast.FuncType); ok { |
||||||
|
if allowedFun == nil { |
||||||
|
allowedFun = make(map[string]bool) |
||||||
|
} |
||||||
|
for _, name := range v.Names { |
||||||
|
allowedFun[name.Name] = true |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if ex, ok := n.(*ast.AssignStmt); ok { |
||||||
|
if exp, ok := ex.Rhs[0].(*ast.FuncLit); ok { |
||||||
|
if ide, ok := ex.Lhs[0].(*ast.Ident); ok { |
||||||
|
if funcDeclPkg == nil { |
||||||
|
funcDeclPkg = make(map[string]*funcBody) |
||||||
|
} |
||||||
|
funcDeclPkg[ide.Name] = &funcBody{body: exp.Body, position: fv.getPos(n)} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return fv |
||||||
|
} |
||||||
|
|
||||||
|
func positionIsIn(illegals []illegal, pos string) bool { |
||||||
|
for _, v := range illegals { |
||||||
|
if v.Pos == pos { |
||||||
|
return true |
||||||
|
} |
||||||
|
} |
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
func (p *pkgVisitor) Visit(n ast.Node) ast.Visitor { |
||||||
|
if exp, ok := n.(*ast.FuncDecl); ok { |
||||||
|
if funcDeclPkg == nil { |
||||||
|
funcDeclPkg = make(map[string]*funcBody) |
||||||
|
} |
||||||
|
funcDeclPkg[exp.Name.Name] = &funcBody{body: exp.Body, position: p.getPos(n)} |
||||||
|
for _, pkg := range pkgName { |
||||||
|
if importPkg[pkg] != nil && isIn(pkg+"."+exp.Name.Name, importPkg[pkg].functions) { |
||||||
|
funcDeclPkg[pkg+"."+exp.Name.Name] = &funcBody{body: exp.Body, position: p.getPos(n)} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if ex, ok := n.(*ast.AssignStmt); ok { |
||||||
|
if exp, ok := ex.Rhs[0].(*ast.FuncLit); ok { |
||||||
|
if ide, ok := ex.Lhs[0].(*ast.Ident); ok { |
||||||
|
if funcDeclPkg == nil { |
||||||
|
funcDeclPkg = make(map[string]*funcBody) |
||||||
|
} |
||||||
|
funcDeclPkg[ide.Name] = &funcBody{body: exp.Body, position: p.getPos(n)} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return p |
||||||
|
} |
||||||
|
|
||||||
|
func setIllegal(illegalType, funcName, pos string) { |
||||||
|
if !positionIsIn(illegals, pos) { |
||||||
|
illegals = append(illegals, illegal{ |
||||||
|
T: illegalType, |
||||||
|
Name: funcName, |
||||||
|
Pos: pos, |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Signals that exists at least one callExpr in the node
|
||||||
|
func (c *callVisitor) Visit(n ast.Node) ast.Visitor { |
||||||
|
if id, ok := n.(*ast.BasicLit); ok { |
||||||
|
if id.Kind != token.CHAR && id.Kind != token.STRING { |
||||||
|
return nil |
||||||
|
} |
||||||
|
basicLits = append(basicLits, nodePos{position: c.getPos(n), name: id.Value}) |
||||||
|
} |
||||||
|
|
||||||
|
if exp, ok := n.(*ast.CallExpr); ok { |
||||||
|
if fun, ok := exp.Fun.(*ast.Ident); ok { |
||||||
|
c.Calls = append(c.Calls, fun.Name) |
||||||
|
newFun := nodePos{position: c.getPos(n), name: fun.Name} |
||||||
|
callX = append(callX, newFun) |
||||||
|
if funcOccurrences == nil { |
||||||
|
funcOccurrences = make(map[string]int) |
||||||
|
} |
||||||
|
funcOccurrences[fun.Name]++ |
||||||
|
return c |
||||||
|
} |
||||||
|
} |
||||||
|
// SelectorExpr is when we access a value (dot opperator)
|
||||||
|
// We need to check those for specific functions
|
||||||
|
if expr, ok := n.(*ast.SelectorExpr); ok { |
||||||
|
x, ok := expr.X.(*ast.Ident) |
||||||
|
if !ok { |
||||||
|
// in this case we are deep in an access
|
||||||
|
// example, fmt is banned, but pouet isn't.
|
||||||
|
// we must allow pouet.fmt.x but not fmt.x
|
||||||
|
// this is the pouet.fmt.x case.
|
||||||
|
return c |
||||||
|
} |
||||||
|
pkg := allowedImp[x.Name] |
||||||
|
f := x.Name + "." + expr.Sel.Name |
||||||
|
if funcDeclPkg[f] != nil { |
||||||
|
c.Calls = append(c.Calls, f) |
||||||
|
return c |
||||||
|
} |
||||||
|
|
||||||
|
if pkg == nil { |
||||||
|
if allImports[x.Name] { |
||||||
|
pos := c.getPos(n) |
||||||
|
setIllegal("illegal-access", f, pos) |
||||||
|
} |
||||||
|
return c |
||||||
|
} |
||||||
|
if !pkg["*"] && !pkg[expr.Sel.Name] { |
||||||
|
// all the package is not whiteList and is not explicitly allowed
|
||||||
|
pos := c.getPos(n) |
||||||
|
setIllegal("illegal-access", f, pos) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if ex, ok := n.(*ast.ArrayType); ok { |
||||||
|
if op, ok := ex.Elt.(*ast.Ident); ok { |
||||||
|
arraysInstances = append(arraysInstances, nodePos{ |
||||||
|
name: op.Name, |
||||||
|
position: c.getPos(n), |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if _, ok := n.(*ast.ForStmt); ok { |
||||||
|
forStmts = append(forStmts, nodePos{ |
||||||
|
name: "for", |
||||||
|
position: c.getPos(n), |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
return c |
||||||
|
} |
||||||
|
|
||||||
|
func (fv *fileVisitor) checkImport(n ast.Node) ast.Visitor { |
||||||
|
if spec, ok := n.(*ast.ImportSpec); ok { |
||||||
|
pkg := spec.Path.Value[1 : len(spec.Path.Value)-1] |
||||||
|
if allowedImp[pkg] == nil { |
||||||
|
pos := fv.getPos(n) |
||||||
|
setIllegal("illegal-import", pkg, pos) |
||||||
|
return fv |
||||||
|
} |
||||||
|
// if the import is named, we need to move it to the new name
|
||||||
|
name := "" |
||||||
|
if spec.Name != nil { |
||||||
|
name = spec.Name.Name |
||||||
|
} else if strings.ContainsRune(pkg, '/') { |
||||||
|
parts := strings.Split(pkg, "/") |
||||||
|
name = parts[len(parts)-1] |
||||||
|
} |
||||||
|
if allowedImp[pkg] != nil { |
||||||
|
if name != "" { |
||||||
|
allowedImp[name] = allowedImp[pkg] |
||||||
|
allowedImp[pkg] = nil |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if isRelativeImport(pkg) { |
||||||
|
if importPkg == nil { |
||||||
|
importPkg = make(map[string]*pkgFunc) |
||||||
|
} |
||||||
|
if name != "" { |
||||||
|
importPkg[name] = &pkgFunc{ |
||||||
|
path: pkg, |
||||||
|
} |
||||||
|
} |
||||||
|
relativeImports = append(relativeImports, name) |
||||||
|
} |
||||||
|
} |
||||||
|
return fv |
||||||
|
} |
||||||
|
|
||||||
|
func (i *impVisitor) Visit(n ast.Node) ast.Visitor { |
||||||
|
if spec, ok := n.(*ast.ImportSpec); ok { |
||||||
|
pkg := spec.Path.Value[1 : len(spec.Path.Value)-1] |
||||||
|
if allImports == nil { |
||||||
|
allImports = make(map[string]bool) |
||||||
|
} |
||||||
|
pkgSplit := strings.Split(pkg, "/") |
||||||
|
|
||||||
|
allImports[pkg] = true |
||||||
|
allImports[pkgSplit[len(pkgSplit)-1]] = true |
||||||
|
|
||||||
|
if isRelativeImport(pkg) { |
||||||
|
i.relativeImports = append(i.relativeImports, pkg) |
||||||
|
} |
||||||
|
} |
||||||
|
return i |
||||||
|
} |
@ -0,0 +1,161 @@ |
|||||||
|
#!/usr/bin/env bash |
||||||
|
|
||||||
|
# Unofficial Bash Strict Mode |
||||||
|
set -euo pipefail |
||||||
|
IFS=' |
||||||
|
' |
||||||
|
|
||||||
|
# Debian stable OS |
||||||
|
apt-get update |
||||||
|
apt-get -y upgrade |
||||||
|
apt-get -y dist-upgrade |
||||||
|
|
||||||
|
# Disable OpenStack SSH malware |
||||||
|
mv /home/debian/.ssh/authorized_keys /root/.ssh/authorized_keys ||: |
||||||
|
sed -i '/Generated-by-Nova/d' /root/.ssh/authorized_keys ||: |
||||||
|
chown root:root /root/.ssh/authorized_keys ||: |
||||||
|
|
||||||
|
# Terminal goodies |
||||||
|
touch .hushlogin |
||||||
|
|
||||||
|
cat <<'EOF'>> /root/.bashrc |
||||||
|
export LS_OPTIONS="--color=auto" |
||||||
|
eval "`dircolors`" |
||||||
|
|
||||||
|
alias ctop="docker run --rm -it --name=ctop -v /var/run/docker.sock:/var/run/docker.sock:ro quay.io/vektorlab/ctop" |
||||||
|
alias df="df --si" |
||||||
|
alias du="du -cs --si" |
||||||
|
alias free="free -h --si" |
||||||
|
alias l="ls $LS_OPTIONS -al --si --group-directories-first" |
||||||
|
alias less="less -i" |
||||||
|
alias nano="nano -clDOST4" |
||||||
|
alias pstree="pstree -palU" |
||||||
|
alias gobuild='CGO_ENABLED=0 GOARCH=amd64 go build -trimpath -ldflags="-s -w"' |
||||||
|
|
||||||
|
export HISTFILESIZE= |
||||||
|
export HISTSIZE= |
||||||
|
export HISTTIMEFORMAT="%F %T " |
||||||
|
|
||||||
|
GOPATH=$HOME/go |
||||||
|
HISTCONTROL=ignoreboth |
||||||
|
HISTFILESIZE= |
||||||
|
HISTSIZE= |
||||||
|
HISTTIMEFORMAT="%F %T " |
||||||
|
EOF |
||||||
|
|
||||||
|
cat <<EOF>> /etc/inputrc |
||||||
|
set completion-ignore-case |
||||||
|
set show-all-if-ambiguous On |
||||||
|
set show-all-if-unmodified On |
||||||
|
EOF |
||||||
|
|
||||||
|
cat <<EOF>> /etc/bash.bashrc |
||||||
|
if ! shopt -oq posix; then |
||||||
|
if [ -f /usr/share/bash-completion/bash_completion ]; then |
||||||
|
. /usr/share/bash-completion/bash_completion |
||||||
|
elif [ -f /etc/bash_completion ]; then |
||||||
|
. /etc/bash_completion |
||||||
|
fi |
||||||
|
fi |
||||||
|
EOF |
||||||
|
|
||||||
|
# Basic packages |
||||||
|
apt-get -y install man bash-completion git ufw jq curl build-essential netcat wget psmisc lz4 file net-tools brotli unzip zip moreutils xauth sysfsutils rsync iperf pv tree mc screen |
||||||
|
|
||||||
|
# Configure screen |
||||||
|
cat <<'EOF'>> /etc/screenrc |
||||||
|
startup_message off |
||||||
|
shell -$SHELL |
||||||
|
defscrollback 100000 |
||||||
|
bind l eval clear "scrollback 0" "scrollback 100000" |
||||||
|
EOF |
||||||
|
|
||||||
|
# Configure SSH |
||||||
|
cat <<EOF>> /etc/ssh/sshd_config |
||||||
|
Port 521 |
||||||
|
PasswordAuthentication no |
||||||
|
AllowUsers root |
||||||
|
X11UseLocalhost no |
||||||
|
EOF |
||||||
|
service ssh restart |
||||||
|
|
||||||
|
touch /root/.Xauthority |
||||||
|
|
||||||
|
# Firewall |
||||||
|
ufw allow in 80/tcp |
||||||
|
ufw allow in 443/tcp |
||||||
|
ufw allow in 521/tcp |
||||||
|
ufw logging off |
||||||
|
ufw --force enable |
||||||
|
ufw --force delete 4 |
||||||
|
ufw --force delete 4 |
||||||
|
ufw --force delete 4 |
||||||
|
|
||||||
|
# Optimize |
||||||
|
systemctl disable unattended-upgrades.service apt-daily.timer apt-daily-upgrade.timer console-setup.service keyboard-setup.service remote-fs.target man-db.timer systemd-timesyncd.service |
||||||
|
apt-get -y purge apparmor |
||||||
|
sed -i 's/MODULES=most/MODULES=dep/g' /etc/initramfs-tools/initramfs.conf |
||||||
|
sed -i 's/COMPRESS=gzip/COMPRESS=lz4/g' /etc/initramfs-tools/initramfs.conf |
||||||
|
update-initramfs -u |
||||||
|
echo 'GRUB_TIMEOUT=0' >> /etc/default/grub |
||||||
|
update-grub |
||||||
|
apt-get -y purge exim\* |
||||||
|
|
||||||
|
for i in $(seq 0 $(nproc --ignore 1)); do |
||||||
|
echo "devices/system/cpu/cpu${i}/cpufreq/scaling_governor = performance" >> /etc/sysfs.conf |
||||||
|
done |
||||||
|
|
||||||
|
# Disable sleep when closing laptop screen |
||||||
|
echo HandleLidSwitch=ignore >> /etc/systemd/logind.conf |
||||||
|
|
||||||
|
# noatime |
||||||
|
sed -i 's| / ext4 | / ext4 noatime,|g' /etc/fstab |
||||||
|
|
||||||
|
# Disable swap |
||||||
|
swapoff -a |
||||||
|
sed -i '/swap/d' /etc/fstab |
||||||
|
|
||||||
|
# node.JS & yarn |
||||||
|
curl -sL https://deb.nodesource.com/setup_12.x | bash - |
||||||
|
apt-get -y install nodejs |
||||||
|
curl -sL https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - |
||||||
|
echo "deb https://dl.yarnpkg.com/debian/ stable main" > /etc/apt/sources.list.d/yarn.list |
||||||
|
apt-get update |
||||||
|
apt-get -y install yarn |
||||||
|
|
||||||
|
# Docker |
||||||
|
apt-get -y install apt-transport-https ca-certificates curl gnupg2 software-properties-common |
||||||
|
curl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add - |
||||||
|
add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable" |
||||||
|
apt-get update |
||||||
|
apt-get -y install docker-ce docker-ce-cli containerd.io |
||||||
|
|
||||||
|
# ripgrep |
||||||
|
curl -LO https://github.com/BurntSushi/ripgrep/releases/download/11.0.2/ripgrep_11.0.2_amd64.deb |
||||||
|
dpkg -i ripgrep_11.0.2_amd64.deb |
||||||
|
rm ripgrep_11.0.2_amd64.deb |
||||||
|
|
||||||
|
# Go |
||||||
|
wget https://dl.google.com/go/go1.14.linux-amd64.tar.gz |
||||||
|
tar -C /usr/local -xzf go1.14.linux-amd64.tar.gz |
||||||
|
rm go1.14.linux-amd64.tar.gz |
||||||
|
echo 'export PATH=$PATH:/usr/local/go/bin' >> /etc/profile |
||||||
|
|
||||||
|
# Netdata |
||||||
|
# bash <(curl -Ss https://my-netdata.io/kickstart-static64.sh) --no-updates --stable-channel --disable-telemetry |
||||||
|
|
||||||
|
# Caddy |
||||||
|
curl https://getcaddy.com | bash -s personal http.ipfilter |
||||||
|
|
||||||
|
# Generate SSH key |
||||||
|
ssh-keygen -ted25519 -f ~/.ssh/id_ed25519 -N '' |
||||||
|
|
||||||
|
# Cleanup |
||||||
|
sed -i '/^deb-src/d' /etc/apt/sources.list |
||||||
|
apt-get update |
||||||
|
apt-get -y purge unattended-upgrades |
||||||
|
apt-get -y autoremove --purge |
||||||
|
apt-get clean |
||||||
|
|
||||||
|
# The end |
||||||
|
reboot |
@ -0,0 +1,55 @@ |
|||||||
|
## chunk |
||||||
|
|
||||||
|
## **WARNING! VERY IMPORTANT!** |
||||||
|
|
||||||
|
For this exercise a function will be tested **with the exam own main**. However the student **still needs** to submit a structured program: |
||||||
|
|
||||||
|
This means that: |
||||||
|
|
||||||
|
- The package needs to be named `package main`. |
||||||
|
- The submitted code needs one declared function main(```func main()```) even if empty. |
||||||
|
- The function main declared needs to **also pass** the `Restrictions Checker`(illegal functions tester). It is advised for the student to just empty the function main after its own testings are done. |
||||||
|
- Every other rules are obviously the same than for a `program`. |
||||||
|
|
||||||
|
### Instructions |
||||||
|
|
||||||
|
Write a function called `Chunk` that receives as parameters a slice, `slice []int`, and an number `size int`. The goal of this function is to chunk a slice into many sub slices where each sub slice has the length of `size`. |
||||||
|
|
||||||
|
- If the `size` is `0` it should print `\n` |
||||||
|
|
||||||
|
### Expected function |
||||||
|
|
||||||
|
```go |
||||||
|
func Chunk(slice []int, size int) { |
||||||
|
|
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
### Usage |
||||||
|
|
||||||
|
Here is a possible program to test your function : |
||||||
|
|
||||||
|
```go |
||||||
|
package main |
||||||
|
|
||||||
|
func main() { |
||||||
|
Chunk([]int{}, 10) |
||||||
|
Chunk([]int{0, 1, 2, 3, 4, 5, 6, 7}, 0) |
||||||
|
Chunk([]int{0, 1, 2, 3, 4, 5, 6, 7}, 3) |
||||||
|
Chunk([]int{0, 1, 2, 3, 4, 5, 6, 7}, 5) |
||||||
|
Chunk([]int{0, 1, 2, 3, 4, 5, 6, 7}, 4) |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
And its output : |
||||||
|
|
||||||
|
```console |
||||||
|
student@ubuntu:~/[[ROOT]]/test$ go build |
||||||
|
student@ubuntu:~/[[ROOT]]/test$ ./test |
||||||
|
[] |
||||||
|
|
||||||
|
[[0 1 2] [3 4 5] [6 7]] |
||||||
|
[[0 1 2 3 4] [5 6 7]] |
||||||
|
[[0 1 2 3] [4 5 6 7]] |
||||||
|
student@ubuntu:~/[[ROOT]]/test$ |
||||||
|
``` |
@ -0,0 +1,24 @@ |
|||||||
|
## costumeprofit |
||||||
|
|
||||||
|
### Instructions |
||||||
|
|
||||||
|
Shop is selling **a** ties, **b** scarfs, **c** waistcoats, **d** jackets. |
||||||
|
|
||||||
|
- You want to make a costume. There are 2 types of costumes : |
||||||
|
- 1 - costume composed of tie and jacket. |
||||||
|
- 2 - costume composed of scarf, waistcoat, and jacket. |
||||||
|
|
||||||
|
Costumes of first type cost **e** dollars, of second type cost **f** dollars. |
||||||
|
|
||||||
|
What is the maximum amount of dollars that shop can earn by selling costumes? |
||||||
|
|
||||||
|
Input will be given as 6 arguments, your output should be displayed as standard output. |
||||||
|
|
||||||
|
In the output put '\n' at the end. |
||||||
|
|
||||||
|
Input: `./main **a** **b** **c** **d** **e** **f**` |
||||||
|
|
||||||
|
```console |
||||||
|
$> ./main 12 11 13 20 4 6 |
||||||
|
102 |
||||||
|
``` |
@ -0,0 +1,47 @@ |
|||||||
|
## doppelganger |
||||||
|
|
||||||
|
## **WARNING! VERY IMPORTANT!** |
||||||
|
|
||||||
|
For this exercise a function will be tested **with the exam own main**. However the student **still needs** to submit a structured program: |
||||||
|
|
||||||
|
This means that: |
||||||
|
|
||||||
|
- The package needs to be named `package main`. |
||||||
|
- The submitted code needs one declared function main(```func main()```) even if empty. |
||||||
|
- The function main declared needs to **also pass** the `Restrictions Checker`(illegal functions tester). It is advised for the student to just empty the function main after its own testings are done. |
||||||
|
- Every other rules are obviously the same than for a `program`. |
||||||
|
|
||||||
|
### Instructions |
||||||
|
|
||||||
|
You are given 2 strings. Find out if first string contains second string. If it does, return index of the first string where second string occurs last time. If it does not contain, return "-1" |
||||||
|
|
||||||
|
### Expected function |
||||||
|
|
||||||
|
```go |
||||||
|
package main |
||||||
|
|
||||||
|
func DoppelGanger(big, little string) int { |
||||||
|
|
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
```go |
||||||
|
package main |
||||||
|
|
||||||
|
import ( |
||||||
|
"fmt" |
||||||
|
) |
||||||
|
|
||||||
|
func main() { |
||||||
|
var result int |
||||||
|
|
||||||
|
result = DoppelGanger("aaaaaaa", "a") |
||||||
|
fmt.Println(result) // 6 |
||||||
|
|
||||||
|
result = DoppelGanger("qwerty", "t") |
||||||
|
fmt.Println(result) // 4 |
||||||
|
|
||||||
|
result = DoppelGanger("a", "b") |
||||||
|
fmt.Println(result) // -1 |
||||||
|
} |
||||||
|
``` |
@ -0,0 +1,60 @@ |
|||||||
|
## fib |
||||||
|
|
||||||
|
## **WARNING! VERY IMPORTANT!** |
||||||
|
|
||||||
|
For this exercise a function will be tested **with the exam own main**. However the student **still needs** to submit a structured program: |
||||||
|
|
||||||
|
This means that: |
||||||
|
|
||||||
|
- The package needs to be named `package main`. |
||||||
|
- The submitted code needs one declared function main(```func main()```) even if empty. |
||||||
|
- The function main declared needs to **also pass** the `Restrictions Checker`(illegal functions tester). It is advised for the student to just empty the function main after its own testings are done. |
||||||
|
- Every other rules are obviously the same than for a `program`. |
||||||
|
|
||||||
|
### Instructions |
||||||
|
|
||||||
|
It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English. Many desktop publishing packages and web page editors now use Lorem Ipsum as their default model text, and a search for 'lorem ipsum' will uncover many web sites still in their infancy. Various versions have evolved over the years, sometimes by accident, sometimes on purpose (injected humour and the like). |
||||||
|
Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in classical literature, discovered the undoubtable source. Lorem Ipsum comes from sections 1.10.32 and 1.10.33 of "de Finibus Bonorum et Malorum" (The Extremes of Good and Evil) by Cicero, written in 45 BC. This book is a treatise on the theory of ethics, very popular during the Renaissance. The first line of Lorem Ipsum, "Lorem ipsum dolor sit amet..", comes from a line in section 1.10.32. |
||||||
|
|
||||||
|
The standard chunk of Lorem Ipsum used since the 1500s is reproduced below for those interested. Sections 1.10.32 and 1.10.33 from "de Finibus Bonorum et Malorum" by Cicero are also reproduced in their exact original form, accompanied by English versions from the 1914 translation by H. Rackham. |
||||||
|
|
||||||
|
You are given a non-negative integer n, please find nth element of fibonacci sequence. |
||||||
|
Fib(0) = 0, |
||||||
|
Fib(1) = 1, otherwise, nth element is the sum of the 2 previous elements of the series. |
||||||
|
|
||||||
|
### Expected function |
||||||
|
|
||||||
|
```go |
||||||
|
func Fib(n int) int { |
||||||
|
|
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
### Usage |
||||||
|
|
||||||
|
Here is a possible program to test your function : |
||||||
|
|
||||||
|
```go |
||||||
|
package main |
||||||
|
|
||||||
|
import ( |
||||||
|
"fmt" |
||||||
|
) |
||||||
|
|
||||||
|
func main() { |
||||||
|
fmt.Println(Fib(0)) |
||||||
|
fmt.Println(Fib(1)) |
||||||
|
fmt.Println(Fib(2)) |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
And its output : |
||||||
|
|
||||||
|
```console |
||||||
|
student@ubuntu:~/[[ROOT]]/test$ go build |
||||||
|
student@ubuntu:~/[[ROOT]]/test$ ./test |
||||||
|
0 |
||||||
|
1 |
||||||
|
1 |
||||||
|
student@ubuntu:~/[[ROOT]]/test$ |
||||||
|
``` |
@ -0,0 +1,53 @@ |
|||||||
|
## findprevprime |
||||||
|
|
||||||
|
## **WARNING! VERY IMPORTANT!** |
||||||
|
|
||||||
|
For this exercise a function will be tested **with the exam own main**. However the student **still needs** to submit a structured program: |
||||||
|
|
||||||
|
This means that: |
||||||
|
|
||||||
|
- The package needs to be named `package main`. |
||||||
|
- The submitted code needs one declared function main(\`\`\`func main()\`\`\`) even if empty. |
||||||
|
- The function main declared needs to **also pass** the \`Restrictions Checker\`(illegal functions tester). It is advised for the student to just empty the function main after its own testings are done. |
||||||
|
- Every other rules are obviously the same than for a \`program\`. |
||||||
|
|
||||||
|
### Instructions |
||||||
|
|
||||||
|
Write a function that returns the first prime number that is equal or inferior to the `int` passed as parameter. |
||||||
|
|
||||||
|
If there are no primes inferior to the `int` passed as parameter the function should return 0. |
||||||
|
|
||||||
|
### Expected function |
||||||
|
|
||||||
|
```go |
||||||
|
func FindPrevPrime(nb int) int { |
||||||
|
|
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
### Usage |
||||||
|
|
||||||
|
Here is a possible [program](TODO-LINK) to test your function : |
||||||
|
|
||||||
|
```go |
||||||
|
package main |
||||||
|
|
||||||
|
import ( |
||||||
|
"fmt" |
||||||
|
) |
||||||
|
|
||||||
|
func main() { |
||||||
|
fmt.Println(FindPrevPrime(5)) |
||||||
|
fmt.Println(FindPrevPrime(4)) |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
And its output : |
||||||
|
|
||||||
|
```console |
||||||
|
student@ubuntu:~/piscine-go/test$ go build |
||||||
|
student@ubuntu:~/piscine-go/test$ ./test |
||||||
|
5 |
||||||
|
3 |
||||||
|
student@ubuntu:~/piscine-go/test$ |
||||||
|
``` |
Some files were not shown because too many files changed in this diff diff.show_more
Loading…
Reference in new issue