Compare commits
	
		
			10 Commits
		
	
	
		
			75cd696b26
			...
			de878594ea
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					de878594ea | ||
| e28751521d | |||
| 0502bc4552 | |||
| 7d8ecfd0e3 | |||
| 78ab27a697 | |||
| 12174b6f20 | |||
| 0d1b64256d | |||
| ac659bef86 | |||
| dd14a96e98 | |||
| 75a0191d40 | 
							
								
								
									
										160
									
								
								Gemfile.lock
									
									
									
									
									
								
							
							
						
						
									
										160
									
								
								Gemfile.lock
									
									
									
									
									
								
							@ -1,29 +1,29 @@
 | 
				
			|||||||
GEM
 | 
					GEM
 | 
				
			||||||
  remote: https://rubygems.org/
 | 
					  remote: https://rubygems.org/
 | 
				
			||||||
  specs:
 | 
					  specs:
 | 
				
			||||||
    actioncable (8.0.2)
 | 
					    actioncable (8.0.2.1)
 | 
				
			||||||
      actionpack (= 8.0.2)
 | 
					      actionpack (= 8.0.2.1)
 | 
				
			||||||
      activesupport (= 8.0.2)
 | 
					      activesupport (= 8.0.2.1)
 | 
				
			||||||
      nio4r (~> 2.0)
 | 
					      nio4r (~> 2.0)
 | 
				
			||||||
      websocket-driver (>= 0.6.1)
 | 
					      websocket-driver (>= 0.6.1)
 | 
				
			||||||
      zeitwerk (~> 2.6)
 | 
					      zeitwerk (~> 2.6)
 | 
				
			||||||
    actionmailbox (8.0.2)
 | 
					    actionmailbox (8.0.2.1)
 | 
				
			||||||
      actionpack (= 8.0.2)
 | 
					      actionpack (= 8.0.2.1)
 | 
				
			||||||
      activejob (= 8.0.2)
 | 
					      activejob (= 8.0.2.1)
 | 
				
			||||||
      activerecord (= 8.0.2)
 | 
					      activerecord (= 8.0.2.1)
 | 
				
			||||||
      activestorage (= 8.0.2)
 | 
					      activestorage (= 8.0.2.1)
 | 
				
			||||||
      activesupport (= 8.0.2)
 | 
					      activesupport (= 8.0.2.1)
 | 
				
			||||||
      mail (>= 2.8.0)
 | 
					      mail (>= 2.8.0)
 | 
				
			||||||
    actionmailer (8.0.2)
 | 
					    actionmailer (8.0.2.1)
 | 
				
			||||||
      actionpack (= 8.0.2)
 | 
					      actionpack (= 8.0.2.1)
 | 
				
			||||||
      actionview (= 8.0.2)
 | 
					      actionview (= 8.0.2.1)
 | 
				
			||||||
      activejob (= 8.0.2)
 | 
					      activejob (= 8.0.2.1)
 | 
				
			||||||
      activesupport (= 8.0.2)
 | 
					      activesupport (= 8.0.2.1)
 | 
				
			||||||
      mail (>= 2.8.0)
 | 
					      mail (>= 2.8.0)
 | 
				
			||||||
      rails-dom-testing (~> 2.2)
 | 
					      rails-dom-testing (~> 2.2)
 | 
				
			||||||
    actionpack (8.0.2)
 | 
					    actionpack (8.0.2.1)
 | 
				
			||||||
      actionview (= 8.0.2)
 | 
					      actionview (= 8.0.2.1)
 | 
				
			||||||
      activesupport (= 8.0.2)
 | 
					      activesupport (= 8.0.2.1)
 | 
				
			||||||
      nokogiri (>= 1.8.5)
 | 
					      nokogiri (>= 1.8.5)
 | 
				
			||||||
      rack (>= 2.2.4)
 | 
					      rack (>= 2.2.4)
 | 
				
			||||||
      rack-session (>= 1.0.1)
 | 
					      rack-session (>= 1.0.1)
 | 
				
			||||||
@ -31,35 +31,35 @@ GEM
 | 
				
			|||||||
      rails-dom-testing (~> 2.2)
 | 
					      rails-dom-testing (~> 2.2)
 | 
				
			||||||
      rails-html-sanitizer (~> 1.6)
 | 
					      rails-html-sanitizer (~> 1.6)
 | 
				
			||||||
      useragent (~> 0.16)
 | 
					      useragent (~> 0.16)
 | 
				
			||||||
    actiontext (8.0.2)
 | 
					    actiontext (8.0.2.1)
 | 
				
			||||||
      actionpack (= 8.0.2)
 | 
					      actionpack (= 8.0.2.1)
 | 
				
			||||||
      activerecord (= 8.0.2)
 | 
					      activerecord (= 8.0.2.1)
 | 
				
			||||||
      activestorage (= 8.0.2)
 | 
					      activestorage (= 8.0.2.1)
 | 
				
			||||||
      activesupport (= 8.0.2)
 | 
					      activesupport (= 8.0.2.1)
 | 
				
			||||||
      globalid (>= 0.6.0)
 | 
					      globalid (>= 0.6.0)
 | 
				
			||||||
      nokogiri (>= 1.8.5)
 | 
					      nokogiri (>= 1.8.5)
 | 
				
			||||||
    actionview (8.0.2)
 | 
					    actionview (8.0.2.1)
 | 
				
			||||||
      activesupport (= 8.0.2)
 | 
					      activesupport (= 8.0.2.1)
 | 
				
			||||||
      builder (~> 3.1)
 | 
					      builder (~> 3.1)
 | 
				
			||||||
      erubi (~> 1.11)
 | 
					      erubi (~> 1.11)
 | 
				
			||||||
      rails-dom-testing (~> 2.2)
 | 
					      rails-dom-testing (~> 2.2)
 | 
				
			||||||
      rails-html-sanitizer (~> 1.6)
 | 
					      rails-html-sanitizer (~> 1.6)
 | 
				
			||||||
    activejob (8.0.2)
 | 
					    activejob (8.0.2.1)
 | 
				
			||||||
      activesupport (= 8.0.2)
 | 
					      activesupport (= 8.0.2.1)
 | 
				
			||||||
      globalid (>= 0.3.6)
 | 
					      globalid (>= 0.3.6)
 | 
				
			||||||
    activemodel (8.0.2)
 | 
					    activemodel (8.0.2.1)
 | 
				
			||||||
      activesupport (= 8.0.2)
 | 
					      activesupport (= 8.0.2.1)
 | 
				
			||||||
    activerecord (8.0.2)
 | 
					    activerecord (8.0.2.1)
 | 
				
			||||||
      activemodel (= 8.0.2)
 | 
					      activemodel (= 8.0.2.1)
 | 
				
			||||||
      activesupport (= 8.0.2)
 | 
					      activesupport (= 8.0.2.1)
 | 
				
			||||||
      timeout (>= 0.4.0)
 | 
					      timeout (>= 0.4.0)
 | 
				
			||||||
    activestorage (8.0.2)
 | 
					    activestorage (8.0.2.1)
 | 
				
			||||||
      actionpack (= 8.0.2)
 | 
					      actionpack (= 8.0.2.1)
 | 
				
			||||||
      activejob (= 8.0.2)
 | 
					      activejob (= 8.0.2.1)
 | 
				
			||||||
      activerecord (= 8.0.2)
 | 
					      activerecord (= 8.0.2.1)
 | 
				
			||||||
      activesupport (= 8.0.2)
 | 
					      activesupport (= 8.0.2.1)
 | 
				
			||||||
      marcel (~> 1.0)
 | 
					      marcel (~> 1.0)
 | 
				
			||||||
    activesupport (8.0.2)
 | 
					    activesupport (8.0.2.1)
 | 
				
			||||||
      base64
 | 
					      base64
 | 
				
			||||||
      benchmark (>= 0.3)
 | 
					      benchmark (>= 0.3)
 | 
				
			||||||
      bigdecimal
 | 
					      bigdecimal
 | 
				
			||||||
