class AnalysisView <<Boundary>>
class AnalysisResultView <<Boundary>>
class PredictionView <<Boundary>>
class EvaluationView <<Boundary>>
class EvaluationRaceView <<Boundary>>
class EvaluationRaceTestDatumView <<Boundary>>

class AnalysisChannel {
  + subscribed() : void
}

class PredictionChannel {
  + subscribed() : void
}

class EvaluationChannel {
  + subscribed() : void
}

class "Evaluation::RaceChannel" {
  + subscribed() : void
}

class ApplicationController {
  + check_schema(schema : HashMap, request_parameter : HashMap, resource : String) : void
  + remove_old_files() : void
}

class AnalysesController {
  + index(request : Object) : Object
  + execute(request : Object) : Object
  + show(request : Object) : Object
  + download(request : Object) : Object
  + rebuild(request : Object) : Object
  - check_request_analysis() : void
  - request_analysis() : Analysis
  - index_params() : HashMap
  - execute_params() : HashMap
  - index_schema() : HashMap
  - execute_schema() : HashMap
  - check_invalid_file() :void
  - user_specified_data?() : boolean
  - race_ids() : ArrayList
}

class PredictionsController {
  + manage(request : Object) : Object
  + execute(request : Object) : Object
  - execute_params() : HashMap
  - execute_schema() : HashMap
  - check_invalid_file_params() : void
  - save_files(prediction_id : Integer) : void
}

class EvaluationsController {
  + manage(request : Object) : Object
  + execute(request : Object) : Object
  + show(request : Object) : Object
  + download(request: Object) : Object
  - check_request_evaluation() : void
  - evaluation() : Evaluation
  - check_invalid_param() : void
  - user_specified_data?() : Boolean
  - num_data() : Integer
  - race_ids() : ArrayList
  - execute_param() : HashMap
  - execute_schema() : HashMap
}

class Evaluation::RacesController {
  + show(request : Object) : Object
  - check_request_evaluation_race() : void
  - evaluation_race() : Evaluation::Race
}

class Api::AnalysesController {
  + show(request : Object) : Object
  + destroy(request : Object) : Object
  - check_request_analysis() : void
  - analysis() : Analysis
}

class Api::Analyses::ParametersController {
  + show(request : Object) : Object
}

class Api::Analyses::ResultController {
  + check_request_analysis_result() : void
  + analysis_result() :" Analysis::Result"
}

class Api::Analyses::Result::ImportancesController {
  + index(request : Object) : Object
}

class Api::Analyses::Result::DecisionTreesController {
  + show(request : Object) : Object
  - check_request_analysis_result_decisiton_tree() : void
  - decision_tree() : "Analysis::Result::DecisionTree"
}

class AnalysisJob {
  + perform(analysis_id : Integer)
  - check_output() : void
  - create_zip(target_files : ArrayList, zip_file_name : String) : void
}

class PredictionJob {
  + perform(prediction_id : Integer)
}

class EvaluationJob {
  + perform(evaluation_id : Integer)
}

class AnalysisMailer {
  + completed(analysis : Analysis)
  + error(analysis : Analysis)
}

class "Analysis::IndexForm" {
  - num_data : String
  - parameter : HashMap
  + to_query() : HashMap
}

class Analysis {
  - analysis_id : String
  - data_source : String
  - num_data : Integer
  - num_feature : Integer
  - state : String
  - performed_at : Datetime
  - completed_at : Datetime
  + start!() : void
  + complete!() : void
  + failed!() : void
  + mktmpdir() : void
  + dump_parameter() : void
  + import_metadata!() : void
  + import_data!() : void
  + copy() : Analysis
  - tmp_dir() : String
  - copy_attributes() : HashMap
  - broadcast(updated_attribute : HashMap) : void
}

class "Analysis::Parameter" {
  - max_depth : Integer
  - max_features : String
  - max_leaf_nodes : Integer
  - min_samples_leaf : Integer
  - min_samples_split : Integer
  - num_tree : Integer
  + copy_attributes() : HashMap
}

class "Analysis::Datum" {
  - race_id : String
  + copy_attributes() : HashMap
}

class "Analysis::Result" {
  + import!() : void
}

class "Analysis::Result::Importance" {
  - feature_name : String
  - value : Double
}

class "Analysis::Result::DecisionTree" {
  - decision_tree_id : String
  + import!() : void
}

class "Analysis::Result::DecisionTree::Node" {
  - node_id : Integer
  - node_type : String
  - depth : Integer
  - group : String
  - feature_name : String
  - threshold : Double
  - num_win : Integer
  - num_lose : Integer
  - parent_id : Integer
}

class Prediction {
  - prediction_id : String
  - model : String
  - test_data : String
  - state : String
  - performed_at : Datetime
  + set_analysis!() : void
  + import_results(result_file : String) : void
  + start!() : void
  + completed!() : void
  + failed!() : void
  - broadcast(attribute : HashMap) : void
}

class PredictionResult {
  - number : Integer
  - won : Boolean
}

