hookercookerman-amee 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +1 -0
- data/LICENSE.txt +20 -0
- data/Manifest.txt +79 -0
- data/README.rdoc +33 -0
- data/Rakefile +29 -0
- data/features/config.feature +22 -0
- data/features/data/data_category.feature +26 -0
- data/features/data/data_item.feature +19 -0
- data/features/data/data_item_value.feature +17 -0
- data/features/data/drill_down.feature +48 -0
- data/features/development.feature +13 -0
- data/features/profile/create.profile.feature +15 -0
- data/features/profile/create.profile_item.feature +12 -0
- data/features/profile/delete.profile.feature +12 -0
- data/features/profile/delete.profile_item.feature +13 -0
- data/features/profile/get.profile.feature +13 -0
- data/features/profile/profile_category.feature +14 -0
- data/features/profile/profile_item.feature +15 -0
- data/features/profile/profiles.feature +15 -0
- data/features/profile/update.profile_item.feature +14 -0
- data/features/session/reauthenticate.feature +16 -0
- data/features/step_definitions/amee_steps.rb +67 -0
- data/features/step_definitions/common_steps.rb +194 -0
- data/features/step_definitions/config_steps.rb +13 -0
- data/features/step_definitions/data_steps.rb +142 -0
- data/features/step_definitions/profile_category_steps.rb +23 -0
- data/features/step_definitions/profile_item_steps.rb +62 -0
- data/features/step_definitions/profile_steps.rb +41 -0
- data/features/support/amee/auth/response.json +11 -0
- data/features/support/amee/data.json +84 -0
- data/features/support/amee/data/transport/car/generic.json +3 -0
- data/features/support/amee/data/transport/car/generic/drill.json +66 -0
- data/features/support/amee/data/transport/car/generic/drill?fuel=diesel&size=large.json +55 -0
- data/features/support/amee/data/transport/car/generic/drill?fuel=diesel.json +59 -0
- data/features/support/amee/data/transport/plane/generic.json +225 -0
- data/features/support/amee/data/transport/plane/generic/FFC7A05D54AD.json +224 -0
- data/features/support/amee/data/transport/plane/generic/FFC7A05D54AD/kgCO2PerPassengerJourney.json +42 -0
- data/features/support/amee/data_category.json +84 -0
- data/features/support/amee/data_category_with_data_items.json +225 -0
- data/features/support/amee/profiles.json +73 -0
- data/features/support/amee/profiles/155DD3C63646/transport/motorcycle/generic/D47C465B8157.json +190 -0
- data/features/support/amee/profiles/155DD3C63646/transport/motorcycle/generic/D47C465B8157?distance=400&representation=true.json +190 -0
- data/features/support/amee/profiles/48B97680BCCF/home/energy/quantity/response.json +9 -0
- data/features/support/amee/profiles/7C7D68C2A7CD/home.json +65 -0
- data/features/support/amee/profiles/BB1BDB4FDD77/home/energy/quantity/920B54ED665B.json +201 -0
- data/features/support/amee/profiles/E0BCB3704D15.json +19 -0
- data/features/support/amee/profiles/E0BCB3704D15/Business.json +6 -0
- data/features/support/amee/profiles/profile.json +27 -0
- data/features/support/env.rb +24 -0
- data/init.rb +4 -0
- data/lib/amee.rb +37 -0
- data/lib/amee/config.rb +59 -0
- data/lib/amee/data_api/data_category.rb +50 -0
- data/lib/amee/data_api/data_item.rb +28 -0
- data/lib/amee/data_api/data_item_value.rb +13 -0
- data/lib/amee/data_api/drill_down.rb +23 -0
- data/lib/amee/data_api/item_definition.rb +11 -0
- data/lib/amee/data_api/item_value_definition.rb +13 -0
- data/lib/amee/data_api/value_definition.rb +10 -0
- data/lib/amee/logging.rb +43 -0
- data/lib/amee/model.rb +128 -0
- data/lib/amee/parser.rb +137 -0
- data/lib/amee/profile_api/profile.rb +39 -0
- data/lib/amee/profile_api/profile_category.rb +42 -0
- data/lib/amee/profile_api/profile_item.rb +47 -0
- data/lib/amee/service.rb +78 -0
- data/lib/amee/session.rb +222 -0
- data/lib/amee/utils/string.rb +11 -0
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/script/txt2html +71 -0
- data/spec/amee_spec.rb +1 -0
- data/spec/service_spec.rb +53 -0
- data/spec/session_spec.rb +45 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +19 -0
- data/tasks/rspec.rake +21 -0
- data/tasks/yard.rake +4 -0
- metadata +184 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
require "amee/data_api/data_item"
|
|
2
|
+
require "amee/data_api/item_definition"
|
|
3
|
+
module Amee
|
|
4
|
+
module DataApi
|
|
5
|
+
class DataCategory
|
|
6
|
+
include Amee::Model
|
|
7
|
+
self.path_prefix = "/data"
|
|
8
|
+
|
|
9
|
+
list_populators :data_categories => {:class => Amee::DataApi::DataCategory},
|
|
10
|
+
:data_items => {:class => Amee::DataApi::DataItem}
|
|
11
|
+
item_populators :item_definition => {:class => Amee::DataApi::ItemDefinition}
|
|
12
|
+
|
|
13
|
+
# essentially the parent category
|
|
14
|
+
attr_accessor :data_category, :pager
|
|
15
|
+
|
|
16
|
+
# we can only drill with a data_category that has data_items
|
|
17
|
+
#
|
|
18
|
+
# @param [Hash] selection of what we wish to drill down
|
|
19
|
+
#
|
|
20
|
+
# @return [Amee::DataApi::Drill] if we can drill down we get a drill object
|
|
21
|
+
# @return [nil] if we cannot drill then nil will be the name of the day
|
|
22
|
+
def drill(selections = {})
|
|
23
|
+
if can_drill?
|
|
24
|
+
session.drill(self.full_path, :selections => selections)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def can_drill?
|
|
29
|
+
!data_items.empty?
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
# lets delagate this one
|
|
34
|
+
def drill_down
|
|
35
|
+
item_definition && item_definition.drill_down
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def paginate(options = {})
|
|
39
|
+
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def populate!
|
|
43
|
+
session.api_call(:get, "data.category", self.full_path) do |response|
|
|
44
|
+
populate_from_hash!(response)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
require "amee/data_api/data_item_value"
|
|
2
|
+
require "amee/data_api/item_definition"
|
|
3
|
+
module Amee
|
|
4
|
+
module DataApi
|
|
5
|
+
class DataItem
|
|
6
|
+
require "amee/data_api/data_category"
|
|
7
|
+
include Amee::Model
|
|
8
|
+
self.path_prefix = "/data"
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
attr_accessor :start_date, :end_date, :label, :choices, :kg_c_o2_per_k_wh, :source
|
|
12
|
+
list_populators :item_values => {:class => Amee::DataApi::DataItemValue}
|
|
13
|
+
item_populators :data_category => {:class => Amee::DataApi::DataCategory},
|
|
14
|
+
:item_definition => {:class => Amee::DataApi::ItemDefinition}
|
|
15
|
+
|
|
16
|
+
def populate!
|
|
17
|
+
session.api_call(:get, "data.item", self.full_path) do |response|
|
|
18
|
+
populate_from_hash!(response)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def kg_co2_per_kwh
|
|
23
|
+
kg_c_o2_per_k_wh
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
require "amee/data_api/item_value_definition"
|
|
2
|
+
module Amee
|
|
3
|
+
module DataApi
|
|
4
|
+
class DataItemValue
|
|
5
|
+
include ::Amee::Model
|
|
6
|
+
self.path_prefix = "/data"
|
|
7
|
+
|
|
8
|
+
attr_accessor :display_name, :description, :value, :display_path, :unit, :per_unit, :data_item
|
|
9
|
+
item_populators :item_value_definition => {:class => Amee::DataApi::ItemValueDefinition}
|
|
10
|
+
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module Amee
|
|
2
|
+
module DataApi
|
|
3
|
+
class DrillDown
|
|
4
|
+
include ::Amee::Model
|
|
5
|
+
self.path_prefix = "/data"
|
|
6
|
+
|
|
7
|
+
# choices are an array of hashes with keys "value" and "name"
|
|
8
|
+
# same for the selections as well
|
|
9
|
+
attr_accessor :choice_name, :choices, :selections
|
|
10
|
+
item_populators :data_category => {:class => Amee::DataApi::DataCategory}
|
|
11
|
+
|
|
12
|
+
def data_item_uid
|
|
13
|
+
if uid_found?
|
|
14
|
+
choices.first["value"]
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def uid_found?
|
|
19
|
+
choice_name == "uid"
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
require "amee/data_api/value_definition"
|
|
2
|
+
module Amee
|
|
3
|
+
module DataApi
|
|
4
|
+
class ItemValueDefinition
|
|
5
|
+
include Amee::Model
|
|
6
|
+
self.path_prefix = "/data"
|
|
7
|
+
|
|
8
|
+
attr_accessor :from_profile, :from_data
|
|
9
|
+
item_populators :value_definition => {:class => Amee::DataApi::ValueDefinition}
|
|
10
|
+
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
data/lib/amee/logging.rb
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Approach taken from facebookers logging
|
|
2
|
+
# need to really look into what we want from Amee logging
|
|
3
|
+
require 'benchmark'
|
|
4
|
+
module Amee
|
|
5
|
+
@@logger = nil
|
|
6
|
+
def self.logger=(logger)
|
|
7
|
+
@@logger = logger
|
|
8
|
+
end
|
|
9
|
+
def self.logger
|
|
10
|
+
@@logger
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
module Logging
|
|
14
|
+
def self.log_amee_api(method, parser_name, path, options)
|
|
15
|
+
message = method
|
|
16
|
+
dump = format_da_dump(parser_name, path, options)
|
|
17
|
+
if block_given?
|
|
18
|
+
result = nil
|
|
19
|
+
seconds = Benchmark.realtime { result = yield }
|
|
20
|
+
log_info(message, dump, seconds)
|
|
21
|
+
result
|
|
22
|
+
else
|
|
23
|
+
log_info(message, dump)
|
|
24
|
+
nil
|
|
25
|
+
end
|
|
26
|
+
rescue Exception => e
|
|
27
|
+
exception = "#{e.class.name}: #{e.message}: #{dump}"
|
|
28
|
+
log_info(message, exception)
|
|
29
|
+
raise
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def self.format_da_dump(parser_name, path, options)
|
|
33
|
+
"AMEE: PARSER NAME: #{parser_name} PATH: #{path} OPTIONS: #{options.inspect}"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def self.log_info(message, dump, seconds = 0)
|
|
37
|
+
return unless Amee.logger
|
|
38
|
+
log_message = "#{message} (#{seconds}) #{dump}"
|
|
39
|
+
Amee.logger.info(log_message)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
end
|
|
43
|
+
end
|
data/lib/amee/model.rb
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# Approach taken from facebooker
|
|
2
|
+
module Amee
|
|
3
|
+
module Model
|
|
4
|
+
def self.included(base)
|
|
5
|
+
base.extend ClassMethods
|
|
6
|
+
base.__send__(:attr_writer, :session)
|
|
7
|
+
base.__send__(:attr_accessor, :path)
|
|
8
|
+
base.__send__(:attr_accessor, :uid)
|
|
9
|
+
base.__send__(:attr_accessor, :name)
|
|
10
|
+
base.__send__(:attr_accessor, :modified)
|
|
11
|
+
base.__send__(:attr_accessor, :created)
|
|
12
|
+
base.__send__(:attr_accessor, :resource_path)
|
|
13
|
+
|
|
14
|
+
base.class_eval do
|
|
15
|
+
class << base; attr_reader :lazy_populators end
|
|
16
|
+
class << base; attr_accessor :path_prefix end
|
|
17
|
+
path_prefix = ""
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
module ClassMethods
|
|
22
|
+
|
|
23
|
+
def from_hash(hash, session = nil)
|
|
24
|
+
instance = new(hash, session)
|
|
25
|
+
yield instance if block_given?
|
|
26
|
+
instance
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def item_populators(hash)
|
|
30
|
+
@lazy_populators ||= [] << hash.keys
|
|
31
|
+
populator_getters(hash.keys)
|
|
32
|
+
hash.each_pair do |key, value|
|
|
33
|
+
|
|
34
|
+
define_method("#{key}=") do |definition|
|
|
35
|
+
if session && !definition.nil?
|
|
36
|
+
if self.resource_path
|
|
37
|
+
definition["resource_path"] = self.resource_path+"/#{definition["path"]}"
|
|
38
|
+
end
|
|
39
|
+
instance_variable_set("@#{key}", value[:class].new(definition, session))
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def list_populators(hash)
|
|
47
|
+
@lazy_populators ||= [] << hash.keys
|
|
48
|
+
populator_getters(hash.keys)
|
|
49
|
+
hash.each_pair do |key, value|
|
|
50
|
+
|
|
51
|
+
define_method("#{key}=") do |list|
|
|
52
|
+
instance_variable_set("@#{key}", list.map do |item|
|
|
53
|
+
if self.resource_path
|
|
54
|
+
item["resource_path"] = self.resource_path+"/#{item["path"]}"
|
|
55
|
+
end
|
|
56
|
+
value[:class].new(item, session)
|
|
57
|
+
end) if session
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def populator_getters(pops)
|
|
64
|
+
pops.each do |symbol|
|
|
65
|
+
define_method(symbol) do
|
|
66
|
+
if !populated? && self.resource_path
|
|
67
|
+
populate!
|
|
68
|
+
end
|
|
69
|
+
instance_variable_get("@#{symbol}")
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
end # ClassMethods
|
|
75
|
+
|
|
76
|
+
def session
|
|
77
|
+
@session || (raise "Must bind this object to a Amee session before using")
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def initialize(hash = {}, session = nil)
|
|
81
|
+
@session = session
|
|
82
|
+
populate_from_hash!(hash)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def full_path
|
|
86
|
+
self.class.path_prefix + resource_path
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def populated?
|
|
90
|
+
@populated && lazy_populators_populated?
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def populate!
|
|
94
|
+
raise NotImplementError, "#{self.class} included me and has not overriden me"
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def populate_from_hash!(hash)
|
|
98
|
+
unless hash.nil? || hash.empty?
|
|
99
|
+
populate_paths(hash["resource_path"], hash["path"])
|
|
100
|
+
hash.each do |key, value|
|
|
101
|
+
set_attr_method = "#{Amee::Utils::String.snake_case(key)}="
|
|
102
|
+
if !value.nil? && respond_to?(set_attr_method)
|
|
103
|
+
self.__send__(set_attr_method, value)
|
|
104
|
+
else
|
|
105
|
+
# attempt to set attribute basically
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
@populated = true
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# we want the resource paths populated along with the path
|
|
113
|
+
# before we populate any other attribute as
|
|
114
|
+
# they may use these attributes
|
|
115
|
+
def populate_paths(resource_path, path)
|
|
116
|
+
self.resource_path, self.path = resource_path, path
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# if the all the lazy populators have been set then
|
|
120
|
+
# we now when are populated!
|
|
121
|
+
def lazy_populators_populated?
|
|
122
|
+
if self.class.lazy_populators
|
|
123
|
+
self.class.lazy_populators.find_all {|pop| !instance_variable_get("@#{pop}").nil?} == self.class.lazy_populators
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
end
|
|
128
|
+
end
|
data/lib/amee/parser.rb
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# Approach taken from facebooker
|
|
2
|
+
module Amee
|
|
3
|
+
class Parser
|
|
4
|
+
def self.parse(method, data)
|
|
5
|
+
parser = Parser::PARSERS[method]
|
|
6
|
+
parser.process(
|
|
7
|
+
data
|
|
8
|
+
)
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
class DataCategory < Parser
|
|
13
|
+
def self.process(data)
|
|
14
|
+
category = data["dataCategory"]
|
|
15
|
+
parent_category = data["dataCategory"]["dataCategory"] if data["dataCategory"]
|
|
16
|
+
pager = {"pager" => data["children"].delete("pager")}
|
|
17
|
+
categories = {"data_categories" => data["children"].delete("dataCategories")}
|
|
18
|
+
data_items = {"data_items" => data["children"]["dataItems"].delete("rows")} if data["children"]["dataItems"]
|
|
19
|
+
category.merge(categories).
|
|
20
|
+
merge(data_items).
|
|
21
|
+
merge(pager).
|
|
22
|
+
merge({"resource_path" => data["path"]})
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
class DataItem < Parser
|
|
27
|
+
def self.process(data)
|
|
28
|
+
data_item = data["dataItem"]
|
|
29
|
+
item_values = {"item_values" => data["dataItem"].delete("itemValues")}
|
|
30
|
+
data_item.merge(item_values).
|
|
31
|
+
merge({"choices" => data["userValueChoices"]["choices"]}).
|
|
32
|
+
merge({"resource_path" => data["path"]})
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
class DataItemValue < Parser
|
|
37
|
+
def self.process(data)
|
|
38
|
+
data_item_value = data["itemValue"]
|
|
39
|
+
data_item_value.merge({"resource_path" => data["path"]})
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
class Drill < Parser
|
|
44
|
+
def self.process(data)
|
|
45
|
+
choices = {"choices", data["choices"].delete("choices")}
|
|
46
|
+
data.merge(choices).merge({"choice_name" => data["choices"].delete("name")})
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
class Profiles < Parser
|
|
51
|
+
def self.process(data)
|
|
52
|
+
data["profiles"]
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
class ProfileCategory < Parser
|
|
57
|
+
def self.process(data)
|
|
58
|
+
profile_categories = {"profile_categories" => data["children"].delete("dataCategories")}
|
|
59
|
+
profile_items = {"profile_items" => data["children"].delete("profileItems")}
|
|
60
|
+
data.merge(profile_items).merge(profile_categories).
|
|
61
|
+
merge({"resource_path" => data["path"]})
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
class ProfileItem < Parser
|
|
66
|
+
def self.process(data)
|
|
67
|
+
data["profileItem"].merge({"resource_path" => data["path"]})
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
class CreateProfile < Parser
|
|
72
|
+
def self.process(data)
|
|
73
|
+
data["profile"].
|
|
74
|
+
merge({"resource_path" => data["path"]})
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
class UpdateProfile < Parser
|
|
79
|
+
def self.process(data)
|
|
80
|
+
data["profile"].
|
|
81
|
+
merge({"resource_path" => data["path"]})
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
class DeleteProfile < Parser
|
|
86
|
+
def self.process(data)
|
|
87
|
+
data
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
class GetProfile < Parser
|
|
92
|
+
def self.process(data)
|
|
93
|
+
categories = {"profile_categories" => data["children"].delete("dataCategories")}
|
|
94
|
+
data["profile"].merge(categories).
|
|
95
|
+
merge({"resource_path" => data["path"]})
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
class CreateProfileItem < Parser
|
|
100
|
+
def self.process(data)
|
|
101
|
+
data
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
class DeleteProfileItem < Parser
|
|
106
|
+
def self.process(data)
|
|
107
|
+
data
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
class Raw < Parser
|
|
113
|
+
def self.process(data)
|
|
114
|
+
data
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
class Parser
|
|
119
|
+
PARSERS = {
|
|
120
|
+
'data.category' => DataCategory,
|
|
121
|
+
'data.item' => DataItem,
|
|
122
|
+
"data.item_value" => DataItemValue,
|
|
123
|
+
"raw" => Raw,
|
|
124
|
+
"profiles" => Profiles,
|
|
125
|
+
"create.profile" =>CreateProfile,
|
|
126
|
+
"update.profile" => UpdateProfile,
|
|
127
|
+
"delete.profile" => DeleteProfile,
|
|
128
|
+
"create.profile_item" => CreateProfileItem,
|
|
129
|
+
"profile_category" => ProfileCategory,
|
|
130
|
+
"profile_item" => ProfileItem,
|
|
131
|
+
"delete.profile_item" => DeleteProfileItem,
|
|
132
|
+
"get.profile" => GetProfile,
|
|
133
|
+
"profile.category" => ProfileCategory,
|
|
134
|
+
"data.drill" => Drill
|
|
135
|
+
}
|
|
136
|
+
end
|
|
137
|
+
end
|