@ -201,7 +201,7 @@ GEM
 | 
				
			|||||||
    msgpack (1.7.5)
 | 
					    msgpack (1.7.5)
 | 
				
			||||||
    multi_xml (0.7.1)
 | 
					    multi_xml (0.7.1)
 | 
				
			||||||
      bigdecimal (~> 3.1)
 | 
					      bigdecimal (~> 3.1)
 | 
				
			||||||
    net-imap (0.5.6)
 | 
					    net-imap (0.5.10)
 | 
				
			||||||
      date
 | 
					      date
 | 
				
			||||||
      net-protocol
 | 
					      net-protocol
 | 
				
			||||||
    net-pop (0.1.2)
 | 
					    net-pop (0.1.2)
 | 
				
			||||||
@ -211,18 +211,18 @@ GEM
 | 
				
			|||||||
    net-smtp (0.5.1)
 | 
					    net-smtp (0.5.1)
 | 
				
			||||||
      net-protocol
 | 
					      net-protocol
 | 
				
			||||||
    nio4r (2.7.4)
 | 
					    nio4r (2.7.4)
 | 
				
			||||||
    nokogiri (1.18.9)
 | 
					    nokogiri (1.18.10)
 | 
				
			||||||
      mini_portile2 (~> 2.8.2)
 | 
					      mini_portile2 (~> 2.8.2)
 | 
				
			||||||
      racc (~> 1.4)
 | 
					      racc (~> 1.4)
 | 
				
			||||||
    nokogiri (1.18.9-aarch64-linux-gnu)
 | 
					    nokogiri (1.18.10-aarch64-linux-gnu)
 | 
				
			||||||
      racc (~> 1.4)
 | 
					      racc (~> 1.4)
 | 
				
			||||||
    nokogiri (1.18.9-arm-linux-gnu)
 | 
					    nokogiri (1.18.10-arm-linux-gnu)
 | 
				
			||||||
      racc (~> 1.4)
 | 
					      racc (~> 1.4)
 | 
				
			||||||
    nokogiri (1.18.9-arm64-darwin)
 | 
					    nokogiri (1.18.10-arm64-darwin)
 | 
				
			||||||
      racc (~> 1.4)
 | 
					      racc (~> 1.4)
 | 
				
			||||||
    nokogiri (1.18.9-x86_64-darwin)
 | 
					    nokogiri (1.18.10-x86_64-darwin)
 | 
				
			||||||
      racc (~> 1.4)
 | 
					      racc (~> 1.4)
 | 
				
			||||||
    nokogiri (1.18.9-x86_64-linux-gnu)
 | 
					    nokogiri (1.18.10-x86_64-linux-gnu)
 | 
				
			||||||
      racc (~> 1.4)
 | 
					      racc (~> 1.4)
 | 
				
			||||||
    orm_adapter (0.5.0)
 | 
					    orm_adapter (0.5.0)
 | 
				
			||||||
    ostruct (0.6.2)
 | 
					    ostruct (0.6.2)
 | 
				
			||||||
@ -264,20 +264,20 @@ GEM
 | 
				
			|||||||
      rack (>= 1.3)
 | 
					      rack (>= 1.3)
 | 
				
			||||||
    rackup (2.2.1)
 | 
					    rackup (2.2.1)
 | 
				
			||||||
      rack (>= 3)
 | 
					      rack (>= 3)
 | 
				
			||||||
    rails (8.0.2)
 | 
					    rails (8.0.2.1)
 | 
				
			||||||
      actioncable (= 8.0.2)
 | 
					      actioncable (= 8.0.2.1)
 | 
				
			||||||
      actionmailbox (= 8.0.2)
 | 
					      actionmailbox (= 8.0.2.1)
 | 
				
			||||||
      actionmailer (= 8.0.2)
 | 
					      actionmailer (= 8.0.2.1)
 | 
				
			||||||
      actionpack (= 8.0.2)
 | 
					      actionpack (= 8.0.2.1)
 | 
				
			||||||
      actiontext (= 8.0.2)
 | 
					      actiontext (= 8.0.2.1)
 | 
				
			||||||
      actionview (= 8.0.2)
 | 
					      actionview (= 8.0.2.1)
 | 
				
			||||||
      activejob (= 8.0.2)
 | 
					      activejob (= 8.0.2.1)
 | 
				
			||||||
      activemodel (= 8.0.2)
 | 
					      activemodel (= 8.0.2.1)
 | 
				
			||||||
      activerecord (= 8.0.2)
 | 
					      activerecord (= 8.0.2.1)
 | 
				
			||||||
      activestorage (= 8.0.2)
 | 
					      activestorage (= 8.0.2.1)
 | 
				
			||||||
      activesupport (= 8.0.2)
 | 
					      activesupport (= 8.0.2.1)
 | 
				
			||||||
      bundler (>= 1.15.0)
 | 
					      bundler (>= 1.15.0)
 | 
				
			||||||
      railties (= 8.0.2)
 | 
					      railties (= 8.0.2.1)
 | 
				
			||||||
    rails-dom-testing (2.3.0)
 | 
					    rails-dom-testing (2.3.0)
 | 
				
			||||||
      activesupport (>= 5.0.0)
 | 
					      activesupport (>= 5.0.0)
 | 
				
			||||||
      minitest
 | 
					      minitest
 | 
				
			||||||
@ -285,9 +285,9 @@ GEM
 | 
				
			|||||||
    rails-html-sanitizer (1.6.2)
 | 
					    rails-html-sanitizer (1.6.2)
 | 
				
			||||||
      loofah (~> 2.21)
 | 
					      loofah (~> 2.21)
 | 
				
			||||||
      nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
 | 
					      nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
 | 
				
			||||||
    railties (8.0.2)
 | 
					    railties (8.0.2.1)
 | 
				
			||||||
      actionpack (= 8.0.2)
 | 
					      actionpack (= 8.0.2.1)
 | 
				
			||||||
      activesupport (= 8.0.2)
 | 
					      activesupport (= 8.0.2.1)
 | 
				
			||||||
      irb (~> 1.13)
 | 
					      irb (~> 1.13)
 | 
				
			||||||
      rackup (>= 1.0.0)
 | 
					      rackup (>= 1.0.0)
 | 
				
			||||||
      rake (>= 12.2)
 | 
					      rake (>= 12.2)
 | 
				
			||||||