class Evaluation {
  - evaluation_id : String
  - model : String
  - data_source : String
  - num_data : Integer
  - state : String
  - precision : Double
  - recall : Double
  - specificity : Double
  - f_measure : Double
  - performed_at : Datetime
  - completed_at : Datetime
  + set_analysis!() : void
  + fetch_data!() : ArrayList
  + calculate_performance!() : void
  + output_race_ids() : void
  + change_state!() : void
  + start!() : void
  + complete!() : void
  + failed!() : void
  - remote?() : Boolean
  - sample_race_ids() : ArrayList
  - true_positive() : Double
  - true_negative() : Double
  - false_positive() : Double
  - false_negative() : Double
  - calculate_precision(true_positive : Double, false_positive : Double)
  - calculate_recall(true_positive : Double, false_negative : Double)
  - calculate_specificity(true_negative : Double, false_positive : Double)
  - calculate_f_measure(precision : Double, recall : Double)
  - broadcast(attribute : HashMap) : void
}

class "Evaluation::Race" {
  - race_id : String
  - race_name : String
  - race_url : String
  - ground_truth : Integer
  - profit : Integer
  + import_prediction_results!(result_file : String) : void
  - calculate_profit!() : void
  - broadcast(attribute : HashMap) : void
}

class "Evaluation::Race::TestDatum" {
  - number : Integer
  - win_probability : Double
  + order() : Integer
  + feature() : Denebola::Feature
}

class NetkeibaClient {
  + http_get_race_top() : ArrayList
  + http_get_race(path : String) : HashMap
  + http_get_horse(path : String) : HashMap
  + http_get_jockey(path : String) : HashMap
  - send_request(path : String) : Object
}

class FeatureExtractor <<module>> {
  + extract_race(place : Object, race_data : Object, race_date : Object) : HashMap
  + extract_entries(race_data : Object) : HashMap
  + extract_horse(table : Object) : HashMap
  + extract_horse_results(table : Object) : HashMap
  + extract_jockey_results(table : Object) : HashMap
}

class FeatureUtil {
  + {static} create_feature_from_netkeiba(race_path : String) : HashMap
  + {static} create_feature_from_denebola(race_id : String) : HashMap
}

class ModelUtil <<module>> {
  + unzip_model(zip_path : String, output_dir : String) : void
  + read_analysis_id(metadata_file : String) : String
}

ブラウザ -- AnalysisView
ブラウザ -- AnalysisResultView
AnalysisView --> AnalysisResultView
ブラウザ -- PredictionView
ブラウザ -- EvaluationView
ブラウザ -- EvaluationRaceView
ブラウザ -- EvaluationRaceTestDatumView
EvaluationView --> EvaluationRaceView
EvaluationRaceView --> EvaluationRaceTestDatumView

AnalysisView --> AnalysesController
AnalysisView --> Api::AnalysesController
AnalysisView --> Api::Analyses::ParametersController
AnalysisResultView --> Api::Analyses::Result::ImportancesController
AnalysisResultView --> Api::Analyses::Result::DecisionTreesController
ApplicationController <|-- AnalysesController
ApplicationController <|-- Api::AnalysesController
Api::AnalysesController <|-- Api::Analyses::ParametersController
Api::AnalysesController <|-- Api::Analyses::ResultController
Api::Analyses::ResultController <|-- Api::Analyses::Result::ImportancesController
Api::Analyses::ResultController <|-- Api::Analyses::Result::DecisionTreesController
AnalysesController --> AnalysisJob
AnalysesController --> Analysis::IndexForm
AnalysesController --> Analysis
Api::AnalysesController --> Analysis
Api::Analyses::ParametersController --> Analysis::Parameter
Api::Analyses::Result::ImportancesController --> Analysis::Result::Importance
Api::Analyses::Result::DecisionTreesController --> Analysis::Result::DecisionTree
AnalysisJob --> Analysis
AnalysisJob --> AnalysisMailer
Analysis --> AnalysisChannel
Analysis "1" -- "1" Analysis::Parameter
Analysis "1" -- "1 .. *" Analysis::Datum
Analysis "1" -- "1" Analysis::Result
Analysis::Result "1" -- "0 .. *" Analysis::Result::Importance
Analysis::Result "1" -- "0 .. *" Analysis::Result::DecisionTree
Analysis::Result::DecisionTree "1" -- "1 .. *" Analysis::Result::DecisionTree::Node
Analysis "1" -- "0 .. *" Prediction
Analysis "1" -- "0 .. *" Evaluation

PredictionView --> PredictionsController
ApplicationController <|-- PredictionsController
PredictionsController --> PredictionJob
PredictionsController --> Prediction
PredictionJob --> Prediction
PredictionJob --> FeatureUtil
PredictionJob ..> ModelUtil : <<include>>
Prediction --> PredictionChannel
Prediction "1" -- "*" PredictionResult
Prediction ..> ModelUtil : <<include>>

EvaluationView --> EvaluationsController
EvaluationView --> Api::Analyses::ParametersController
ApplicationController <|-- EvaluationsController
EvaluationsController --> EvaluationJob
EvaluationsController --> Evaluation
EvaluationJob --> FeatureUtil
EvaluationJob ..> ModelUtil : <<include>>
EvaluationJob --> Evaluation
Evaluation --> EvaluationChannel
Evaluation "1" -- "1 .. *" Evaluation::Race
Evaluation ..> ModelUtil : <<include>>
Evaluation::Race --> Evaluation::RaceChannel

EvaluationRaceView -- EvaluationsController

EvaluationRaceTestDatumView -- Evaluation::RacesController
Evaluation::RacesController --> Evaluation::Race
Evaluation::Race "1" -- "1 .. *" Evaluation::Race::TestDatum

FeatureUtil --> NetkeibaClient
NetkeibaClient ..> FeatureExtractor : <<include>>
