reflekt 0.4.0 → 0.9.0
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.
- checksums.yaml +4 -4
- data/lib/Execution.rb +45 -0
- data/lib/Reflection.rb +145 -0
- data/lib/ShadowStack.rb +56 -0
- data/lib/reflekt.rb +115 -79
- data/lib/web/script.js +8 -0
- data/lib/web/style.css +139 -0
- data/lib/web/template.html.erb +210 -0
- metadata +8 -3
- data/lib/template.html.erb +0 -20
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e4d3c0c32672fd8813482a3f546032904d3d6f65e592fd4435eb7ada2bb1b201
|
4
|
+
data.tar.gz: d48f2b100986c4408db5cb055f4ebf1e6a50d99fa99dc6d98e8af8e5d8bcd66e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1422110bc34f7b88f8b4ba71359c408d38f3ebf72235735e51864fd0bd16c32fd5abc20e5cfa8a516478932800590f80f7f1b7b4d0dac3c0ebd18a3d8dfffd54
|
7
|
+
data.tar.gz: 4019f5868ca20d1aebfa9e4ddb2c5136782aa52185588cb44558f4725f51ea59f90bc75896e8bfac383151d7346bb534d98bc00a11a569c350d0c460fe3b31ab
|
data/lib/Execution.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
class Execution
|
2
|
+
|
3
|
+
attr_accessor :object
|
4
|
+
attr_accessor :caller_id
|
5
|
+
attr_accessor :caller_class
|
6
|
+
attr_accessor :parent
|
7
|
+
attr_accessor :child
|
8
|
+
attr_accessor :reflections
|
9
|
+
attr_accessor :is_reflecting
|
10
|
+
|
11
|
+
def initialize(object, reflection_count)
|
12
|
+
|
13
|
+
@object = object
|
14
|
+
@caller_id = object.object_id
|
15
|
+
@caller_class = object.class
|
16
|
+
@parent = nil
|
17
|
+
@child = nil
|
18
|
+
|
19
|
+
@reflections = Array.new(reflection_count)
|
20
|
+
@is_reflecting = false
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
def has_empty_reflections?
|
25
|
+
@reflections.include? nil
|
26
|
+
end
|
27
|
+
|
28
|
+
##
|
29
|
+
# Is the Execution currently reflecting methods?
|
30
|
+
##
|
31
|
+
def is_reflecting?
|
32
|
+
@is_reflecting
|
33
|
+
end
|
34
|
+
|
35
|
+
def has_finished_reflecting?
|
36
|
+
if is_reflecting?
|
37
|
+
return false
|
38
|
+
end
|
39
|
+
if has_empty_reflections?
|
40
|
+
return false
|
41
|
+
end
|
42
|
+
return true
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
data/lib/Reflection.rb
ADDED
@@ -0,0 +1,145 @@
|
|
1
|
+
class Reflection
|
2
|
+
|
3
|
+
# Keys.
|
4
|
+
TIME = "t"
|
5
|
+
INPUT = "i"
|
6
|
+
OUTPUT = "o"
|
7
|
+
TYPE = "T"
|
8
|
+
COUNT = "C"
|
9
|
+
VALUE = "V"
|
10
|
+
STATUS = "s"
|
11
|
+
MESSAGE = "m"
|
12
|
+
# Values.
|
13
|
+
PASS = "p"
|
14
|
+
FAIL = "f"
|
15
|
+
|
16
|
+
attr_accessor :clone
|
17
|
+
|
18
|
+
def initialize(execution, method, is_control)
|
19
|
+
|
20
|
+
@execution = execution
|
21
|
+
@method = method
|
22
|
+
@is_control = is_control
|
23
|
+
|
24
|
+
# Clone the execution's object.
|
25
|
+
@clone = execution.object.clone
|
26
|
+
@clone_id = nil
|
27
|
+
|
28
|
+
# Result.
|
29
|
+
@status = nil
|
30
|
+
@time = Time.now.to_i
|
31
|
+
@input = []
|
32
|
+
@output = nil
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
##
|
37
|
+
# Reflect on a method.
|
38
|
+
#
|
39
|
+
# Creates a shadow execution stack.
|
40
|
+
#
|
41
|
+
# @param method - The name of the method.
|
42
|
+
# @param *args - The method arguments.
|
43
|
+
#
|
44
|
+
# @return - A reflection hash.
|
45
|
+
##
|
46
|
+
def reflect(*args)
|
47
|
+
|
48
|
+
# Reflect on real world arguments.
|
49
|
+
if @is_control
|
50
|
+
@input = *args
|
51
|
+
# Reflect on deviated arguments.
|
52
|
+
else
|
53
|
+
args.each do |arg|
|
54
|
+
case arg
|
55
|
+
when Integer
|
56
|
+
@input << rand(9999)
|
57
|
+
else
|
58
|
+
@input << arg
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# Action method with new arguments.
|
64
|
+
begin
|
65
|
+
@output = @clone.send(@method, *@input)
|
66
|
+
# When fail.
|
67
|
+
rescue StandardError => message
|
68
|
+
@status = MESSAGE
|
69
|
+
@message = message
|
70
|
+
# When pass.
|
71
|
+
else
|
72
|
+
@status = PASS
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
def result()
|
78
|
+
# Build reflection.
|
79
|
+
reflection = {
|
80
|
+
TIME => @time,
|
81
|
+
STATUS => @status,
|
82
|
+
INPUT => normalize_input(@input),
|
83
|
+
OUTPUT => normalize_output(@output),
|
84
|
+
MESSAGE => @message
|
85
|
+
}
|
86
|
+
end
|
87
|
+
|
88
|
+
##
|
89
|
+
# Normalize inputs.
|
90
|
+
#
|
91
|
+
# @param args - The actual inputs.
|
92
|
+
# @return - A generic inputs representation.
|
93
|
+
##
|
94
|
+
def normalize_input(args)
|
95
|
+
inputs = []
|
96
|
+
args.each do |arg|
|
97
|
+
input = {
|
98
|
+
TYPE => arg.class.to_s,
|
99
|
+
VALUE => normalize_value(arg)
|
100
|
+
}
|
101
|
+
if (arg.class == Array)
|
102
|
+
input[COUNT] = arg.count
|
103
|
+
end
|
104
|
+
inputs << input
|
105
|
+
end
|
106
|
+
inputs
|
107
|
+
end
|
108
|
+
|
109
|
+
##
|
110
|
+
# Normalize output.
|
111
|
+
#
|
112
|
+
# @param input - The actual output.
|
113
|
+
# @return - A generic output representation.
|
114
|
+
##
|
115
|
+
def normalize_output(input)
|
116
|
+
|
117
|
+
output = {
|
118
|
+
TYPE => input.class.to_s,
|
119
|
+
VALUE => normalize_value(input)
|
120
|
+
}
|
121
|
+
|
122
|
+
if (input.class == Array || input.class == Hash)
|
123
|
+
output[COUNT] = input.count
|
124
|
+
elsif (input.class == TrueClass || input.class == FalseClass)
|
125
|
+
output[TYPE] = :Boolean
|
126
|
+
end
|
127
|
+
|
128
|
+
return output
|
129
|
+
|
130
|
+
end
|
131
|
+
|
132
|
+
def normalize_value(value)
|
133
|
+
|
134
|
+
unless value.nil?
|
135
|
+
value = value.to_s.gsub(/\r?\n/, " ").to_s
|
136
|
+
if value.length >= 30
|
137
|
+
value = value[0, value.rindex(/\s/,30)].rstrip() + '...'
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
return value
|
142
|
+
|
143
|
+
end
|
144
|
+
|
145
|
+
end
|
data/lib/ShadowStack.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
################################################################################
|
2
|
+
# SHADOW STACK
|
3
|
+
#
|
4
|
+
# Track the executions in a call stack.
|
5
|
+
################################################################################
|
6
|
+
|
7
|
+
class ShadowStack
|
8
|
+
|
9
|
+
def initialize()
|
10
|
+
@bottom = nil
|
11
|
+
@top = nil
|
12
|
+
end
|
13
|
+
|
14
|
+
def peek()
|
15
|
+
@top
|
16
|
+
end
|
17
|
+
|
18
|
+
def base()
|
19
|
+
@bottom
|
20
|
+
end
|
21
|
+
|
22
|
+
##
|
23
|
+
# Push Execution.
|
24
|
+
#
|
25
|
+
# @param object - The object being executed.
|
26
|
+
# @param args - The arguments being executed.
|
27
|
+
#
|
28
|
+
# @return Execution - The new execution.
|
29
|
+
##
|
30
|
+
def push(execution)
|
31
|
+
|
32
|
+
# Reference previous execution.
|
33
|
+
if @bottom.nil?
|
34
|
+
@bottom = execution
|
35
|
+
else
|
36
|
+
execution.child = @top
|
37
|
+
@top.parent = execution
|
38
|
+
end
|
39
|
+
|
40
|
+
# Place new execution at the top of the stack.
|
41
|
+
@top = execution
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
def display
|
46
|
+
display_execution_tree(@bottom)
|
47
|
+
end
|
48
|
+
|
49
|
+
def display_execution_tree(execution)
|
50
|
+
p execution
|
51
|
+
unless execution.parent == nil
|
52
|
+
display_execution_tree(execution.parent)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
data/lib/reflekt.rb
CHANGED
@@ -1,11 +1,19 @@
|
|
1
1
|
require 'set'
|
2
2
|
require 'erb'
|
3
3
|
require 'rowdb'
|
4
|
+
require 'Execution'
|
5
|
+
require 'Reflection'
|
6
|
+
require 'ShadowStack'
|
4
7
|
|
5
8
|
################################################################################
|
6
9
|
# REFLEKT
|
7
10
|
#
|
8
|
-
#
|
11
|
+
# An Execution is created each time a method is called.
|
12
|
+
# Multiple Refections are created per Execution.
|
13
|
+
# These Reflections execute on a ShadowStack on cloned objects.
|
14
|
+
# Then flow is returned to the original method and normal execution continues.
|
15
|
+
#
|
16
|
+
# Usage:
|
9
17
|
#
|
10
18
|
# class ExampleClass
|
11
19
|
# prepend Reflekt
|
@@ -13,131 +21,155 @@ require 'rowdb'
|
|
13
21
|
|
14
22
|
module Reflekt
|
15
23
|
|
16
|
-
|
24
|
+
# The amount of reflections to create per method call.
|
25
|
+
@@reflekt_reflect_amount = 2
|
26
|
+
|
27
|
+
# Limit the amount of reflections that can be created per instance method.
|
28
|
+
# A method called thousands of times doesn't need that many reflections.
|
29
|
+
@@reflection_limit = 10
|
17
30
|
|
18
31
|
def initialize(*args)
|
19
32
|
|
20
|
-
@
|
21
|
-
@reflekt_clones = []
|
33
|
+
@reflection_counts = {}
|
22
34
|
|
23
|
-
#
|
35
|
+
# Get instance methods.
|
36
|
+
# TODO: Include parent methods like "Array.include?".
|
24
37
|
self.class.instance_methods(false).each do |method|
|
38
|
+
|
39
|
+
# Don't process skipped methods.
|
40
|
+
next if self.class.reflekt_skipped?(method)
|
41
|
+
|
42
|
+
@reflection_counts[method] = 0
|
43
|
+
|
44
|
+
# When method called in flow.
|
25
45
|
self.define_singleton_method(method) do |*args|
|
26
46
|
|
27
|
-
#
|
28
|
-
|
29
|
-
|
47
|
+
# Don't reflect when limit reached.
|
48
|
+
unless @reflection_counts[method] >= @@reflection_limit
|
49
|
+
|
50
|
+
# Get current execution.
|
51
|
+
execution = @@reflekt_stack.peek()
|
52
|
+
|
53
|
+
# When stack empty or past execution done reflecting.
|
54
|
+
if execution.nil? || execution.has_finished_reflecting?
|
55
|
+
|
56
|
+
# Create execution.
|
57
|
+
execution = Execution.new(self, @@reflekt_reflect_amount)
|
58
|
+
@@reflekt_stack.push(execution)
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
# Reflect.
|
63
|
+
# The first method call in the Execution creates a Reflection.
|
64
|
+
# Subsequent method calls are shadow executions on cloned objects.
|
65
|
+
if execution.has_empty_reflections? && !execution.is_reflecting?
|
66
|
+
execution.is_reflecting = true
|
67
|
+
|
68
|
+
# Multiple reflections per execution.
|
69
|
+
execution.reflections.each_with_index do |value, index|
|
70
|
+
|
71
|
+
# Flag first reflection is a control.
|
72
|
+
is_control = false
|
73
|
+
is_control = true if index == 0
|
74
|
+
|
75
|
+
# Create reflection.
|
76
|
+
reflection = Reflection.new(execution, method, is_control)
|
77
|
+
execution.reflections[index] = reflection
|
78
|
+
|
79
|
+
# Execute reflection.
|
80
|
+
reflection.reflect(*args)
|
81
|
+
|
82
|
+
# Add result.
|
83
|
+
class_name = execution.caller_class.to_s
|
84
|
+
method_name = method.to_s
|
85
|
+
@@reflekt_db.get("#{class_name}.#{method_name}").push(reflection.result())
|
30
86
|
|
31
|
-
# Reflekt on method.
|
32
|
-
@reflekt_clones.each do |clone|
|
33
|
-
reflekt_action(clone, method, *args)
|
34
87
|
end
|
35
88
|
|
36
89
|
# Save results.
|
37
90
|
@@reflekt_db.write()
|
38
91
|
|
39
92
|
# Render results.
|
40
|
-
|
41
|
-
template = File.read("#{@@reflekt_path}/template.html.erb")
|
42
|
-
rendered = ERB.new(template).result(binding)
|
43
|
-
|
44
|
-
# Write results.
|
45
|
-
File.open("#{@@reflekt_output_path}/index.html", 'w+') do |f|
|
46
|
-
f.write rendered
|
47
|
-
end
|
93
|
+
reflekt_render()
|
48
94
|
|
95
|
+
execution.is_reflecting = false
|
49
96
|
end
|
97
|
+
|
50
98
|
end
|
51
99
|
|
52
|
-
|
100
|
+
@reflection_counts[method] = @reflection_counts[method] + 1
|
101
|
+
|
102
|
+
# Continue execution / shadow execution.
|
53
103
|
super *args
|
104
|
+
|
54
105
|
end
|
55
106
|
|
56
107
|
end
|
57
108
|
|
58
|
-
# Continue
|
109
|
+
# Continue initialization.
|
59
110
|
super
|
60
111
|
|
61
|
-
# Create forks.
|
62
|
-
reflekt_fork()
|
63
|
-
|
64
112
|
end
|
65
113
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
end
|
71
|
-
|
72
|
-
@reflekt_forked = true
|
73
|
-
|
74
|
-
end
|
114
|
+
##
|
115
|
+
# Render results.
|
116
|
+
##
|
117
|
+
def reflekt_render()
|
75
118
|
|
76
|
-
|
119
|
+
# Get JSON.
|
120
|
+
@@reflekt_json = File.read("#{@@reflekt_output_path}/db.json")
|
77
121
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
#
|
82
|
-
|
83
|
-
args.each do |arg|
|
84
|
-
case arg
|
85
|
-
when Integer
|
86
|
-
new_args << rand(9999)
|
87
|
-
else
|
88
|
-
new_args << arg
|
89
|
-
end
|
122
|
+
# Save HTML.
|
123
|
+
template = File.read("#{@@reflekt_path}/web/template.html.erb")
|
124
|
+
rendered = ERB.new(template).result(binding)
|
125
|
+
File.open("#{@@reflekt_output_path}/index.html", 'w+') do |f|
|
126
|
+
f.write rendered
|
90
127
|
end
|
91
128
|
|
92
|
-
#
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
# Build reflection.
|
97
|
-
reflection = {
|
98
|
-
"time" => Time.now.to_i,
|
99
|
-
}
|
100
|
-
# When error.
|
101
|
-
rescue StandardError => error
|
102
|
-
reflection["status"] = "error"
|
103
|
-
reflection["error"] = error
|
104
|
-
# When success.
|
105
|
-
else
|
106
|
-
reflection["status"] = "success"
|
129
|
+
# Add JS.
|
130
|
+
javascript = File.read("#{@@reflekt_path}/web/script.js")
|
131
|
+
File.open("#{@@reflekt_output_path}/script.js", 'w+') do |f|
|
132
|
+
f.write javascript
|
107
133
|
end
|
108
134
|
|
109
|
-
#
|
110
|
-
|
111
|
-
|
135
|
+
# Add CSS.
|
136
|
+
stylesheet = File.read("#{@@reflekt_path}/web/style.css")
|
137
|
+
File.open("#{@@reflekt_output_path}/style.css", 'w+') do |f|
|
138
|
+
f.write stylesheet
|
139
|
+
end
|
112
140
|
|
113
141
|
end
|
114
142
|
|
115
143
|
private
|
116
144
|
|
117
|
-
# Prepend Klass to the instance's singleton class.
|
118
145
|
def self.prepended(base)
|
119
|
-
|
146
|
+
# Prepend class methods to the instance's singleton class.
|
147
|
+
base.singleton_class.prepend(SingletonClassMethods)
|
120
148
|
|
121
|
-
@@reflekt_setup ||=
|
149
|
+
@@reflekt_setup ||= reflekt_setup_class
|
122
150
|
end
|
123
151
|
|
124
|
-
# Setup
|
125
|
-
def self.
|
152
|
+
# Setup class.
|
153
|
+
def self.reflekt_setup_class()
|
126
154
|
|
127
|
-
# Receive configuration
|
155
|
+
# Receive configuration.
|
128
156
|
$ENV ||= {}
|
129
157
|
$ENV[:reflekt] ||= $ENV[:reflekt] = {}
|
130
158
|
|
159
|
+
# Set configuration.
|
131
160
|
@@reflekt_path = File.dirname(File.realpath(__FILE__))
|
132
161
|
|
133
|
-
# Create
|
162
|
+
# Create reflection tree.
|
163
|
+
@@reflekt_stack = ShadowStack.new()
|
164
|
+
|
165
|
+
# Build reflections directory.
|
134
166
|
if $ENV[:reflekt][:output_path]
|
135
167
|
@@reflekt_output_path = File.join($ENV[:reflekt][:output_path], 'reflections')
|
136
|
-
#
|
168
|
+
# Build reflections directory in current execution path.
|
137
169
|
else
|
138
170
|
@@reflekt_output_path = File.join(Dir.pwd, 'reflections')
|
139
171
|
end
|
140
|
-
|
172
|
+
# Create reflections directory.
|
141
173
|
unless Dir.exist? @@reflekt_output_path
|
142
174
|
Dir.mkdir(@@reflekt_output_path)
|
143
175
|
end
|
@@ -149,24 +181,28 @@ module Reflekt
|
|
149
181
|
return true
|
150
182
|
end
|
151
183
|
|
152
|
-
module
|
184
|
+
module SingletonClassMethods
|
153
185
|
|
154
|
-
@@
|
186
|
+
@@reflekt_skipped_methods = Set.new
|
155
187
|
|
156
188
|
##
|
157
189
|
# Skip a method.
|
158
190
|
#
|
159
|
-
# method - A symbol representing the method name.
|
191
|
+
# @param method - A symbol representing the method name.
|
160
192
|
##
|
161
193
|
def reflekt_skip(method)
|
162
|
-
@@
|
194
|
+
@@reflekt_skipped_methods.add(method)
|
163
195
|
end
|
164
196
|
|
165
|
-
def
|
166
|
-
return true if @@
|
197
|
+
def reflekt_skipped?(method)
|
198
|
+
return true if @@reflekt_skipped_methods.include?(method)
|
167
199
|
false
|
168
200
|
end
|
169
201
|
|
202
|
+
def reflekt_limit(amount)
|
203
|
+
@@reflection_limit = amount
|
204
|
+
end
|
205
|
+
|
170
206
|
end
|
171
207
|
|
172
208
|
end
|
data/lib/web/script.js
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
/**
|
2
|
+
* Minified by jsDelivr using Terser v3.14.1.
|
3
|
+
* Original file: /gh/alpinejs/alpine@2.6.0/dist/alpine.js
|
4
|
+
*
|
5
|
+
* Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files
|
6
|
+
*/
|
7
|
+
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e=e||self).Alpine=t()}(this,function(){"use strict";function e(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function t(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),n.push.apply(n,i)}return n}function n(n){for(var i=1;i<arguments.length;i++){var r=null!=arguments[i]?arguments[i]:{};i%2?t(Object(r),!0).forEach(function(t){e(n,t,r[t])}):Object.getOwnPropertyDescriptors?Object.defineProperties(n,Object.getOwnPropertyDescriptors(r)):t(Object(r)).forEach(function(e){Object.defineProperty(n,e,Object.getOwnPropertyDescriptor(r,e))})}return n}function i(e){return Array.from(new Set(e))}function r(){return navigator.userAgent.includes("Node.js")||navigator.userAgent.includes("jsdom")}function s(e,t){"template"!==e.tagName.toLowerCase()?console.warn(`Alpine: [${t}] directive should only be added to <template> tags. See https://github.com/alpinejs/alpine#${t}`):1!==e.content.childElementCount&&console.warn(`Alpine: <template> tag with [${t}] encountered with multiple element roots. Make sure <template> only has a single child node.`)}function o(e){return e.toLowerCase().replace(/-(\w)/g,(e,t)=>t.toUpperCase())}function a(e,t){var n;return function(){var i=this,r=arguments;clearTimeout(n),n=setTimeout(function(){n=null,e.apply(i,r)},t)}}function l(e,t,n={}){return"function"==typeof e?e.call(t):new Function(["$data",...Object.keys(n)],`var __alpine_result; with($data) { __alpine_result = ${e} }; return __alpine_result`)(t,...Object.values(n))}const c=/^x-(on|bind|data|text|html|model|if|for|show|cloak|transition|ref|spread)\b/;function u(e){const t=m(e.name);return c.test(t)}function d(e,t,n){let i=Array.from(e.attributes).filter(u).map(f),r=i.filter(e=>"spread"===e.type)[0];if(r){let e=l(r.expression,t.$data);i=i.concat(Object.entries(e).map(([e,t])=>f({name:e,value:t})))}return n?i.filter(e=>e.type===n):function(e){let t=["bind","model","show","catch-all"];return e.sort((e,n)=>{let i=-1===t.indexOf(e.type)?"catch-all":e.type,r=-1===t.indexOf(n.type)?"catch-all":n.type;return t.indexOf(i)-t.indexOf(r)})}(i)}function f({name:e,value:t}){const n=m(e),i=n.match(c),r=n.match(/:([a-zA-Z0-9\-:]+)/),s=n.match(/\.[^.\]]+(?=[^\]]*$)/g)||[];return{type:i?i[1]:null,value:r?r[1]:null,modifiers:s.map(e=>e.replace(".","")),expression:t}}function m(e){return e.startsWith("@")?e.replace("@","x-on:"):e.startsWith(":")?e.replace(":","x-bind:"):e}function p(e,t=Boolean){return e.split(" ").filter(t)}const h="in",v="out";function b(e,t,n,i=!1){if(i)return t();if(e.__x_transition&&e.__x_transition.type===h)return;const r=d(e,n,"transition"),s=d(e,n,"show")[0];if(s&&s.modifiers.includes("transition")){let n=s.modifiers;if(n.includes("out")&&!n.includes("in"))return t();const i=n.includes("in")&&n.includes("out");(function(e,t,n){const i={duration:g(t,"duration",150),origin:g(t,"origin","center"),first:{opacity:0,scale:g(t,"scale",95)},second:{opacity:1,scale:100}};x(e,t,n,()=>{},i,h)})(e,n=i?n.filter((e,t)=>t<n.indexOf("out")):n,t)}else r.some(e=>["enter","enter-start","enter-end"].includes(e.value))?function(e,t,n,i){let r=n=>"function"==typeof n?t.evaluateReturnExpression(e,n):n;const s=p(r((n.find(e=>"enter"===e.value)||{expression:""}).expression)),o=p(r((n.find(e=>"enter-start"===e.value)||{expression:""}).expression)),a=p(r((n.find(e=>"enter-end"===e.value)||{expression:""}).expression));_(e,s,o,a,i,()=>{},h)}(e,n,r,t):t()}function y(e,t,n,i=!1){if(i)return t();if(e.__x_transition&&e.__x_transition.type===v)return;const r=d(e,n,"transition"),s=d(e,n,"show")[0];if(s&&s.modifiers.includes("transition")){let n=s.modifiers;if(n.includes("in")&&!n.includes("out"))return t();const i=n.includes("in")&&n.includes("out");(function(e,t,n,i){const r={duration:n?g(t,"duration",150):g(t,"duration",150)/2,origin:g(t,"origin","center"),first:{opacity:1,scale:100},second:{opacity:0,scale:g(t,"scale",95)}};x(e,t,()=>{},i,r,v)})(e,n=i?n.filter((e,t)=>t>n.indexOf("out")):n,i,t)}else r.some(e=>["leave","leave-start","leave-end"].includes(e.value))?function(e,t,n,i){const r=p((n.find(e=>"leave"===e.value)||{expression:""}).expression),s=p((n.find(e=>"leave-start"===e.value)||{expression:""}).expression),o=p((n.find(e=>"leave-end"===e.value)||{expression:""}).expression);_(e,r,s,o,()=>{},i,v)}(e,0,r,t):t()}function g(e,t,n){if(-1===e.indexOf(t))return n;const i=e[e.indexOf(t)+1];if(!i)return n;if("scale"===t&&!E(i))return n;if("duration"===t){let e=i.match(/([0-9]+)ms/);if(e)return e[1]}return"origin"===t&&["top","right","left","center","bottom"].includes(e[e.indexOf(t)+2])?[i,e[e.indexOf(t)+2]].join(" "):i}function x(e,t,n,i,r,s){e.__x_transition&&(cancelAnimationFrame(e.__x_transition.nextFrame),e.__x_transition.callback&&e.__x_transition.callback());const o=e.style.opacity,a=e.style.transform,l=e.style.transformOrigin,c=!t.includes("opacity")&&!t.includes("scale"),u=c||t.includes("opacity"),d=c||t.includes("scale"),f={start(){u&&(e.style.opacity=r.first.opacity),d&&(e.style.transform=`scale(${r.first.scale/100})`)},during(){d&&(e.style.transformOrigin=r.origin),e.style.transitionProperty=[u?"opacity":"",d?"transform":""].join(" ").trim(),e.style.transitionDuration=`${r.duration/1e3}s`,e.style.transitionTimingFunction="cubic-bezier(0.4, 0.0, 0.2, 1)"},show(){n()},end(){u&&(e.style.opacity=r.second.opacity),d&&(e.style.transform=`scale(${r.second.scale/100})`)},hide(){i()},cleanup(){u&&(e.style.opacity=o),d&&(e.style.transform=a),d&&(e.style.transformOrigin=l),e.style.transitionProperty=null,e.style.transitionDuration=null,e.style.transitionTimingFunction=null}};w(e,f,s)}function _(e,t,n,i,r,s,o){e.__x_transition&&(cancelAnimationFrame(e.__x_transition.nextFrame),e.__x_transition.callback&&e.__x_transition.callback());const a=e.__x_original_classes||[],l={start(){e.classList.add(...n)},during(){e.classList.add(...t)},show(){r()},end(){e.classList.remove(...n.filter(e=>!a.includes(e))),e.classList.add(...i)},hide(){s()},cleanup(){e.classList.remove(...t.filter(e=>!a.includes(e))),e.classList.remove(...i.filter(e=>!a.includes(e)))}};w(e,l,o)}function w(e,t,n){e.__x_transition={type:n,callback:O(()=>{t.hide(),e.isConnected&&t.cleanup(),delete e.__x_transition}),nextFrame:null},t.start(),t.during(),e.__x_transition.nextFrame=requestAnimationFrame(()=>{let n=1e3*Number(getComputedStyle(e).transitionDuration.replace(/,.*/,"").replace("s",""));0===n&&(n=1e3*Number(getComputedStyle(e).animationDuration.replace("s",""))),t.show(),e.__x_transition.nextFrame=requestAnimationFrame(()=>{t.end(),setTimeout(e.__x_transition.callback,n)})})}function E(e){return!isNaN(e)}function O(e){let t=!1;return function(){t||(t=!0,e.apply(this,arguments))}}function k(e,t,i,r,o){s(t,"x-for");let a=A("function"==typeof i?e.evaluateReturnExpression(t,i):i),l=function(e,t,n,i){let r=d(t,e,"if")[0];if(r&&!e.evaluateReturnExpression(t,r.expression))return[];return e.evaluateReturnExpression(t,n.items,i)}(e,t,a,o),c=t;l.forEach((i,s)=>{let u=function(e,t,i,r,s){let o=s?n({},s):{};o[e.item]=t,e.index&&(o[e.index]=i);e.collection&&(o[e.collection]=r);return o}(a,i,s,l,o()),f=function(e,t,n,i){let r=d(t,e,"bind").filter(e=>"key"===e.value)[0];return r?e.evaluateReturnExpression(t,r.expression,()=>i):n}(e,t,s,u),m=function(e,t){if(!e)return;if(e.__x_for_key===t)return e;let n=e;for(;n;){if(n.__x_for_key===t)return n.parentElement.insertBefore(n,e);n=!(!n.nextElementSibling||void 0===n.nextElementSibling.__x_for_key)&&n.nextElementSibling}}(c.nextElementSibling,f);m?(delete m.__x_for_key,m.__x_for=u,e.updateElements(m,()=>m.__x_for)):(b(m=function(e,t){let n=document.importNode(e.content,!0);return t.parentElement.insertBefore(n,t.nextElementSibling),t.nextElementSibling}(t,c),()=>{},e,r),m.__x_for=u,e.initializeElements(m,()=>m.__x_for)),(c=m).__x_for_key=f}),function(e,t){var n=!(!e.nextElementSibling||void 0===e.nextElementSibling.__x_for_key)&&e.nextElementSibling;for(;n;){let e=n,i=n.nextElementSibling;y(n,()=>{e.remove()},t),n=!(!i||void 0===i.__x_for_key)&&i}}(c,e)}function A(e){let t=/,([^,\}\]]*)(?:,([^,\}\]]*))?$/,n=e.match(/([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/);if(!n)return;let i={};i.items=n[2].trim();let r=n[1].trim().replace(/^\(|\)$/g,""),s=r.match(t);return s?(i.item=r.replace(t,"").trim(),i.index=s[1].trim(),s[2]&&(i.collection=s[2].trim())):i.item=r,i}function S(e,t,n,r,s,a,l){var c=e.evaluateReturnExpression(t,r,s);if("value"===n){if(me.ignoreFocusedForValueBinding&&document.activeElement.isSameNode(t))return;if(void 0===c&&r.match(/\./)&&(c=""),"radio"===t.type)void 0===t.attributes.value&&"bind"===a?t.value=c:"bind"!==a&&(t.checked=t.value==c);else if("checkbox"===t.type)"string"==typeof c&&"bind"===a?t.value=c:"bind"!==a&&(Array.isArray(c)?t.checked=c.some(e=>e==t.value):t.checked=!!c);else if("SELECT"===t.tagName)!function(e,t){const n=[].concat(t).map(e=>e+"");Array.from(e.options).forEach(e=>{e.selected=n.includes(e.value||e.text)})}(t,c);else{if(t.value===c)return;t.value=c}}else if("class"===n)if(Array.isArray(c)){const e=t.__x_original_classes||[];t.setAttribute("class",i(e.concat(c)).join(" "))}else if("object"==typeof c){Object.keys(c).sort((e,t)=>c[e]-c[t]).forEach(e=>{c[e]?p(e).forEach(e=>t.classList.add(e)):p(e).forEach(e=>t.classList.remove(e))})}else{const e=t.__x_original_classes||[],n=p(c);t.setAttribute("class",i(e.concat(n)).join(" "))}else n=l.includes("camel")?o(n):n,[null,void 0,!1].includes(c)?t.removeAttribute(n):!function(e){return["disabled","checked","required","readonly","hidden","open","selected","autofocus","itemscope","multiple","novalidate","allowfullscreen","allowpaymentrequest","formnovalidate","autoplay","controls","loop","muted","playsinline","default","ismap","reversed","async","defer","nomodule"].includes(e)}(n)?$(t,n,c):$(t,n,n)}function $(e,t,n){e.getAttribute(t)!=n&&e.setAttribute(t,n)}function P(e,t,n,i,r,s={}){const l={passive:i.includes("passive")};if(i.includes("camel")&&(n=o(n)),i.includes("away")){let o=a=>{t.contains(a.target)||t.offsetWidth<1&&t.offsetHeight<1||(C(e,r,a,s),i.includes("once")&&document.removeEventListener(n,o,l))};document.addEventListener(n,o,l)}else{let o=i.includes("window")?window:i.includes("document")?document:t,c=a=>{if(o!==window&&o!==document||document.body.contains(t)){if(!(function(e){return["keydown","keyup"].includes(e)}(n)&&function(e,t){let n=t.filter(e=>!["window","document","prevent","stop"].includes(e));if(n.includes("debounce")){let e=n.indexOf("debounce");n.splice(e,E((n[e+1]||"invalid-wait").split("ms")[0])?2:1)}if(0===n.length)return!1;if(1===n.length&&n[0]===D(e.key))return!1;const i=["ctrl","shift","alt","meta","cmd","super"].filter(e=>n.includes(e));if(n=n.filter(e=>!i.includes(e)),i.length>0){const t=i.filter(t=>("cmd"!==t&&"super"!==t||(t="meta"),e[`${t}Key`]));if(t.length===i.length&&n[0]===D(e.key))return!1}return!0}(a,i)||(i.includes("prevent")&&a.preventDefault(),i.includes("stop")&&a.stopPropagation(),i.includes("self")&&a.target!==t))){C(e,r,a,s).then(e=>{!1===e?a.preventDefault():i.includes("once")&&o.removeEventListener(n,c,l)})}}else o.removeEventListener(n,c,l)};if(i.includes("debounce")){let e=i[i.indexOf("debounce")+1]||"invalid-wait",t=E(e.split("ms")[0])?Number(e.split("ms")[0]):250;c=a(c,t)}o.addEventListener(n,c,l)}}function C(e,t,i,r){return e.evaluateCommandExpression(i.target,t,()=>n(n({},r()),{},{$event:i}))}function D(e){switch(e){case"/":return"slash";case" ":case"Spacebar":return"space";default:return e&&e.replace(/([a-z])([A-Z])/g,"$1-$2").replace(/[_\s]/,"-").toLowerCase()}}function j(e,t,n){return"radio"===e.type&&(e.hasAttribute("name")||e.setAttribute("name",n)),(n,i)=>{if(n instanceof CustomEvent&&n.detail)return n.detail;if("checkbox"===e.type){if(Array.isArray(i)){const e=t.includes("number")?T(n.target.value):n.target.value;return n.target.checked?i.concat([e]):i.filter(t=>t!==e)}return n.target.checked}if("select"===e.tagName.toLowerCase()&&e.multiple)return t.includes("number")?Array.from(n.target.selectedOptions).map(e=>{return T(e.value||e.text)}):Array.from(n.target.selectedOptions).map(e=>e.value||e.text);{const e=n.target.value;return t.includes("number")?T(e):t.includes("trim")?e.trim():e}}}function T(e){const t=e?parseFloat(e):null;return E(t)?t:e}const{isArray:L}=Array,{getPrototypeOf:N,create:z,defineProperty:R,defineProperties:F,isExtensible:I,getOwnPropertyDescriptor:M,getOwnPropertyNames:B,getOwnPropertySymbols:U,preventExtensions:q,hasOwnProperty:W}=Object,{push:K,concat:G,map:H}=Array.prototype;function V(e){return void 0===e}function Z(e){return"function"==typeof e}const J=new WeakMap;function Q(e,t){J.set(e,t)}const X=e=>J.get(e)||e;function Y(e,t){return e.valueIsObservable(t)?e.getProxy(t):t}function ee(e,t,n){G.call(B(n),U(n)).forEach(i=>{let r=M(n,i);r.configurable||(r=ue(e,r,Y)),R(t,i,r)}),q(t)}class te{constructor(e,t){this.originalTarget=t,this.membrane=e}get(e,t){const{originalTarget:n,membrane:i}=this,r=n[t],{valueObserved:s}=i;return s(n,t),i.getProxy(r)}set(e,t,n){const{originalTarget:i,membrane:{valueMutated:r}}=this;return i[t]!==n?(i[t]=n,r(i,t)):"length"===t&&L(i)&&r(i,t),!0}deleteProperty(e,t){const{originalTarget:n,membrane:{valueMutated:i}}=this;return delete n[t],i(n,t),!0}apply(e,t,n){}construct(e,t,n){}has(e,t){const{originalTarget:n,membrane:{valueObserved:i}}=this;return i(n,t),t in n}ownKeys(e){const{originalTarget:t}=this;return G.call(B(t),U(t))}isExtensible(e){const t=I(e);if(!t)return t;const{originalTarget:n,membrane:i}=this,r=I(n);return r||ee(i,e,n),r}setPrototypeOf(e,t){}getPrototypeOf(e){const{originalTarget:t}=this;return N(t)}getOwnPropertyDescriptor(e,t){const{originalTarget:n,membrane:i}=this,{valueObserved:r}=this.membrane;r(n,t);let s=M(n,t);if(V(s))return s;const o=M(e,t);return V(o)?((s=ue(i,s,Y)).configurable||R(e,t,s),s):o}preventExtensions(e){const{originalTarget:t,membrane:n}=this;return ee(n,e,t),q(t),!0}defineProperty(e,t,n){const{originalTarget:i,membrane:r}=this,{valueMutated:s}=r,{configurable:o}=n;if(W.call(n,"writable")&&!W.call(n,"value")){const e=M(i,t);n.value=e.value}return R(i,t,function(e){return W.call(e,"value")&&(e.value=X(e.value)),e}(n)),!1===o&&R(e,t,ue(r,n,Y)),s(i,t),!0}}function ne(e,t){return e.valueIsObservable(t)?e.getReadOnlyProxy(t):t}class ie{constructor(e,t){this.originalTarget=t,this.membrane=e}get(e,t){const{membrane:n,originalTarget:i}=this,r=i[t],{valueObserved:s}=n;return s(i,t),n.getReadOnlyProxy(r)}set(e,t,n){return!1}deleteProperty(e,t){return!1}apply(e,t,n){}construct(e,t,n){}has(e,t){const{originalTarget:n,membrane:{valueObserved:i}}=this;return i(n,t),t in n}ownKeys(e){const{originalTarget:t}=this;return G.call(B(t),U(t))}setPrototypeOf(e,t){}getOwnPropertyDescriptor(e,t){const{originalTarget:n,membrane:i}=this,{valueObserved:r}=i;r(n,t);let s=M(n,t);if(V(s))return s;const o=M(e,t);return V(o)?(s=ue(i,s,ne),W.call(s,"set")&&(s.set=void 0),s.configurable||R(e,t,s),s):o}preventExtensions(e){return!1}defineProperty(e,t,n){return!1}}function re(e){let t=void 0;return L(e)?t=[]:"object"==typeof e&&(t={}),t}const se=Object.prototype;function oe(e){if(null===e)return!1;if("object"!=typeof e)return!1;if(L(e))return!0;const t=N(e);return t===se||null===t||null===N(t)}const ae=(e,t)=>{},le=(e,t)=>{},ce=e=>e;function ue(e,t,n){const{set:i,get:r}=t;return W.call(t,"value")?t.value=n(e,t.value):(V(r)||(t.get=function(){return n(e,r.call(X(this)))}),V(i)||(t.set=function(t){i.call(X(this),e.unwrapProxy(t))})),t}class de{constructor(e){if(this.valueDistortion=ce,this.valueMutated=le,this.valueObserved=ae,this.valueIsObservable=oe,this.objectGraph=new WeakMap,!V(e)){const{valueDistortion:t,valueMutated:n,valueObserved:i,valueIsObservable:r}=e;this.valueDistortion=Z(t)?t:ce,this.valueMutated=Z(n)?n:le,this.valueObserved=Z(i)?i:ae,this.valueIsObservable=Z(r)?r:oe}}getProxy(e){const t=X(e),n=this.valueDistortion(t);if(this.valueIsObservable(n)){const i=this.getReactiveState(t,n);return i.readOnly===e?e:i.reactive}return n}getReadOnlyProxy(e){e=X(e);const t=this.valueDistortion(e);return this.valueIsObservable(t)?this.getReactiveState(e,t).readOnly:t}unwrapProxy(e){return X(e)}getReactiveState(e,t){const{objectGraph:n}=this;let i=n.get(t);if(i)return i;const r=this;return i={get reactive(){const n=new te(r,t),i=new Proxy(re(t),n);return Q(i,e),R(this,"reactive",{value:i}),i},get readOnly(){const n=new ie(r,t),i=new Proxy(re(t),n);return Q(i,e),R(this,"readOnly",{value:i}),i}},n.set(t,i),i}}class fe{constructor(e,t=null){this.$el=e;const n=this.$el.getAttribute("x-data"),i=""===n?"{}":n,r=this.$el.getAttribute("x-init");let s={$el:this.$el},o=t?t.$el:this.$el;Object.entries(me.magicProperties).forEach(([e,t])=>{Object.defineProperty(s,`$${e}`,{get:function(){return t(o)}})}),this.unobservedData=t?t.getUnobservedData():l(i,s);let{membrane:a,data:c}=this.wrapDataInObservable(this.unobservedData);var u;this.$data=c,this.membrane=a,this.unobservedData.$el=this.$el,this.unobservedData.$refs=this.getRefsProxy(),this.nextTickStack=[],this.unobservedData.$nextTick=(e=>{this.nextTickStack.push(e)}),this.watchers={},this.unobservedData.$watch=((e,t)=>{this.watchers[e]||(this.watchers[e]=[]),this.watchers[e].push(t)}),Object.entries(me.magicProperties).forEach(([e,t])=>{Object.defineProperty(this.unobservedData,`$${e}`,{get:function(){return t(o)}})}),this.showDirectiveStack=[],this.showDirectiveLastElement,t||me.onBeforeComponentInitializeds.forEach(e=>e(this)),r&&!t&&(this.pauseReactivity=!0,u=this.evaluateReturnExpression(this.$el,r),this.pauseReactivity=!1),this.initializeElements(this.$el),this.listenForNewElementsToInitialize(),"function"==typeof u&&u.call(this.$data),t||setTimeout(()=>{me.onComponentInitializeds.forEach(e=>e(this))},0)}getUnobservedData(){return function(e,t){let n=e.unwrapProxy(t),i={};return Object.keys(n).forEach(e=>{["$el","$refs","$nextTick","$watch"].includes(e)||(i[e]=n[e])}),i}(this.membrane,this.$data)}wrapDataInObservable(e){var t=this;let n=a(function(){t.updateElements(t.$el)},0);return function(e,t){let n=new de({valueMutated(e,n){t(e,n)}});return{data:n.getProxy(e),membrane:n}}(e,(e,i)=>{t.watchers[i]?t.watchers[i].forEach(t=>t(e[i])):Object.keys(t.watchers).filter(e=>e.includes(".")).forEach(n=>{let r=n.split(".");i===r[r.length-1]&&r.reduce((r,s)=>(Object.is(e,r)&&t.watchers[n].forEach(t=>t(e[i])),r[s]),t.getUnobservedData())}),t.pauseReactivity||n()})}walkAndSkipNestedComponents(e,t,n=(()=>{})){!function e(t,n){if(!1===n(t))return;let i=t.firstElementChild;for(;i;)e(i,n),i=i.nextElementSibling}(e,e=>e.hasAttribute("x-data")&&!e.isSameNode(this.$el)?(e.__x||n(e),!1):t(e))}initializeElements(e,t=(()=>{})){this.walkAndSkipNestedComponents(e,e=>void 0===e.__x_for_key&&(void 0===e.__x_inserted_me&&void this.initializeElement(e,t)),e=>{e.__x=new fe(e)}),this.executeAndClearRemainingShowDirectiveStack(),this.executeAndClearNextTickStack(e)}initializeElement(e,t){e.hasAttribute("class")&&d(e,this).length>0&&(e.__x_original_classes=p(e.getAttribute("class"))),this.registerListeners(e,t),this.resolveBoundAttributes(e,!0,t)}updateElements(e,t=(()=>{})){this.walkAndSkipNestedComponents(e,e=>{if(void 0!==e.__x_for_key&&!e.isSameNode(this.$el))return!1;this.updateElement(e,t)},e=>{e.__x=new fe(e)}),this.executeAndClearRemainingShowDirectiveStack(),this.executeAndClearNextTickStack(e)}executeAndClearNextTickStack(e){e===this.$el&&this.nextTickStack.length>0&&requestAnimationFrame(()=>{for(;this.nextTickStack.length>0;)this.nextTickStack.shift()()})}executeAndClearRemainingShowDirectiveStack(){this.showDirectiveStack.reverse().map(e=>new Promise(t=>{e(e=>{t(e)})})).reduce((e,t)=>e.then(()=>t.then(e=>e())),Promise.resolve(()=>{})),this.showDirectiveStack=[],this.showDirectiveLastElement=void 0}updateElement(e,t){this.resolveBoundAttributes(e,!1,t)}registerListeners(e,t){d(e,this).forEach(({type:i,value:r,modifiers:s,expression:o})=>{switch(i){case"on":P(this,e,r,s,o,t);break;case"model":!function(e,t,i,r,s){var o="select"===t.tagName.toLowerCase()||["checkbox","radio"].includes(t.type)||i.includes("lazy")?"change":"input";P(e,t,o,i,`${r} = rightSideOfExpression($event, ${r})`,()=>n(n({},s()),{},{rightSideOfExpression:j(t,i,r)}))}(this,e,s,o,t)}})}resolveBoundAttributes(e,t=!1,n){let i=d(e,this);i.forEach(({type:r,value:o,modifiers:a,expression:l})=>{switch(r){case"model":S(this,e,"value",l,n,r,a);break;case"bind":if("template"===e.tagName.toLowerCase()&&"key"===o)return;S(this,e,o,l,n,r,a);break;case"text":var c=this.evaluateReturnExpression(e,l,n);!function(e,t,n){void 0===t&&n.match(/\./)&&(t=""),e.innerText=t}(e,c,l);break;case"html":!function(e,t,n,i){t.innerHTML=e.evaluateReturnExpression(t,n,i)}(this,e,l,n);break;case"show":c=this.evaluateReturnExpression(e,l,n);!function(e,t,n,i,r=!1){const s=()=>{t.style.display="none"},o=()=>{1===t.style.length&&"none"===t.style.display?t.removeAttribute("style"):t.style.removeProperty("display")};if(!0===r)return void(n?o():s());const a=i=>{n?(("none"===t.style.display||t.__x_transition)&&b(t,()=>{o()},e),i(()=>{})):"none"!==t.style.display?y(t,()=>{i(()=>{s()})},e):i(()=>{})};i.includes("immediate")?a(e=>e()):(e.showDirectiveLastElement&&!e.showDirectiveLastElement.contains(t)&&e.executeAndClearRemainingShowDirectiveStack(),e.showDirectiveStack.push(a),e.showDirectiveLastElement=t)}(this,e,c,a,t);break;case"if":if(i.some(e=>"for"===e.type))return;c=this.evaluateReturnExpression(e,l,n);!function(e,t,n,i,r){s(t,"x-if");const o=t.nextElementSibling&&!0===t.nextElementSibling.__x_inserted_me;if(!n||o&&!t.__x_transition)!n&&o&&y(t.nextElementSibling,()=>{t.nextElementSibling.remove()},e,i);else{const n=document.importNode(t.content,!0);t.parentElement.insertBefore(n,t.nextElementSibling),b(t.nextElementSibling,()=>{},e,i),e.initializeElements(t.nextElementSibling,r),t.nextElementSibling.__x_inserted_me=!0}}(this,e,c,t,n);break;case"for":k(this,e,l,t,n);break;case"cloak":e.removeAttribute("x-cloak")}})}evaluateReturnExpression(e,t,i=(()=>{})){return l(t,this.$data,n(n({},i()),{},{$dispatch:this.getDispatchFunction(e)}))}evaluateCommandExpression(e,t,i=(()=>{})){return function(e,t,n={}){if("function"==typeof e)return Promise.resolve(e.call(t,n.$event));let i=Function;if(i=Object.getPrototypeOf(async function(){}).constructor,Object.keys(t).includes(e)){let i=new Function(["dataContext",...Object.keys(n)],`with(dataContext) { return ${e} }`)(t,...Object.values(n));return"function"==typeof i?Promise.resolve(i.call(t,n.$event)):Promise.resolve()}return Promise.resolve(new i(["dataContext",...Object.keys(n)],`with(dataContext) { ${e} }`)(t,...Object.values(n)))}(t,this.$data,n(n({},i()),{},{$dispatch:this.getDispatchFunction(e)}))}getDispatchFunction(e){return(t,n={})=>{e.dispatchEvent(new CustomEvent(t,{detail:n,bubbles:!0}))}}listenForNewElementsToInitialize(){const e=this.$el;new MutationObserver(e=>{for(let t=0;t<e.length;t++){const n=e[t].target.closest("[x-data]");if(n&&n.isSameNode(this.$el)){if("attributes"===e[t].type&&"x-data"===e[t].attributeName){const n=l(e[t].target.getAttribute("x-data")||"{}",{$el:this.$el});Object.keys(n).forEach(e=>{this.$data[e]!==n[e]&&(this.$data[e]=n[e])})}e[t].addedNodes.length>0&&e[t].addedNodes.forEach(e=>{1!==e.nodeType||e.__x_inserted_me||(!e.matches("[x-data]")||e.__x?this.initializeElements(e):e.__x=new fe(e))})}}}).observe(e,{childList:!0,attributes:!0,subtree:!0})}getRefsProxy(){var e=this;return new Proxy({},{get(t,n){return"$isAlpineProxy"===n||(e.walkAndSkipNestedComponents(e.$el,e=>{e.hasAttribute("x-ref")&&e.getAttribute("x-ref")===n&&(i=e)}),i);var i}})}}const me={version:"2.6.0",pauseMutationObserver:!1,magicProperties:{},onComponentInitializeds:[],onBeforeComponentInitializeds:[],ignoreFocusedForValueBinding:!1,start:async function(){r()||await new Promise(e=>{"loading"==document.readyState?document.addEventListener("DOMContentLoaded",e):e()}),this.discoverComponents(e=>{this.initializeComponent(e)}),document.addEventListener("turbolinks:load",()=>{this.discoverUninitializedComponents(e=>{this.initializeComponent(e)})}),this.listenForNewUninitializedComponentsAtRunTime(e=>{this.initializeComponent(e)})},discoverComponents:function(e){document.querySelectorAll("[x-data]").forEach(t=>{e(t)})},discoverUninitializedComponents:function(e,t=null){const n=(t||document).querySelectorAll("[x-data]");Array.from(n).filter(e=>void 0===e.__x).forEach(t=>{e(t)})},listenForNewUninitializedComponentsAtRunTime:function(e){const t=document.querySelector("body");new MutationObserver(e=>{if(!this.pauseMutationObserver)for(let t=0;t<e.length;t++)e[t].addedNodes.length>0&&e[t].addedNodes.forEach(e=>{1===e.nodeType&&(e.parentElement&&e.parentElement.closest("[x-data]")||this.discoverUninitializedComponents(e=>{this.initializeComponent(e)},e.parentElement))})}).observe(t,{childList:!0,attributes:!0,subtree:!0})},initializeComponent:function(e){if(!e.__x)try{e.__x=new fe(e)}catch(e){setTimeout(()=>{throw e},0)}},clone:function(e,t){t.__x||(t.__x=new fe(t,e))},addMagicProperty:function(e,t){this.magicProperties[e]=t},onComponentInitialized:function(e){this.onComponentInitializeds.push(e)},onBeforeComponentInitialized:function(e){this.onBeforeComponentInitializeds.push(e)}};return r()||(window.Alpine=me,window.deferLoadingAlpine?window.deferLoadingAlpine(function(){window.Alpine.start()}):window.Alpine.start()),me});
|
8
|
+
//# sourceMappingURL=/sm/54d8acf4bec59c2ac38179fad55c741f03c418f9ea483b114454c0827631f4ba.map
|
data/lib/web/style.css
ADDED
@@ -0,0 +1,139 @@
|
|
1
|
+
/* Layout. */
|
2
|
+
body {
|
3
|
+
padding: 0.5rem;
|
4
|
+
background: #C9D2E6;
|
5
|
+
font-family: 'Roboto', sans-serif;
|
6
|
+
}
|
7
|
+
|
8
|
+
.container {
|
9
|
+
margin: 0 auto;
|
10
|
+
max-width: 1000px;
|
11
|
+
padding: 2rem;
|
12
|
+
background: white;
|
13
|
+
}
|
14
|
+
|
15
|
+
/* Header. */
|
16
|
+
#logo {
|
17
|
+
display: block;
|
18
|
+
margin: 0 auto;
|
19
|
+
max-width: 100px;
|
20
|
+
}
|
21
|
+
|
22
|
+
/* Structure */
|
23
|
+
ul.classes,
|
24
|
+
ul.methods,
|
25
|
+
ul.reflections {
|
26
|
+
padding-left: 0;
|
27
|
+
}
|
28
|
+
|
29
|
+
li.class-container,
|
30
|
+
li.method-container {
|
31
|
+
list-style: none;
|
32
|
+
padding: 1rem;
|
33
|
+
border: 5px solid #dadcdc;
|
34
|
+
}
|
35
|
+
|
36
|
+
/* State. */
|
37
|
+
.status-row {
|
38
|
+
width: 100%;
|
39
|
+
display: flex;
|
40
|
+
align-items: center;
|
41
|
+
flex-direction: row;
|
42
|
+
color: white;
|
43
|
+
background: #A9B6D2;
|
44
|
+
}
|
45
|
+
.status-row.pass {
|
46
|
+
background: #008C32;
|
47
|
+
}
|
48
|
+
.status-row.fail {
|
49
|
+
background: #D04700;
|
50
|
+
}
|
51
|
+
|
52
|
+
/* Stats. */
|
53
|
+
.stats {
|
54
|
+
margin-left: auto;
|
55
|
+
}
|
56
|
+
.stat {
|
57
|
+
color: #efefef;
|
58
|
+
font-size: 3.5rem;
|
59
|
+
font-family: 'Merriweather', serif;
|
60
|
+
}
|
61
|
+
|
62
|
+
/* Class. */
|
63
|
+
.class {
|
64
|
+
padding: 2rem;
|
65
|
+
margin-bottom: 1rem;
|
66
|
+
}
|
67
|
+
.class:hover {
|
68
|
+
cursor: pointer;
|
69
|
+
}
|
70
|
+
.class h2 {
|
71
|
+
margin: 0;
|
72
|
+
}
|
73
|
+
|
74
|
+
/* Method. */
|
75
|
+
.method {
|
76
|
+
padding: 2rem;
|
77
|
+
margin-left: 1rem;
|
78
|
+
margin-bottom: 1rem;
|
79
|
+
}
|
80
|
+
.method:hover {
|
81
|
+
cursor: pointer;
|
82
|
+
}
|
83
|
+
.method .stat {
|
84
|
+
font-size: 2.5rem;
|
85
|
+
}
|
86
|
+
|
87
|
+
/* Reflection. */
|
88
|
+
.reflection {
|
89
|
+
list-style: none;
|
90
|
+
margin-left: 2rem;
|
91
|
+
display: flex;
|
92
|
+
flex-direction: row;
|
93
|
+
align-items: center;
|
94
|
+
background: #EFEFEF;
|
95
|
+
padding: 0.5rem 1.5rem;
|
96
|
+
margin-bottom: 0.3rem;
|
97
|
+
}
|
98
|
+
.reflection .time {
|
99
|
+
color: #777777;
|
100
|
+
margin-right: 2rem;
|
101
|
+
}
|
102
|
+
|
103
|
+
.info {
|
104
|
+
display: flex;
|
105
|
+
flex-direction: row;
|
106
|
+
align-items: center;
|
107
|
+
padding: 0.5rem 1rem;
|
108
|
+
border: 1px solid #aaa;
|
109
|
+
border-radius: 5px;
|
110
|
+
}
|
111
|
+
.info:not(:last-child) {
|
112
|
+
margin-right: 0.5rem;
|
113
|
+
}
|
114
|
+
.info h4 {
|
115
|
+
margin: 0;
|
116
|
+
color: #777777;
|
117
|
+
font-size: 1.2rem;
|
118
|
+
font-weight: normal;
|
119
|
+
}
|
120
|
+
|
121
|
+
.info-items {
|
122
|
+
display: flex;
|
123
|
+
flex-direction: row;
|
124
|
+
}
|
125
|
+
.info-item {
|
126
|
+
padding-left: 1rem;
|
127
|
+
padding-right: 1rem;
|
128
|
+
border-right: 1px solid #ccc;
|
129
|
+
}
|
130
|
+
.info-item:last-of-type {
|
131
|
+
padding-right: 0;
|
132
|
+
border-right: 0;
|
133
|
+
}
|
134
|
+
.info-item strong {
|
135
|
+
padding-bottom: 0.1rem;
|
136
|
+
}
|
137
|
+
.info-item pre {
|
138
|
+
margin: 0;
|
139
|
+
}
|
@@ -0,0 +1,210 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
|
4
|
+
<head>
|
5
|
+
<meta charset="utf-8">
|
6
|
+
<title>Reflekt</title>
|
7
|
+
<meta name="description" content="Reflective testing results.">
|
8
|
+
<meta name="author" content="Maedi Prichard">
|
9
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
10
|
+
<link rel="stylesheet" href="style.css">
|
11
|
+
<link rel="shortcut icon" href="">
|
12
|
+
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;700&display=swap" rel="stylesheet">
|
13
|
+
<link href="https://fonts.googleapis.com/css2?family=Merriweather&display=swap" rel="stylesheet">
|
14
|
+
</head>
|
15
|
+
|
16
|
+
<body>
|
17
|
+
|
18
|
+
<script>
|
19
|
+
|
20
|
+
// Reflection keys.
|
21
|
+
const TIME = "t";
|
22
|
+
const INPUT = "i";
|
23
|
+
const OUTPUT = "o";
|
24
|
+
const TYPE = "T";
|
25
|
+
const COUNT = "C";
|
26
|
+
const VALUE = "V";
|
27
|
+
const STATUS = "s";
|
28
|
+
const MESSAGE = "m";
|
29
|
+
// Reflection values.
|
30
|
+
const PASS = "p";
|
31
|
+
const FAIL = "f";
|
32
|
+
|
33
|
+
function getData() {
|
34
|
+
|
35
|
+
var reflections = JSON.parse(<%= @@reflekt_json %>);
|
36
|
+
console.log("REFLECTIONS:");
|
37
|
+
console.log(reflections);
|
38
|
+
var results = {};
|
39
|
+
|
40
|
+
if ('reflekt' in reflections) {
|
41
|
+
delete(reflections.reflekt);
|
42
|
+
}
|
43
|
+
|
44
|
+
// Classes.
|
45
|
+
for ([class_id, class_value] of Object.entries(reflections)) {
|
46
|
+
|
47
|
+
// Class pass rate.
|
48
|
+
results[class_id] = {
|
49
|
+
'stats': {
|
50
|
+
'pass_rate': undefined,
|
51
|
+
'test_count': 0,
|
52
|
+
'pass_count': 0
|
53
|
+
},
|
54
|
+
'methods': {}
|
55
|
+
};
|
56
|
+
|
57
|
+
// Methods.
|
58
|
+
for ([method_id, method] of Object.entries(class_value)) {
|
59
|
+
|
60
|
+
// Method pass rate.
|
61
|
+
var pass_count = method.reduce(function(obj, v) {
|
62
|
+
obj[v[STATUS]] = (obj[v[STATUS]] || 0) + 1;
|
63
|
+
return obj;
|
64
|
+
}, {});
|
65
|
+
|
66
|
+
var pass_rate = (pass_count[PASS] / method.length) * 100;
|
67
|
+
results[class_id]['methods'][method_id] = {
|
68
|
+
'stats': {
|
69
|
+
'pass_rate': pass_rate,
|
70
|
+
'test_count': method.length,
|
71
|
+
'pass_count': pass_count[PASS]
|
72
|
+
}
|
73
|
+
};
|
74
|
+
if (pass_rate == 100) {
|
75
|
+
results[class_id]['methods'][method_id]['status'] = 'pass';
|
76
|
+
}
|
77
|
+
else if (pass_rate < 100) {
|
78
|
+
results[class_id]['methods'][method_id]['status'] = 'fail';
|
79
|
+
}
|
80
|
+
|
81
|
+
// Class pass rate.
|
82
|
+
results[class_id]['stats']['test_count'] += method.length;
|
83
|
+
results[class_id]['stats']['pass_count'] += pass_count[PASS];
|
84
|
+
|
85
|
+
}
|
86
|
+
|
87
|
+
// Class pass rate.
|
88
|
+
var class_stats = results[class_id]['stats'];
|
89
|
+
var pass_rate = (class_stats['pass_count'] / class_stats['test_count']) * 100;
|
90
|
+
class_stats['pass_rate'] = pass_rate;
|
91
|
+
if (pass_rate == 100) {
|
92
|
+
results[class_id]['status'] = 'pass';
|
93
|
+
}
|
94
|
+
else if (pass_rate < 100) {
|
95
|
+
results[class_id]['status'] = 'fail';
|
96
|
+
}
|
97
|
+
}
|
98
|
+
|
99
|
+
return {
|
100
|
+
reflections: reflections,
|
101
|
+
results: results
|
102
|
+
};
|
103
|
+
}
|
104
|
+
|
105
|
+
</script>
|
106
|
+
|
107
|
+
<div class="container" x-data="getData()">
|
108
|
+
|
109
|
+
<div id="header">
|
110
|
+
<svg id="logo" enable-background="new 0 0 500 500" viewBox="0 0 500 500" xmlns="http://www.w3.org/2000/svg">
|
111
|
+
<path d="m307.5 80.5h-115l-57.5 205h230z" fill="#0047d0"/>
|
112
|
+
<path d="m178 76.5-53.1-44-117.9 139 116 112z" fill="#d04800"/>
|
113
|
+
<path d="m190.4 467.5h115l57.5-168h-229z" fill="#0047d0" opacity=".7"/>
|
114
|
+
<path d="m177 467.5-81-85-92-197 115 113z" fill="#d04800" opacity=".7"/>
|
115
|
+
<g fill="#008c33"><path d="m322 76.5 53.1-44 118 139-116 112z"/>
|
116
|
+
<path d="m320 467.5 84-85 92-197-117 113z" opacity=".7"/>
|
117
|
+
</g>
|
118
|
+
</svg>
|
119
|
+
</div>
|
120
|
+
|
121
|
+
<ul class="classes">
|
122
|
+
<template x-for="[class_id, klass] in Object.entries(results)" :key="class_id">
|
123
|
+
|
124
|
+
<li class="class-container">
|
125
|
+
|
126
|
+
<div class="status-row class" x-bind:class="`${klass.status}`" @click="klass['show'] = !klass['show']" :aria-expanded="klass['show'] ? 'true' : 'false'" :class="{ 'active': klass['show'] }">
|
127
|
+
<h2 x-text="`${class_id}()`"></h2>
|
128
|
+
<div class="stats">
|
129
|
+
<div class="stat" x-text="`${klass.stats.pass_rate.toFixed(2)}%`"></div>
|
130
|
+
</div>
|
131
|
+
</div>
|
132
|
+
|
133
|
+
<ul class="methods" x-show="klass['show']">
|
134
|
+
<template x-for="[method_id, method] in Object.entries(klass['methods'])" :key="method_id">
|
135
|
+
<li class="method-container">
|
136
|
+
|
137
|
+
<div class="status-row method" x-bind:class="`${method.status}`" @click="method['show'] = !method['show']" :aria-expanded="method['show'] ? 'true' : 'false'" :class="{ 'active': method['show'] }">
|
138
|
+
<h3 x-text="`${method_id}()`"></h3>
|
139
|
+
<div class="stats">
|
140
|
+
<div class="stat" x-text="`${method.stats.pass_rate.toFixed(2)}%`"></div>
|
141
|
+
</div>
|
142
|
+
</div>
|
143
|
+
|
144
|
+
<ul class="reflections" x-show="method['show']">
|
145
|
+
<template x-for="[reflection_id, reflection] in Object.entries(reflections[class_id][method_id])">
|
146
|
+
|
147
|
+
<li class="reflection">
|
148
|
+
|
149
|
+
<div class="time" x-text="`${new Date(reflection.t * 1000).getFullYear()}/${new Date(reflection.t * 1000).getMonth() + 1}/${new Date(reflection.t * 1000).getDate()} ${new Date(reflection.t * 1000).getHours()}:${new Date(reflection.t * 1000).getMinutes()}:${new Date(reflection.t * 1000).getSeconds()}`"></div>
|
150
|
+
|
151
|
+
<template x-for="[input_id, input] in Object.entries(reflection.i)">
|
152
|
+
|
153
|
+
<div class="info">
|
154
|
+
<h4>Input</h4>
|
155
|
+
<div class="info-items">
|
156
|
+
<div class="info-item">
|
157
|
+
<strong>Type:</strong><div class="input" x-text="input.T"></div>
|
158
|
+
</div>
|
159
|
+
<template x-if="input.V != undefined">
|
160
|
+
<div class="info-item">
|
161
|
+
<strong>Value:</strong><pre><div class="output" x-text="input.V"></div></pre>
|
162
|
+
</div>
|
163
|
+
</template>
|
164
|
+
<template x-if="input.C != undefined">
|
165
|
+
<div class="info-item">
|
166
|
+
<strong>Count:</strong><div class="input" x-text="input.C"></div>
|
167
|
+
</div>
|
168
|
+
</template>
|
169
|
+
</div>
|
170
|
+
</div>
|
171
|
+
|
172
|
+
</template>
|
173
|
+
|
174
|
+
<div class="info">
|
175
|
+
<h4>Output</h4>
|
176
|
+
<div class="info-items">
|
177
|
+
<div class="info-item">
|
178
|
+
<strong>Type:</strong><div class="output" x-text="reflection.o.T"></div>
|
179
|
+
</div>
|
180
|
+
<template x-if="reflection.o.C != undefined">
|
181
|
+
<div class="info-item">
|
182
|
+
<strong>Count:</strong><div class="output" x-text="reflection.o.C"></div>
|
183
|
+
</div>
|
184
|
+
</template>
|
185
|
+
<div class="info-item">
|
186
|
+
<strong>Value:</strong><pre><div class="output" x-text="reflection.o.V"></div></pre>
|
187
|
+
</div>
|
188
|
+
</div>
|
189
|
+
</div>
|
190
|
+
</li>
|
191
|
+
|
192
|
+
</template>
|
193
|
+
</ul>
|
194
|
+
|
195
|
+
</li>
|
196
|
+
</template>
|
197
|
+
</ul>
|
198
|
+
|
199
|
+
</li>
|
200
|
+
</template>
|
201
|
+
|
202
|
+
</ul>
|
203
|
+
|
204
|
+
</div>
|
205
|
+
|
206
|
+
<script src="script.js"></script>
|
207
|
+
|
208
|
+
</body>
|
209
|
+
|
210
|
+
</html>
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: reflekt
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Maedi Prichard
|
@@ -30,9 +30,14 @@ executables: []
|
|
30
30
|
extensions: []
|
31
31
|
extra_rdoc_files: []
|
32
32
|
files:
|
33
|
+
- lib/Execution.rb
|
34
|
+
- lib/Reflection.rb
|
35
|
+
- lib/ShadowStack.rb
|
33
36
|
- lib/reflekt.rb
|
34
|
-
- lib/
|
35
|
-
|
37
|
+
- lib/web/script.js
|
38
|
+
- lib/web/style.css
|
39
|
+
- lib/web/template.html.erb
|
40
|
+
homepage: https://github.com/refIekt/reflekt
|
36
41
|
licenses:
|
37
42
|
- MPL-2.0
|
38
43
|
metadata: {}
|
data/lib/template.html.erb
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
<!DOCTYPE html>
|
2
|
-
<html>
|
3
|
-
<head>
|
4
|
-
<meta charset="utf-8">
|
5
|
-
<title>Reflekt</title>
|
6
|
-
<meta name="description" content="">
|
7
|
-
<meta name="author" content="">
|
8
|
-
<meta name="viewport" content="width=device-width, initial-scale=1">
|
9
|
-
<link rel="stylesheet" href="">
|
10
|
-
<link rel="shortcut icon" href="">
|
11
|
-
</head>
|
12
|
-
<body>
|
13
|
-
|
14
|
-
<script>
|
15
|
-
var reflections = JSON.parse(<%= @@reflekt_json %>)
|
16
|
-
console.log(reflections)
|
17
|
-
</script>
|
18
|
-
|
19
|
-
</body>
|
20
|
-
</html>
|