@ -488,17 +488,17 @@ DEPENDENCIES
 | 
				
			|||||||
  wicked_pdf (~> 2.8)
 | 
					  wicked_pdf (~> 2.8)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CHECKSUMS
 | 
					CHECKSUMS
 | 
				
			||||||
  actioncable (8.0.2) sha256=7bcce2df62e91a80143592600e16583c273e98aab50ae40a9f6a2604bb3289a0
 | 
					  actioncable (8.0.2.1) sha256=6f1cb20db39fba28a93569e8d5dab42b2749d7ddd4baebb5bbecd4217e49d6a2
 | 
				
			||||||
  actionmailbox (8.0.2) sha256=3d8fb3453913e6257da4d02004bbfa2b997dfd10672f8d990e95013983e2cedb
 | 
					  actionmailbox (8.0.2.1) sha256=8ea8c6e31e448961c06fc1d6282775b32aff1c009f232d4564e07e54850a6cad
 | 
				
			||||||
  actionmailer (8.0.2) sha256=b0c968b38576ec56a3dc2795931818e0aaae6a18cc9801f53f175c12d4b277d0
 | 
					  actionmailer (8.0.2.1) sha256=0de14d8d04541eab130858cb2f0697266be42de1afe1104bc43d7998137ddb9c
 | 
				
			||||||
  actionpack (8.0.2) sha256=93e703064f3815295ccf820f57acbca719aec836749597da9262781c9b2f4b78
 | 
					  actionpack (8.0.2.1) sha256=61e7e11a31dbe5152ca57221788bdca42ef302c4cc53b4c8993d68dce8982b0a
 | 
				
			||||||
  actiontext (8.0.2) sha256=a40db32032ee2fbb479d5d69318c4284344c1cda73836fd73ffcdb917d203abf
 | 
					  actiontext (8.0.2.1) sha256=0cc4b3b5cfb9d915c6697b05b013dad7f4eaf074d9989700b6a0a55cf620d6b8
 | 
				
			||||||
  actionview (8.0.2) sha256=e038e1405cdfc18f04f17243da4fb8eeda3a4992f63a6d70a7281d255cf7cebb
 | 
					  actionview (8.0.2.1) sha256=2ea6d20ccb0b7b84a221a940ac06853ce99235e4ecb4947815839c7c5ecbf347
 | 
				
			||||||
  activejob (8.0.2) sha256=b0228b45e36b1ef3a081c684e81494147e094a6baf729018756ccf125b1853ca
 | 
					  activejob (8.0.2.1) sha256=d6e5f2da07ec8efac13a38af1752416770dc74e95783f7b252506d707aa32b89
 | 
				
			||||||
  activemodel (8.0.2) sha256=0ae1fb7fa1fae0699ba041a9e97702df42ea3b13f2d39f2d0fde51fca5f0656c
 | 
					  activemodel (8.0.2.1) sha256=17bab6cdb86531844113df22f864480a89a276bf0318246e628f99e0ac077ec4
 | 
				
			||||||
  activerecord (8.0.2) sha256=793470b92c44e4198d0262ac60086b7822f0ea585079ad67e32a6e4c86f2d90a
 | 
					  activerecord (8.0.2.1) sha256=a6556e7bdd53f3889d18d2aa3a7ff115fd6c5e1463dd06f97fb88d06b58c6df1
 | 
				
			||||||
  activestorage (8.0.2) sha256=f83d221e0f06ae38f2200e55490bd155c76d0add330f6e300e8646048d672977
 | 
					  activestorage (8.0.2.1) sha256=43bb3d9e115471e201e6a66813810c1d15b607a321f29d62efdf9d90ffaf76f8
 | 
				
			||||||
  activesupport (8.0.2) sha256=8565cddba31b900cdc17682fd66ecd020441e3eef320a9930285394e8c07a45e
 | 
					  activesupport (8.0.2.1) sha256=0405a76fd1ca989975d9ae00d46a4d3979bdf3817482d846b63affa84bd561c6
 | 
				
			||||||
  acts_as_tenant (1.0.1) sha256=6944e4d64533337938a8817a6b4ff9b11189c9dcc0b1333bb89f3821a4c14c53
 | 
					  acts_as_tenant (1.0.1) sha256=6944e4d64533337938a8817a6b4ff9b11189c9dcc0b1333bb89f3821a4c14c53
 | 
				
			||||||
  addressable (2.8.7) sha256=462986537cf3735ab5f3c0f557f14155d778f4b43ea4f485a9deb9c8f7c58232
 | 
					  addressable (2.8.7) sha256=462986537cf3735ab5f3c0f557f14155d778f4b43ea4f485a9deb9c8f7c58232
 | 
				
			||||||
  annotaterb (4.18.0) sha256=a07ec5d3e8f063308dbbf17970a74155434504a3c3887511cd94fbc83c4f4294
 | 
					  annotaterb (4.18.0) sha256=a07ec5d3e8f063308dbbf17970a74155434504a3c3887511cd94fbc83c4f4294
 | 
				
			||||||
