diff --git a/.Rbuildignore b/.Rbuildignore
new file mode 100644
index 0000000000000000000000000000000000000000..91114bf2f2bba5e0c5252e75018da19b869776f1
--- /dev/null
+++ b/.Rbuildignore
@@ -0,0 +1,2 @@
+^.*\.Rproj$
+^\.Rproj\.user$
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..f4f606b08247414e98fdb3ffca335cef87e17e7d
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+.Rproj.user
+.Rhistory
+.RData
+.Ruserdata
+*.Rproj
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..4f9e7da87f1ca9ec3ba840966c18ec8d3a51d487
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,44 @@
+image: rocker/rstudio
+stages:
+- build
+- test
+- deploy
+building:
+  stage: build
+  script:
+    - Rscript -e 'install.packages("remotes")'
+    - Rscript -e 'install.packages("devtools")'
+    - R -e "remotes::install_deps(dependencies = TRUE)"
+    - R -e 'devtools::check()'
+
+testing:
+  stage: test
+  allow_failure: true
+  when: on_success
+  only:
+      - master
+  coverage: '/coverage: \d+.\d+% of statements/'
+  script:
+      - Rscript -e 'install.packages("testthat")'
+      - Rscript -e 'install.packages("DT")'
+      - Rscript -e 'install.packages("covr")'
+      - Rscript -e 'covr::gitlab(quiet = FALSE)'
+  artifacts:
+      paths:
+        - public
+# To produce a code coverage report as a GitLab page see
+# https://about.gitlab.com/2016/11/03/publish-code-coverage-report-with-gitlab-pages/
+pages:
+  stage: deploy
+  dependencies:
+      - testing
+  script:
+      - mkdir .public
+      - cp -r * .public
+      - mv .public public
+  artifacts:
+      paths:
+          - public
+      expire_in: 30 days
+  only:
+      - master
\ No newline at end of file
diff --git a/DESCRIPTION b/DESCRIPTION
new file mode 100644
index 0000000000000000000000000000000000000000..f4d51532443268b7121f1046c60cdc36f6b8d0fc
--- /dev/null
+++ b/DESCRIPTION
@@ -0,0 +1,17 @@
+Package: lab
+Type: Package
+Title: Advanced R Group Cooperation
+Version: 1.0
+Date: 2024-09-12
+Author: Liuxi Mei,Xiaochen Liu
+Maintainer: Liuxi Mei <liume102@student.liu.se>,Xiaochen Liu<xiali125@student.liu.se>
+Description: This is a exercise package for advanced R .
+License: GPL (>= 2)
+RoxygenNote: 7.3.2
+Encoding: UTF-8
+Depends: 
+    R (>= 2.10)
+LazyData: true
+Suggests: 
+    testthat (>= 3.0.0)
+Config/testthat/edition: 3
diff --git a/NAMESPACE b/NAMESPACE
new file mode 100644
index 0000000000000000000000000000000000000000..6ae926839dd1829f1016a96f766d970ff184ad97
--- /dev/null
+++ b/NAMESPACE
@@ -0,0 +1,2 @@
+# Generated by roxygen2: do not edit by hand
+
diff --git a/R/lab_3_submission.R b/R/lab_3_submission.R
new file mode 100644
index 0000000000000000000000000000000000000000..8af145a27e53d641d3d527a0b96283a0516d6d2a
--- /dev/null
+++ b/R/lab_3_submission.R
@@ -0,0 +1,135 @@
+
+
+#' Euclidian algorithm to find the 
+#' greatest common divisor of two numbers
+#' @title  euclidean algorithm
+#' @param x first number
+#' @param y second number
+
+euclidean <- function(x,y) {
+  x <- abs(x)
+  y <- abs(y)
+  if (!is.numeric(x) | length(x) != 1){
+    stop('pls check your input x')
+  }
+  if (!is.numeric(y) | length(y) != 1){
+    stop('pls check your input y')
+  }
+  a <- ifelse(x < y, y, x)
+  b <- ifelse(x < y, x, y)
+  repeat{
+    mode = a %% b
+    if (mode == 0) {
+      return (b)
+    }
+    a <- b
+    b <- mode
+  }
+  return (b)
+}
+
+
+#' @description init the detail table
+#' @title  initial the detail frame 
+#' @param init_node the start node to find the shortest path
+#' @param graph the structure of the graph,
+#' eg:wiki_graph <- data.frame(v1=c(1,1,1,2,2,2,3,3,3,3,4,4,4,5,5,6,6,6),
+#'            v2=c(2,3,6,1,3,4,1,2,4,6,2,3,5,4,6,1,3,5),
+#'             w=c(7,9,14,7,10,15,9,10,11,2,15,11,6,6,9,14,2,9))
+init_node_distance_list <- function (init_node, graph) {
+  node_distance_list <- list(init_node = 0)
+  # first, get all unqiue nodes 
+  all_nodes <- unique(append(graph[,'v1'],graph[,'v2']))
+  if (!init_node %in% all_nodes) {
+    stop('node is not in graph')
+  }
+  detail_frame <- data.frame(matrix(ncol=length(all_nodes),nrow = 3))
+  names(detail_frame) <- all_nodes
+  row.names(detail_frame) <- c('is_best_node','node_distance','previous_node')
+  detail_frame['node_distance', ]<- Inf
+  detail_frame['node_distance',init_node] <- 0
+  detail_frame['is_best_node',init_node] <- TRUE
+  checked_nodes <- list(init_node)
+  unchecked_nodes <- all_nodes[-which( all_nodes == init_node)]
+  return (list(detail_frame=detail_frame, checked_nodes=checked_nodes, unchecked_nodes=unchecked_nodes))
+}
+
+
+#' @description
+#' the update method for detail table to record the shortest path
+#' @title update the detail frame when traversing to a new node
+#' @param node the current the node when traversing all the nodes to find the best way
+#' @param init_node the start node in the algorithm
+#' @param checked_nodes the nodes that having found the shortest path
+#' @param unchecked_nodes the nodes that having not found the shortest path
+#' @param detail_frame to store the shorest path , if it is the best node and the related distance
+#' @param graph the graph indicates the relationship of different nodes
+
+update_detail_path <- function(node,init_node,detail_frame,graph,checked_nodes,unchecked_nodes) {
+  #get connected nodes to node
+  if (length(unchecked_nodes) == 0){
+    # browser() 
+    return (detail_frame)
+  }
+  connected_nodes <- graph[graph$v1 == node,]$v2
+  next_node <- NULL
+  min_path <- Inf
+  for (c_node in connected_nodes){
+    current_distance <- graph[graph$v1 == node & graph$v2 == c_node,]$w 
+    if (node == init_node) {
+      detail_frame['node_distance',c_node] <- current_distance
+      detail_frame['previous_node',c_node] <- init_node
+      if(current_distance < min_path) {
+        min_path <- current_distance
+        next_node <- c_node
+        # detail_frame['best_node',c_node] <-TRUE
+      }
+    }else{
+      # browser() 
+      if (c_node %in% checked_nodes) next
+      
+      previous_distance <- detail_frame['node_distance',node] 
+      source_distance <-  previous_distance + current_distance
+      exist_distance <- detail_frame['node_distance',c_node]
+      #差更新前置节点
+      if (source_distance < exist_distance) {
+        
+        # update source distance
+        detail_frame['node_distance',c_node] <- source_distance
+        # update previous node
+        detail_frame['previous_node',c_node] <- node
+      }else{
+        source_distance <- exist_distance
+      }
+      if (source_distance < min_path) {
+        min_path <- source_distance
+        next_node <- c_node
+      }
+    }
+  }
+  
+  checked_nodes <- append(checked_nodes,next_node)
+  unchecked_nodes <- unchecked_nodes[-which(unchecked_nodes==next_node)]
+  detail_frame['is_best_node',next_node] <-TRUE
+  return (update_detail_path(next_node,init_node,detail_frame,graph,checked_nodes,unchecked_nodes))
+}
+
+#' @description
+#' the dijkstra algorithm to find the shortest path in the graph
+#' @title the entrance of the dijkstra algorithm
+#' @param graph a graph to find the shortest path 
+#' @param init_node the start node to find the shortest path in the graph 
+dijkstra <- function(graph, init_node) {
+  
+  res<- init_node_distance_list(init_node,graph)
+  detail_frame <- res$detail_frame
+  checked_nodes <- res$checked_nodes
+  unchecked_nodes <- res$unchecked_nodes
+  updated_detail_frame <- update_detail_path(init_node,init_node,detail_frame,graph,checked_nodes,unchecked_nodes)
+  return (unname(unlist(updated_detail_frame['node_distance',])))
+}
+  
+  
+  
+  
+  
diff --git a/R/wiki_graph.R b/R/wiki_graph.R
new file mode 100644
index 0000000000000000000000000000000000000000..d480674eade0fe0389e6e04556cf74b99f6450db
--- /dev/null
+++ b/R/wiki_graph.R
@@ -0,0 +1,10 @@
+
+#' graph
+#' @format A data frame with 18 rows and 3 columns:
+#' \describe{
+#'   \item{v1}{node name}
+#'   \item{v2}{node name}
+#'   \item{w}{the weight between node v1 and node v2}
+#'   ...
+#' }
+"wiki_graph" 
\ No newline at end of file
diff --git a/data-raw/.gitkeep b/data-raw/.gitkeep
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/data-raw/wiki_graph.R b/data-raw/wiki_graph.R
new file mode 100644
index 0000000000000000000000000000000000000000..bf14777b4f98387ad5a98acfd0e823013850c113
--- /dev/null
+++ b/data-raw/wiki_graph.R
@@ -0,0 +1,12 @@
+library(dplyr, warn.conflicts = FALSE)
+library(rvest)
+library(tidyr)
+library(readr)
+library(usethis)
+
+wiki_graph <-data.frame(v1=c(1,1,1,2,2,2,3,3,3,3,4,4,4,5,5,6,6,6),
+             v2=c(2,3,6,1,3,4,1,2,4,6,2,3,5,4,6,1,3,5),
+             w=c(7,9,14,7,10,15,9,10,11,2,15,11,6,6,9,14,2,9))
+
+write_csv(wiki_graph, "data-raw/wiki_graph.csv")
+usethis::use_data(wiki_graph, overwrite = TRUE)
\ No newline at end of file
diff --git a/data-raw/wiki_graph.csv b/data-raw/wiki_graph.csv
new file mode 100644
index 0000000000000000000000000000000000000000..8a673824f7bdf1b61c863af9ee966ea1349e84bc
--- /dev/null
+++ b/data-raw/wiki_graph.csv
@@ -0,0 +1,19 @@
+v1,v2,w
+1,2,7
+1,3,9
+1,6,14
+2,1,7
+2,3,10
+2,4,15
+3,1,9
+3,2,10
+3,4,11
+3,6,2
+4,2,15
+4,3,11
+4,5,6
+5,4,6
+5,6,9
+6,1,14
+6,3,2
+6,5,9
diff --git a/data/wiki_graph.rda b/data/wiki_graph.rda
new file mode 100644
index 0000000000000000000000000000000000000000..b9513341241f425a3aece1bb3c043a2cb7efc6f4
Binary files /dev/null and b/data/wiki_graph.rda differ
diff --git a/man/dijkstra.Rd b/man/dijkstra.Rd
new file mode 100644
index 0000000000000000000000000000000000000000..74004cc6837dc5872c7a0ebedbe259cbf697cb78
--- /dev/null
+++ b/man/dijkstra.Rd
@@ -0,0 +1,16 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/lab_3_submission.R
+\name{dijkstra}
+\alias{dijkstra}
+\title{the entrance of the dijkstra algorithm}
+\usage{
+dijkstra(graph, init_node)
+}
+\arguments{
+\item{graph}{a graph to find the shortest path}
+
+\item{init_node}{the start node to find the shortest path in the graph}
+}
+\description{
+the dijkstra algorithm to find the shortest path in the graph
+}
diff --git a/man/euclidean.Rd b/man/euclidean.Rd
new file mode 100644
index 0000000000000000000000000000000000000000..c3c30c97ffd649b8ac4ca3e0b8488db467e2a55a
--- /dev/null
+++ b/man/euclidean.Rd
@@ -0,0 +1,17 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/lab_3_submission.R
+\name{euclidean}
+\alias{euclidean}
+\title{euclidean algorithm}
+\usage{
+euclidean(x, y)
+}
+\arguments{
+\item{x}{first number}
+
+\item{y}{second number}
+}
+\description{
+Euclidian algorithm to find the 
+greatest common divisor of two numbers
+}
diff --git a/man/init_node_distance_list.Rd b/man/init_node_distance_list.Rd
new file mode 100644
index 0000000000000000000000000000000000000000..af02e37f6e9a6551219d2f174ea91003c63ec349
--- /dev/null
+++ b/man/init_node_distance_list.Rd
@@ -0,0 +1,19 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/lab_3_submission.R
+\name{init_node_distance_list}
+\alias{init_node_distance_list}
+\title{initial the detail frame}
+\usage{
+init_node_distance_list(init_node, graph)
+}
+\arguments{
+\item{init_node}{the start node to find the shortest path}
+
+\item{graph}{the structure of the graph,
+eg:wiki_graph <- data.frame(v1=c(1,1,1,2,2,2,3,3,3,3,4,4,4,5,5,6,6,6),
+           v2=c(2,3,6,1,3,4,1,2,4,6,2,3,5,4,6,1,3,5),
+            w=c(7,9,14,7,10,15,9,10,11,2,15,11,6,6,9,14,2,9))}
+}
+\description{
+init the detail table
+}
diff --git a/man/update_detail_path.Rd b/man/update_detail_path.Rd
new file mode 100644
index 0000000000000000000000000000000000000000..b7013cc4139d3e0454e5b3906a1b68194e75a90b
--- /dev/null
+++ b/man/update_detail_path.Rd
@@ -0,0 +1,31 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/lab_3_submission.R
+\name{update_detail_path}
+\alias{update_detail_path}
+\title{update the detail frame when traversing to a new node}
+\usage{
+update_detail_path(
+  node,
+  init_node,
+  detail_frame,
+  graph,
+  checked_nodes,
+  unchecked_nodes
+)
+}
+\arguments{
+\item{node}{the current the node when traversing all the nodes to find the best way}
+
+\item{init_node}{the start node in the algorithm}
+
+\item{detail_frame}{to store the shorest path , if it is the best node and the related distance}
+
+\item{graph}{the graph indicates the relationship of different nodes}
+
+\item{checked_nodes}{the nodes that having found the shortest path}
+
+\item{unchecked_nodes}{the nodes that having not found the shortest path}
+}
+\description{
+the update method for detail table to record the shortest path
+}
diff --git a/man/wiki_graph.Rd b/man/wiki_graph.Rd
new file mode 100644
index 0000000000000000000000000000000000000000..23c0a343b4384d33105f36c6ef9ff27f1bf8db12
--- /dev/null
+++ b/man/wiki_graph.Rd
@@ -0,0 +1,22 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/wiki_graph.R
+\docType{data}
+\name{wiki_graph}
+\alias{wiki_graph}
+\title{graph}
+\format{
+A data frame with 18 rows and 3 columns:
+\describe{
+  \item{v1}{node name}
+  \item{v2}{node name}
+  \item{w}{the weight between node v1 and node v2}
+  ...
+}
+}
+\usage{
+wiki_graph
+}
+\description{
+graph
+}
+\keyword{datasets}
diff --git a/tests/testthat.R b/tests/testthat.R
new file mode 100644
index 0000000000000000000000000000000000000000..480670efebea35a2ea53e93eab972825ff6ff824
--- /dev/null
+++ b/tests/testthat.R
@@ -0,0 +1,12 @@
+# This file is part of the standard setup for testthat.
+# It is recommended that you do not modify it.
+#
+# Where should you do additional test configuration?
+# Learn more about the roles of various files in:
+# * https://r-pkgs.org/testing-design.html#sec-tests-files-overview
+# * https://testthat.r-lib.org/articles/special-files.html
+
+library(testthat)
+library(lab)
+
+test_check("lab")
diff --git a/tests/testthat/test.dijkstra.R b/tests/testthat/test.dijkstra.R
new file mode 100644
index 0000000000000000000000000000000000000000..f49d110330679e06c1302dc3b1d70be5155ec0ef
--- /dev/null
+++ b/tests/testthat/test.dijkstra.R
@@ -0,0 +1,23 @@
+#  context("dijkstra")
+library(testthat)
+
+wiki_graph <-
+  data.frame(v1=c(1,1,1,2,2,2,3,3,3,3,4,4,4,5,5,6,6,6),
+             v2=c(2,3,6,1,3,4,1,2,4,6,2,3,5,4,6,1,3,5),
+             w=c(7,9,14,7,10,15,9,10,11,2,15,11,6,6,9,14,2,9))
+
+test_that("outputs are correct in the Dijkstra algorithm.", {
+  expect_equal(dijkstra(wiki_graph,1), c(0,7,9,20,20,11))
+  expect_equal(dijkstra(wiki_graph,3), c(9,10,0,11,11,2))
+})
+
+
+test_that("Error messages are returned for erronous input in the Dijkstra algorithm.", {
+  wiki_wrong_graph <- wiki_graph
+  names(wiki_wrong_graph) <- c("v1, v3, w")
+  expect_error(dijkstra(wiki_wrong_graph, 3))
+  wiki_wrong_graph <- wiki_graph[1:2]
+  expect_error(dijkstra(wiki_wrong_graph, 3))
+  expect_error(dijkstra(wiki_graph, 7))
+  expect_error(dijkstra(as.matrix(wiki_graph), 3))  
+})
diff --git a/tests/testthat/test_euclidean.R b/tests/testthat/test_euclidean.R
new file mode 100644
index 0000000000000000000000000000000000000000..98138cdf3d88b3dae8f2683bde6ca94d40d1a319
--- /dev/null
+++ b/tests/testthat/test_euclidean.R
@@ -0,0 +1,15 @@
+library(testthat)
+
+
+test_that("GDC is calculated correctly.", {
+  expect_equal(euclidean(123612, 13892347912), 4)
+  expect_equal(euclidean(100, 1000), 100)
+  expect_equal(euclidean(-100, 1000), 100)
+})
+
+
+test_that("Wrong input throws an error.", {
+  expect_error(euclidean("100", 1000))  
+  expect_error(euclidean(100, "1000"))
+  expect_error(euclidean(TRUE, "1000"))  
+})
\ No newline at end of file