test_track_rails_client 4.0.0.alpha32 → 4.0.0.rc3
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 +5 -5
- data/README.md +14 -13
- data/Rakefile +6 -4
- data/app/assets/javascripts/testTrack.bundle.min.js +1 -1
- data/app/controllers/concerns/test_track/controller.rb +1 -3
- data/app/models/concerns/test_track/required_options.rb +1 -0
- data/app/models/test_track/ab_configuration.rb +3 -5
- data/app/models/test_track/analytics/mixpanel_client.rb +1 -0
- data/app/models/test_track/analytics/safe_wrapper.rb +1 -0
- data/app/models/test_track/application_identity.rb +1 -0
- data/app/models/test_track/assignment.rb +2 -1
- data/app/models/test_track/config_updater.rb +3 -3
- data/app/models/test_track/fake/split_registry.rb +4 -6
- data/app/models/test_track/job_session.rb +1 -3
- data/app/models/test_track/lazy_visitor_by_identity.rb +8 -4
- data/app/models/test_track/misconfiguration_notifier.rb +1 -0
- data/app/models/test_track/notify_assignment_job.rb +1 -0
- data/app/models/test_track/remote/assignment_event.rb +1 -1
- data/app/models/test_track/remote/fake_server.rb +1 -0
- data/app/models/test_track/remote/identifier.rb +2 -1
- data/app/models/test_track/remote/identifier_type.rb +1 -1
- data/app/models/test_track/remote/split_config.rb +1 -1
- data/app/models/test_track/remote/split_detail.rb +2 -2
- data/app/models/test_track/remote/split_registry.rb +2 -2
- data/app/models/test_track/remote/visitor.rb +2 -2
- data/app/models/test_track/remote/visitor_detail.rb +1 -1
- data/app/models/test_track/split_registry.rb +3 -3
- data/app/models/test_track/threaded_visitor_notifier.rb +6 -8
- data/app/models/test_track/unsynced_assignments_notifier.rb +4 -6
- data/app/models/test_track/variant_calculator.rb +1 -0
- data/app/models/test_track/vary_dsl.rb +4 -0
- data/app/models/test_track/visitor.rb +5 -4
- data/app/models/test_track/web_session.rb +5 -3
- data/app/models/test_track/web_session_visitor_repository.rb +1 -3
- data/config/initializers/set_build_timestamp.rb +1 -0
- data/lib/tasks/test_track_rails_client_tasks.rake +21 -0
- data/lib/test_track.rb +27 -0
- data/lib/test_track_rails_client/engine.rb +4 -2
- data/lib/test_track_rails_client/version.rb +1 -1
- data/vendor/bin/testtrack-cli/testtrack.darwin +0 -0
- data/vendor/bin/testtrack-cli/testtrack.linux +0 -0
- metadata +129 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 5c66d9d6a03b2089f12dc29601ef72d3b24a38c2772f719c84a33561d87c38d9
|
4
|
+
data.tar.gz: 6a884499fd36e03da076595c460fd32e5177a1fc8961957d8014a42b3faef8a7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 13493acef4dfb8e0a74318fa32b8e23636710b07cc9d90544a0d4bea406a41ae69810e78a73323d538b41ba5ee208713dc07c15e387a69fc5c0cb900dc3cf051
|
7
|
+
data.tar.gz: 5175ed66bec77901a9206155da9ff7d6a7e9c0ec10d4d98406a8038e8ad1a14834a226321cda18b5ba5a3ce1355afae4950507fbc8cbd5a68e763ca04dc56799
|
data/README.md
CHANGED
@@ -50,7 +50,7 @@ Set up ENV vars in every environment:
|
|
50
50
|
* `TEST_TRACK_API_URL` - Set this to the URL of your TestTrack instance with your app credentials, e.g. `http://[myapp]:[your new app password]@[your-app-domain]/`
|
51
51
|
|
52
52
|
[your-app-domain] can be
|
53
|
-
* `testtrack.
|
53
|
+
* `testtrack.test`
|
54
54
|
* `localhost:PORT`
|
55
55
|
* `example.org`
|
56
56
|
* etc
|
@@ -72,8 +72,8 @@ If your app doesn't support authentication, set
|
|
72
72
|
|
73
73
|
### Prepare your identity models (optional)
|
74
74
|
|
75
|
-
If your app supports authentication,
|
76
|
-
`User` model as a [TestTrack Identity](#varying-app-behavior-from-within-a-model)
|
75
|
+
If your app supports authentication, you'll need to configure your
|
76
|
+
`User` model as a [TestTrack Identity](#varying-app-behavior-from-within-a-model).
|
77
77
|
|
78
78
|
### Set up the Chrome extension (optional)
|
79
79
|
|
@@ -288,7 +288,7 @@ class BackgroundWorkJob
|
|
288
288
|
end
|
289
289
|
end
|
290
290
|
end
|
291
|
-
```
|
291
|
+
```
|
292
292
|
|
293
293
|
## Tracking visitor logins
|
294
294
|
|
@@ -391,28 +391,29 @@ def notify(message)
|
|
391
391
|
|
392
392
|
### From 3.0 to 4.0
|
393
393
|
|
394
|
-
The contract of custom analytics plugins has changed. Instead of
|
394
|
+
* The contract of custom analytics plugins has changed. Instead of
|
395
395
|
implementing `track_assignment` you now must implement `track`. It's
|
396
396
|
easier and more conventional, though, and takes care of differentiating
|
397
|
-
between
|
397
|
+
between experiment assignments and feature gate experiences, which are
|
398
398
|
no longer recorded server-side.
|
399
399
|
|
400
|
-
You
|
400
|
+
* You must add `self.test_track_identity = :current_user` (or
|
401
401
|
whatever your controller uses as a sign-in identity) to your
|
402
402
|
TestTrack-enabled controllers, or set it to `:none` if your app doesn't
|
403
|
-
support authentication.
|
403
|
+
support authentication. If your app supports authentication, you'll need to configure your
|
404
|
+
user model as a [TestTrack Identity](#varying-app-behavior-from-within-a-model).
|
404
405
|
|
405
|
-
If your
|
406
|
-
user model as a [TestTrack Identity](#varying-app-behavior-from-within-a-model)
|
406
|
+
* TestTrack server [introduced a new endpoint](https://github.com/Betterment/test_track/pull/133) for fetching the split registry that requires a timestamp of when the application was built. This prevents dropped splits from breaking a running application. If you use `rake assets:precompile` in your build pipeline, you're all set. If you don't, you'll need to call `rake test_track:generate_build_timestamp` and ensure that the file `testtrack/build_timestamp` is deployed along with your app.
|
407
407
|
|
408
408
|
### From 2.0 to 3.0
|
409
409
|
|
410
|
-
TestTrack Rails Client no longer manages your Mixpanel cookie. The analytics plugin now provides a callback on `sign_up!` that will allow you to implement this functionality within your application. Please see the [analytics documentation](#analytics) for more details.
|
411
|
-
|
410
|
+
* TestTrack Rails Client no longer manages your Mixpanel cookie. The analytics plugin now provides a callback on `sign_up!` that will allow you to implement this functionality within your application. Please see the [analytics documentation](#analytics) for more details.
|
411
|
+
|
412
|
+
* `TestTrack.analytics#track_assignment` no longer accepts a properties hash as an argument as `mixpanel_distinct_id` is no longer relevant.
|
412
413
|
|
413
414
|
### From 1.x to 1.3
|
414
415
|
|
415
|
-
`TestTrack::Session#log_in!` and `TestTrack:Session#sign_up!` now take a `TestTrack::Identity` instance argument instead of an identity type and identity value.
|
416
|
+
* `TestTrack::Session#log_in!` and `TestTrack:Session#sign_up!` now take a `TestTrack::Identity` instance argument instead of an identity type and identity value.
|
416
417
|
|
417
418
|
## How to Contribute
|
418
419
|
|
data/Rakefile
CHANGED
@@ -14,7 +14,7 @@ RDoc::Task.new(:rdoc) do |rdoc|
|
|
14
14
|
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
15
|
end
|
16
16
|
|
17
|
-
APP_RAKEFILE = File.expand_path(
|
17
|
+
APP_RAKEFILE = File.expand_path('spec/dummy/Rakefile', __dir__)
|
18
18
|
load 'rails/tasks/engine.rake'
|
19
19
|
|
20
20
|
Bundler::GemHelper.install_tasks
|
@@ -28,12 +28,14 @@ RuboCop::RakeTask.new
|
|
28
28
|
|
29
29
|
desc "Pull the latest versions of all dependencies into the gem for distribution"
|
30
30
|
task :vendor_deps do
|
31
|
-
TEST_TRACK_JS_CLIENT_VERSION = '
|
32
|
-
TEST_TRACK_CLI_VERSION = 'v1.
|
31
|
+
TEST_TRACK_JS_CLIENT_VERSION = '2.0.0-alpha.6'.freeze
|
32
|
+
TEST_TRACK_CLI_VERSION = 'v1.1.3'.freeze
|
33
33
|
|
34
34
|
# Bundle JS client
|
35
|
+
sh 'npm init -y'
|
35
36
|
sh "npm install --no-save test_track_js_client@#{TEST_TRACK_JS_CLIENT_VERSION}"
|
36
|
-
sh 'cp', 'node_modules/test_track_js_client/dist/testTrack.bundle.
|
37
|
+
sh 'cp', 'node_modules/test_track_js_client/dist/testTrack.bundle.js', 'app/assets/javascripts/testTrack.bundle.min.js'
|
38
|
+
sh 'rm package.json'
|
37
39
|
|
38
40
|
# Download testtrack-cli
|
39
41
|
FileUtils.module_eval do
|
@@ -1 +1 @@
|
|
1
|
-
!function(t){var e="object"==typeof exports&&exports,i="object"==typeof module&&module&&module.exports==e&&module,n="object"==typeof global&&global;n.global!==n&&n.window!==n||(t=n);var r=function(t){this.message=t};(r.prototype=new Error).name="InvalidCharacterError";var o=function(t){throw new r(t)},s="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",a=/[\t\n\f\r ]/g,u={encode:function(t){t=String(t),/[^\0-\xFF]/.test(t)&&o("The string to be encoded contains characters outside of the Latin1 range.");for(var e,i=t.length%3,n="",r=-1,a=t.length-i;++r<a;)e=(t.charCodeAt(r)<<16)+(t.charCodeAt(++r)<<8)+t.charCodeAt(++r),n+=s.charAt(e>>18&63)+s.charAt(e>>12&63)+s.charAt(e>>6&63)+s.charAt(63&e);return 2==i?(e=(t.charCodeAt(r)<<8)+t.charCodeAt(++r),n+=s.charAt(e>>10)+s.charAt(e>>4&63)+s.charAt(e<<2&63)+"="):1==i&&(e=t.charCodeAt(r),n+=s.charAt(e>>2)+s.charAt(e<<4&63)+"=="),n},decode:function(t){var e=(t=String(t).replace(a,"")).length;e%4==0&&(e=(t=t.replace(/==?$/,"")).length),(e%4==1||/[^+a-zA-Z0-9/]/.test(t))&&o("Invalid character: the string to be decoded is not correctly encoded.");for(var i,n,r=0,u="",f=-1;++f<e;)n=s.indexOf(t.charAt(f)),i=r%4?64*i+n:n,r++%4&&(u+=String.fromCharCode(255&i>>(-2*r&6)));return u},version:"0.1.0"};if("function"==typeof define&&"object"==typeof define.amd&&define.amd)define(function(){return u});else if(e&&!e.nodeType)if(i)i.exports=u;else for(var f in u)u.hasOwnProperty(f)&&(e[f]=u[f]);else t.base64=u}(this),function(t){"use strict";function e(t,e){var i=(65535&t)+(65535&e);return(t>>16)+(e>>16)+(i>>16)<<16|65535&i}function i(t,e){return t<<e|t>>>32-e}function n(t,n,r,o,s,a){return e(i(e(e(n,t),e(o,a)),s),r)}function r(t,e,i,r,o,s,a){return n(e&i|~e&r,t,e,o,s,a)}function o(t,e,i,r,o,s,a){return n(e&r|i&~r,t,e,o,s,a)}function s(t,e,i,r,o,s,a){return n(e^i^r,t,e,o,s,a)}function a(t,e,i,r,o,s,a){return n(i^(e|~r),t,e,o,s,a)}function u(t,i){t[i>>5]|=128<<i%32,t[14+(i+64>>>9<<4)]=i;var n,u,f,c,p,d=1732584193,h=-271733879,l=-1732584194,g=271733878;for(n=0;n<t.length;n+=16)u=d,f=h,c=l,p=g,h=a(h=a(h=a(h=a(h=s(h=s(h=s(h=s(h=o(h=o(h=o(h=o(h=r(h=r(h=r(h=r(h,l=r(l,g=r(g,d=r(d,h,l,g,t[n],7,-680876936),h,l,t[n+1],12,-389564586),d,h,t[n+2],17,606105819),g,d,t[n+3],22,-1044525330),l=r(l,g=r(g,d=r(d,h,l,g,t[n+4],7,-176418897),h,l,t[n+5],12,1200080426),d,h,t[n+6],17,-1473231341),g,d,t[n+7],22,-45705983),l=r(l,g=r(g,d=r(d,h,l,g,t[n+8],7,1770035416),h,l,t[n+9],12,-1958414417),d,h,t[n+10],17,-42063),g,d,t[n+11],22,-1990404162),l=r(l,g=r(g,d=r(d,h,l,g,t[n+12],7,1804603682),h,l,t[n+13],12,-40341101),d,h,t[n+14],17,-1502002290),g,d,t[n+15],22,1236535329),l=o(l,g=o(g,d=o(d,h,l,g,t[n+1],5,-165796510),h,l,t[n+6],9,-1069501632),d,h,t[n+11],14,643717713),g,d,t[n],20,-373897302),l=o(l,g=o(g,d=o(d,h,l,g,t[n+5],5,-701558691),h,l,t[n+10],9,38016083),d,h,t[n+15],14,-660478335),g,d,t[n+4],20,-405537848),l=o(l,g=o(g,d=o(d,h,l,g,t[n+9],5,568446438),h,l,t[n+14],9,-1019803690),d,h,t[n+3],14,-187363961),g,d,t[n+8],20,1163531501),l=o(l,g=o(g,d=o(d,h,l,g,t[n+13],5,-1444681467),h,l,t[n+2],9,-51403784),d,h,t[n+7],14,1735328473),g,d,t[n+12],20,-1926607734),l=s(l,g=s(g,d=s(d,h,l,g,t[n+5],4,-378558),h,l,t[n+8],11,-2022574463),d,h,t[n+11],16,1839030562),g,d,t[n+14],23,-35309556),l=s(l,g=s(g,d=s(d,h,l,g,t[n+1],4,-1530992060),h,l,t[n+4],11,1272893353),d,h,t[n+7],16,-155497632),g,d,t[n+10],23,-1094730640),l=s(l,g=s(g,d=s(d,h,l,g,t[n+13],4,681279174),h,l,t[n],11,-358537222),d,h,t[n+3],16,-722521979),g,d,t[n+6],23,76029189),l=s(l,g=s(g,d=s(d,h,l,g,t[n+9],4,-640364487),h,l,t[n+12],11,-421815835),d,h,t[n+15],16,530742520),g,d,t[n+2],23,-995338651),l=a(l,g=a(g,d=a(d,h,l,g,t[n],6,-198630844),h,l,t[n+7],10,1126891415),d,h,t[n+14],15,-1416354905),g,d,t[n+5],21,-57434055),l=a(l,g=a(g,d=a(d,h,l,g,t[n+12],6,1700485571),h,l,t[n+3],10,-1894986606),d,h,t[n+10],15,-1051523),g,d,t[n+1],21,-2054922799),l=a(l,g=a(g,d=a(d,h,l,g,t[n+8],6,1873313359),h,l,t[n+15],10,-30611744),d,h,t[n+6],15,-1560198380),g,d,t[n+13],21,1309151649),l=a(l,g=a(g,d=a(d,h,l,g,t[n+4],6,-145523070),h,l,t[n+11],10,-1120210379),d,h,t[n+2],15,718787259),g,d,t[n+9],21,-343485551),d=e(d,u),h=e(h,f),l=e(l,c),g=e(g,p);return[d,h,l,g]}function f(t){var e,i="";for(e=0;e<32*t.length;e+=8)i+=String.fromCharCode(t[e>>5]>>>e%32&255);return i}function c(t){var e,i=[];for(i[(t.length>>2)-1]=void 0,e=0;e<i.length;e+=1)i[e]=0;for(e=0;e<8*t.length;e+=8)i[e>>5]|=(255&t.charCodeAt(e/8))<<e%32;return i}function p(t){return f(u(c(t),8*t.length))}function d(t,e){var i,n,r=c(t),o=[],s=[];for(o[15]=s[15]=void 0,r.length>16&&(r=u(r,8*t.length)),i=0;i<16;i+=1)o[i]=909522486^r[i],s[i]=1549556828^r[i];return n=u(o.concat(c(e)),512+8*e.length),f(u(s.concat(n),640))}function h(t){var e,i,n="";for(i=0;i<t.length;i+=1)e=t.charCodeAt(i),n+="0123456789abcdef".charAt(e>>>4&15)+"0123456789abcdef".charAt(15&e);return n}function l(t){return unescape(encodeURIComponent(t))}function g(t){return p(l(t))}function v(t){return h(g(t))}function m(t,e){return d(l(t),l(e))}function y(t,e){return h(m(t,e))}function w(t,e,i){return e?i?m(e,t):y(e,t):i?g(t):v(t)}"function"==typeof define&&define.amd?define(function(){return w}):t.md5=w}(this),function(){function t(t,e){var i=e||0,n=u;return n[t[i++]]+n[t[i++]]+n[t[i++]]+n[t[i++]]+"-"+n[t[i++]]+n[t[i++]]+"-"+n[t[i++]]+n[t[i++]]+"-"+n[t[i++]]+n[t[i++]]+"-"+n[t[i++]]+n[t[i++]]+n[t[i++]]+n[t[i++]]+n[t[i++]]+n[t[i++]]}function e(e,n,r){var o=n&&r||0;"string"==typeof e&&(n="binary"==e?new a(16):null,e=null);var s=(e=e||{}).random||(e.rng||i)();if(s[6]=15&s[6]|64,s[8]=63&s[8]|128,n)for(var u=0;u<16;u++)n[o+u]=s[u];return n||t(s)}var i,n=this;if("function"==typeof n.require)try{var r=n.require("crypto").randomBytes;i=r&&function(){return r(16)}}catch(t){}if(!i&&n.crypto&&crypto.getRandomValues){var o=new Uint8Array(16);i=function(){return crypto.getRandomValues(o),o}}if(!i){var s=new Array(16);i=function(){for(var t,e=0;e<16;e++)0==(3&e)&&(t=4294967296*Math.random()),s[e]=t>>>((3&e)<<3)&255;return s}}for(var a="function"==typeof n.Buffer?n.Buffer:Array,u=[],f={},c=0;c<256;c++)u[c]=(c+256).toString(16).substr(1),f[u[c]]=c;var p=i(),d=[1|p[0],p[1],p[2],p[3],p[4],p[5]],h=16383&(p[6]<<8|p[7]),l=0,g=0,v=e;if(v.v1=function(e,i,n){var r=i&&n||0,o=i||[],s=null!=(e=e||{}).clockseq?e.clockseq:h,a=null!=e.msecs?e.msecs:(new Date).getTime(),u=null!=e.nsecs?e.nsecs:g+1,f=a-l+(u-g)/1e4;if(f<0&&null==e.clockseq&&(s=s+1&16383),(f<0||a>l)&&null==e.nsecs&&(u=0),u>=1e4)throw new Error("uuid.v1(): Can't create more than 10M uuids/sec");l=a,g=u,h=s;var c=(1e4*(268435455&(a+=122192928e5))+u)%4294967296;o[r++]=c>>>24&255,o[r++]=c>>>16&255,o[r++]=c>>>8&255,o[r++]=255&c;var p=a/4294967296*1e4&268435455;o[r++]=p>>>8&255,o[r++]=255&p,o[r++]=p>>>24&15|16,o[r++]=p>>>16&255,o[r++]=s>>>8|128,o[r++]=255&s;for(var v=e.node||d,m=0;m<6;m++)o[r+m]=v[m];return i||t(o)},v.v4=e,v.parse=function(t,e,i){var n=e&&i||0,r=0;for(e=e||[],t.toLowerCase().replace(/[0-9a-f]{2}/g,function(t){r<16&&(e[n+r++]=f[t])});r<16;)e[n+r++]=0;return e},v.unparse=t,v.BufferClass=a,"function"==typeof define&&define.amd)define(function(){return v});else if("undefined"!=typeof module&&module.exports)module.exports=v;else{var m=n.uuid;v.noConflict=function(){return n.uuid=m,v},n.uuid=v}}.call(this),function(t){"function"==typeof define&&define.amd?define(["jquery"],t):t("object"==typeof exports?require("jquery"):jQuery)}(function(t){function e(t){return a.raw?t:encodeURIComponent(t)}function i(t){return a.raw?t:decodeURIComponent(t)}function n(t){return e(a.json?JSON.stringify(t):String(t))}function r(t){0===t.indexOf('"')&&(t=t.slice(1,-1).replace(/\\"/g,'"').replace(/\\\\/g,"\\"));try{return t=decodeURIComponent(t.replace(s," ")),a.json?JSON.parse(t):t}catch(t){}}function o(e,i){var n=a.raw?e:r(e);return t.isFunction(i)?i(n):n}var s=/\+/g,a=t.cookie=function(r,s,u){if(void 0!==s&&!t.isFunction(s)){if("number"==typeof(u=t.extend({},a.defaults,u)).expires){var f=u.expires,c=u.expires=new Date;c.setTime(+c+864e5*f)}return document.cookie=[e(r),"=",n(s),u.expires?"; expires="+u.expires.toUTCString():"",u.path?"; path="+u.path:"",u.domain?"; domain="+u.domain:"",u.secure?"; secure":""].join("")}for(var p=r?void 0:{},d=document.cookie?document.cookie.split("; "):[],h=0,l=d.length;h<l;h++){var g=d[h].split("="),v=i(g.shift()),m=g.join("=");if(r&&r===v){p=o(m,s);break}r||void 0===(m=o(m))||(p[v]=m)}return p};a.defaults={},t.removeCookie=function(e,i){return void 0!==t.cookie(e)&&(t.cookie(e,"",t.extend({},i,{expires:-1})),!t.cookie(e))}}),function(t,e){if("function"==typeof define&&define.amd)define(["node-uuid","blueimp-md5","jquery","base-64","jquery.cookie"],e);else if("undefined"!=typeof exports){var i=require("node-uuid"),n=require("blueimp-md5"),r=require("jquery"),o=require("base-64");require("jquery.cookie");module.exports=e(i,n,r,o)}else t.TestTrack=e(t.uuid,t.md5,t.jQuery,t.base64)}(this,function(t,e,i,n){"use strict";if(void 0===t)throw new Error('TestTrack depends on node-uuid. Make sure you are including "node_modules/node-uuid/uuid.js"');if(void 0===e)throw new Error('TestTrack depends on blueimp-md5. Make sure you are including "node_modules/blueimp-md5/js/md5.js"');if(void 0===i)throw new Error('TestTrack depends on jquery. You can use your own copy of jquery or the one in "node_modules/jquery/dist/jquery.js"');if("function"!=typeof i.cookie)throw new Error("TestTrack depends on jquery.cookie. You can user your own copy of jquery.cooke or the one in node_modules/jquery.cookie/jquery.cookie.js");if(void 0===n)throw new Error('TestTrack depends on base-64. Make sure you are including "node_modules/base-64/base64.js"');Function.prototype.bind||(Function.prototype.bind=function(t){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var e=Array.prototype.slice.call(arguments,1),i=this,n=function(){},r=function(){return i.apply(this instanceof n?this:t,e.concat(Array.prototype.slice.call(arguments)))};return this.prototype&&(n.prototype=this.prototype),r.prototype=new n,r});var r=function(){var t=function(){};return t.prototype.trackAssignment=function(t,e,i){var n={TTVisitorID:t,SplitName:e.getSplitName(),SplitVariant:e.getVariant(),SplitContext:e.getContext()};window.mixpanel&&window.mixpanel.track("SplitAssigned",n,i)},t.prototype.identify=function(t){window.mixpanel&&window.mixpanel.identify(t)},t.prototype.alias=function(t){window.mixpanel&&window.mixpanel.alias(t)},t}(),o=function(){var t=function(t){if(!t.splitName)throw new Error("must provide splitName");if(!t.hasOwnProperty("variant"))throw new Error("must provide variant");if(!t.hasOwnProperty("isUnsynced"))throw new Error("must provide isUnsynced");this._splitName=t.splitName,this._variant=t.variant,this._context=t.context,this._isUnsynced=t.isUnsynced};return t.fromJsonArray=function(t){for(var e=[],i=0;i<t.length;i++)e.push(new o({splitName:t[i].split_name,variant:t[i].variant,context:t[i].context,isUnsynced:t[i].unsynced}));return e},t.prototype.getSplitName=function(){return this._splitName},t.prototype.getVariant=function(){return this._variant},t.prototype.setVariant=function(t){this._variant=t},t.prototype.getContext=function(){return this._context},t.prototype.setContext=function(t){this._context=t},t.prototype.isUnsynced=function(){return this._isUnsynced},t.prototype.setUnsynced=function(t){this._isUnsynced=t},t}(),s=function(){var t=function(){};return t.prototype.getConfig=function(){return"function"==typeof window.atob?JSON.parse(window.atob(window.TT)):JSON.parse(n.decode(window.TT))},t}(),a=function(){var t,e,i=function(){if(!t){var e=new s;t=e.getConfig()}return t};return{_clear:function(){t=null},getUrl:function(){return i().url},getCookieDomain:function(){return i().cookieDomain},getCookieName:function(){return i().cookieName||"tt_visitor_id"},getSplitRegistry:function(){return i().registry},getAssignments:function(){var t=i().assignments;if(!t)return null;if(!e){e=[];for(var n in t)e.push(new o({splitName:n,variant:t[n],isUnsynced:!1}))}return e}}}(),u=function(){var t=function(t){if(this.visitor=t.visitor,this.splitName=t.splitName,!this.visitor)throw new Error("must provide visitor");if(!this.splitName)throw new Error("must provide splitName")};return t.prototype.getVariant=function(){if(!a.getSplitRegistry())return null;for(var t=0,e=this.getAssignmentBucket(),i=this.getWeighting(),n=this.getSortedVariants(),r=0;r<n.length;r++){var o=n[r];if((t+=i[o])>e)return o}throw new Error("Assignment bucket out of range. "+e+" unmatched in "+this.splitName+": "+JSON.stringify(i))},t.prototype.getSplitVisitorHash=function(){return e(this.splitName+this.visitor.getId())},t.prototype.getHashFixnum=function(){return parseInt(this.getSplitVisitorHash().substr(0,8),16)},t.prototype.getAssignmentBucket=function(){return this.getHashFixnum()%100},t.prototype.getSortedVariants=function(){return this.getVariants().sort()},t.prototype.getVariants=function(){return Object.getOwnPropertyNames(this.getWeighting())},t.prototype.getWeighting=function(){var t=a.getSplitRegistry()[this.splitName];if(!t){var e='Unknown split: "'+this.splitName+'"';throw this.visitor.logError(e),new Error(e)}return t},t}(),f=function(){var t=function(t){if(t=t||{},this._visitor=t.visitor,this._assignment=t.assignment,!this._visitor)throw new Error("must provide visitor");if(!this._assignment)throw new Error("must provide assignment")};return t.prototype.send=function(){this.persistAssignment(),this._visitor.analytics.trackAssignment(this._visitor.getId(),this._assignment,function(t){this.persistAssignment(t?"success":"failure")}.bind(this))},t.prototype.persistAssignment=function(t){return i.ajax(a.getUrl()+"/api/v1/assignment_event",{method:"POST",dataType:"json",crossDomain:!0,data:{visitor_id:this._visitor.getId(),split_name:this._assignment.getSplitName(),context:this._assignment.getContext(),mixpanel_result:t}}).fail(function(t,e,i){var n=t&&t.status,r=t&&t.responseText;this._visitor.logError("test_track persistAssignment error: "+[t,n,r,e,i].join(", "))}.bind(this))},t}(),c=function(){var t=function(t){if(t=t||{},this._visitor=t.visitor,this._assignment=t.assignment,this._username=t.username,this._password=t.password,!this._visitor)throw new Error("must provide visitor");if(!this._assignment)throw new Error("must provide assignment");if(!this._username)throw new Error("must provide username");if(!this._password)throw new Error("must provide password")};return t.prototype.send=function(){this.persistAssignment(),this._visitor.analytics.trackAssignment(this._visitor.getId(),this._assignment,function(t){this.persistAssignment(t?"success":"failure")}.bind(this))},t.prototype.persistAssignment=function(t){return i.ajax(a.getUrl()+"/api/v1/assignment_override",{method:"POST",dataType:"json",crossDomain:!0,headers:{Authorization:"Basic "+btoa(this._username+":"+this._password)},data:{visitor_id:this._visitor.getId(),split_name:this._assignment.getSplitName(),variant:this._assignment.getVariant(),context:this._assignment.getContext(),mixpanel_result:t}}).fail(function(t,e,i){var n=t&&t.status,r=t&&t.responseText;this._visitor.logError("test_track persistAssignment error: "+[t,n,r,e,i].join(", "))}.bind(this))},t}(),p=function(){var e=function(t){if(t=t||{},this._id=t.id,this._assignments=t.assignments,this._ttOffline=t.ttOffline,!this._id)throw new Error("must provide id");if(!this._assignments)throw new Error("must provide assignments");this._errorLogger=function(t){window.console.error(t)},this.analytics=new r};return e.loadVisitor=function(e){var n=i.Deferred(),r=function(t){n.resolve(new p(t))};return e?a.getAssignments()?r({id:e,assignments:a.getAssignments(),ttOffline:!1}):i.ajax(a.getUrl()+"/api/v1/visitors/"+e,{method:"GET",timeout:5e3}).done(function(t){r({id:t.id,assignments:o.fromJsonArray(t.assignments),ttOffline:!1})}).fail(function(){r({id:e,assignments:[],ttOffline:!0})}):r({id:t.v4(),assignments:[],ttOffline:!1}),n.promise()},e.prototype.getId=function(){return this._id},e.prototype.getAssignmentRegistry=function(){if(!this._assignmentRegistry){for(var t={},e=0;e<this._assignments.length;e++){var i=this._assignments[e];t[i.getSplitName()]=i}this._assignmentRegistry=t}return this._assignmentRegistry},e.prototype.vary=function(t,e){if("object"!=typeof e.variants)throw new Error("must provide variants object to `vary` for "+t);if(!e.context)throw new Error("must provide context to `vary` for "+t);if(!e.defaultVariant&&!1!==e.defaultVariant)throw new Error("must provide defaultVariant to `vary` for "+t);var i=e.defaultVariant.toString(),n=e.variants,r=e.context;if(!n.hasOwnProperty(i))throw new Error("defaultVariant: "+i+" must be represented in variants object");var o=this._getAssignmentFor(t,r),s=new l({assignment:o,visitor:this});for(var a in n)n.hasOwnProperty(a)&&(a===i?s.default(a,n[a]):s.when(a,n[a]));s.run(),s.isDefaulted()&&(o.setVariant(s.getDefaultVariant()),o.setUnsynced(!0),o.setContext(r)),this.notifyUnsyncedAssignments()},e.prototype.ab=function(t,e){var i=new g({splitName:t,trueVariant:e.trueVariant,visitor:this}).getVariants(),n={};n[i.true]=function(){e.callback(!0)},n[i.false]=function(){e.callback(!1)},this.vary(t,{context:e.context,variants:n,defaultVariant:i.false})},e.prototype.setErrorLogger=function(t){if("function"!=typeof t)throw new Error("must provide function for errorLogger");this._errorLogger=t},e.prototype.logError=function(t){this._errorLogger.call(null,t)},e.prototype.linkIdentifier=function(t,e){var n=i.Deferred();return new h({visitorId:this.getId(),identifierType:t,value:e}).save().then(function(t){this._merge(t),this.notifyUnsyncedAssignments(),n.resolve()}.bind(this)),n.promise()},e.prototype.setAnalytics=function(t){if("object"!=typeof t)throw new Error("must provide object for setAnalytics");this.analytics=t},e.prototype.notifyUnsyncedAssignments=function(){for(var t=this._getUnsyncedAssignments(),e=0;e<t.length;e++)this._notify(t[e])},e.prototype._getUnsyncedAssignments=function(){var t=[],e=this.getAssignmentRegistry();return Object.keys(e).forEach(function(i){var n=e[i];n.isUnsynced()&&t.push(n)}),t},e.prototype._merge=function(t){var e=this.getAssignmentRegistry(),i=t.getAssignmentRegistry();this._id=t.getId();for(var n in i)i.hasOwnProperty(n)&&(e[n]=i[n])},e.prototype._getAssignmentFor=function(t,e){return this.getAssignmentRegistry()[t]||this._generateAssignmentFor(t,e)},e.prototype._generateAssignmentFor=function(t,e){var i=new u({visitor:this,splitName:t}).getVariant();i||(this._ttOffline=!0);var n=new o({splitName:t,variant:i,context:e,isUnsynced:!0});return this._assignments.push(n),this._assignmentRegistry=null,n},e.prototype._notify=function(t){try{if(this._ttOffline)return;new f({visitor:this,assignment:t}).send(),t.setUnsynced(!1)}catch(t){this.logError("test_track notify error: "+t)}},e}(),d=function(){var t=function(){this._visitorDeferred=i.Deferred()};return t.prototype.initialize=function(t){var e=i.cookie(a.getCookieName());this._visitorDeferred.then(function(t){t.notifyUnsyncedAssignments()}),p.loadVisitor(e).then(function(e){t&&t.analytics&&e.setAnalytics(t.analytics),t&&t.errorLogger&&e.setErrorLogger(t.errorLogger),t&&"function"==typeof t.onVisitorLoaded&&t.onVisitorLoaded.call(null,e),this._visitorDeferred.resolve(e)}.bind(this)),this._setCookie()},t.prototype.vary=function(t,e){this._visitorDeferred.then(function(i){i.vary(t,e)})},t.prototype.ab=function(t,e){this._visitorDeferred.then(function(i){i.ab(t,e)})},t.prototype.logIn=function(t,e){var n=i.Deferred();return this._visitorDeferred.then(function(i){i.linkIdentifier(t,e).then(function(){this._setCookie(),i.analytics.identify(i.getId()),n.resolve()}.bind(this))}.bind(this)),n.promise()},t.prototype.signUp=function(t,e){var n=i.Deferred();return this._visitorDeferred.then(function(i){i.linkIdentifier(t,e).then(function(){this._setCookie(),i.analytics.alias(i.getId()),n.resolve()}.bind(this))}.bind(this)),n.promise()},t.prototype._setCookie=function(){this._visitorDeferred.then(function(t){i.cookie(a.getCookieName(),t.getId(),{expires:365,path:"/",domain:a.getCookieDomain()})})},t.prototype.getPublicAPI=function(){return{vary:this.vary.bind(this),ab:this.ab.bind(this),logIn:this.logIn.bind(this),signUp:this.signUp.bind(this),initialize:this.initialize.bind(this),_crx:{loadInfo:function(){var t=i.Deferred();return this._visitorDeferred.then(function(e){var i={};for(var n in e.getAssignmentRegistry())i[n]=e.getAssignmentRegistry()[n].getVariant();t.resolve({visitorId:e.getId(),splitRegistry:a.getSplitRegistry(),assignmentRegistry:i})}),t.promise()}.bind(this),persistAssignment:function(t,e,n,r){var s=i.Deferred();return this._visitorDeferred.then(function(i){new c({visitor:i,username:n,password:r,assignment:new o({splitName:t,variant:e,context:"chrome_extension",isUnsynced:!0})}).persistAssignment().then(function(){s.resolve()})}),s.promise()}.bind(this)}}},t}(),h=function(){var t=function(t){if(this.visitorId=t.visitorId,this.identifierType=t.identifierType,this.value=t.value,!this.visitorId)throw new Error("must provide visitorId");if(!this.identifierType)throw new Error("must provide identifierType");if(!this.value)throw new Error("must provide value")};return t.prototype.save=function(t,e){var n=i.Deferred();return i.ajax(a.getUrl()+"/api/v1/identifier",{method:"POST",dataType:"json",crossDomain:!0,data:{identifier_type:this.identifierType,value:this.value,visitor_id:this.visitorId}}).then(function(t){var e=new p({id:t.visitor.id,assignments:o.fromJsonArray(t.visitor.assignments)});n.resolve(e)}),n.promise()},t}(),l=function(){var t=function(t){if(!t.assignment)throw new Error("must provide assignment");if(!t.visitor)throw new Error("must provide visitor");this._assignment=t.assignment,this._visitor=t.visitor,this._splitRegistry=a.getSplitRegistry(),this._variantHandlers={}};return t.prototype.when=function(){var t=Array.prototype.slice.call(arguments,0),e=t.length-1,i="function"!=typeof t[0]&&t.length>0?t.slice(0,Math.max(1,e)):[],n=t[e];if(0===i.length)throw new Error("must provide at least one variant");for(var r=0;r<i.length;r++)this._assignHandlerToVariant(i[r],n)},t.prototype.default=function(t,e){if(this._defaultVariant)throw new Error("must provide exactly one `default`");this._defaultVariant=this._assignHandlerToVariant(t,e)},t.prototype.run=function(){this._validate();var t;this._variantHandlers[this._assignment.getVariant()]?t=this._variantHandlers[this._assignment.getVariant()]:(t=this._variantHandlers[this.getDefaultVariant()],this._defaulted=!0),t()},t.prototype.isDefaulted=function(){return this._defaulted||!1},t.prototype.getDefaultVariant=function(){return this._defaultVariant},t.prototype._assignHandlerToVariant=function(t,e){if("function"!=typeof e)throw new Error("must provide handler for "+t);return t=t.toString(),this._getSplit()&&!this._getSplit().hasOwnProperty(t)&&this._visitor.logError("configures unknown variant "+t),this._variantHandlers[t]=e,t},t.prototype._validate=function(){if(!this.getDefaultVariant())throw new Error("must provide exactly one `default`");if(this._getVariants().length<2)throw new Error("must provide at least one `when`");if(this._getSplit()){var t=this._getMissingVariants();if(t.length>0){var e=t.join(", ").replace(/, (.+)$/," and $1");this._visitor.logError("does not configure variants "+e)}}},t.prototype._getSplit=function(){return this._splitRegistry?this._splitRegistry[this._assignment.getSplitName()]:null},t.prototype._getVariants=function(){return Object.getOwnPropertyNames(this._variantHandlers)},t.prototype._getMissingVariants=function(){for(var t=this._getVariants(),e=this._getSplit(),i=Object.getOwnPropertyNames(e),n=[],r=0;r<i.length;r++){var o=i[r];-1===t.indexOf(o)&&n.push(o)}return n},t}(),g=function(){var t=function(t){if(!t.splitName)throw new Error("must provide splitName");if(!t.hasOwnProperty("trueVariant"))throw new Error("must provide trueVariant");if(!t.visitor)throw new Error("must provide visitor");this._splitName=t.splitName,this._trueVariant=t.trueVariant,this._visitor=t.visitor,this._splitRegistry=a.getSplitRegistry()};return t.prototype.getVariants=function(){var t=this._getSplitVariants();return t&&t.length>2&&this._visitor.logError("A/B for "+this._splitName+" configures split with more than 2 variants"),{true:this._getTrueVariant(),false:this._getFalseVariant()}},t.prototype._getTrueVariant=function(){return this._trueVariant||!0},t.prototype._getFalseVariant=function(){var t=this._getNonTrueVariants();return!!t&&t.sort()[0]},t.prototype._getNonTrueVariants=function(){var t=this._getSplitVariants();if(t){var e=this._getTrueVariant(),i=t.indexOf(e);return-1!==i&&t.splice(i,1),t}return null},t.prototype._getSplit=function(){return this._splitRegistry?this._splitRegistry[this._splitName]:null},t.prototype._getSplitVariants=function(){return this._getSplit()&&Object.getOwnPropertyNames(this._getSplit())},t}(),v=(new d).getPublicAPI(),m=function(){window.dispatchEvent(new CustomEvent("tt:lib:loaded",{detail:{TestTrack:v}}))};try{i(document).ready(function(){i(document.body).addClass("_tt");try{window.dispatchEvent(new CustomEvent("tt:class:added"))}catch(t){}}),m(),window.addEventListener("tt:listener:ready",m)}catch(t){}return v});
|
1
|
+
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t=t||self).TestTrack=e()}(this,function(){"use strict";var t="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{};function e(t,e,r){return t(r={path:e,exports:{},require:function(t,e){return function(){throw new Error("Dynamic requires are not currently supported by @rollup/plugin-commonjs")}(null==e&&r.path)}},r.exports),r.exports}var r=e(function(t,e){var r;r=function(){function t(){for(var t=0,e={};t<arguments.length;t++){var r=arguments[t];for(var n in r)e[n]=r[n]}return e}return function e(r){function n(e,i,o){var s;if("undefined"!=typeof document){if(arguments.length>1){if("number"==typeof(o=t({path:"/"},n.defaults,o)).expires){var a=new Date;a.setMilliseconds(a.getMilliseconds()+864e5*o.expires),o.expires=a}o.expires=o.expires?o.expires.toUTCString():"";try{s=JSON.stringify(i),/^[\{\[]/.test(s)&&(i=s)}catch(t){}i=r.write?r.write(i,e):encodeURIComponent(String(i)).replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g,decodeURIComponent),e=(e=(e=encodeURIComponent(String(e))).replace(/%(23|24|26|2B|5E|60|7C)/g,decodeURIComponent)).replace(/[\(\)]/g,escape);var u="";for(var c in o)o[c]&&(u+="; "+c,!0!==o[c]&&(u+="="+o[c]));return document.cookie=e+"="+i+u}e||(s={});for(var f=document.cookie?document.cookie.split("; "):[],p=/(%[0-9A-Z]{2})+/g,l=0;l<f.length;l++){var d=f[l].split("="),h=d.slice(1).join("=");this.json||'"'!==h.charAt(0)||(h=h.slice(1,-1));try{var g=d[0].replace(p,decodeURIComponent);if(h=r.read?r.read(h,g):r(h,g)||h.replace(p,decodeURIComponent),this.json)try{h=JSON.parse(h)}catch(t){}if(e===g){s=h;break}e||(s[g]=h)}catch(t){}}return s}}return n.set=n,n.get=function(t){return n.call(n,t)},n.getJSON=function(){return n.apply({json:!0},[].slice.call(arguments))},n.defaults={},n.remove=function(e,r){n(e,"",t(r,{expires:-1}))},n.withConverter=e,n}(function(){})},t.exports=r()}),n=function(){function t(t){if(!t.splitName)throw new Error("must provide splitName");if(!t.hasOwnProperty("variant"))throw new Error("must provide variant");if(!t.hasOwnProperty("isUnsynced"))throw new Error("must provide isUnsynced");this._splitName=t.splitName,this._variant=t.variant,this._context=t.context,this._isUnsynced=t.isUnsynced}return t.fromJsonArray=function(e){return e.map(function(e){var r=e.split_name,n=e.variant;return new t({context:e.context,variant:n,splitName:r,isUnsynced:e.unsynced})})},t.prototype.getSplitName=function(){return this._splitName},t.prototype.getVariant=function(){return this._variant},t.prototype.setVariant=function(t){this._variant=t},t.prototype.getContext=function(){return this._context},t.prototype.setContext=function(t){this._context=t},t.prototype.isUnsynced=function(){return this._isUnsynced},t.prototype.setUnsynced=function(t){this._isUnsynced=t},t}(),i=Object.prototype.hasOwnProperty,o=Array.isArray,s=function(){for(var t=[],e=0;e<256;++e)t.push("%"+((e<16?"0":"")+e.toString(16)).toUpperCase());return t}(),a=function(t,e){for(var r=e&&e.plainObjects?Object.create(null):{},n=0;n<t.length;++n)void 0!==t[n]&&(r[n]=t[n]);return r},u={arrayToObject:a,assign:function(t,e){return Object.keys(e).reduce(function(t,r){return t[r]=e[r],t},t)},combine:function(t,e){return[].concat(t,e)},compact:function(t){for(var e=[{obj:{o:t},prop:"o"}],r=[],n=0;n<e.length;++n)for(var i=e[n],s=i.obj[i.prop],a=Object.keys(s),u=0;u<a.length;++u){var c=a[u],f=s[c];"object"==typeof f&&null!==f&&-1===r.indexOf(f)&&(e.push({obj:s,prop:c}),r.push(f))}return function(t){for(;t.length>1;){var e=t.pop(),r=e.obj[e.prop];if(o(r)){for(var n=[],i=0;i<r.length;++i)void 0!==r[i]&&n.push(r[i]);e.obj[e.prop]=n}}}(e),t},decode:function(t,e,r){var n=t.replace(/\+/g," ");if("iso-8859-1"===r)return n.replace(/%[0-9a-f]{2}/gi,unescape);try{return decodeURIComponent(n)}catch(t){return n}},encode:function(t,e,r){if(0===t.length)return t;var n=t;if("symbol"==typeof t?n=Symbol.prototype.toString.call(t):"string"!=typeof t&&(n=String(t)),"iso-8859-1"===r)return escape(n).replace(/%u[0-9a-f]{4}/gi,function(t){return"%26%23"+parseInt(t.slice(2),16)+"%3B"});for(var i="",o=0;o<n.length;++o){var a=n.charCodeAt(o);45===a||46===a||95===a||126===a||a>=48&&a<=57||a>=65&&a<=90||a>=97&&a<=122?i+=n.charAt(o):a<128?i+=s[a]:a<2048?i+=s[192|a>>6]+s[128|63&a]:a<55296||a>=57344?i+=s[224|a>>12]+s[128|a>>6&63]+s[128|63&a]:(o+=1,a=65536+((1023&a)<<10|1023&n.charCodeAt(o)),i+=s[240|a>>18]+s[128|a>>12&63]+s[128|a>>6&63]+s[128|63&a])}return i},isBuffer:function(t){return!(!t||"object"!=typeof t||!(t.constructor&&t.constructor.isBuffer&&t.constructor.isBuffer(t)))},isRegExp:function(t){return"[object RegExp]"===Object.prototype.toString.call(t)},merge:function t(e,r,n){if(!r)return e;if("object"!=typeof r){if(o(e))e.push(r);else{if(!e||"object"!=typeof e)return[e,r];(n&&(n.plainObjects||n.allowPrototypes)||!i.call(Object.prototype,r))&&(e[r]=!0)}return e}if(!e||"object"!=typeof e)return[e].concat(r);var s=e;return o(e)&&!o(r)&&(s=a(e,n)),o(e)&&o(r)?(r.forEach(function(r,o){if(i.call(e,o)){var s=e[o];s&&"object"==typeof s&&r&&"object"==typeof r?e[o]=t(s,r,n):e.push(r)}else e[o]=r}),e):Object.keys(r).reduce(function(e,o){var s=r[o];return i.call(e,o)?e[o]=t(e[o],s,n):e[o]=s,e},s)}},c=String.prototype.replace,f=/%20/g,p={RFC1738:"RFC1738",RFC3986:"RFC3986"},l=u.assign({default:p.RFC3986,formatters:{RFC1738:function(t){return c.call(t,f,"+")},RFC3986:function(t){return String(t)}}},p),d=Object.prototype.hasOwnProperty,h={brackets:function(t){return t+"[]"},comma:"comma",indices:function(t,e){return t+"["+e+"]"},repeat:function(t){return t}},g=Array.isArray,m=Array.prototype.push,y=function(t,e){m.apply(t,g(e)?e:[e])},v=Date.prototype.toISOString,w=l.default,_={addQueryPrefix:!1,allowDots:!1,charset:"utf-8",charsetSentinel:!1,delimiter:"&",encode:!0,encoder:u.encode,encodeValuesOnly:!1,format:w,formatter:l.formatters[w],indices:!1,serializeDate:function(t){return v.call(t)},skipNulls:!1,strictNullHandling:!1},b=function t(e,r,n,i,o,s,a,c,f,p,l,d,h){var m,v=e;if("function"==typeof a?v=a(r,v):v instanceof Date?v=p(v):"comma"===n&&g(v)&&(v=v.join(",")),null===v){if(i)return s&&!d?s(r,_.encoder,h,"key"):r;v=""}if("string"==typeof(m=v)||"number"==typeof m||"boolean"==typeof m||"symbol"==typeof m||"bigint"==typeof m||u.isBuffer(v))return s?[l(d?r:s(r,_.encoder,h,"key"))+"="+l(s(v,_.encoder,h,"value"))]:[l(r)+"="+l(String(v))];var w,b=[];if(void 0===v)return b;if(g(a))w=a;else{var C=Object.keys(v);w=c?C.sort(c):C}for(var S=0;S<w.length;++S){var A=w[S];o&&null===v[A]||(g(v)?y(b,t(v[A],"function"==typeof n?n(r,A):r,n,i,o,s,a,c,f,p,l,d,h)):y(b,t(v[A],r+(f?"."+A:"["+A+"]"),n,i,o,s,a,c,f,p,l,d,h)))}return b},C=(Object.prototype.hasOwnProperty,Array.isArray,function(t,e){var r,n=t,i=function(t){if(!t)return _;if(null!==t.encoder&&void 0!==t.encoder&&"function"!=typeof t.encoder)throw new TypeError("Encoder has to be a function.");var e=t.charset||_.charset;if(void 0!==t.charset&&"utf-8"!==t.charset&&"iso-8859-1"!==t.charset)throw new TypeError("The charset option must be either utf-8, iso-8859-1, or undefined");var r=l.default;if(void 0!==t.format){if(!d.call(l.formatters,t.format))throw new TypeError("Unknown format option provided.");r=t.format}var n=l.formatters[r],i=_.filter;return("function"==typeof t.filter||g(t.filter))&&(i=t.filter),{addQueryPrefix:"boolean"==typeof t.addQueryPrefix?t.addQueryPrefix:_.addQueryPrefix,allowDots:void 0===t.allowDots?_.allowDots:!!t.allowDots,charset:e,charsetSentinel:"boolean"==typeof t.charsetSentinel?t.charsetSentinel:_.charsetSentinel,delimiter:void 0===t.delimiter?_.delimiter:t.delimiter,encode:"boolean"==typeof t.encode?t.encode:_.encode,encoder:"function"==typeof t.encoder?t.encoder:_.encoder,encodeValuesOnly:"boolean"==typeof t.encodeValuesOnly?t.encodeValuesOnly:_.encodeValuesOnly,filter:i,formatter:n,serializeDate:"function"==typeof t.serializeDate?t.serializeDate:_.serializeDate,skipNulls:"boolean"==typeof t.skipNulls?t.skipNulls:_.skipNulls,sort:"function"==typeof t.sort?t.sort:null,strictNullHandling:"boolean"==typeof t.strictNullHandling?t.strictNullHandling:_.strictNullHandling}}(e);"function"==typeof i.filter?n=(0,i.filter)("",n):g(i.filter)&&(r=i.filter);var o,s=[];if("object"!=typeof n||null===n)return"";o=e&&e.arrayFormat in h?e.arrayFormat:e&&"indices"in e?e.indices?"indices":"repeat":"indices";var a=h[o];r||(r=Object.keys(n)),i.sort&&r.sort(i.sort);for(var u=0;u<r.length;++u){var c=r[u];i.skipNulls&&null===n[c]||y(s,b(n[c],c,a,i.strictNullHandling,i.skipNulls,i.encode?i.encoder:null,i.filter,i.sort,i.allowDots,i.serializeDate,i.formatter,i.encodeValuesOnly,i.charset))}var f=s.join(i.delimiter),p=!0===i.addQueryPrefix?"?":"";return i.charsetSentinel&&("iso-8859-1"===i.charset?p+="utf8=%26%2310003%3B&":p+="utf8=%E2%9C%93&"),f.length>0?p+f:""}),S=function(t,e){return function(){for(var r=new Array(arguments.length),n=0;n<r.length;n++)r[n]=arguments[n];return t.apply(e,r)}},A=Object.prototype.toString;function E(t){return"[object Array]"===A.call(t)}function x(t){return null!==t&&"object"==typeof t}function N(t){return"[object Function]"===A.call(t)}function j(t,e){if(null!=t)if("object"!=typeof t&&(t=[t]),E(t))for(var r=0,n=t.length;r<n;r++)e.call(null,t[r],r,t);else for(var i in t)Object.prototype.hasOwnProperty.call(t,i)&&e.call(null,t[i],i,t)}var R={isArray:E,isArrayBuffer:function(t){return"[object ArrayBuffer]"===A.call(t)},isBuffer:function(t){return null!=t&&null!=t.constructor&&"function"==typeof t.constructor.isBuffer&&t.constructor.isBuffer(t)},isFormData:function(t){return"undefined"!=typeof FormData&&t instanceof FormData},isArrayBufferView:function(t){return"undefined"!=typeof ArrayBuffer&&ArrayBuffer.isView?ArrayBuffer.isView(t):t&&t.buffer&&t.buffer instanceof ArrayBuffer},isString:function(t){return"string"==typeof t},isNumber:function(t){return"number"==typeof t},isObject:x,isUndefined:function(t){return void 0===t},isDate:function(t){return"[object Date]"===A.call(t)},isFile:function(t){return"[object File]"===A.call(t)},isBlob:function(t){return"[object Blob]"===A.call(t)},isFunction:N,isStream:function(t){return x(t)&&N(t.pipe)},isURLSearchParams:function(t){return"undefined"!=typeof URLSearchParams&&t instanceof URLSearchParams},isStandardBrowserEnv:function(){return("undefined"==typeof navigator||"ReactNative"!==navigator.product&&"NativeScript"!==navigator.product&&"NS"!==navigator.product)&&"undefined"!=typeof window&&"undefined"!=typeof document},forEach:j,merge:function t(){var e={};function r(r,n){"object"==typeof e[n]&&"object"==typeof r?e[n]=t(e[n],r):e[n]=r}for(var n=0,i=arguments.length;n<i;n++)j(arguments[n],r);return e},deepMerge:function t(){var e={};function r(r,n){"object"==typeof e[n]&&"object"==typeof r?e[n]=t(e[n],r):e[n]="object"==typeof r?t({},r):r}for(var n=0,i=arguments.length;n<i;n++)j(arguments[n],r);return e},extend:function(t,e,r){return j(e,function(e,n){t[n]=r&&"function"==typeof e?S(e,r):e}),t},trim:function(t){return t.replace(/^\s*/,"").replace(/\s*$/,"")}};function V(t){return encodeURIComponent(t).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,"+").replace(/%5B/gi,"[").replace(/%5D/gi,"]")}var O=function(t,e,r){if(!e)return t;var n;if(r)n=r(e);else if(R.isURLSearchParams(e))n=e.toString();else{var i=[];R.forEach(e,function(t,e){null!=t&&(R.isArray(t)?e+="[]":t=[t],R.forEach(t,function(t){R.isDate(t)?t=t.toISOString():R.isObject(t)&&(t=JSON.stringify(t)),i.push(V(e)+"="+V(t))}))}),n=i.join("&")}if(n){var o=t.indexOf("#");-1!==o&&(t=t.slice(0,o)),t+=(-1===t.indexOf("?")?"?":"&")+n}return t};function k(){this.handlers=[]}k.prototype.use=function(t,e){return this.handlers.push({fulfilled:t,rejected:e}),this.handlers.length-1},k.prototype.eject=function(t){this.handlers[t]&&(this.handlers[t]=null)},k.prototype.forEach=function(t){R.forEach(this.handlers,function(e){null!==e&&t(e)})};var U=k,T=function(t,e,r){return R.forEach(r,function(r){t=r(t,e)}),t},D=function(t){return!(!t||!t.__CANCEL__)},L=function(t,e){R.forEach(t,function(r,n){n!==e&&n.toUpperCase()===e.toUpperCase()&&(t[e]=r,delete t[n])})},I=function(t,e,r,n,i){return function(t,e,r,n,i){return t.config=e,r&&(t.code=r),t.request=n,t.response=i,t.isAxiosError=!0,t.toJSON=function(){return{message:this.message,name:this.name,description:this.description,number:this.number,fileName:this.fileName,lineNumber:this.lineNumber,columnNumber:this.columnNumber,stack:this.stack,config:this.config,code:this.code}},t}(new Error(t),e,r,n,i)},P=["age","authorization","content-length","content-type","etag","expires","from","host","if-modified-since","if-unmodified-since","last-modified","location","max-forwards","proxy-authorization","referer","retry-after","user-agent"],B=R.isStandardBrowserEnv()?function(){var t,e=/(msie|trident)/i.test(navigator.userAgent),r=document.createElement("a");function n(t){var n=t;return e&&(r.setAttribute("href",n),n=r.href),r.setAttribute("href",n),{href:r.href,protocol:r.protocol?r.protocol.replace(/:$/,""):"",host:r.host,search:r.search?r.search.replace(/^\?/,""):"",hash:r.hash?r.hash.replace(/^#/,""):"",hostname:r.hostname,port:r.port,pathname:"/"===r.pathname.charAt(0)?r.pathname:"/"+r.pathname}}return t=n(window.location.href),function(e){var r=R.isString(e)?n(e):e;return r.protocol===t.protocol&&r.host===t.host}}():function(){return!0},F=R.isStandardBrowserEnv()?{write:function(t,e,r,n,i,o){var s=[];s.push(t+"="+encodeURIComponent(e)),R.isNumber(r)&&s.push("expires="+new Date(r).toGMTString()),R.isString(n)&&s.push("path="+n),R.isString(i)&&s.push("domain="+i),!0===o&&s.push("secure"),document.cookie=s.join("; ")},read:function(t){var e=document.cookie.match(new RegExp("(^|;\\s*)("+t+")=([^;]*)"));return e?decodeURIComponent(e[3]):null},remove:function(t){this.write(t,"",Date.now()-864e5)}}:{write:function(){},read:function(){return null},remove:function(){}},H=function(t){return new Promise(function(e,r){var n=t.data,i=t.headers;R.isFormData(n)&&delete i["Content-Type"];var o=new XMLHttpRequest;if(t.auth){var s=t.auth.username||"",a=t.auth.password||"";i.Authorization="Basic "+btoa(s+":"+a)}if(o.open(t.method.toUpperCase(),O(t.url,t.params,t.paramsSerializer),!0),o.timeout=t.timeout,o.onreadystatechange=function(){if(o&&4===o.readyState&&(0!==o.status||o.responseURL&&0===o.responseURL.indexOf("file:"))){var n,i,s,a,u,c="getAllResponseHeaders"in o?(n=o.getAllResponseHeaders(),u={},n?(R.forEach(n.split("\n"),function(t){if(a=t.indexOf(":"),i=R.trim(t.substr(0,a)).toLowerCase(),s=R.trim(t.substr(a+1)),i){if(u[i]&&P.indexOf(i)>=0)return;u[i]="set-cookie"===i?(u[i]?u[i]:[]).concat([s]):u[i]?u[i]+", "+s:s}}),u):u):null,f={data:t.responseType&&"text"!==t.responseType?o.response:o.responseText,status:o.status,statusText:o.statusText,headers:c,config:t,request:o};!function(t,e,r){var n=r.config.validateStatus;!n||n(r.status)?t(r):e(I("Request failed with status code "+r.status,r.config,null,r.request,r))}(e,r,f),o=null}},o.onabort=function(){o&&(r(I("Request aborted",t,"ECONNABORTED",o)),o=null)},o.onerror=function(){r(I("Network Error",t,null,o)),o=null},o.ontimeout=function(){r(I("timeout of "+t.timeout+"ms exceeded",t,"ECONNABORTED",o)),o=null},R.isStandardBrowserEnv()){var u=F,c=(t.withCredentials||B(t.url))&&t.xsrfCookieName?u.read(t.xsrfCookieName):void 0;c&&(i[t.xsrfHeaderName]=c)}if("setRequestHeader"in o&&R.forEach(i,function(t,e){void 0===n&&"content-type"===e.toLowerCase()?delete i[e]:o.setRequestHeader(e,t)}),t.withCredentials&&(o.withCredentials=!0),t.responseType)try{o.responseType=t.responseType}catch(e){if("json"!==t.responseType)throw e}"function"==typeof t.onDownloadProgress&&o.addEventListener("progress",t.onDownloadProgress),"function"==typeof t.onUploadProgress&&o.upload&&o.upload.addEventListener("progress",t.onUploadProgress),t.cancelToken&&t.cancelToken.promise.then(function(t){o&&(o.abort(),r(t),o=null)}),void 0===n&&(n=null),o.send(n)})},q={"Content-Type":"application/x-www-form-urlencoded"};function z(t,e){!R.isUndefined(t)&&R.isUndefined(t["Content-Type"])&&(t["Content-Type"]=e)}var J,M={adapter:("undefined"!=typeof process&&"[object process]"===Object.prototype.toString.call(process)?J=H:"undefined"!=typeof XMLHttpRequest&&(J=H),J),transformRequest:[function(t,e){return L(e,"Accept"),L(e,"Content-Type"),R.isFormData(t)||R.isArrayBuffer(t)||R.isBuffer(t)||R.isStream(t)||R.isFile(t)||R.isBlob(t)?t:R.isArrayBufferView(t)?t.buffer:R.isURLSearchParams(t)?(z(e,"application/x-www-form-urlencoded;charset=utf-8"),t.toString()):R.isObject(t)?(z(e,"application/json;charset=utf-8"),JSON.stringify(t)):t}],transformResponse:[function(t){if("string"==typeof t)try{t=JSON.parse(t)}catch(t){}return t}],timeout:0,xsrfCookieName:"XSRF-TOKEN",xsrfHeaderName:"X-XSRF-TOKEN",maxContentLength:-1,validateStatus:function(t){return t>=200&&t<300}};M.headers={common:{Accept:"application/json, text/plain, */*"}},R.forEach(["delete","get","head"],function(t){M.headers[t]={}}),R.forEach(["post","put","patch"],function(t){M.headers[t]=R.merge(q)});var $=M;function W(t){t.cancelToken&&t.cancelToken.throwIfRequested()}var Q=function(t){var e,r,n;return W(t),t.baseURL&&(n=t.url,!/^([a-z][a-z\d\+\-\.]*:)?\/\//i.test(n))&&(t.url=(e=t.baseURL,(r=t.url)?e.replace(/\/+$/,"")+"/"+r.replace(/^\/+/,""):e)),t.headers=t.headers||{},t.data=T(t.data,t.headers,t.transformRequest),t.headers=R.merge(t.headers.common||{},t.headers[t.method]||{},t.headers||{}),R.forEach(["delete","get","head","post","put","patch","common"],function(e){delete t.headers[e]}),(t.adapter||$.adapter)(t).then(function(e){return W(t),e.data=T(e.data,e.headers,t.transformResponse),e},function(e){return D(e)||(W(t),e&&e.response&&(e.response.data=T(e.response.data,e.response.headers,t.transformResponse))),Promise.reject(e)})},X=function(t,e){e=e||{};var r={};return R.forEach(["url","method","params","data"],function(t){void 0!==e[t]&&(r[t]=e[t])}),R.forEach(["headers","auth","proxy"],function(n){R.isObject(e[n])?r[n]=R.deepMerge(t[n],e[n]):void 0!==e[n]?r[n]=e[n]:R.isObject(t[n])?r[n]=R.deepMerge(t[n]):void 0!==t[n]&&(r[n]=t[n])}),R.forEach(["baseURL","transformRequest","transformResponse","paramsSerializer","timeout","withCredentials","adapter","responseType","xsrfCookieName","xsrfHeaderName","onUploadProgress","onDownloadProgress","maxContentLength","validateStatus","maxRedirects","httpAgent","httpsAgent","cancelToken","socketPath"],function(n){void 0!==e[n]?r[n]=e[n]:void 0!==t[n]&&(r[n]=t[n])}),r};function G(t){this.defaults=t,this.interceptors={request:new U,response:new U}}G.prototype.request=function(t){"string"==typeof t?(t=arguments[1]||{}).url=arguments[0]:t=t||{},(t=X(this.defaults,t)).method=t.method?t.method.toLowerCase():"get";var e=[Q,void 0],r=Promise.resolve(t);for(this.interceptors.request.forEach(function(t){e.unshift(t.fulfilled,t.rejected)}),this.interceptors.response.forEach(function(t){e.push(t.fulfilled,t.rejected)});e.length;)r=r.then(e.shift(),e.shift());return r},G.prototype.getUri=function(t){return t=X(this.defaults,t),O(t.url,t.params,t.paramsSerializer).replace(/^\?/,"")},R.forEach(["delete","get","head","options"],function(t){G.prototype[t]=function(e,r){return this.request(R.merge(r||{},{method:t,url:e}))}}),R.forEach(["post","put","patch"],function(t){G.prototype[t]=function(e,r,n){return this.request(R.merge(n||{},{method:t,url:e,data:r}))}});var Z=G;function K(t){this.message=t}K.prototype.toString=function(){return"Cancel"+(this.message?": "+this.message:"")},K.prototype.__CANCEL__=!0;var Y=K;function tt(t){if("function"!=typeof t)throw new TypeError("executor must be a function.");var e;this.promise=new Promise(function(t){e=t});var r=this;t(function(t){r.reason||(r.reason=new Y(t),e(r.reason))})}tt.prototype.throwIfRequested=function(){if(this.reason)throw this.reason},tt.source=function(){var t;return{token:new tt(function(e){t=e}),cancel:t}};var et=tt;function rt(t){var e=new Z(t),r=S(Z.prototype.request,e);return R.extend(r,Z.prototype,e),R.extend(r,e),r}var nt=rt($);nt.Axios=Z,nt.create=function(t){return rt(X(nt.defaults,t))},nt.Cancel=Y,nt.CancelToken=et,nt.isCancel=D,nt.all=function(t){return Promise.all(t)},nt.spread=function(t){return function(e){return t.apply(null,e)}};var it=nt,ot=nt;it.default=ot;var st=it;for(var at={atob:function(t){if((t=(t=`${t}`).replace(/[ \t\n\f\r]/g,"")).length%4==0&&(t=t.replace(/==?$/,"")),t.length%4==1||/[^+\/0-9A-Za-z]/.test(t))return null;let e="",r=0,n=0;for(let o=0;o<t.length;o++)r<<=6,r|=(i=t[o],/[A-Z]/.test(i)?i.charCodeAt(0)-"A".charCodeAt(0):/[a-z]/.test(i)?i.charCodeAt(0)-"a".charCodeAt(0)+26:/[0-9]/.test(i)?i.charCodeAt(0)-"0".charCodeAt(0)+52:"+"===i?62:"/"===i?63:void 0),24===(n+=6)&&(e+=String.fromCharCode((16711680&r)>>16),e+=String.fromCharCode((65280&r)>>8),e+=String.fromCharCode(255&r),r=n=0);var i;return 12===n?(r>>=4,e+=String.fromCharCode(r)):18===n&&(r>>=2,e+=String.fromCharCode((65280&r)>>8),e+=String.fromCharCode(255&r)),e},btoa:function(t){let e;for(t=`${t}`,e=0;e<t.length;e++)if(t.charCodeAt(e)>255)return null;let r="";for(e=0;e<t.length;e+=3){const i=[void 0,void 0,void 0,void 0];i[0]=t.charCodeAt(e)>>2,i[1]=(3&t.charCodeAt(e))<<4,t.length>e+1&&(i[1]|=t.charCodeAt(e+1)>>4,i[2]=(15&t.charCodeAt(e+1))<<2),t.length>e+2&&(i[2]|=t.charCodeAt(e+2)>>6,i[3]=63&t.charCodeAt(e+2));for(let t=0;t<i.length;t++)void 0===i[t]?r+="=":r+=(n=i[t])<26?String.fromCharCode(n+"A".charCodeAt(0)):n<52?String.fromCharCode(n-26+"a".charCodeAt(0)):n<62?String.fromCharCode(n-52+"0".charCodeAt(0)):62===n?"+":63===n?"/":void 0}var n;return r}},ut=function(){function t(){}return t.prototype.getConfig=function(){var t=at.atob(window.TT);if(t)return JSON.parse(t);throw new Error("Unable to parse configuration")},t}(),ct=function(){function t(t,e,r){this._name=t,this._isFeatureGate=e,this._weighting=r}return t.prototype.getName=function(){return this._name},t.prototype.isFeatureGate=function(){return this._isFeatureGate},t.prototype.getVariants=function(){return Object.keys(this._weighting)},t.prototype.getWeighting=function(){return this._weighting},t.prototype.hasVariant=function(t){return t in this._weighting},t}(),ft=function(){return(ft=Object.assign||function(t){for(var e,r=1,n=arguments.length;r<n;r++)for(var i in e=arguments[r])Object.prototype.hasOwnProperty.call(e,i)&&(t[i]=e[i]);return t}).apply(this,arguments)},pt=function(){function t(t){this._splitArray=t||[],this._loaded=null!==t}return t.prototype.getSplit=function(t){return this.getSplits()[t]},t.prototype.isLoaded=function(){return this._loaded},t.prototype.asV1Hash=function(){var t={};for(var e in this.getSplits()){var r=this.getSplits()[e];t[e]=r.getWeighting()}return t},t.prototype.getSplits=function(){return this._loaded?(this._splits||(this._splits=this._splitArray.reduce(function(t,e){var r;return ft(ft({},t),((r={})[e.getName()]=e,r))},{})),this._splits):{}},t}(),lt=null,dt=null,ht=null,gt=function(){if(!lt){var t=new ut;lt=t.getConfig()}return lt},mt={_clear:function(){lt=null},getUrl:function(){return gt().url},getCookieDomain:function(){return gt().cookieDomain},getCookieName:function(){return gt().cookieName||"tt_visitor_id"},getExperienceSamplingWeight:function(){return gt().experienceSamplingWeight},getSplitRegistry:function(){var t=gt().splits;if(!t)return new pt(null);if(!ht){var e=Object.keys(t).map(function(e){var r=t[e];return new ct(e,r.feature_gate,r.weights)});ht=new pt(e)}return ht},getAssignments:function(){var t=gt().assignments;if(!t)return null;if(!dt)for(var e in dt=[],t)dt.push(new n({splitName:e,variant:t[e],isUnsynced:!1}));return dt}},yt=st.create({baseURL:mt.getUrl()+"/api",headers:{"Content-Type":"application/x-www-form-urlencoded"},crossDomain:!0}),vt=function(){function t(t){if(this._visitor=t.visitor,this._assignment=t.assignment,this._username=t.username,this._password=t.password,!this._visitor)throw new Error("must provide visitor");if(!this._assignment)throw new Error("must provide assignment");if(!this._username)throw new Error("must provide username");if(!this._password)throw new Error("must provide password")}return t.prototype.persistAssignment=function(){var t=this;return yt.post("/v1/assignment_override",C({visitor_id:this._visitor.getId(),split_name:this._assignment.getSplitName(),variant:this._assignment.getVariant(),context:this._assignment.getContext(),mixpanel_result:"success"}),{auth:{username:this._username,password:this._password}}).catch(function(e){if(e.response){var r=e.response,n=r.status,i=r.statusText,o=r.data;t._visitor.logError("test_track persistAssignment response error: "+n+", "+i+", "+o)}else t._visitor.logError("test_track persistAssignment other error: "+e)})},t}(),wt=function(){function t(t){if(!t.splitName)throw new Error("must provide splitName");if(!t.hasOwnProperty("trueVariant"))throw new Error("must provide trueVariant");if(!t.visitor)throw new Error("must provide visitor");this._splitName=t.splitName,this._trueVariant=t.trueVariant,this._visitor=t.visitor,this._splitRegistry=mt.getSplitRegistry()}return t.prototype.getVariants=function(){var t=this._getSplitVariants();return t&&t.length>2&&this._visitor.logError("A/B for "+this._splitName+" configures split with more than 2 variants"),{true:this._getTrueVariant(),false:this._getFalseVariant()}},t.prototype._getTrueVariant=function(){return this._trueVariant||"true"},t.prototype._getFalseVariant=function(){var t=this._getNonTrueVariants();return Array.isArray(t)&&0!==t.length?t.sort()[0]:"false"},t.prototype._getNonTrueVariants=function(){var t=this._getSplitVariants();if(t){var e=this._getTrueVariant(),r=t.indexOf(e.toString());return-1!==r&&t.splice(r,1),t}return null},t.prototype._getSplit=function(){return this._splitRegistry.getSplit(this._splitName)},t.prototype._getSplitVariants=function(){return this._getSplit()&&this._getSplit().getVariants()},t}(),_t=function(){function t(t){var e=t.visitor,r=t.assignment;if(this._visitor=e,this._assignment=r,!this._visitor)throw new Error("must provide visitor");if(!this._assignment)throw new Error("must provide assignment")}return t.prototype.send=function(){var t=this,e=this._persistAssignment(),r=new Promise(function(e){t._visitor.analytics.trackAssignment(t._visitor.getId(),t._assignment,function(r){return t._persistAssignment(r?"success":"failure").then(e)})});return Promise.all([e,r])},t.prototype._persistAssignment=function(t){var e=this;return yt.post("/v1/assignment_event",C({visitor_id:this._visitor.getId(),split_name:this._assignment.getSplitName(),context:this._assignment.getContext(),mixpanel_result:t})).catch(function(t){if(t.response){var r=t.response,n=r.status,i=r.statusText,o=r.data;e._visitor.logError("test_track persistAssignment response error: "+n+", "+i+", "+o)}else e._visitor.logError("test_track persistAssignment other error: "+t)})},t}(),bt=function(){function t(t){if(this.visitorId=t.visitorId,this.identifierType=t.identifierType,this.value=t.value,!this.visitorId)throw new Error("must provide visitorId");if(!this.identifierType)throw new Error("must provide identifierType");if(!this.value)throw new Error("must provide value")}return t.prototype.save=function(){return yt.post("/v1/identifier",C({identifier_type:this.identifierType,value:this.value,visitor_id:this.visitorId})).then(function(t){var e=t.data;return new Ot({id:e.visitor.id,assignments:n.fromJsonArray(e.visitor.assignments)})})},t}(),Ct=function(){function t(){}return t.prototype.trackAssignment=function(t,e,r){var n={TTVisitorID:t,SplitName:e.getSplitName(),SplitVariant:e.getVariant(),SplitContext:e.getContext()};window.mixpanel&&window.mixpanel.track("SplitAssigned",n,r)},t.prototype.identify=function(t){window.mixpanel&&window.mixpanel.identify(t)},t.prototype.alias=function(t){window.mixpanel&&window.mixpanel.alias(t)},t}(),St=e(function(t){var e="undefined"!=typeof crypto&&crypto.getRandomValues&&crypto.getRandomValues.bind(crypto)||"undefined"!=typeof msCrypto&&"function"==typeof window.msCrypto.getRandomValues&&msCrypto.getRandomValues.bind(msCrypto);if(e){var r=new Uint8Array(16);t.exports=function(){return e(r),r}}else{var n=new Array(16);t.exports=function(){for(var t,e=0;e<16;e++)0==(3&e)&&(t=4294967296*Math.random()),n[e]=t>>>((3&e)<<3)&255;return n}}}),At=[],Et=0;Et<256;++Et)At[Et]=(Et+256).toString(16).substr(1);var xt=function(t,e){var r=e||0,n=At;return[n[t[r++]],n[t[r++]],n[t[r++]],n[t[r++]],"-",n[t[r++]],n[t[r++]],"-",n[t[r++]],n[t[r++]],"-",n[t[r++]],n[t[r++]],"-",n[t[r++]],n[t[r++]],n[t[r++]],n[t[r++]],n[t[r++]],n[t[r++]]].join("")};var Nt=function(t,e,r){var n=e&&r||0;"string"==typeof t&&(e="binary"===t?new Array(16):null,t=null);var i=(t=t||{}).random||(t.rng||St)();if(i[6]=15&i[6]|64,i[8]=63&i[8]|128,e)for(var o=0;o<16;++o)e[n+o]=i[o];return e||xt(i)},jt=e(function(e){!function(t){function r(t,e){var r=(65535&t)+(65535&e);return(t>>16)+(e>>16)+(r>>16)<<16|65535&r}function n(t,e,n,i,o,s){return r((a=r(r(e,t),r(i,s)))<<(u=o)|a>>>32-u,n);var a,u}function i(t,e,r,i,o,s,a){return n(e&r|~e&i,t,e,o,s,a)}function o(t,e,r,i,o,s,a){return n(e&i|r&~i,t,e,o,s,a)}function s(t,e,r,i,o,s,a){return n(e^r^i,t,e,o,s,a)}function a(t,e,r,i,o,s,a){return n(r^(e|~i),t,e,o,s,a)}function u(t,e){var n,u,c,f,p;t[e>>5]|=128<<e%32,t[14+(e+64>>>9<<4)]=e;var l=1732584193,d=-271733879,h=-1732584194,g=271733878;for(n=0;n<t.length;n+=16)u=l,c=d,f=h,p=g,l=i(l,d,h,g,t[n],7,-680876936),g=i(g,l,d,h,t[n+1],12,-389564586),h=i(h,g,l,d,t[n+2],17,606105819),d=i(d,h,g,l,t[n+3],22,-1044525330),l=i(l,d,h,g,t[n+4],7,-176418897),g=i(g,l,d,h,t[n+5],12,1200080426),h=i(h,g,l,d,t[n+6],17,-1473231341),d=i(d,h,g,l,t[n+7],22,-45705983),l=i(l,d,h,g,t[n+8],7,1770035416),g=i(g,l,d,h,t[n+9],12,-1958414417),h=i(h,g,l,d,t[n+10],17,-42063),d=i(d,h,g,l,t[n+11],22,-1990404162),l=i(l,d,h,g,t[n+12],7,1804603682),g=i(g,l,d,h,t[n+13],12,-40341101),h=i(h,g,l,d,t[n+14],17,-1502002290),l=o(l,d=i(d,h,g,l,t[n+15],22,1236535329),h,g,t[n+1],5,-165796510),g=o(g,l,d,h,t[n+6],9,-1069501632),h=o(h,g,l,d,t[n+11],14,643717713),d=o(d,h,g,l,t[n],20,-373897302),l=o(l,d,h,g,t[n+5],5,-701558691),g=o(g,l,d,h,t[n+10],9,38016083),h=o(h,g,l,d,t[n+15],14,-660478335),d=o(d,h,g,l,t[n+4],20,-405537848),l=o(l,d,h,g,t[n+9],5,568446438),g=o(g,l,d,h,t[n+14],9,-1019803690),h=o(h,g,l,d,t[n+3],14,-187363961),d=o(d,h,g,l,t[n+8],20,1163531501),l=o(l,d,h,g,t[n+13],5,-1444681467),g=o(g,l,d,h,t[n+2],9,-51403784),h=o(h,g,l,d,t[n+7],14,1735328473),l=s(l,d=o(d,h,g,l,t[n+12],20,-1926607734),h,g,t[n+5],4,-378558),g=s(g,l,d,h,t[n+8],11,-2022574463),h=s(h,g,l,d,t[n+11],16,1839030562),d=s(d,h,g,l,t[n+14],23,-35309556),l=s(l,d,h,g,t[n+1],4,-1530992060),g=s(g,l,d,h,t[n+4],11,1272893353),h=s(h,g,l,d,t[n+7],16,-155497632),d=s(d,h,g,l,t[n+10],23,-1094730640),l=s(l,d,h,g,t[n+13],4,681279174),g=s(g,l,d,h,t[n],11,-358537222),h=s(h,g,l,d,t[n+3],16,-722521979),d=s(d,h,g,l,t[n+6],23,76029189),l=s(l,d,h,g,t[n+9],4,-640364487),g=s(g,l,d,h,t[n+12],11,-421815835),h=s(h,g,l,d,t[n+15],16,530742520),l=a(l,d=s(d,h,g,l,t[n+2],23,-995338651),h,g,t[n],6,-198630844),g=a(g,l,d,h,t[n+7],10,1126891415),h=a(h,g,l,d,t[n+14],15,-1416354905),d=a(d,h,g,l,t[n+5],21,-57434055),l=a(l,d,h,g,t[n+12],6,1700485571),g=a(g,l,d,h,t[n+3],10,-1894986606),h=a(h,g,l,d,t[n+10],15,-1051523),d=a(d,h,g,l,t[n+1],21,-2054922799),l=a(l,d,h,g,t[n+8],6,1873313359),g=a(g,l,d,h,t[n+15],10,-30611744),h=a(h,g,l,d,t[n+6],15,-1560198380),d=a(d,h,g,l,t[n+13],21,1309151649),l=a(l,d,h,g,t[n+4],6,-145523070),g=a(g,l,d,h,t[n+11],10,-1120210379),h=a(h,g,l,d,t[n+2],15,718787259),d=a(d,h,g,l,t[n+9],21,-343485551),l=r(l,u),d=r(d,c),h=r(h,f),g=r(g,p);return[l,d,h,g]}function c(t){var e,r="",n=32*t.length;for(e=0;e<n;e+=8)r+=String.fromCharCode(t[e>>5]>>>e%32&255);return r}function f(t){var e,r=[];for(r[(t.length>>2)-1]=void 0,e=0;e<r.length;e+=1)r[e]=0;var n=8*t.length;for(e=0;e<n;e+=8)r[e>>5]|=(255&t.charCodeAt(e/8))<<e%32;return r}function p(t){var e,r,n="";for(r=0;r<t.length;r+=1)e=t.charCodeAt(r),n+="0123456789abcdef".charAt(e>>>4&15)+"0123456789abcdef".charAt(15&e);return n}function l(t){return unescape(encodeURIComponent(t))}function d(t){return function(t){return c(u(f(t),8*t.length))}(l(t))}function h(t,e){return function(t,e){var r,n,i=f(t),o=[],s=[];for(o[15]=s[15]=void 0,i.length>16&&(i=u(i,8*t.length)),r=0;r<16;r+=1)o[r]=909522486^i[r],s[r]=1549556828^i[r];return n=u(o.concat(f(e)),512+8*e.length),c(u(s.concat(n),640))}(l(t),l(e))}function g(t,e,r){return e?r?h(e,t):p(h(e,t)):r?d(t):p(d(t))}e.exports?e.exports=g:t.md5=g}(t)}),Rt=function(){function t(t){if(this.visitor=t.visitor,this.splitName=t.splitName,!this.visitor)throw new Error("must provide visitor");if(!this.splitName)throw new Error("must provide splitName")}return t.prototype.getVariant=function(){if(!mt.getSplitRegistry().isLoaded())return null;for(var t=0,e=this.getAssignmentBucket(),r=this.getWeighting(),n=this.getSortedVariants(),i=0;i<n.length;i++){var o=n[i];if((t+=r[o])>e)return o}throw new Error("Assignment bucket out of range. "+e+" unmatched in "+this.splitName+": "+JSON.stringify(r))},t.prototype.getSplitVisitorHash=function(){return jt(this.splitName+this.visitor.getId())},t.prototype.getHashFixnum=function(){return parseInt(this.getSplitVisitorHash().substr(0,8),16)},t.prototype.getAssignmentBucket=function(){return this.getHashFixnum()%100},t.prototype.getSortedVariants=function(){return this.getVariants().sort()},t.prototype.getVariants=function(){return Object.getOwnPropertyNames(this.getWeighting())},t.prototype.getWeighting=function(){var t=mt.getSplitRegistry().getSplit(this.splitName);if(!t){var e='Unknown split: "'+this.splitName+'"';throw this.visitor.logError(e),new Error(e)}return t.getWeighting()},t}(),Vt=function(){function t(t){if(!t.assignment)throw new Error("must provide assignment");if(!t.visitor)throw new Error("must provide visitor");this._assignment=t.assignment,this._visitor=t.visitor,this._splitRegistry=mt.getSplitRegistry(),this._variantHandlers={}}return t.prototype.when=function(){for(var t=this,e=[],r=0;r<arguments.length;r++)e[r]=arguments[r];var n="function"==typeof e[e.length-1]?e.pop():null;if(0===e.length)throw new Error("must provide at least one variant");e.forEach(function(e){"string"==typeof e&&t._assignHandlerToVariant(e,n)})},t.prototype.default=function(t,e){if(this._defaultVariant)throw new Error("must provide exactly one `default`");this._defaultVariant=this._assignHandlerToVariant(t,e)},t.prototype.run=function(){this._validate();var t=this.getDefaultVariant();if(void 0===t)throw new Error("must provide exactly one `default`");var e=this._variantHandlers[t],r=this._assignment.getVariant();r&&this._variantHandlers[r]?e=this._variantHandlers[r]:this._defaulted=!0,e()},t.prototype.isDefaulted=function(){return this._defaulted||!1},t.prototype.getDefaultVariant=function(){return this._defaultVariant},t.prototype._assignHandlerToVariant=function(t,e){if("function"!=typeof e)throw new Error("must provide handler for "+t);return t=t.toString(),this._getSplit()&&!this._getSplit().hasVariant(t)&&this._visitor.logError("configures unknown variant "+t),this._variantHandlers[t]=e,t},t.prototype._validate=function(){if(!this.getDefaultVariant())throw new Error("must provide exactly one `default`");if(this._getVariants().length<2)throw new Error("must provide at least one `when`");if(this._getSplit()){var t=this._getMissingVariants();if(t.length>0){var e=t.join(", ").replace(/, (.+)$/," and $1");this._visitor.logError("does not configure variants "+e)}}},t.prototype._getSplit=function(){return this._splitRegistry.getSplit(this._assignment.getSplitName())},t.prototype._getVariants=function(){return Object.getOwnPropertyNames(this._variantHandlers)},t.prototype._getMissingVariants=function(){var t=this._getVariants();return this._getSplit().getVariants().filter(function(e){return!t.includes(e)})},t}(),Ot=function(){function t(t){var e=t.id,r=t.assignments,n=t.ttOffline;if(this._id=e,this._assignments=r,this._ttOffline=n,!this._id)throw new Error("must provide id");if(!this._assignments)throw new Error("must provide assignments");this._errorLogger=function(t){window.console.error(t)},this.analytics=new Ct}return t.loadVisitor=function(e){if(e){var r=mt.getAssignments();return r?Promise.resolve(new t({id:e,assignments:r,ttOffline:!1})):yt.get("/v1/visitors/"+e,{timeout:5e3}).then(function(e){var r=e.data;return new t({id:r.id,assignments:n.fromJsonArray(r.assignments),ttOffline:!1})}).catch(function(){return new t({id:e,assignments:[],ttOffline:!0})})}return Promise.resolve(new t({id:Nt(),assignments:[],ttOffline:!1}))},t.prototype.getId=function(){return this._id},t.prototype.getAssignmentRegistry=function(){return this._assignmentRegistry||(this._assignmentRegistry=this._assignments.reduce(function(t,e){var r;return ft(ft({},t),((r={})[e.getSplitName()]=e,r))},{})),this._assignmentRegistry},t.prototype.vary=function(t,e){if("object"!=typeof e.variants)throw new Error("must provide variants object to `vary` for "+t);if(!e.context)throw new Error("must provide context to `vary` for "+t);if(!e.defaultVariant&&!1!==e.defaultVariant)throw new Error("must provide defaultVariant to `vary` for "+t);var r=e.defaultVariant.toString(),n=e.variants,i=e.context;if(!n.hasOwnProperty(r))throw new Error("defaultVariant: "+r+" must be represented in variants object");var o=this._getAssignmentFor(t,i),s=new Vt({assignment:o,visitor:this});for(var a in n)n.hasOwnProperty(a)&&(a===r?s.default(a,n[a]):s.when(a,n[a]));s.run(),s.isDefaulted()&&(o.setVariant(s.getDefaultVariant()),o.setUnsynced(!0),o.setContext(i)),this.notifyUnsyncedAssignments()},t.prototype.ab=function(t,e){var r=new wt({splitName:t,trueVariant:e.trueVariant,visitor:this}).getVariants(),n={};n[r.true.toString()]=function(){e.callback(!0)},n[r.false.toString()]=function(){e.callback(!1)},this.vary(t,{context:e.context,variants:n,defaultVariant:r.false})},t.prototype.setErrorLogger=function(t){if("function"!=typeof t)throw new Error("must provide function for errorLogger");this._errorLogger=t},t.prototype.logError=function(t){this._errorLogger.call(null,t)},t.prototype.linkIdentifier=function(t,e){var r=this;return new bt({identifierType:t,value:e,visitorId:this.getId()}).save().then(function(t){r._merge(t),r.notifyUnsyncedAssignments()})},t.prototype.setAnalytics=function(t){if("object"!=typeof t)throw new Error("must provide object for setAnalytics");this.analytics=t},t.prototype.notifyUnsyncedAssignments=function(){this._getUnsyncedAssignments().forEach(this._notify.bind(this))},t.prototype._getUnsyncedAssignments=function(){var t=this.getAssignmentRegistry();return Object.keys(t).reduce(function(e,r){var n=t[r];return n.isUnsynced()&&e.push(n),e},[])},t.prototype._merge=function(t){var e=this.getAssignmentRegistry(),r=t.getAssignmentRegistry();this._id=t.getId(),Object.assign(e,r)},t.prototype._getAssignmentFor=function(t,e){return this.getAssignmentRegistry()[t]||this._generateAssignmentFor(t,e)},t.prototype._generateAssignmentFor=function(t,e){var r=new Rt({visitor:this,splitName:t}).getVariant();r||(this._ttOffline=!0);var i=new n({splitName:t,variant:r,context:e,isUnsynced:!0});return this._assignments.push(i),this._assignmentRegistry=null,i},t.prototype._notify=function(t){try{if(this._ttOffline)return;new _t({visitor:this,assignment:t}).send(),t.setUnsynced(!1)}catch(t){this.logError("test_track notify error: "+t)}},t}(),kt=null,Ut=(new(function(){function t(){this._visitorLoaded=new Promise(function(t){return kt=t})}return t.prototype.initialize=function(t){var e=r.get(mt.getCookieName());return Ot.loadVisitor(e).then(function(e){t&&t.analytics&&e.setAnalytics(t.analytics),t&&t.errorLogger&&e.setErrorLogger(t.errorLogger),t&&"function"==typeof t.onVisitorLoaded&&t.onVisitorLoaded.call(null,e),e.notifyUnsyncedAssignments(),kt&&kt(e)}),this._setCookie(),this._visitorLoaded},t.prototype.vary=function(t,e){return this._visitorLoaded.then(function(r){r.vary(t,e)})},t.prototype.ab=function(t,e){return this._visitorLoaded.then(function(r){r.ab(t,e)})},t.prototype.logIn=function(t,e){var r=this;return this._visitorLoaded.then(function(n){return n.linkIdentifier(t,e).then(function(){r._setCookie(),n.analytics.identify(n.getId())})})},t.prototype.signUp=function(t,e){var r=this;return this._visitorLoaded.then(function(n){return n.linkIdentifier(t,e).then(function(){r._setCookie(),n.analytics.alias(n.getId())})})},t.prototype._setCookie=function(){return this._visitorLoaded.then(function(t){r.set(mt.getCookieName(),t.getId(),{expires:365,path:"/",domain:mt.getCookieDomain()})})},t.prototype.getPublicAPI=function(){var t=this;return{vary:this.vary.bind(this),ab:this.ab.bind(this),logIn:this.logIn.bind(this),signUp:this.signUp.bind(this),initialize:this.initialize.bind(this),_crx:{loadInfo:function(){return t._visitorLoaded.then(function(t){var e={};for(var r in t.getAssignmentRegistry())e[r]=t.getAssignmentRegistry()[r].getVariant();return{visitorId:t.getId(),splitRegistry:mt.getSplitRegistry().asV1Hash(),assignmentRegistry:e}})},persistAssignment:function(e,r,i,o){return t._visitorLoaded.then(function(t){return new vt({visitor:t,username:i,password:o,assignment:new n({splitName:e,variant:r,context:"chrome_extension",isUnsynced:!0})}).persistAssignment()})}}}},t}())).getPublicAPI(),Tt=function(){window.dispatchEvent(new CustomEvent("tt:lib:loaded",{detail:{TestTrack:Ut}}))},Dt=function(){document.body.classList.add("_tt");try{window.dispatchEvent(new CustomEvent("tt:class:added"))}catch(t){}};try{"loading"===document.readyState?document.addEventListener("DOMContentLoaded",Dt):Dt(),Tt(),window.addEventListener("tt:listener:ready",Tt)}catch(t){}return Ut});
|
@@ -12,9 +12,7 @@ module TestTrack::Controller
|
|
12
12
|
class_methods do
|
13
13
|
def require_feature_flag(feature_flag, *args)
|
14
14
|
before_action(*args) do
|
15
|
-
unless test_track_visitor.ab(feature_flag, context: self.class.name.underscore)
|
16
|
-
raise ActionController::RoutingError, 'Not Found'
|
17
|
-
end
|
15
|
+
raise ActionController::RoutingError, 'Not Found' unless test_track_visitor.ab(feature_flag, context: self.class.name.underscore)
|
18
16
|
end
|
19
17
|
end
|
20
18
|
end
|
@@ -6,6 +6,7 @@ module TestTrack::RequiredOptions
|
|
6
6
|
def require_option!(opts, opt_name, my_opts = {})
|
7
7
|
opt_provided = my_opts[:allow_nil] ? opts.key?(opt_name) : opts[opt_name]
|
8
8
|
raise(ArgumentError, "Must provide #{opt_name}") unless opt_provided
|
9
|
+
|
9
10
|
opts.delete(opt_name)
|
10
11
|
end
|
11
12
|
end
|
@@ -19,10 +19,8 @@ class TestTrack::ABConfiguration
|
|
19
19
|
private
|
20
20
|
|
21
21
|
def build_variant_hash
|
22
|
-
if split_variants && split_variants.size > 2
|
23
|
-
|
24
|
-
end
|
25
|
-
{ true: true_variant, false: false_variant }
|
22
|
+
notify_because_ab("configures split with more than 2 variants") if split_variants && split_variants.size > 2
|
23
|
+
{ true: true_variant, false: false_variant } # rubocop:disable Lint/BooleanSymbol
|
26
24
|
end
|
27
25
|
|
28
26
|
def true_variant
|
@@ -30,7 +28,7 @@ class TestTrack::ABConfiguration
|
|
30
28
|
end
|
31
29
|
|
32
30
|
def false_variant
|
33
|
-
@false_variant ||= non_true_variants.present? ? non_true_variants.
|
31
|
+
@false_variant ||= non_true_variants.present? ? non_true_variants.min : false
|
34
32
|
end
|
35
33
|
|
36
34
|
attr_reader :split_name, :split_registry
|
@@ -9,6 +9,7 @@ module TestTrack::Analytics
|
|
9
9
|
def error_handler=(handler)
|
10
10
|
raise ArgumentError, "error_handler must be a lambda" unless handler.lambda?
|
11
11
|
raise ArgumentError, "error_handler must accept 1 argument" unless handler.arity == 1
|
12
|
+
|
12
13
|
@error_handler = handler
|
13
14
|
end
|
14
15
|
|
@@ -1,5 +1,5 @@
|
|
1
1
|
class TestTrack::ConfigUpdater
|
2
|
-
def initialize(schema_file_path = Rails.root.join('db
|
2
|
+
def initialize(schema_file_path = Rails.root.join('db/test_track_schema.yml'))
|
3
3
|
@schema_file_path = schema_file_path
|
4
4
|
end
|
5
5
|
|
@@ -75,7 +75,7 @@ class TestTrack::ConfigUpdater
|
|
75
75
|
end
|
76
76
|
|
77
77
|
def unpersisted_split_names
|
78
|
-
@
|
78
|
+
@unpersisted_split_names ||= splits.keys - remote_splits.keys
|
79
79
|
end
|
80
80
|
|
81
81
|
def splits
|
@@ -90,7 +90,7 @@ class TestTrack::ConfigUpdater
|
|
90
90
|
end
|
91
91
|
|
92
92
|
def schema_file_hash
|
93
|
-
@
|
93
|
+
@schema_file_hash ||= YAML.safe_load(schema_file_contents) || {}
|
94
94
|
end
|
95
95
|
|
96
96
|
def schema_file_contents
|
@@ -50,26 +50,24 @@ class TestTrack::Fake::SplitRegistry
|
|
50
50
|
end
|
51
51
|
|
52
52
|
def legacy_test_track_schema_yml
|
53
|
-
unless instance_variable_defined?(:@legacy_test_track_schema_yml)
|
54
|
-
@legacy_test_track_schema_yml = _legacy_test_track_schema_yml
|
55
|
-
end
|
53
|
+
@legacy_test_track_schema_yml = _legacy_test_track_schema_yml unless instance_variable_defined?(:@legacy_test_track_schema_yml)
|
56
54
|
@legacy_test_track_schema_yml
|
57
55
|
end
|
58
56
|
|
59
57
|
def _legacy_test_track_schema_yml
|
60
58
|
File.exist?(legacy_test_track_schema_yml_path) &&
|
61
59
|
YAML.load_file(legacy_test_track_schema_yml_path).with_indifferent_access
|
62
|
-
rescue
|
60
|
+
rescue StandardError
|
63
61
|
nil
|
64
62
|
end
|
65
63
|
|
66
64
|
def legacy_test_track_schema_yml_path
|
67
|
-
ENV["TEST_TRACK_SCHEMA_FILE_PATH"] || Rails.root.join('db
|
65
|
+
ENV["TEST_TRACK_SCHEMA_FILE_PATH"] || Rails.root.join('db/test_track_schema.yml').to_s
|
68
66
|
end
|
69
67
|
|
70
68
|
def split_registry_with_deterministic_weights
|
71
69
|
splits = split_hash.each_with_object({}) do |(split_name, weighting_registry), result|
|
72
|
-
default_variant = weighting_registry.keys.
|
70
|
+
default_variant = weighting_registry.keys.min
|
73
71
|
|
74
72
|
adjusted_weights = { default_variant => 100 }
|
75
73
|
weighting_registry.except(default_variant).each_key do |variant|
|
@@ -24,9 +24,7 @@ class TestTrack::JobSession
|
|
24
24
|
|
25
25
|
def notify_unsynced_assignments!
|
26
26
|
identity_visitor_map.each_value do |visitor|
|
27
|
-
if visitor.loaded? && visitor.unsynced_assignments.present?
|
28
|
-
TestTrack::ThreadedVisitorNotifier.new(visitor).notify
|
29
|
-
end
|
27
|
+
TestTrack::ThreadedVisitorNotifier.new(visitor).notify if visitor.loaded? && visitor.unsynced_assignments.present?
|
30
28
|
end
|
31
29
|
end
|
32
30
|
|
@@ -4,7 +4,7 @@ class TestTrack::LazyVisitorByIdentity
|
|
4
4
|
end
|
5
5
|
|
6
6
|
def loaded?
|
7
|
-
@
|
7
|
+
@__visitor__.present?
|
8
8
|
end
|
9
9
|
|
10
10
|
def id_loaded?
|
@@ -13,8 +13,12 @@ class TestTrack::LazyVisitorByIdentity
|
|
13
13
|
|
14
14
|
private
|
15
15
|
|
16
|
-
def method_missing(method, *args, &block)
|
17
|
-
__visitor__.
|
16
|
+
def method_missing(method, *args, &block)
|
17
|
+
if __visitor__.respond_to?(method)
|
18
|
+
__visitor__.send(method, *args, &block)
|
19
|
+
else
|
20
|
+
super
|
21
|
+
end
|
18
22
|
end
|
19
23
|
|
20
24
|
def respond_to_missing?(method, include_private = false)
|
@@ -22,7 +26,7 @@ class TestTrack::LazyVisitorByIdentity
|
|
22
26
|
end
|
23
27
|
|
24
28
|
def __visitor__
|
25
|
-
@
|
29
|
+
@__visitor__ ||= __load_visitor__
|
26
30
|
end
|
27
31
|
|
28
32
|
def __load_visitor__
|
@@ -22,6 +22,7 @@ module TestTrack::MisconfigurationNotifier
|
|
22
22
|
class Airbrake
|
23
23
|
def notify(msg)
|
24
24
|
raise "Aibrake was configured but not found" unless defined?(::Airbrake)
|
25
|
+
|
25
26
|
if ::Airbrake.respond_to?(:notify_or_ignore)
|
26
27
|
::Airbrake.notify_or_ignore(StandardError.new, error_message: msg)
|
27
28
|
else
|
@@ -28,6 +28,7 @@ class TestTrack::NotifyAssignmentJob
|
|
28
28
|
def maybe_track
|
29
29
|
return "failure" unless TestTrack.enabled?
|
30
30
|
return "success" if skip_analytics_event?
|
31
|
+
|
31
32
|
result = TestTrack.analytics.track(TestTrack::AnalyticsEvent.new(visitor_id, assignment))
|
32
33
|
result ? "success" : "failure"
|
33
34
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
class TestTrack::Remote::Identifier
|
2
2
|
include TestTrack::RemoteModel
|
3
3
|
|
4
|
-
collection_path '
|
4
|
+
collection_path 'api/v1/identifier'
|
5
5
|
|
6
6
|
has_one :remote_visitor, data_key: :visitor, class_name: "TestTrack::Remote::Visitor"
|
7
7
|
|
@@ -21,6 +21,7 @@ class TestTrack::Remote::Identifier
|
|
21
21
|
|
22
22
|
def visitor_opts!
|
23
23
|
raise("Visitor data unavailable until you save this identifier.") unless attributes[:remote_visitor]
|
24
|
+
|
24
25
|
{ id: remote_visitor.id, assignments: remote_visitor.assignments }
|
25
26
|
end
|
26
27
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
class TestTrack::Remote::SplitDetail
|
2
2
|
include TestTrack::RemoteModel
|
3
3
|
|
4
|
-
collection_path '
|
4
|
+
collection_path 'api/v1/split_details'
|
5
5
|
|
6
6
|
attributes :name, :hypothesis, :assignment_criteria, :description, :owner, :location, :platform, :variant_details
|
7
7
|
|
@@ -10,7 +10,7 @@ class TestTrack::Remote::SplitDetail
|
|
10
10
|
if faked?
|
11
11
|
new(fake_instance_attributes(name))
|
12
12
|
else
|
13
|
-
get("
|
13
|
+
get("api/v1/split_details/#{name}")
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
@@ -3,7 +3,7 @@ class TestTrack::Remote::SplitRegistry
|
|
3
3
|
|
4
4
|
CACHE_KEY = 'test_track_split_registry'.freeze
|
5
5
|
|
6
|
-
collection_path '
|
6
|
+
collection_path 'api/v3/builds/:build_timestamp/split_registry'
|
7
7
|
|
8
8
|
class << self
|
9
9
|
def fake_instance_attributes(_)
|
@@ -15,7 +15,7 @@ class TestTrack::Remote::SplitRegistry
|
|
15
15
|
if faked?
|
16
16
|
new(fake_instance_attributes(nil))
|
17
17
|
else
|
18
|
-
get(
|
18
|
+
get("api/v3/builds/#{TestTrack.build_timestamp}/split_registry")
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
class TestTrack::Remote::Visitor
|
2
2
|
include TestTrack::RemoteModel
|
3
3
|
|
4
|
-
collection_path '
|
4
|
+
collection_path 'api/v1/visitors'
|
5
5
|
|
6
6
|
has_many :assignments
|
7
7
|
|
@@ -13,7 +13,7 @@ class TestTrack::Remote::Visitor
|
|
13
13
|
if faked?
|
14
14
|
new(fake_instance_attributes(nil))
|
15
15
|
else
|
16
|
-
get("
|
16
|
+
get("api/v1/identifier_types/#{identifier_type}/identifiers/#{identifier_value}/visitor")
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
@@ -8,7 +8,7 @@ class TestTrack::Remote::VisitorDetail
|
|
8
8
|
if faked?
|
9
9
|
new(fake_instance_attributes(nil))
|
10
10
|
else
|
11
|
-
get("
|
11
|
+
get("api/v1/identifier_types/#{identifier_type}/identifiers/#{identifier_value}/visitor_detail")
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
@@ -27,9 +27,9 @@ class TestTrack::SplitRegistry
|
|
27
27
|
registry_hash && registry_hash['splits'][split_name] && registry_hash['splits'][split_name]['weights'].freeze
|
28
28
|
end
|
29
29
|
|
30
|
-
def
|
31
|
-
registry_hash && registry_hash['splits'].
|
32
|
-
|
30
|
+
def to_hash
|
31
|
+
registry_hash && registry_hash['splits'].transform_values do |v|
|
32
|
+
{ weights: v['weights'], feature_gate: v['feature_gate'] }
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
@@ -21,14 +21,12 @@ class TestTrack::ThreadedVisitorNotifier
|
|
21
21
|
|
22
22
|
def new_thread_with_request_store
|
23
23
|
Thread.new(RequestStore.store) do |original_store|
|
24
|
-
begin
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
RequestStore.clear!
|
31
|
-
end
|
24
|
+
RequestStore.begin!
|
25
|
+
RequestStore.store.merge!(original_store)
|
26
|
+
yield
|
27
|
+
ensure
|
28
|
+
RequestStore.end!
|
29
|
+
RequestStore.clear!
|
32
30
|
end
|
33
31
|
end
|
34
32
|
end
|
@@ -14,12 +14,10 @@ class TestTrack::UnsyncedAssignmentsNotifier
|
|
14
14
|
def notify
|
15
15
|
assignments.each do |assignment|
|
16
16
|
build_notify_assignment_job(assignment).tap do |job|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
Delayed::Job.enqueue(build_notify_assignment_job(assignment))
|
22
|
-
end
|
17
|
+
job.perform
|
18
|
+
rescue *TestTrack::SERVER_ERRORS => e
|
19
|
+
Rails.logger.error "TestTrack failed to notify unsynced assignments, retrying. #{e}"
|
20
|
+
Delayed::Job.enqueue(build_notify_assignment_job(assignment))
|
23
21
|
end
|
24
22
|
end
|
25
23
|
end
|
@@ -18,6 +18,7 @@ class TestTrack::VaryDSL
|
|
18
18
|
|
19
19
|
def when(*variants, &block)
|
20
20
|
raise ArgumentError, "must provide at least one variant" if variants.blank?
|
21
|
+
|
21
22
|
variants.each do |variant|
|
22
23
|
assign_behavior_to_variant(variant, block)
|
23
24
|
end
|
@@ -25,6 +26,7 @@ class TestTrack::VaryDSL
|
|
25
26
|
|
26
27
|
def default(variant, &block)
|
27
28
|
raise ArgumentError, "cannot provide more than one `default`" unless default_variant.nil?
|
29
|
+
|
28
30
|
@default_variant = assign_behavior_to_variant(variant, block)
|
29
31
|
end
|
30
32
|
|
@@ -57,6 +59,7 @@ class TestTrack::VaryDSL
|
|
57
59
|
variant = variant.to_s
|
58
60
|
|
59
61
|
raise ArgumentError, "must provide block for #{variant}" unless behavior_proc
|
62
|
+
|
60
63
|
notify_because_vary(<<-MESSAGE) if variant_behaviors.include?(variant)
|
61
64
|
configures variant "#{variant}" more than once.
|
62
65
|
This will raise an error in the next version of test_track_rails_client.
|
@@ -93,6 +96,7 @@ class TestTrack::VaryDSL
|
|
93
96
|
raise ArgumentError, "must provide exactly one `default`" unless default_variant
|
94
97
|
raise ArgumentError, "must provide at least one `when`" unless variant_behaviors.size >= 2
|
95
98
|
return true unless split_variants
|
99
|
+
|
96
100
|
missing_variants = split_variants - variant_behaviors.keys
|
97
101
|
notify_because_vary("does not configure variants #{missing_variants.to_sentence}") && false unless missing_variants.empty?
|
98
102
|
end
|
@@ -23,6 +23,7 @@ class TestTrack::Visitor
|
|
23
23
|
raise "unknown opts: #{opts.keys.to_sentence}" if opts.present?
|
24
24
|
|
25
25
|
raise ArgumentError, "must provide block to `vary` for #{split_name}" unless block_given?
|
26
|
+
|
26
27
|
v = TestTrack::VaryDSL.new(assignment: assignment_for(split_name), context: context, split_registry: split_registry)
|
27
28
|
yield v
|
28
29
|
v.send :run
|
@@ -38,18 +39,18 @@ class TestTrack::Visitor
|
|
38
39
|
ab_configuration = TestTrack::ABConfiguration.new split_name: split_name, true_variant: true_variant, split_registry: split_registry
|
39
40
|
|
40
41
|
vary(split_name, context: context) do |v|
|
41
|
-
v.when ab_configuration.variants[:true] do
|
42
|
+
v.when ab_configuration.variants[:true] do # rubocop:disable Lint/BooleanSymbol
|
42
43
|
true
|
43
44
|
end
|
44
|
-
v.default ab_configuration.variants[:false] do
|
45
|
+
v.default ab_configuration.variants[:false] do # rubocop:disable Lint/BooleanSymbol
|
45
46
|
false
|
46
47
|
end
|
47
48
|
end
|
48
49
|
end
|
49
50
|
|
50
51
|
def assignment_registry
|
51
|
-
@assignment_registry ||= assignments.
|
52
|
-
|
52
|
+
@assignment_registry ||= assignments.index_by do |assignment|
|
53
|
+
assignment.split_name
|
53
54
|
end
|
54
55
|
end
|
55
56
|
|
@@ -28,8 +28,9 @@ class TestTrack::WebSession
|
|
28
28
|
url: TestTrack.url,
|
29
29
|
cookieDomain: cookie_domain,
|
30
30
|
cookieName: visitor_cookie_name,
|
31
|
-
|
32
|
-
assignments: current_visitor.assignment_json
|
31
|
+
splits: current_visitor.split_registry.to_hash,
|
32
|
+
assignments: current_visitor.assignment_json,
|
33
|
+
experienceSamplingWeight: current_visitor.split_registry.experience_sampling_weight
|
33
34
|
}
|
34
35
|
end
|
35
36
|
|
@@ -58,6 +59,7 @@ class TestTrack::WebSession
|
|
58
59
|
|
59
60
|
If your app doesn't support authentication, set it to `:none`.
|
60
61
|
ERROR
|
62
|
+
|
61
63
|
identity = controller.class.test_track_identity
|
62
64
|
controller.send(identity) unless identity == :none
|
63
65
|
end
|
@@ -92,7 +94,7 @@ class TestTrack::WebSession
|
|
92
94
|
end
|
93
95
|
|
94
96
|
def _cookie_domain
|
95
|
-
if bare_ip_address? || fully_qualified_cookie_domain_enabled?
|
97
|
+
if bare_ip_address? || request.local? || fully_qualified_cookie_domain_enabled?
|
96
98
|
request.host
|
97
99
|
else
|
98
100
|
wildcard_domain
|
@@ -34,9 +34,7 @@ class TestTrack::WebSessionVisitorRepository
|
|
34
34
|
|
35
35
|
def notify_unsynced_assignments!
|
36
36
|
all.each do |visitor|
|
37
|
-
if visitor.loaded? && visitor.unsynced_assignments.present?
|
38
|
-
TestTrack::ThreadedVisitorNotifier.new(visitor).notify
|
39
|
-
end
|
37
|
+
TestTrack::ThreadedVisitorNotifier.new(visitor).notify if visitor.loaded? && visitor.unsynced_assignments.present?
|
40
38
|
end
|
41
39
|
end
|
42
40
|
|
@@ -0,0 +1 @@
|
|
1
|
+
TestTrack.set_build_timestamp! unless ENV['SKIP_TESTTRACK_SET_BUILD_TIMESTAMP'] == '1'
|
@@ -10,6 +10,24 @@ namespace :test_track do
|
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
13
|
+
desc 'Generates build timestamp for fetching point-in-time split registries'
|
14
|
+
task generate_build_timestamp: :environment do
|
15
|
+
cli = TesttrackCli.instance
|
16
|
+
|
17
|
+
result = cli.call('generate_build_timestamp')
|
18
|
+
exit(result.exitstatus) unless result.success?
|
19
|
+
end
|
20
|
+
|
21
|
+
desc 'Sets an environment variable to block build timestamp generation on application initialization'
|
22
|
+
task :skip_set_build_timestamp do # rubocop:disable Rails/RakeEnvironment
|
23
|
+
ENV['SKIP_TESTTRACK_SET_BUILD_TIMESTAMP'] = '1'
|
24
|
+
end
|
25
|
+
|
26
|
+
desc 'Removes the testtrack/build_timestamp file'
|
27
|
+
task remove_build_timestamp: :environment do
|
28
|
+
File.delete('testtrack/build_timestamp') if File.exist?('testtrack/build_timestamp')
|
29
|
+
end
|
30
|
+
|
13
31
|
namespace :schema do
|
14
32
|
desc 'Load schema.yml state into TestTrack server'
|
15
33
|
task load: :environment do
|
@@ -28,6 +46,9 @@ namespace :test_track do
|
|
28
46
|
end
|
29
47
|
end
|
30
48
|
|
49
|
+
task 'assets:clobber' => ['test_track:remove_build_timestamp']
|
50
|
+
task 'assets:environment' => ['test_track:skip_set_build_timestamp']
|
51
|
+
task 'assets:precompile' => ['test_track:generate_build_timestamp']
|
31
52
|
task 'db:schema:load' => ['test_track:schema:load']
|
32
53
|
task 'db:structure:load' => ['test_track:schema:load']
|
33
54
|
task 'db:migrate' => ['test_track:migrate']
|
data/lib/test_track.rb
CHANGED
@@ -16,6 +16,8 @@ module TestTrack
|
|
16
16
|
module_function
|
17
17
|
|
18
18
|
SERVER_ERRORS = [Faraday::ConnectionFailed, Faraday::TimeoutError, Her::Errors::RemoteServerError].freeze
|
19
|
+
BUILD_TIMESTAMP_FILE_PATH = 'testtrack/build_timestamp'.freeze
|
20
|
+
BUILD_TIMESTAMP_REGEX = /\A\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d(.\d+)?([+-][0-2]\d:[0-5]\d|Z)\z/.freeze
|
19
21
|
|
20
22
|
mattr_accessor :enabled_override, :app_name
|
21
23
|
|
@@ -52,6 +54,26 @@ module TestTrack
|
|
52
54
|
@misconfiguration_notifier_class_name = notifier_class_name
|
53
55
|
end
|
54
56
|
|
57
|
+
def build_timestamp # rubocop:disable Metrics/MethodLength
|
58
|
+
@build_timestamp ||= begin
|
59
|
+
timestamp = _build_timestamp
|
60
|
+
|
61
|
+
if Rails.env.test? || Rails.env.development?
|
62
|
+
Time.zone.now.iso8601
|
63
|
+
elsif timestamp.present?
|
64
|
+
unless BUILD_TIMESTAMP_REGEX.match?(timestamp)
|
65
|
+
raise "./testtrack/build_timestamp is not a valid ISO 8601 timestamp, got '#{timestamp}'"
|
66
|
+
end
|
67
|
+
|
68
|
+
timestamp
|
69
|
+
else
|
70
|
+
raise 'TestTrack failed to load the required build timestamp. ' \
|
71
|
+
'Ensure `test_track:generate_build_timestamp` task is run in `assets:precompile` and the build timestamp file is present.'
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
alias set_build_timestamp! build_timestamp
|
76
|
+
|
55
77
|
private
|
56
78
|
|
57
79
|
def analytics_instance
|
@@ -95,6 +117,7 @@ module TestTrack
|
|
95
117
|
|
96
118
|
def url
|
97
119
|
return nil unless private_url
|
120
|
+
|
98
121
|
full_uri = URI.parse(private_url)
|
99
122
|
full_uri.user = nil
|
100
123
|
full_uri.password = nil
|
@@ -105,6 +128,10 @@ module TestTrack
|
|
105
128
|
ENV['TEST_TRACK_API_URL']
|
106
129
|
end
|
107
130
|
|
131
|
+
def _build_timestamp
|
132
|
+
File.read(BUILD_TIMESTAMP_FILE_PATH).chomp.presence if File.exist?(BUILD_TIMESTAMP_FILE_PATH)
|
133
|
+
end
|
134
|
+
|
108
135
|
def enabled?
|
109
136
|
enabled_override.nil? ? !Rails.env.test? : enabled_override
|
110
137
|
end
|
@@ -2,13 +2,15 @@ require 'delayed_job'
|
|
2
2
|
|
3
3
|
begin
|
4
4
|
require 'airbrake'
|
5
|
-
rescue LoadError
|
5
|
+
rescue LoadError
|
6
|
+
# no-op
|
6
7
|
end
|
7
8
|
|
8
9
|
unless defined?(Delayed::Plugins::Airbrake) && Delayed::Worker.plugins.include?(Delayed::Plugins::Airbrake)
|
9
10
|
begin
|
10
11
|
require 'delayed-plugins-airbrake'
|
11
|
-
rescue LoadError
|
12
|
+
rescue LoadError
|
13
|
+
# no-op
|
12
14
|
end
|
13
15
|
end
|
14
16
|
|
Binary file
|
Binary file
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: test_track_rails_client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.0.0.
|
4
|
+
version: 4.0.0.rc3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ryan O'Neill
|
@@ -10,10 +10,10 @@ authors:
|
|
10
10
|
- John Mileham
|
11
11
|
- Alan Norton
|
12
12
|
- Sam Moore
|
13
|
-
autorequire:
|
13
|
+
autorequire:
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
|
-
date:
|
16
|
+
date: 2020-12-04 00:00:00.000000000 Z
|
17
17
|
dependencies:
|
18
18
|
- !ruby/object:Gem::Dependency
|
19
19
|
name: delayed_job
|
@@ -134,7 +134,7 @@ dependencies:
|
|
134
134
|
version: '4.1'
|
135
135
|
- - "<"
|
136
136
|
- !ruby/object:Gem::Version
|
137
|
-
version: '
|
137
|
+
version: '7.0'
|
138
138
|
type: :runtime
|
139
139
|
prerelease: false
|
140
140
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -144,7 +144,7 @@ dependencies:
|
|
144
144
|
version: '4.1'
|
145
145
|
- - "<"
|
146
146
|
- !ruby/object:Gem::Version
|
147
|
-
version: '
|
147
|
+
version: '7.0'
|
148
148
|
- !ruby/object:Gem::Dependency
|
149
149
|
name: request_store
|
150
150
|
requirement: !ruby/object:Gem::Requirement
|
@@ -161,20 +161,132 @@ dependencies:
|
|
161
161
|
version: '1.3'
|
162
162
|
- !ruby/object:Gem::Dependency
|
163
163
|
name: appraisal
|
164
|
+
requirement: !ruby/object:Gem::Requirement
|
165
|
+
requirements:
|
166
|
+
- - ">="
|
167
|
+
- !ruby/object:Gem::Version
|
168
|
+
version: '0'
|
169
|
+
type: :development
|
170
|
+
prerelease: false
|
171
|
+
version_requirements: !ruby/object:Gem::Requirement
|
172
|
+
requirements:
|
173
|
+
- - ">="
|
174
|
+
- !ruby/object:Gem::Version
|
175
|
+
version: '0'
|
176
|
+
- !ruby/object:Gem::Dependency
|
177
|
+
name: pry-rails
|
178
|
+
requirement: !ruby/object:Gem::Requirement
|
179
|
+
requirements:
|
180
|
+
- - ">="
|
181
|
+
- !ruby/object:Gem::Version
|
182
|
+
version: '0'
|
183
|
+
type: :development
|
184
|
+
prerelease: false
|
185
|
+
version_requirements: !ruby/object:Gem::Requirement
|
186
|
+
requirements:
|
187
|
+
- - ">="
|
188
|
+
- !ruby/object:Gem::Version
|
189
|
+
version: '0'
|
190
|
+
- !ruby/object:Gem::Dependency
|
191
|
+
name: rails-controller-testing
|
192
|
+
requirement: !ruby/object:Gem::Requirement
|
193
|
+
requirements:
|
194
|
+
- - ">="
|
195
|
+
- !ruby/object:Gem::Version
|
196
|
+
version: '0'
|
197
|
+
type: :development
|
198
|
+
prerelease: false
|
199
|
+
version_requirements: !ruby/object:Gem::Requirement
|
200
|
+
requirements:
|
201
|
+
- - ">="
|
202
|
+
- !ruby/object:Gem::Version
|
203
|
+
version: '0'
|
204
|
+
- !ruby/object:Gem::Dependency
|
205
|
+
name: rspec-rails
|
206
|
+
requirement: !ruby/object:Gem::Requirement
|
207
|
+
requirements:
|
208
|
+
- - ">="
|
209
|
+
- !ruby/object:Gem::Version
|
210
|
+
version: '0'
|
211
|
+
type: :development
|
212
|
+
prerelease: false
|
213
|
+
version_requirements: !ruby/object:Gem::Requirement
|
214
|
+
requirements:
|
215
|
+
- - ">="
|
216
|
+
- !ruby/object:Gem::Version
|
217
|
+
version: '0'
|
218
|
+
- !ruby/object:Gem::Dependency
|
219
|
+
name: rubocop
|
164
220
|
requirement: !ruby/object:Gem::Requirement
|
165
221
|
requirements:
|
166
222
|
- - "~>"
|
167
223
|
- !ruby/object:Gem::Version
|
168
|
-
version:
|
224
|
+
version: 0.81.0
|
169
225
|
type: :development
|
170
226
|
prerelease: false
|
171
227
|
version_requirements: !ruby/object:Gem::Requirement
|
172
228
|
requirements:
|
173
229
|
- - "~>"
|
174
230
|
- !ruby/object:Gem::Version
|
175
|
-
version:
|
231
|
+
version: 0.81.0
|
176
232
|
- !ruby/object:Gem::Dependency
|
177
|
-
name:
|
233
|
+
name: rubocop-performance
|
234
|
+
requirement: !ruby/object:Gem::Requirement
|
235
|
+
requirements:
|
236
|
+
- - ">="
|
237
|
+
- !ruby/object:Gem::Version
|
238
|
+
version: '0'
|
239
|
+
type: :development
|
240
|
+
prerelease: false
|
241
|
+
version_requirements: !ruby/object:Gem::Requirement
|
242
|
+
requirements:
|
243
|
+
- - ">="
|
244
|
+
- !ruby/object:Gem::Version
|
245
|
+
version: '0'
|
246
|
+
- !ruby/object:Gem::Dependency
|
247
|
+
name: rubocop-rails
|
248
|
+
requirement: !ruby/object:Gem::Requirement
|
249
|
+
requirements:
|
250
|
+
- - ">="
|
251
|
+
- !ruby/object:Gem::Version
|
252
|
+
version: '0'
|
253
|
+
type: :development
|
254
|
+
prerelease: false
|
255
|
+
version_requirements: !ruby/object:Gem::Requirement
|
256
|
+
requirements:
|
257
|
+
- - ">="
|
258
|
+
- !ruby/object:Gem::Version
|
259
|
+
version: '0'
|
260
|
+
- !ruby/object:Gem::Dependency
|
261
|
+
name: shoulda-matchers
|
262
|
+
requirement: !ruby/object:Gem::Requirement
|
263
|
+
requirements:
|
264
|
+
- - ">="
|
265
|
+
- !ruby/object:Gem::Version
|
266
|
+
version: '2.8'
|
267
|
+
type: :development
|
268
|
+
prerelease: false
|
269
|
+
version_requirements: !ruby/object:Gem::Requirement
|
270
|
+
requirements:
|
271
|
+
- - ">="
|
272
|
+
- !ruby/object:Gem::Version
|
273
|
+
version: '2.8'
|
274
|
+
- !ruby/object:Gem::Dependency
|
275
|
+
name: simplecov
|
276
|
+
requirement: !ruby/object:Gem::Requirement
|
277
|
+
requirements:
|
278
|
+
- - ">="
|
279
|
+
- !ruby/object:Gem::Version
|
280
|
+
version: '0'
|
281
|
+
type: :development
|
282
|
+
prerelease: false
|
283
|
+
version_requirements: !ruby/object:Gem::Requirement
|
284
|
+
requirements:
|
285
|
+
- - ">="
|
286
|
+
- !ruby/object:Gem::Version
|
287
|
+
version: '0'
|
288
|
+
- !ruby/object:Gem::Dependency
|
289
|
+
name: sqlite3
|
178
290
|
requirement: !ruby/object:Gem::Requirement
|
179
291
|
requirements:
|
180
292
|
- - ">="
|
@@ -205,16 +317,16 @@ dependencies:
|
|
205
317
|
name: webmock
|
206
318
|
requirement: !ruby/object:Gem::Requirement
|
207
319
|
requirements:
|
208
|
-
- - "
|
320
|
+
- - ">="
|
209
321
|
- !ruby/object:Gem::Version
|
210
|
-
version:
|
322
|
+
version: '0'
|
211
323
|
type: :development
|
212
324
|
prerelease: false
|
213
325
|
version_requirements: !ruby/object:Gem::Requirement
|
214
326
|
requirements:
|
215
|
-
- - "
|
327
|
+
- - ">="
|
216
328
|
- !ruby/object:Gem::Version
|
217
|
-
version:
|
329
|
+
version: '0'
|
218
330
|
description: Easy split testing and feature flagging for Rails with TestTrack server
|
219
331
|
email:
|
220
332
|
- ryan.oneill@betterment.com
|
@@ -285,6 +397,7 @@ files:
|
|
285
397
|
- app/views/tt/api/v1/split_details/show.json.jbuilder
|
286
398
|
- app/views/tt/api/v1/visitors/_show.json.jbuilder
|
287
399
|
- app/views/tt/api/v1/visitors/show.json.jbuilder
|
400
|
+
- config/initializers/set_build_timestamp.rb
|
288
401
|
- config/initializers/test_track_api.rb
|
289
402
|
- config/routes.rb
|
290
403
|
- lib/generators/test_track/migration_generator.rb
|
@@ -341,7 +454,7 @@ homepage: https://github.com/Betterment
|
|
341
454
|
licenses:
|
342
455
|
- MIT
|
343
456
|
metadata: {}
|
344
|
-
post_install_message:
|
457
|
+
post_install_message:
|
345
458
|
rdoc_options: []
|
346
459
|
require_paths:
|
347
460
|
- lib
|
@@ -349,16 +462,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
349
462
|
requirements:
|
350
463
|
- - ">="
|
351
464
|
- !ruby/object:Gem::Version
|
352
|
-
version: 2.
|
465
|
+
version: 2.5.0
|
353
466
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
354
467
|
requirements:
|
355
468
|
- - ">"
|
356
469
|
- !ruby/object:Gem::Version
|
357
470
|
version: 1.3.1
|
358
471
|
requirements: []
|
359
|
-
|
360
|
-
|
361
|
-
signing_key:
|
472
|
+
rubygems_version: 3.1.4
|
473
|
+
signing_key:
|
362
474
|
specification_version: 4
|
363
475
|
summary: Rails client for TestTrack
|
364
476
|
test_files: []
|