@ -565,17 +565,17 @@ CHECKSUMS
 | 
				
			|||||||
  money (6.19.0) sha256=ec936fa1e42f2783719241ed9fd52725d0efa628f928feea1eb5c37d5de7daf3
 | 
					  money (6.19.0) sha256=ec936fa1e42f2783719241ed9fd52725d0efa628f928feea1eb5c37d5de7daf3
 | 
				
			||||||
  msgpack (1.7.5) sha256=ffb04979f51e6406823c03abe50e1da2c825c55a37dee138518cdd09d9d3aea8
 | 
					  msgpack (1.7.5) sha256=ffb04979f51e6406823c03abe50e1da2c825c55a37dee138518cdd09d9d3aea8
 | 
				
			||||||
  multi_xml (0.7.1) sha256=4fce100c68af588ff91b8ba90a0bb3f0466f06c909f21a32f4962059140ba61b
 | 
					  multi_xml (0.7.1) sha256=4fce100c68af588ff91b8ba90a0bb3f0466f06c909f21a32f4962059140ba61b
 | 
				
			||||||
  net-imap (0.5.6) sha256=1ede8048ee688a14206060bf37a716d18cb6ea00855f6c9b15daee97ee51fbe5
 | 
					  net-imap (0.5.10) sha256=f84d206a296bff48a3a10507567fc38b050d2a40c92ea0d448164f64e60d6205
 | 
				
			||||||
  net-pop (0.1.2) sha256=848b4e982013c15b2f0382792268763b748cce91c9e91e36b0f27ed26420dff3
 | 
					  net-pop (0.1.2) sha256=848b4e982013c15b2f0382792268763b748cce91c9e91e36b0f27ed26420dff3
 | 
				
			||||||
  net-protocol (0.2.2) sha256=aa73e0cba6a125369de9837b8d8ef82a61849360eba0521900e2c3713aa162a8
 | 
					  net-protocol (0.2.2) sha256=aa73e0cba6a125369de9837b8d8ef82a61849360eba0521900e2c3713aa162a8
 | 
				
			||||||
  net-smtp (0.5.1) sha256=ed96a0af63c524fceb4b29b0d352195c30d82dd916a42f03c62a3a70e5b70736
 | 
					  net-smtp (0.5.1) sha256=ed96a0af63c524fceb4b29b0d352195c30d82dd916a42f03c62a3a70e5b70736
 | 
				
			||||||
  nio4r (2.7.4) sha256=d95dee68e0bb251b8ff90ac3423a511e3b784124e5db7ff5f4813a220ae73ca9
 | 
					  nio4r (2.7.4) sha256=d95dee68e0bb251b8ff90ac3423a511e3b784124e5db7ff5f4813a220ae73ca9
 | 
				
			||||||
  nokogiri (1.18.9) sha256=ac5a7d93fd0e3cef388800b037407890882413feccca79eb0272a2715a82fa33
 | 
					  nokogiri (1.18.10) sha256=d5cc0731008aa3b3a87b361203ea3d19b2069628cb55e46ac7d84a0445e69cc1
 | 
				
			||||||
  nokogiri (1.18.9-aarch64-linux-gnu) sha256=5bcfdf7aa8d1056a7ad5e52e1adffc64ef53d12d0724fbc6f458a3af1a4b9e32
 | 
					  nokogiri (1.18.10-aarch64-linux-gnu) sha256=7fb87235d729c74a2be635376d82b1d459230cc17c50300f8e4fcaabc6195344
 | 
				
			||||||
  nokogiri (1.18.9-arm-linux-gnu) sha256=fe611ae65880e445a9c0f650d52327db239f3488626df4173c05beafd161d46e
 | 
					  nokogiri (1.18.10-arm-linux-gnu) sha256=51f4f25ab5d5ba1012d6b16aad96b840a10b067b93f35af6a55a2c104a7ee322
 | 
				
			||||||
  nokogiri (1.18.9-arm64-darwin) sha256=eea3f1f06463ff6309d3ff5b88033c4948d0da1ab3cc0a3a24f63c4d4a763979
 | 
					  nokogiri (1.18.10-arm64-darwin) sha256=c2b0de30770f50b92c9323fa34a4e1cf5a0af322afcacd239cd66ee1c1b22c85
 | 
				
			||||||
  nokogiri (1.18.9-x86_64-darwin) sha256=e0d2deb03d3d7af8016e8c9df5ff4a7d692159cefb135cbb6a4109f265652348
 | 
					  nokogiri (1.18.10-x86_64-darwin) sha256=536e74bed6db2b5076769cab5e5f5af0cd1dccbbd75f1b3e1fa69d1f5c2d79e2
 | 
				
			||||||
  nokogiri (1.18.9-x86_64-linux-gnu) sha256=b52f5defedc53d14f71eeaaf990da66b077e1918a2e13088b6a96d0230f44360
 | 
					  nokogiri (1.18.10-x86_64-linux-gnu) sha256=ff5ba26ba2dbce5c04b9ea200777fd225061d7a3930548806f31db907e500f72
 | 
				
			||||||
  orm_adapter (0.5.0) sha256=aa5d0be5d540cbb46d3a93e88061f4ece6a25f6e97d6a47122beb84fe595e9b9
 | 
					  orm_adapter (0.5.0) sha256=aa5d0be5d540cbb46d3a93e88061f4ece6a25f6e97d6a47122beb84fe595e9b9
 | 
				
			||||||
  ostruct (0.6.2) sha256=6d7302a299e400a2c248d6ce0dad18fc3a5714e8096facc25ffd0c54ee57cfc0
 | 
					  ostruct (0.6.2) sha256=6d7302a299e400a2c248d6ce0dad18fc3a5714e8096facc25ffd0c54ee57cfc0
 | 
				
			||||||
  parallel (1.27.0) sha256=4ac151e1806b755fb4e2dc2332cbf0e54f2e24ba821ff2d3dcf86bf6dc4ae130
 | 
					  parallel (1.27.0) sha256=4ac151e1806b755fb4e2dc2332cbf0e54f2e24ba821ff2d3dcf86bf6dc4ae130
 | 
				
			||||||
@ -600,10 +600,10 @@ CHECKSUMS
 | 
				
			|||||||
  rack-session (2.1.1) sha256=0b6dc07dea7e4b583f58a48e8b806d4c9f1c6c9214ebc202ec94562cbea2e4e9
 | 
					  rack-session (2.1.1) sha256=0b6dc07dea7e4b583f58a48e8b806d4c9f1c6c9214ebc202ec94562cbea2e4e9
 | 
				
			||||||
  rack-test (2.2.0) sha256=005a36692c306ac0b4a9350355ee080fd09ddef1148a5f8b2ac636c720f5c463
 | 
					  rack-test (2.2.0) sha256=005a36692c306ac0b4a9350355ee080fd09ddef1148a5f8b2ac636c720f5c463
 | 
				
			||||||
  rackup (2.2.1) sha256=f737191fd5c5b348b7f0a4412a3b86383f88c43e13b8217b63d4c8d90b9e798d
 | 
					  rackup (2.2.1) sha256=f737191fd5c5b348b7f0a4412a3b86383f88c43e13b8217b63d4c8d90b9e798d
 | 
				
			||||||
  rails (8.0.2) sha256=fdfaa5a83ec0388e02864e88d515959caedc88053b5f701c4deb1652d8f164c6
 | 
					  rails (8.0.2.1) sha256=13ab95615569e74e364384b346b1d83e4795dbde83d9edf584e8768e8049b3ac
 | 
				
			||||||
  rails-dom-testing (2.3.0) sha256=8acc7953a7b911ca44588bf08737bc16719f431a1cc3091a292bca7317925c1d
 | 
					  rails-dom-testing (2.3.0) sha256=8acc7953a7b911ca44588bf08737bc16719f431a1cc3091a292bca7317925c1d
 | 
				
			||||||
  rails-html-sanitizer (1.6.2) sha256=35fce2ca8242da8775c83b6ba9c1bcaad6751d9eb73c1abaa8403475ab89a560
 | 
					  rails-html-sanitizer (1.6.2) sha256=35fce2ca8242da8775c83b6ba9c1bcaad6751d9eb73c1abaa8403475ab89a560
 | 
				
			||||||
  railties (8.0.2) sha256=0d7c3f40c49ba74980f1bac1d4bb153a9331c5ee8a9631d89c7bf79db82e5cf9
 | 
					  railties (8.0.2.1) sha256=54e40e1771fc2878f572d5a4e076cddb057ba8d4d471f8b7d9bfc61bc1301d4c
 | 
				
			||||||
  rainbow (3.1.1) sha256=039491aa3a89f42efa1d6dec2fc4e62ede96eb6acd95e52f1ad581182b79bc6a
 | 
					  rainbow (3.1.1) sha256=039491aa3a89f42efa1d6dec2fc4e62ede96eb6acd95e52f1ad581182b79bc6a
 | 
				
			||||||
  rake (13.3.0) sha256=96f5092d786ff412c62fde76f793cc0541bd84d2eb579caa529aa8a059934493
 | 
					  rake (13.3.0) sha256=96f5092d786ff412c62fde76f793cc0541bd84d2eb579caa529aa8a059934493
 | 
				
			||||||
  rdoc (6.14.2) sha256=9fdd44df130f856ae70cc9a264dfd659b9b40de369b16581f4ab746e42439226
 | 
					  rdoc (6.14.2) sha256=9fdd44df130f856ae70cc9a264dfd659b9b40de369b16581f4ab746e42439226
 | 
				
			||||||
 | 
				
			|||||||
