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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9dab0fd8f1b076c4d4a4d6d7f571af7a6488e6d7a2a2fb430c4563cf12a8b011
4
- data.tar.gz: 22ac5bf780e0d048b50a902ce498f679d03c24a6e251b48ce31511c3d0829a6c
3
+ metadata.gz: e4d3c0c32672fd8813482a3f546032904d3d6f65e592fd4435eb7ada2bb1b201
4
+ data.tar.gz: d48f2b100986c4408db5cb055f4ebf1e6a50d99fa99dc6d98e8af8e5d8bcd66e
5
5
  SHA512:
6
- metadata.gz: 251b7a98ea53230c50f2b3f77e602b5456b4a60b59a73c41e511b498d25b72c50a632cbadce1d887644c08ae32c90a30e36fb0ea51cffb437e0c3037a857ae7d
7
- data.tar.gz: ba4872b5ef00a2fec12e9a2ebb662f3024e1411f529bc467fdd6d8c67a54382fb99c72e800c7cb07671eee165e00f6e231d1e600e9dfb91c59b175d3e48989d3
6
+ metadata.gz: 1422110bc34f7b88f8b4ba71359c408d38f3ebf72235735e51864fd0bd16c32fd5abc20e5cfa8a516478932800590f80f7f1b7b4d0dac3c0ebd18a3d8dfffd54
7
+ data.tar.gz: 4019f5868ca20d1aebfa9e4ddb2c5136782aa52185588cb44558f4725f51ea59f90bc75896e8bfac383151d7346bb534d98bc00a11a569c350d0c460fe3b31ab
@@ -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
@@ -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
@@ -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
@@ -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
- # Usage. Prepend to the class like so:
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
- @@reflekt_clone_count = 5
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
- @reflekt_forked = false
21
- @reflekt_clones = []
33
+ @reflection_counts = {}
22
34
 
23
- # Override methods.
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
- # When method called in flow.
28
- if @reflekt_forked
29
- unless self.class.deflekted?(method)
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
- @@reflekt_json = File.read("#{@@reflekt_output_path}/db.json")
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
- # Continue method flow.
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 contructor flow.
109
+ # Continue initialization.
59
110
  super
60
111
 
61
- # Create forks.
62
- reflekt_fork()
63
-
64
112
  end
65
113
 
66
- def reflekt_fork()
67
-
68
- @@reflekt_clone_count.times do |clone|
69
- @reflekt_clones << self.clone
70
- end
71
-
72
- @reflekt_forked = true
73
-
74
- end
114
+ ##
115
+ # Render results.
116
+ ##
117
+ def reflekt_render()
75
118
 
76
- def reflekt_action(clone, method, *args)
119
+ # Get JSON.
120
+ @@reflekt_json = File.read("#{@@reflekt_output_path}/db.json")
77
121
 
78
- class_name = clone.class.to_s
79
- method_name = method.to_s
80
-
81
- # Create new arguments.
82
- new_args = []
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
- # Action method with new arguments.
93
- begin
94
- clone.send(method, *new_args)
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
- # Save reflection.
110
- @@reflekt_db.get("#{class_name}.#{method_name}")
111
- .push(reflection)
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
- base.singleton_class.prepend(Klass)
146
+ # Prepend class methods to the instance's singleton class.
147
+ base.singleton_class.prepend(SingletonClassMethods)
120
148
 
121
- @@reflekt_setup ||= reflekt_setup_klass
149
+ @@reflekt_setup ||= reflekt_setup_class
122
150
  end
123
151
 
124
- # Setup Klass.
125
- def self.reflekt_setup_klass()
152
+ # Setup class.
153
+ def self.reflekt_setup_class()
126
154
 
127
- # Receive configuration from host application.
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 "reflections" directory in configured path.
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
- # Create "reflections" directory in current execution path.
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 Klass
184
+ module SingletonClassMethods
153
185
 
154
- @@deflekted_methods = Set.new
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
- @@deflekted_methods.add(method)
194
+ @@reflekt_skipped_methods.add(method)
163
195
  end
164
196
 
165
- def deflekted?(method)
166
- return true if @@deflekted_methods.include?(method)
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
@@ -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
@@ -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.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/template.html.erb
35
- homepage: https://github.com/maedi/reflekt
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: {}
@@ -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>