@ -9,10 +9,10 @@ class TablesArrangementsController < ApplicationController
 | 
				
			|||||||
    render json: TablesArrangement
 | 
					    render json: TablesArrangement
 | 
				
			||||||
      .order(valid: :desc)
 | 
					      .order(valid: :desc)
 | 
				
			||||||
      .order(discomfort: :asc)
 | 
					      .order(discomfort: :asc)
 | 
				
			||||||
      .select(:id, :name, :discomfort)
 | 
					      .select(:id, :name, :discomfort, :status, :progress)
 | 
				
			||||||
      .select("digest = '#{current_digest}'::uuid as valid")
 | 
					      .select("digest = '#{current_digest}'::uuid OR discomfort IS NULL as valid")
 | 
				
			||||||
      .limit(20)
 | 
					      .limit(20)
 | 
				
			||||||
      .as_json(only: %i[id name discomfort valid])
 | 
					      .as_json(only: %i[id name discomfort valid status progress])
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def show
 | 
					  def show
 | 
				
			||||||
@ -25,7 +25,10 @@ class TablesArrangementsController < ApplicationController
 | 
				
			|||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def create
 | 
					  def create
 | 
				
			||||||
    TableSimulatorJob.perform_later(current_tenant.id)
 | 
					    ActiveRecord::Base.transaction do
 | 
				
			||||||
 | 
					      tables_arrangement = TablesArrangement.create!(status: :not_started)
 | 
				
			||||||
 | 
					      TableSimulatorJob.perform_later(current_tenant.id, tables_arrangement.id)
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    render json: {}, status: :created
 | 
					    render json: {}, status: :created
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
				
			|||||||
@ -8,16 +8,35 @@ class TableSimulatorJob < ApplicationJob
 | 
				
			|||||||
  MIN_PER_TABLE = 8
 | 
					  MIN_PER_TABLE = 8
 | 
				
			||||||
  MAX_PER_TABLE = 10
 | 
					  MAX_PER_TABLE = 10
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def perform(wedding_id)
 | 
					  def perform(wedding_id, tables_arrangement_id) # rubocop:disable Metrics/MethodLength
 | 
				
			||||||
 | 
					    Rails.logger.info "Starting table simulation #{tables_arrangement_id} for wedding #{wedding_id}"
 | 
				
			||||||
    ActsAsTenant.with_tenant(Wedding.find(wedding_id)) do
 | 
					    ActsAsTenant.with_tenant(Wedding.find(wedding_id)) do
 | 
				
			||||||
      engine = VNS::Engine.new
 | 
					      engine = VNS::Engine.new
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      engine.add_optimization(Tables::Swap)
 | 
					      engine.add_optimization(Tables::Swap)
 | 
				
			||||||
      engine.add_optimization(Tables::Shift)
 | 
					      engine.add_optimization(Tables::Shift)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      initial_solution = Tables::Distribution.new(min_per_table: MIN_PER_TABLE, max_per_table: MAX_PER_TABLE)
 | 
					      tables_arrangement = TablesArrangement.find(tables_arrangement_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      initial_solution = Tables::Distribution.new(
 | 
				
			||||||
 | 
					        min_per_table: MIN_PER_TABLE,
 | 
				
			||||||
 | 
					        max_per_table: MAX_PER_TABLE,
 | 
				
			||||||
 | 
					        tables_arrangement_id:
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      initial_solution.random_distribution(Guest.potential.shuffle)
 | 
					      initial_solution.random_distribution(Guest.potential.shuffle)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      initial_solution.save!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      engine.notify_progress do |current_progress|
 | 
				
			||||||
 | 
					        tables_arrangement.update_columns(status: :in_progress, progress: current_progress)
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      engine.on_better_solution do |better_solution|
 | 
				
			||||||
 | 
					        better_solution.save!
 | 
				
			||||||
 | 
					        tables_arrangement.update_columns(discomfort: better_solution.discomfort) # TODO: remove?
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      engine.initial_solution = initial_solution
 | 
					      engine.initial_solution = initial_solution
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      engine.target_function(&:discomfort)
 | 
					      engine.target_function(&:discomfort)
 | 
				
			||||||
@ -25,6 +44,8 @@ class TableSimulatorJob < ApplicationJob
 | 
				
			|||||||
      best_solution = engine.run
 | 
					      best_solution = engine.run
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      best_solution.save!
 | 
					      best_solution.save!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      tables_arrangement.update_columns(status: :completed)
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
				
			|||||||
@ -29,5 +29,5 @@
 | 
				
			|||||||
class Seat < ApplicationRecord
 | 
					class Seat < ApplicationRecord
 | 
				
			||||||
  acts_as_tenant :wedding
 | 
					  acts_as_tenant :wedding
 | 
				
			||||||
  belongs_to :guest
 | 
					  belongs_to :guest
 | 
				
			||||||
  belongs_to :table_arrangement
 | 
					  belongs_to :tables_arrangement
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
				
			|||||||
@ -10,6 +10,8 @@
 | 
				
			|||||||
#  digest     :uuid             not null
 | 
					#  digest     :uuid             not null
 | 
				
			||||||
#  discomfort :integer
 | 
					#  discomfort :integer
 | 
				
			||||||
#  name       :string           not null
 | 
					#  name       :string           not null
 | 
				
			||||||
 | 
					#  progress   :float            default(0.0), not null
 | 
				
			||||||
 | 
					#  status     :string           default("complete"), not null
 | 
				
			||||||
#  created_at :datetime         not null
 | 
					#  created_at :datetime         not null
 | 
				
			||||||
#  updated_at :datetime         not null
 | 
					#  updated_at :datetime         not null
 | 
				
			||||||
#  wedding_id :uuid             not null
 | 
					#  wedding_id :uuid             not null
 | 
				
			||||||
 | 
				
			|||||||
@ -12,13 +12,14 @@ module Tables
 | 
				
			|||||||
      end
 | 
					      end
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    attr_accessor :tables, :min_per_table, :max_per_table, :hierarchy
 | 
					    attr_accessor :tables, :min_per_table, :max_per_table, :hierarchy, :tables_arrangement_id
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def initialize(min_per_table:, max_per_table:, hierarchy: AffinityGroupsHierarchy.new)
 | 
					    def initialize(min_per_table:, max_per_table:, tables_arrangement_id:, hierarchy: AffinityGroupsHierarchy.new)
 | 
				
			||||||
      @min_per_table = min_per_table
 | 
					      @min_per_table = min_per_table
 | 
				
			||||||
      @max_per_table = max_per_table
 | 
					      @max_per_table = max_per_table
 | 
				
			||||||
      @hierarchy = hierarchy
 | 
					      @hierarchy = hierarchy
 | 
				
			||||||
      @tables = []
 | 
					      @tables = []
 | 
				
			||||||
 | 
					      @tables_arrangement_id = tables_arrangement_id
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def random_distribution(people, random: Random.new)
 | 
					    def random_distribution(people, random: Random.new)
 | 
				
			||||||
@ -42,15 +43,23 @@ module Tables
 | 
				
			|||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def deep_dup
 | 
					    def deep_dup
 | 
				
			||||||
      self.class.new(min_per_table: @min_per_table, max_per_table: @max_per_table,
 | 
					      self.class.new(
 | 
				
			||||||
                     hierarchy: @hierarchy).tap do |new_distribution|
 | 
					        min_per_table: @min_per_table,
 | 
				
			||||||
 | 
					        max_per_table: @max_per_table,
 | 
				
			||||||
 | 
					        hierarchy: @hierarchy,
 | 
				
			||||||
 | 
					        tables_arrangement_id: @tables_arrangement_id
 | 
				
			||||||
 | 
					      ).tap do |new_distribution|
 | 
				
			||||||
        new_distribution.tables = @tables.map(&:dup)
 | 
					        new_distribution.tables = @tables.map(&:dup)
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def save!
 | 
					    def save!
 | 
				
			||||||
      ActiveRecord::Base.transaction do
 | 
					      ActiveRecord::Base.transaction do
 | 
				
			||||||
        arrangement = TablesArrangement.create!
 | 
					        arrangement = TablesArrangement.find(tables_arrangement_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.tables_arrangement_id = arrangement.id
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        arrangement.seats.delete_all
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        records_to_store = []
 | 
					        records_to_store = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -5,6 +5,7 @@
 | 
				
			|||||||
module VNS
 | 
					module VNS
 | 
				
			||||||
  class Engine
 | 
					  class Engine
 | 
				
			||||||
    PERTURBATION_SIZES = [1, 1, 1, 2, 2, 3].freeze
 | 
					    PERTURBATION_SIZES = [1, 1, 1, 2, 2, 3].freeze
 | 
				
			||||||
 | 
					    ITERATIONS = 50
 | 
				
			||||||
    class << self
 | 
					    class << self
 | 
				
			||||||
      def sequence(elements)
 | 
					      def sequence(elements)
 | 
				
			||||||
        elements = elements.to_a
 | 
					        elements = elements.to_a
 | 
				
			||||||
@ -12,6 +13,10 @@ module VNS
 | 
				
			|||||||
      end
 | 
					      end
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def initialize
 | 
				
			||||||
 | 
					      @perturbations = Set.new
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def target_function(&function)
 | 
					    def target_function(&function)
 | 
				
			||||||
      @target_function = function
 | 
					      @target_function = function
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
@ -22,36 +27,45 @@ module VNS
 | 
				
			|||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def add_perturbation(klass)
 | 
					    def add_perturbation(klass)
 | 
				
			||||||
      @perturbations ||= Set.new
 | 
					 | 
				
			||||||
      @perturbations << klass
 | 
					      @perturbations << klass
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def notify_progress(&block)
 | 
				
			||||||
 | 
					      @progress_notifier = block
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_better_solution(&block)
 | 
				
			||||||
 | 
					      @better_solution_notifier = block
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    attr_writer :initial_solution
 | 
					    attr_writer :initial_solution
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def run
 | 
					    def run
 | 
				
			||||||
      raise 'No target function defined' unless @target_function
 | 
					      check_preconditions!
 | 
				
			||||||
      raise 'No optimizations defined' unless @optimizations
 | 
					 | 
				
			||||||
      raise 'No initial solution defined' unless @initial_solution
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      @perturbations ||= Set.new
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      @current_solution = @initial_solution
 | 
					      @current_solution = @initial_solution
 | 
				
			||||||
      @best_score = @target_function.call(@current_solution)
 | 
					      @best_score = @target_function.call(@current_solution)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      run_all_optimizations
 | 
					      run_all_optimizations
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      @progress_notifier&.call(Rational(1, ITERATIONS + 1))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      best_solution = @current_solution
 | 
					      best_solution = @current_solution
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      50.times do
 | 
					      (1..ITERATIONS).each do |iteration|
 | 
				
			||||||
        @current_solution = Tables::WheelSwap.new(best_solution).call(PERTURBATION_SIZES.sample)
 | 
					        @current_solution = Tables::WheelSwap.new(best_solution).call(PERTURBATION_SIZES.sample)
 | 
				
			||||||
        @best_score = @target_function.call(@current_solution)
 | 
					        @best_score = @target_function.call(@current_solution)
 | 
				
			||||||
        Rails.logger.debug { "After perturbation: #{@best_score}" }
 | 
					        Rails.logger.debug { "After perturbation: #{@best_score}" }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        run_all_optimizations
 | 
					        run_all_optimizations
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        @progress_notifier&.call(Rational(iteration + 1, ITERATIONS + 1))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        next unless best_solution.discomfort > @current_solution.discomfort
 | 
					        next unless best_solution.discomfort > @current_solution.discomfort
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        best_solution = @current_solution
 | 
					        best_solution = @current_solution
 | 
				
			||||||
 | 
					        @better_solution_notifier&.call(best_solution)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Rails.logger.debug do
 | 
					        Rails.logger.debug do
 | 
				
			||||||
          "Found better solution after perturbation optimization: #{@current_solution.discomfort}"
 | 
					          "Found better solution after perturbation optimization: #{@current_solution.discomfort}"
 | 
				
			||||||
        end
 | 
					        end
 | 
				
			||||||
@ -62,6 +76,12 @@ module VNS
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    private
 | 
					    private
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def check_preconditions!
 | 
				
			||||||
 | 
					      raise 'No target function defined' unless @target_function
 | 
				
			||||||
 | 
					      raise 'No optimizations defined' unless @optimizations
 | 
				
			||||||
 | 
					      raise 'No initial solution defined' unless @initial_solution
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def run_all_optimizations
 | 
					    def run_all_optimizations
 | 
				
			||||||
      self.class.sequence(@optimizations).each do |optimization|
 | 
					      self.class.sequence(@optimizations).each do |optimization|
 | 
				
			||||||
        optimize(optimization)
 | 
					        optimize(optimization)
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										1
									
								
								bin/jobs
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								bin/jobs
									
									
									
									
									
								
							@ -3,4 +3,5 @@
 | 
				
			|||||||
require_relative "../config/environment"
 | 
					require_relative "../config/environment"
 | 
				
			||||||
require "solid_queue/cli"
 | 
					require "solid_queue/cli"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SolidQueue.logger = ActiveSupport::Logger.new($stdout)
 | 
				
			||||||
SolidQueue::Cli.start(ARGV)
 | 
					SolidQueue::Cli.start(ARGV)
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					class AddStatusColumnToTablesArrangements < ActiveRecord::Migration[8.0]
 | 
				
			||||||
 | 
					  def change
 | 
				
			||||||
 | 
					    add_column :tables_arrangements, :status, :string, default: :complete, null: false
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					class AddProgressToTablesArrangements < ActiveRecord::Migration[8.0]
 | 
				
			||||||
 | 
					  def change
 | 
				
			||||||
 | 
					    add_column :tables_arrangements, :progress, :float, default: 0, null: false
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										4
									
								
								db/schema.rb
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										4
									
								
								db/schema.rb
									
									
									
										generated
									
									
									
								
							@ -10,7 +10,7 @@
 | 
				
			|||||||
#
 | 
					#
 | 
				
			||||||
# It's strongly recommended that you check this file into your version control system.
 | 
					# It's strongly recommended that you check this file into your version control system.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ActiveRecord::Schema[8.0].define(version: 2025_06_08_181054) do
 | 
					ActiveRecord::Schema[8.0].define(version: 2025_09_08_145119) do
 | 
				
			||||||
  # These are extensions that must be enabled in order to support this database
 | 
					  # These are extensions that must be enabled in order to support this database
 | 
				
			||||||
  enable_extension "pg_catalog.plpgsql"
 | 
					  enable_extension "pg_catalog.plpgsql"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -216,6 +216,8 @@ ActiveRecord::Schema[8.0].define(version: 2025_06_08_181054) do
 | 
				
			|||||||
    t.string "name", null: false
 | 
					    t.string "name", null: false
 | 
				
			||||||
    t.uuid "wedding_id", null: false
 | 
					    t.uuid "wedding_id", null: false
 | 
				
			||||||
    t.uuid "digest", default: -> { "gen_random_uuid()" }, null: false
 | 
					    t.uuid "digest", default: -> { "gen_random_uuid()" }, null: false
 | 
				
			||||||
 | 
					    t.string "status", default: "complete", null: false
 | 
				
			||||||
 | 
					    t.float "progress", default: 0.0, null: false
 | 
				
			||||||
    t.index ["wedding_id"], name: "index_tables_arrangements_on_wedding_id"
 | 
					    t.index ["wedding_id"], name: "index_tables_arrangements_on_wedding_id"
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -86,7 +86,9 @@ ActsAsTenant.with_tenant(wedding) do
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  # TODO: Clean up invitations with no guests
 | 
					  # TODO: Clean up invitations with no guests
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ActiveJob.perform_all_later(3.times.map { TableSimulatorJob.new(wedding.id) })
 | 
					  3.times { TablesArrangement.create! }
 | 
				
			||||||
 | 
					    .map { |arrangement| TableSimulatorJob.new(wedding.id, arrangement.id) }
 | 
				
			||||||
 | 
					    .then { |jobs| ActiveJob.perform_all_later }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  "red".dup.paint.palette.triad(as: :hex).zip(Group.roots).each { |(color, group)| group.update!(color: color.paint.desaturate(40)) }
 | 
					  "red".dup.paint.palette.triad(as: :hex).zip(Group.roots).each { |(color, group)| group.update!(color: color.paint.desaturate(40)) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -21,6 +21,14 @@ namespace :vns do
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      engine.target_function(&:discomfort)
 | 
					      engine.target_function(&:discomfort)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      engine.notify_progress do |current_progress|
 | 
				
			||||||
 | 
					        Rails.logger.info "Progress: #{(current_progress * 100.0).round(2)}%"
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      engine.on_better_solution do |better_solution|
 | 
				
			||||||
 | 
					        Rails.logger.info "New best solution found with discomfort: #{better_solution.discomfort}"
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      solution = Rails.benchmark('VNS Benchmarking') { engine.run }
 | 
					      solution = Rails.benchmark('VNS Benchmarking') { engine.run }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      Rails.logger.info "Best solution found with discomfort: #{solution.discomfort}"
 | 
					      Rails.logger.info "Best solution found with discomfort: #{solution.discomfort}"
 | 
				
			||||||
 | 
				
			|||||||
@ -12,6 +12,11 @@ server {
 | 
				
			|||||||
        proxy_set_header Host $http_host;
 | 
					        proxy_set_header Host $http_host;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    location /jobs/ {
 | 
				
			||||||
 | 
					        proxy_pass http://backend:3000/jobs/;
 | 
				
			||||||
 | 
					        proxy_set_header Host $http_host;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    location /captcha/v2/media/ {
 | 
					    location /captcha/v2/media/ {
 | 
				
			||||||
        proxy_pass http://libre-captcha:8888/v2/media/;
 | 
					        proxy_pass http://libre-captcha:8888/v2/media/;
 | 
				
			||||||
        proxy_set_header Host $http_host;
 | 
					        proxy_set_header Host $http_host;
 | 
				
			||||||
 | 
				
			|||||||
@ -19,7 +19,8 @@ RSpec.describe 'tables_arrangements' do
 | 
				
			|||||||
                   id: { type: :string, format: :uuid },
 | 
					                   id: { type: :string, format: :uuid },
 | 
				
			||||||
                   name: { type: :string },
 | 
					                   name: { type: :string },
 | 
				
			||||||
                   discomfort: { type: :integer },
 | 
					                   discomfort: { type: :integer },
 | 
				
			||||||
                   valid: { type: :boolean }
 | 
					                   valid: { type: :boolean },
 | 
				
			||||||
 | 
					                   status: { type: :string, enum: %w[complete in_progress] }
 | 
				
			||||||
                 }
 | 
					                 }
 | 
				
			||||||
               }
 | 
					               }
 | 
				
			||||||
        xit
 | 
					        xit
 | 
				
			||||||
 | 
				
			|||||||
@ -6,8 +6,43 @@ require 'rails_helper'
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
module Tables
 | 
					module Tables
 | 
				
			||||||
  RSpec.describe Distribution do
 | 
					  RSpec.describe Distribution do
 | 
				
			||||||
 | 
					    let(:tables_arrangement) { TablesArrangement.create! }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    around do |example|
 | 
				
			||||||
 | 
					      ActsAsTenant.with_tenant(create(:wedding)) do
 | 
				
			||||||
 | 
					        example.run
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    describe '#save!' do
 | 
				
			||||||
 | 
					      let(:people) { create_list(:guest, 2, status: :invited) }
 | 
				
			||||||
 | 
					      let(:distribution) do
 | 
				
			||||||
 | 
					        described_class.new(min_per_table: 5, max_per_table: 10, tables_arrangement_id: tables_arrangement.id)
 | 
				
			||||||
 | 
					                       .tap { |d| d.random_distribution(people) }
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      context 'when tables_arrangement_id is nil' do
 | 
				
			||||||
 | 
					        it { expect { distribution.save! }.to change(TablesArrangement, :count).by(1) }
 | 
				
			||||||
 | 
					        it { expect { distribution.save! }.to change(Seat, :count).by(2) }
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      context 'when tables_arrangement_id is set' do
 | 
				
			||||||
 | 
					        before do
 | 
				
			||||||
 | 
					          existing_arrangement = TablesArrangement.create!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          existing_arrangement.seats.create!(guest: people.first, table_number: 1)
 | 
				
			||||||
 | 
					          distribution.tables_arrangement_id = existing_arrangement.id
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        it { expect { distribution.save! }.not_to(change(TablesArrangement, :count)) }
 | 
				
			||||||
 | 
					        it { expect { distribution.save! }.to change(Seat, :count).by(1) }
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    describe '#random_distribution' do
 | 
					    describe '#random_distribution' do
 | 
				
			||||||
      subject(:distribution) { described_class.new(min_per_table: 5, max_per_table: 10) }
 | 
					      subject(:distribution) do
 | 
				
			||||||
 | 
					        described_class.new(min_per_table: 5, max_per_table: 10, tables_arrangement_id: tables_arrangement.id)
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      context 'when there are fewer people than the minimum per table' do
 | 
					      context 'when there are fewer people than the minimum per table' do
 | 
				
			||||||
        it 'creates one table' do
 | 
					        it 'creates one table' do
 | 
				
			||||||
 | 
				
			|||||||
@ -17,7 +17,7 @@ module Tables
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      context 'when there are two tables with two people each' do
 | 
					      context 'when there are two tables with two people each' do
 | 
				
			||||||
        let(:initial_solution) do
 | 
					        let(:initial_solution) do
 | 
				
			||||||
          Distribution.new(min_per_table: 2, max_per_table: 2).tap do |distribution|
 | 
					          Distribution.new(min_per_table: 2, max_per_table: 2, tables_arrangement_id: nil).tap do |distribution|
 | 
				
			||||||
            distribution.tables << Set[:a, :b].to_table
 | 
					            distribution.tables << Set[:a, :b].to_table
 | 
				
			||||||
            distribution.tables << Set[:c, :d].to_table
 | 
					            distribution.tables << Set[:c, :d].to_table
 | 
				
			||||||
          end
 | 
					          end
 | 
				
			||||||
@ -35,7 +35,7 @@ module Tables
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      context 'when there are two tables with three people each' do
 | 
					      context 'when there are two tables with three people each' do
 | 
				
			||||||
        let(:initial_solution) do
 | 
					        let(:initial_solution) do
 | 
				
			||||||
          Distribution.new(min_per_table: 3, max_per_table: 3).tap do |distribution|
 | 
					          Distribution.new(min_per_table: 3, max_per_table: 3, tables_arrangement_id: nil).tap do |distribution|
 | 
				
			||||||
            distribution.tables << Set[:a, :b, :c].to_table
 | 
					            distribution.tables << Set[:a, :b, :c].to_table
 | 
				
			||||||
            distribution.tables << Set[:d, :e, :f].to_table
 | 
					            distribution.tables << Set[:d, :e, :f].to_table
 | 
				
			||||||
          end
 | 
					          end
 | 
				
			||||||
 | 
				
			|||||||
@ -17,7 +17,7 @@ module Tables
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      context 'when there are two tables with two people each' do
 | 
					      context 'when there are two tables with two people each' do
 | 
				
			||||||
        let(:initial_solution) do
 | 
					        let(:initial_solution) do
 | 
				
			||||||
          Distribution.new(min_per_table: 2, max_per_table: 2).tap do |distribution|
 | 
					          Distribution.new(min_per_table: 2, max_per_table: 2, tables_arrangement_id: nil).tap do |distribution|
 | 
				
			||||||
            distribution.tables << Set[:a, :b].to_table
 | 
					            distribution.tables << Set[:a, :b].to_table
 | 
				
			||||||
            distribution.tables << Set[:c, :d].to_table
 | 
					            distribution.tables << Set[:c, :d].to_table
 | 
				
			||||||
          end
 | 
					          end
 | 
				
			||||||
@ -35,7 +35,7 @@ module Tables
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      context 'when there are two tables with three people each' do
 | 
					      context 'when there are two tables with three people each' do
 | 
				
			||||||
        let(:initial_solution) do
 | 
					        let(:initial_solution) do
 | 
				
			||||||
          Distribution.new(min_per_table: 3, max_per_table: 3).tap do |distribution|
 | 
					          Distribution.new(min_per_table: 3, max_per_table: 3, tables_arrangement_id: nil).tap do |distribution|
 | 
				
			||||||
            distribution.tables << Set[:a, :b, :c].to_table
 | 
					            distribution.tables << Set[:a, :b, :c].to_table
 | 
				
			||||||
            distribution.tables << Set[:d, :e, :f].to_table
 | 
					            distribution.tables << Set[:d, :e, :f].to_table
 | 
				
			||||||
          end
 | 
					          end
 | 
				
			||||||
@ -58,7 +58,7 @@ module Tables
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      context 'when there are three tables with two people each' do
 | 
					      context 'when there are three tables with two people each' do
 | 
				
			||||||
        let(:initial_solution) do
 | 
					        let(:initial_solution) do
 | 
				
			||||||
          Distribution.new(min_per_table: 2, max_per_table: 2).tap do |distribution|
 | 
					          Distribution.new(min_per_table: 2, max_per_table: 2, tables_arrangement_id: nil).tap do |distribution|
 | 
				
			||||||
            distribution.tables << Set[:a, :b].to_table
 | 
					            distribution.tables << Set[:a, :b].to_table
 | 
				
			||||||
            distribution.tables << Set[:c, :d].to_table
 | 
					            distribution.tables << Set[:c, :d].to_table
 | 
				
			||||||
            distribution.tables << Set[:e, :f].to_table
 | 
					            distribution.tables << Set[:e, :f].to_table
 | 
				
			||||||
 | 
				
			|||||||
@ -8,7 +8,7 @@ module Tables
 | 
				
			|||||||
  RSpec.describe WheelSwap do
 | 
					  RSpec.describe WheelSwap do
 | 
				
			||||||
    context 'when the solution has three tables' do
 | 
					    context 'when the solution has three tables' do
 | 
				
			||||||
      let(:initial_solution) do
 | 
					      let(:initial_solution) do
 | 
				
			||||||
        Distribution.new(min_per_table: 3, max_per_table: 3).tap do |distribution|
 | 
					        Distribution.new(min_per_table: 3, max_per_table: 3, tables_arrangement_id: nil).tap do |distribution|
 | 
				
			||||||
          distribution.tables << Set[:a, :b, :c].to_table
 | 
					          distribution.tables << Set[:a, :b, :c].to_table
 | 
				
			||||||
          distribution.tables << Set[:d, :e, :f].to_table
 | 
					          distribution.tables << Set[:d, :e, :f].to_table
 | 
				
			||||||
          distribution.tables << Set[:g, :h, :i].to_table
 | 
					          distribution.tables << Set[:g, :h, :i].to_table
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user