localtower 0.4.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +31 -34
- data/app/controllers/localtower/pages_controller.rb +20 -42
- data/app/helpers/localtower/application_helper.rb +2 -14
- data/app/views/layouts/localtower/application.html.erb +6 -58
- data/app/views/localtower/pages/_migrations.html.erb +57 -0
- data/app/views/localtower/pages/migrations.html.erb +3 -6
- data/app/views/localtower/pages/models.html.erb +6 -8
- data/app/views/localtower/pages/{dashboard.html.erb → schema.html.erb} +0 -0
- data/config/routes.rb +7 -14
- data/lib/localtower/generators/migration.rb +8 -67
- data/lib/localtower/generators/model.rb +5 -8
- data/lib/localtower/status.rb +14 -15
- data/lib/localtower/tools.rb +25 -29
- data/lib/localtower/version.rb +1 -1
- data/lib/localtower.rb +0 -1
- data/public/css/app.css +4 -0
- data/public/js/app.js +14 -29
- data/public/light-bootstrap-dashboard-master/assets/css/light-bootstrap-dashboard.css +9 -35
- data/public/vendor/font-awesome.min.css +4 -0
- data/public/vendor/highlight-js-default.min.css +9 -0
- data/public/vendor/highlight.min.js +1198 -0
- data/public/{js → vendor}/masonry.pkgd.min.js +0 -0
- data/spec/dummy/Gemfile +1 -1
- data/spec/dummy/Gemfile.lock +109 -87
- data/spec/dummy/app/controllers/pages_controller.rb +0 -2
- data/spec/dummy/app/models/application_record.rb +3 -0
- data/spec/dummy/app/models/user.rb +2 -0
- data/spec/dummy/app/views/pages/home.html.erb +0 -1
- data/spec/dummy/config/application.rb +1 -1
- data/spec/dummy/config/database.yml +1 -1
- data/spec/dummy/config/environments/development.rb +5 -4
- data/spec/dummy/config/environments/production.rb +2 -2
- data/spec/dummy/config/initializers/assets.rb +1 -1
- data/spec/dummy/db/migrate/20221115190039_create_users.rb +13 -0
- data/spec/dummy/db/migrate/20221115193020_change_users.rb +8 -0
- data/spec/dummy/db/migrate/20221115193532_change_users_at1668540931.rb +5 -0
- data/spec/dummy/db/migrate/20221115193605_change_users_at1668540964.rb +5 -0
- data/spec/dummy/db/migrate/20221115193637_change_users_at1668540996.rb +5 -0
- data/spec/dummy/db/migrate/20221115193642_change_users_at1668541001.rb +5 -0
- data/spec/dummy/db/schema.rb +27 -2
- data/spec/dummy/log/development.log +4623 -2
- data/spec/dummy/log/localtower.log +142 -2500
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/-Y/-YOiiBKqc2UODHFjctm8xc7xFoZaL7zOjWQj6qQ2wyE.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/-d/-dwueM4vmPt8L51S3jeSyg_AjGDcj0GUN6pDpCA1gCg.cache +3 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/0g/0gaJnJQdtd2ACbihXxn8OnjLWlDjnQ_WxfgOpbiLzhg.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/0r/0rFCsCV9kZnEYtZZ6sfig8329OU31bqjecDFqSVank8.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/1J/1J2k_CpnQE3d-PZAQwOVGQALGkta4qVvhdsKjgG0e4Q.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/2p/2pYVH2Z_syqh6ok8QYxJNKxXpx1Iwppf6JGElZI0gpw.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/3W/3WBmqd-2V6q5N-jvbyp-tlcfn3aHYMwBppbOUm7x4qg.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/4K/4KFPlHkhdDW0riGUmlbaR-kmDz6JUnQvY6fwW8qsdaE.cache +3 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/6x/6xMeRWmLpNK_flx6-JA3KazvUxSCxyPxHv9Zm3eC26Q.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/7d/7dNqI_dCDJLJmI1oM4xwFp9nRRNOem-4P4OD7PMyz2E.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/8X/8XquhxVcp5A8QquLtxO8NgKTMJch0eqQmzFmRGIZP6I.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/Ah/AhdfXXtU63kXS4TnsH2Vi1yWgVkIEeV8Z8XA68hrNQc.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/Bt/BtAePnwLSGw82xUGI7wuhWDfuwarOQVS91YqCsweMcs.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/Bx/BxzoG0KxeNLac4xTNeJv3qfeytbNBw58xj2zD-xdbrE.cache +2 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/CC/CCD0ROPX0yxHwNpVZmuP8ZNtgQpaVCMXpdzC0Wb5n24.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/DS/DS43oxBg6K5PMWLn2mTy_4EnxI03ehHkxpjV7NCi8yM.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/Do/Do83AoOat5W-c1g7piDGy2GMmffsY6JY0Qfuh5PY3GM.cache +2 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/EI/EI0Nxk-VRATWstMuVCVc0_GdYlQ-a0dx6n2g0l3vIik.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/EN/ENhJnzJAU2IK-7aHqubj9N8Jo_UTmjG_VEQqyIkolQ8.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/Fc/FcS6VUHN3Bd4pHGqd5NHA8jA4OLwWrU94s3b4GGxX9c.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/G0/G0kukI-r0q0Vbrg6e_jnYJoYcOX8K__h-mwKbCf4twE.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/I1/I1Jw08-mz8xzgrgi6giCzpf1UmzGTSbl4eJEw4DAoJM.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/IV/IVOO1dXBmgjieDk__g57p6aYt0Z3CmfTa32jhegoyko.cache +3 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/JY/JYPmv5WP4wxdI9EKEEPkK_fVtqeSLfmint_5E8fQLQ8.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/MX/MXI3KxaQPZGImSvCNZ_TbQVruWCJ3E0xiVxza1ZCAjM.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/OU/OUoioCqXALK909jXPV3VSyCJIdNC7bsogUfdnRTpc5o.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/PH/PHjtqNLUPAUDiSlu5AbPjlIo20mOGNm0uNjMLhX2NvM.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/RC/RC9vfALY5K634pTeau0BAhTHl7d5_5yA3tM-QTLiKtI.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/RG/RG1PrmlixwaUlG8BV0kcm_3F7OQekxsrLYjBdf403-k.cache +2 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/Ut/UtoMO6n6FHTpRCGk9VfxlfTI2Ao2GYJ_6kMzx3B9VH8.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/VE/VExnbpDk3LxYdPk3htUrZQXPI8NK_zlKtSFfVXJlxU4.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/Wm/WmKTjykiU-Tx_Faf5zduEeEQ-DozAs5omKToM2l1cZM.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/X-/X-KjhDPd0nI155N_FaxFSgaOiYo0_ytqlmkBlLM7ayw.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/XX/XXVhj-O91tJ5c8pz7DQlTABOv8TIRVg5haw9VOq9HuI.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/YC/YCiifo5NCMwDChFqYFiV4EaYEx8hy3Efle1PsGbIdak.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/Ya/YayMISAqD-Y3vBFywwKrXbUovGf5o77HUF5s8mnQgO0.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/Zl/Zl-NEb0aDLmZ9gN4gdY1OYlbUXD4JhkFY_y23m55zmo.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/_h/_hnjPptBeD3GP5B0iJR6pvyVkiMiq-o2TxaYmGf9KJo.cache +3 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/_p/_poEF6QbTPYJiQCFGoXxIXjmvcn6T0I87ElzJGHguk0.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/aa/aaSj2zt8ddc87nZqTpOI9gRCKVnoalXKFBww7t4t3Kg.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/bZ/bZHWUkrOLp0WM_Ogo36Qjt4cxDt-rOFgtcj4LNB-BVE.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/cP/cPSNG_663TNT944Rke919luRS6FtpMwVc_7aDph645w.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/ce/ceq8fcZGIoqWrCl9vrCRrywEdx42iy9PrGG9CwFSIF4.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/cl/cljhP0Jc018nLnG1rpdg-FUf6mlIqrQYvXTNXTNG9Bw.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/dm/dmod3fTZdoKso2FGM5RTQtb4kTB6vywsiXLWDygYFN4.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/dy/dySDGcUTqlKx2MTvOmIEP-WzhyhCfU5xhN9qgxbz3rI.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/gQ/gQYdmEzbLjTcFCnsfzXzEmeminOchF263snAk3IvXM0.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/gh/ghvuMAqccBGljlmEaI3Gt5tH5rEg6hseKYMYfRMkHdY.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/gt/gt8QC7k92A4hXA3HlCpQulW73tqd6x63I3uT-YrGMj0.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/hf/hfVg-y7dPSQKbb7V3I7M5w7IpOhDiIB2H31d2tmbZMU.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/iF/iFLwyhZIu1Jxm77NUT2qWeTDMmyELW4U85t9rGE_KVg.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/kF/kFlIcBBnSyKE00OjpM90pqSn93mLMUv9esz86nrO-Cs.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/ma/MazNt_5OaYexRuZnccZZ_7AONlxn1a4W3KdWyHyBdws.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/ma/ma3w08gnDTeqwY2-C9BlToxA6-AS8bvXlu-nBiz0UYs.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/n_/n_xYqQYhwEMQknb3jFQnjlxxBE9TzMNHCdJ-bEyZFIw.cache +2 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/nx/nxTv3sKVUQZADJyM3dPaVmUA78MIsMLD_K279yN_GsI.cache +2 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/pv/pv6tV3CDkIAmLXdU8EPLlNEkXAKJPufVD4VP30o4fWo.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/qP/qPmv5snMrDw830S6hSICDcnIy7kVEWoFKXhGKT38lG4.cache +2 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/sY/sYvTb1uPWWmnHJNXKuW_xSco-aUb-rN2f0J35zSIzuc.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/su/suQ_jjDxRiIn4VEqFJYKaBWJILaeGKBvoTv49XNX0vo.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/u8/u8IrW5IIQ7espwk2Vpk23zheL9YZA0tnbKq9X7E-WA0.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/wh/whzETExjcZCkn4msasD2aylgfhfpKPZrNxTkY-SOIDg.cache +2 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/x7/x7PYh8DJvPykcEqpVab2vcY9-GFz-3cqtoMlRAu94Uc.cache +2 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/y6/y6oxsJD3pAY9ph1_5M-77uiEjTVw8BheLZNygCKPm1g.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/yH/yHZ-a1J23ZCf2n5mEHINMz23Iec2cLGTKauW7k4yGTE.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/z7/z7KfUWYoSaGq8tQ5mbHwyfXyT3Pa4FWKJswHcIdJuds.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/zu/zuExWc5WHxeOUPZUKHl9a9ZRmN50g7jMOD28macn6M0.cache +0 -0
- data/spec/dummy/{lib/playground.rb → tmp/restart.txt} +0 -0
- data/spec/spec_helper.rb +17 -2
- metadata +161 -33
- data/app/views/localtower/pages/logs.html.erb +0 -84
- data/app/views/localtower/pages/relations.html.erb +0 -64
- data/app/views/localtower/pages/status.html.erb +0 -29
- data/lib/localtower/generators/relation.rb +0 -59
- data/lib/localtower/plugins/capture.rb +0 -194
- data/lib/tasks/localtower_tasks.rake +0 -4
- data/spec/dummy/custom_plan.rb +0 -11
- data/spec/dummy/log/test.log +0 -2229
- data/spec/dummy/zeus.json +0 -22
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0f287a30405aef9188949f37fa3142997d91e188fa0d71db42ba550d47a73bc7
|
|
4
|
+
data.tar.gz: 9ba53f02eefe31b6f6f1901c2dc3b8a17461a72db8086fb2bd845ec7979fde7b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 122fd3997f2540a5fe239cadf8790975c5d881ad85ed4f632f99d53f94719832404b8ce265844f9da00f21661425106c74a6423b608bbdcb649002af6d963789
|
|
7
|
+
data.tar.gz: 8f6c8eda883c0e0dc54f1b9b218cfbd41c5dc15c36ab8ec481ffe1e2c241cefa04714c3f468d0b47556dee5576a18e69b4e42e2c46ad52850ffbb54fb332f641
|
data/README.md
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
<img src="https://raw.githubusercontent.com/damln/localtower/master/public/logo-localtower-white-300.png" alt="Localtower">
|
|
3
3
|
</p>
|
|
4
4
|
|
|
5
|
+
## Intro
|
|
6
|
+
|
|
7
|
+
Update in 2022, please use localtower version `>= 0.4.1`
|
|
8
|
+
See installation process below.
|
|
9
|
+
Compatibility:
|
|
10
|
+
- Rails >= 5.2
|
|
11
|
+
- Ruby >= 2.3
|
|
12
|
+
|
|
5
13
|
### See the schema
|
|
6
14
|

|
|
7
15
|
|
|
@@ -14,12 +22,10 @@
|
|
|
14
22
|
### Create a migration
|
|
15
23
|

|
|
16
24
|
|
|
17
|
-
### Using the Capture plugin
|
|
18
|
-

|
|
19
|
-
|
|
20
25
|
## INSTALL
|
|
21
26
|
|
|
22
|
-
|
|
27
|
+
Should work with any Rails 4.2+ application.
|
|
28
|
+
Only tested with PostgreSQL.
|
|
23
29
|
|
|
24
30
|
Add to your `Gemfile` file:
|
|
25
31
|
```ruby
|
|
@@ -28,13 +34,6 @@ group :development do
|
|
|
28
34
|
end
|
|
29
35
|
```
|
|
30
36
|
|
|
31
|
-
If you want the latest master branch, add to your `Gemfile` file following:
|
|
32
|
-
```ruby
|
|
33
|
-
group :development do
|
|
34
|
-
gem "localtower", github: "damln/localtower"
|
|
35
|
-
end
|
|
36
|
-
```
|
|
37
|
-
|
|
38
37
|
Run command in your terminal:
|
|
39
38
|
```bash
|
|
40
39
|
bundle install
|
|
@@ -52,34 +51,29 @@ MyApp::Application.routes.draw do
|
|
|
52
51
|
end
|
|
53
52
|
```
|
|
54
53
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
Open your browser at [http://localhost:3000/localtower](http://localhost:3000/localtower).
|
|
54
|
+
/!\ IMPORTANT /!\
|
|
55
|
+
Change your config/environments/development.rb:
|
|
58
56
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
Localtower::Plugins::Capture.new(self, binding).save
|
|
57
|
+
```ruby
|
|
58
|
+
Rails.application.configure do
|
|
59
|
+
# ...
|
|
64
60
|
|
|
65
|
-
|
|
61
|
+
# This is the default:
|
|
62
|
+
# config.active_record.migration_error = :page_load
|
|
66
63
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
user = User.find(1)
|
|
70
|
-
some_data = {foo: "bar"}
|
|
64
|
+
# Change it to:
|
|
65
|
+
config.active_record.migration_error = false if defined?(Localtower)
|
|
71
66
|
|
|
72
|
-
|
|
67
|
+
# ...
|
|
73
68
|
end
|
|
74
69
|
```
|
|
75
70
|
|
|
76
|
-
|
|
71
|
+
## Usage
|
|
77
72
|
|
|
78
|
-
|
|
73
|
+
Open your browser at [http://localhost:3000/localtower](http://localhost:3000/localtower).
|
|
79
74
|
|
|
80
|
-
The value for each variable will try to call `.to_json`. If you have a huge collection of models likes `@users` you will see all the collection as an Array.
|
|
81
75
|
|
|
82
|
-
##
|
|
76
|
+
## Run test
|
|
83
77
|
|
|
84
78
|
If you want to contribute to the gem:
|
|
85
79
|
|
|
@@ -96,18 +90,21 @@ bundle install
|
|
|
96
90
|
bundle exec rspec spec/
|
|
97
91
|
```
|
|
98
92
|
|
|
99
|
-
Notes:
|
|
100
|
-
Tests are currently very slow because this is testing rails commands so it boots the framework for each test. Zeus or spring should be introduced.
|
|
101
|
-
|
|
102
93
|
## Contribute
|
|
103
94
|
|
|
104
|
-
Thanks for reporting issues, I'll do my best
|
|
95
|
+
Thanks for reporting issues, I'll do my best 💪
|
|
105
96
|
|
|
106
|
-
|
|
97
|
+

|
|
107
98
|
|
|
108
99
|
|
|
109
100
|
## Deploy
|
|
101
|
+
Only for official contributors.
|
|
110
102
|
|
|
111
103
|
rm *.gem | gem build localtower.gemspec && gem push localtower-*.gem
|
|
112
104
|
|
|
105
|
+
## Notes
|
|
106
|
+
|
|
107
|
+
Do not hesitate to open issues if you have troubles using the gem.
|
|
113
108
|
|
|
109
|
+
- By Damian Le Nouaille Diez: https://damln.com
|
|
110
|
+
- Link on RubyGems: https://rubygems.org/gems/localtower
|
|
@@ -2,33 +2,9 @@ require_dependency 'localtower/application_controller'
|
|
|
2
2
|
|
|
3
3
|
module Localtower
|
|
4
4
|
class PagesController < ApplicationController
|
|
5
|
+
before_action :set_migrations, only: [:migrations, :models]
|
|
5
6
|
|
|
6
|
-
def
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
def logs
|
|
10
|
-
@logs = Localtower::Plugins::Capture.new.logs
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def log
|
|
14
|
-
file = Dir["#{Localtower::Plugins::Capture::LOG_PATH.call}/localtower*#{params[:md5]}*"][0]
|
|
15
|
-
|
|
16
|
-
render json: JSON.parse(open(file).read)
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def log_var
|
|
20
|
-
answer = {}
|
|
21
|
-
|
|
22
|
-
file = Dir["#{Localtower::Plugins::Capture::LOG_PATH.call}/localtower*#{params[:md5]}*"][0]
|
|
23
|
-
data = JSON.parse(open(file).read)
|
|
24
|
-
|
|
25
|
-
answer = data["variables"].select {|i| i["event_name"] == params[:var] }[0]["returned"]
|
|
26
|
-
|
|
27
|
-
render json: answer
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def status
|
|
31
|
-
@data = ::Localtower::Status.new.run
|
|
7
|
+
def schema
|
|
32
8
|
end
|
|
33
9
|
|
|
34
10
|
def migrations
|
|
@@ -36,47 +12,49 @@ module Localtower
|
|
|
36
12
|
|
|
37
13
|
def post_migrations
|
|
38
14
|
# Because we have a list or a field, take the item from the list in priority
|
|
39
|
-
|
|
15
|
+
migrations = clean_params["migrations"]["migrations"].map do |action_line|
|
|
16
|
+
# This is used for "rename_column" action:
|
|
40
17
|
action_line["new_column_type"] = action_line["column_type"]
|
|
41
18
|
|
|
42
|
-
if action_line["column"].present?
|
|
43
|
-
action_line["column"] = action_line["column"]
|
|
44
|
-
end
|
|
45
|
-
|
|
46
19
|
if action_line["column_list"].present?
|
|
47
20
|
action_line["column"] = action_line["column_list"]
|
|
48
21
|
end
|
|
49
22
|
|
|
50
23
|
action_line.delete("column_list")
|
|
24
|
+
# / This is used for "rename_column" action
|
|
51
25
|
|
|
52
26
|
action_line
|
|
53
27
|
end
|
|
54
28
|
|
|
55
|
-
use_generator(::Localtower::Generators::Migration,
|
|
29
|
+
use_generator(::Localtower::Generators::Migration, { 'migrations' => migrations })
|
|
56
30
|
redirect_to migrations_path
|
|
57
31
|
end
|
|
58
32
|
|
|
59
|
-
def relations
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
def post_relations
|
|
63
|
-
use_generator(::Localtower::Generators::Relation, params[:relations])
|
|
64
|
-
redirect_to relations_path
|
|
65
|
-
end
|
|
66
|
-
|
|
67
33
|
def models
|
|
68
34
|
end
|
|
69
35
|
|
|
70
36
|
def post_models
|
|
71
|
-
use_generator(::Localtower::Generators::Model,
|
|
72
|
-
redirect_to
|
|
37
|
+
use_generator(::Localtower::Generators::Model, clean_params["models"])
|
|
38
|
+
redirect_to models_path
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def post_actions
|
|
42
|
+
::Localtower::Tools.perform_cmd(clean_params['cmd'], false)
|
|
43
|
+
redirect_back fallback_location: root_path
|
|
73
44
|
end
|
|
74
45
|
|
|
75
46
|
private
|
|
76
47
|
|
|
48
|
+
def set_migrations
|
|
49
|
+
@migrations = ::Localtower::Status.new.run.select { |entry| entry['status'] == :todo }
|
|
50
|
+
end
|
|
51
|
+
|
|
77
52
|
def use_generator(generator_klass, options)
|
|
78
53
|
generator_klass.new(options).run
|
|
79
54
|
end
|
|
80
55
|
|
|
56
|
+
def clean_params
|
|
57
|
+
params.permit!.to_hash.with_indifferent_access
|
|
58
|
+
end
|
|
81
59
|
end
|
|
82
60
|
end
|
|
@@ -1,19 +1,7 @@
|
|
|
1
1
|
module Localtower
|
|
2
2
|
module ApplicationHelper
|
|
3
|
-
def
|
|
4
|
-
|
|
5
|
-
if block_given?
|
|
6
|
-
str = capture(&block)
|
|
7
|
-
else
|
|
8
|
-
str = name
|
|
9
|
-
end
|
|
10
|
-
link_to str, "subl://open/?url=file://#{file}"
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def to_json_print(hash)
|
|
14
|
-
# str = hash.to_json
|
|
15
|
-
# str.gsub(/,"/, ',<br>"').gsub(/\"\:/, '": ').html_safe
|
|
16
|
-
hash.to_json
|
|
3
|
+
def file_link(file)
|
|
4
|
+
"vscode://file/#{file}"
|
|
17
5
|
end
|
|
18
6
|
end
|
|
19
7
|
end
|
|
@@ -12,10 +12,10 @@
|
|
|
12
12
|
<link rel="stylesheet" type="text/css" href="/light-bootstrap-dashboard-master/assets/css/light-bootstrap-dashboard.css">
|
|
13
13
|
|
|
14
14
|
<!-- Fonts and icons -->
|
|
15
|
-
<link href="
|
|
16
|
-
<link href='http://fonts.googleapis.com/css?family=Roboto:400,700,300' rel='stylesheet' type='text/css'>
|
|
15
|
+
<link href="/vendor/font-awesome.min.css" rel="stylesheet">
|
|
17
16
|
<link rel="stylesheet" type="text/css" href="/light-bootstrap-dashboard-master/assets/css/pe-icon-7-stroke.css">
|
|
18
17
|
|
|
18
|
+
<link rel="stylesheet" type="text/css" href="/vendor/highlight-js-default.min.css">
|
|
19
19
|
<link rel="stylesheet" type="text/css" href="/css/app.css">
|
|
20
20
|
|
|
21
21
|
<%= csrf_meta_tags %>
|
|
@@ -28,8 +28,8 @@
|
|
|
28
28
|
|
|
29
29
|
<div class="sidebar-wrapper">
|
|
30
30
|
<ul class="nav">
|
|
31
|
-
<li class="<%= is_active_link?(
|
|
32
|
-
<a href="<%=
|
|
31
|
+
<li class="<%= is_active_link?(schema_path, :inclusive) ? "active" : nil %>">
|
|
32
|
+
<a href="<%= schema_path %>">
|
|
33
33
|
<i class="pe-7s-home"></i>
|
|
34
34
|
<p>Schema</p>
|
|
35
35
|
</a>
|
|
@@ -42,69 +42,16 @@
|
|
|
42
42
|
</a>
|
|
43
43
|
</li>
|
|
44
44
|
|
|
45
|
-
<li class="<%= is_active_link?(relations_path, :inclusive) ? "active" : nil %>">
|
|
46
|
-
<a href="<%= relations_path %>">
|
|
47
|
-
<i class="pe-7s-shuffle"></i>
|
|
48
|
-
<p>New Relation</p>
|
|
49
|
-
</a>
|
|
50
|
-
</li>
|
|
51
|
-
|
|
52
45
|
<li class="<%= is_active_link?(migrations_path, :inclusive) ? "active" : nil %>">
|
|
53
46
|
<a href="<%= migrations_path %>">
|
|
54
47
|
<i class="pe-7s-edit"></i>
|
|
55
48
|
<p>New Migration</p>
|
|
56
49
|
</a>
|
|
57
50
|
</li>
|
|
58
|
-
|
|
59
|
-
<li class="<%= is_active_link?(logs_path, :inclusive) ? "active" : nil %>">
|
|
60
|
-
<a href="<%= logs_path %>">
|
|
61
|
-
<i class="pe-7s-ticket"></i>
|
|
62
|
-
<p>Logs</p>
|
|
63
|
-
</a>
|
|
64
|
-
</li>
|
|
65
|
-
|
|
66
|
-
<!--
|
|
67
|
-
<li class="<%= is_active_link?(status_path, :inclusive) ? "active" : nil %>">
|
|
68
|
-
<a href="<%= status_path %>">
|
|
69
|
-
<i class=""></i>
|
|
70
|
-
<p>Status</p>
|
|
71
|
-
</a>
|
|
72
|
-
</li>
|
|
73
|
-
-->
|
|
74
|
-
|
|
75
51
|
</ul>
|
|
76
52
|
</div>
|
|
77
53
|
</div>
|
|
78
|
-
<div class="tower-nav">
|
|
79
|
-
<div class="<%= is_active_link?(dashboard_path, :inclusive) ? "active" : nil %>">
|
|
80
|
-
<a class="tower-a" href="<%= dashboard_path %>">
|
|
81
|
-
<i class="pe-7s-home"></i>
|
|
82
|
-
<p>Schema</p>
|
|
83
|
-
</a>
|
|
84
|
-
</div>
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
<div class="<%= is_active_link?(models_path, :inclusive) ? "active" : nil %>">
|
|
88
|
-
<a class="tower-a" href="<%= models_path %>">
|
|
89
|
-
<i class="pe-7s-server"></i>
|
|
90
|
-
<p>New Model</p>
|
|
91
|
-
</a>
|
|
92
|
-
</div>
|
|
93
54
|
|
|
94
|
-
<div class="<%= is_active_link?(relations_path, :inclusive) ? "active" : nil %>">
|
|
95
|
-
<a class="tower-a" href="<%= relations_path %>">
|
|
96
|
-
<i class="pe-7s-shuffle"></i>
|
|
97
|
-
<p>New Relation</p>
|
|
98
|
-
</a>
|
|
99
|
-
</div>
|
|
100
|
-
|
|
101
|
-
<div class="<%= is_active_link?(migrations_path, :inclusive) ? "active" : nil %>">
|
|
102
|
-
<a class="tower-a" href="<%= migrations_path %>">
|
|
103
|
-
<i class="pe-7s-edit"></i>
|
|
104
|
-
<p>New Migration</p>
|
|
105
|
-
</a>
|
|
106
|
-
</div>
|
|
107
|
-
</div>
|
|
108
55
|
|
|
109
56
|
<div class="main-panel">
|
|
110
57
|
<div class="content">
|
|
@@ -144,7 +91,8 @@
|
|
|
144
91
|
|
|
145
92
|
<!-- Light Bootstrap Table Core javascript and methods for Demo purpose -->
|
|
146
93
|
<script src="/light-bootstrap-dashboard-master/assets/js/light-bootstrap-dashboard.js"></script>
|
|
147
|
-
<script src="/
|
|
94
|
+
<script src="/vendor/highlight.min.js"></script>
|
|
95
|
+
<script src="/vendor/masonry.pkgd.min.js"></script>
|
|
148
96
|
<script src="/js/app.js"></script>
|
|
149
97
|
</body>
|
|
150
98
|
</html>
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
<div class="card">
|
|
2
|
+
<div class="header">
|
|
3
|
+
<div class="container-fluid">
|
|
4
|
+
<div class="row">
|
|
5
|
+
<div class="col-md-6"><h4 class="title">Pending migrations</h4></div>
|
|
6
|
+
<div class="col-md-6">
|
|
7
|
+
<div class="pull-right">
|
|
8
|
+
<% if migrations.any? %>
|
|
9
|
+
<%= form_tag actions_path, class: "form" do %>
|
|
10
|
+
<button name="cmd" type="submit" value="rails db:migrate" class="btn btn-warning" data-selector="submit">
|
|
11
|
+
Run Pending Migrations (<code>bundle exec rails db:migrate</code>)
|
|
12
|
+
</button>
|
|
13
|
+
<% end %>
|
|
14
|
+
<% end %>
|
|
15
|
+
</div>
|
|
16
|
+
</div>
|
|
17
|
+
</div>
|
|
18
|
+
</div>
|
|
19
|
+
</div>
|
|
20
|
+
|
|
21
|
+
<div class="content">
|
|
22
|
+
<% if migrations.any? %>
|
|
23
|
+
<% migrations.each do |entry| %>
|
|
24
|
+
<div class="container-fluid">
|
|
25
|
+
<div class="row">
|
|
26
|
+
<div class="col-md-8">
|
|
27
|
+
<h5 style="color: <%= entry['status'] == :todo ? 'red' : 'green' %>;">
|
|
28
|
+
<% if entry['status'] == :todo %>
|
|
29
|
+
<button type="button" class="btn btn-danger btn-xs">PENDING</button>
|
|
30
|
+
<% end %>
|
|
31
|
+
|
|
32
|
+
<a href="<%= file_link(entry['file_full_path']) %>"><%= entry['name'] %></a>
|
|
33
|
+
</h5>
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
36
|
+
|
|
37
|
+
<div class="row">
|
|
38
|
+
<div class="col-md-12">
|
|
39
|
+
<% if entry['status'] == :todo %>
|
|
40
|
+
<pre><code class="language-ruby"><%= entry['content'] %></code></pre>
|
|
41
|
+
<% end %>
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
<% end %>
|
|
46
|
+
|
|
47
|
+
<% else %>
|
|
48
|
+
<div class="container-fluid">
|
|
49
|
+
<div class="row">
|
|
50
|
+
<div class="col-md-8">
|
|
51
|
+
No pending migrations.
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
55
|
+
<% end %>
|
|
56
|
+
</div>
|
|
57
|
+
</div>
|
|
@@ -76,20 +76,17 @@
|
|
|
76
76
|
|
|
77
77
|
<hr>
|
|
78
78
|
|
|
79
|
-
<!-- multiple lines: -->
|
|
80
79
|
<div class="row">
|
|
81
80
|
<div class="col-md-12 text-center">
|
|
82
|
-
<button
|
|
81
|
+
<button type="submit" value="true" class="btn btn-success" data-selector="submit">
|
|
83
82
|
Create the migration
|
|
84
83
|
</button>
|
|
85
|
-
|
|
86
|
-
<button name="migrations[run_migrate]" type="submit" value="true" class="btn btn-success" data-selector="submit">
|
|
87
|
-
Create the migration and <b>migrate</b>
|
|
88
|
-
</button>
|
|
89
84
|
</div>
|
|
90
85
|
</div>
|
|
91
86
|
<% end %>
|
|
92
87
|
</div>
|
|
93
88
|
</div>
|
|
89
|
+
|
|
90
|
+
<%= render partial: "migrations", locals: { migrations: @migrations } %>
|
|
94
91
|
</div>
|
|
95
92
|
</div>
|
|
@@ -14,14 +14,14 @@
|
|
|
14
14
|
<div class="col-md-6">
|
|
15
15
|
<div class="form-group">
|
|
16
16
|
<label>Name of the Model</label>
|
|
17
|
-
<input type="text" name="models[model_name]" class="form-control">
|
|
17
|
+
<input type="text" data-sain name="models[model_name]" class="form-control">
|
|
18
18
|
</div>
|
|
19
19
|
</div>
|
|
20
20
|
</div>
|
|
21
21
|
|
|
22
22
|
<table class="table table-hover table-striped">
|
|
23
23
|
<thead>
|
|
24
|
-
<th>
|
|
24
|
+
<th>Column Name</th>
|
|
25
25
|
<th>Type</th>
|
|
26
26
|
<th>Default</th>
|
|
27
27
|
<th>Index?</th>
|
|
@@ -66,17 +66,15 @@
|
|
|
66
66
|
<!-- multiple lines: -->
|
|
67
67
|
<div class="row">
|
|
68
68
|
<div class="col-md-12 text-center">
|
|
69
|
-
<button
|
|
70
|
-
Create the model
|
|
71
|
-
</button>
|
|
72
|
-
|
|
73
|
-
<button name="models[run_migrate]" type="submit" value="true" class="btn btn-success" data-selector="submit">
|
|
74
|
-
Create the model and <b>migrate</b>
|
|
69
|
+
<button type="submit" value="true" class="btn btn-success" data-selector="submit">
|
|
70
|
+
Create the model Only
|
|
75
71
|
</button>
|
|
76
72
|
</div>
|
|
77
73
|
</div>
|
|
78
74
|
<% end %>
|
|
79
75
|
</div>
|
|
80
76
|
</div>
|
|
77
|
+
|
|
78
|
+
<%= render partial: "migrations", locals: { migrations: @migrations } %>
|
|
81
79
|
</div>
|
|
82
80
|
</div>
|
|
File without changes
|
data/config/routes.rb
CHANGED
|
@@ -1,20 +1,13 @@
|
|
|
1
1
|
Localtower::Engine.routes.draw do
|
|
2
|
-
get
|
|
3
|
-
post
|
|
2
|
+
get 'migrations', to: 'pages#migrations', as: :migrations
|
|
3
|
+
post 'migrations', to: 'pages#post_migrations'
|
|
4
4
|
|
|
5
|
-
get
|
|
6
|
-
post
|
|
5
|
+
get 'models', to: 'pages#models', as: :models
|
|
6
|
+
post 'models', to: 'pages#post_models'
|
|
7
7
|
|
|
8
|
-
get "relations", to: "pages#relations", as: :relations
|
|
9
|
-
post "relations", to: "pages#post_relations"
|
|
10
|
-
|
|
11
|
-
get "status", to: "pages#status", as: :status
|
|
12
8
|
# get ':v/:asset', to: 'pages#asset_render', as: 'asset_render', :constraints => { :v => /[^\/]*/, :asset => /[^\/]*/ }
|
|
9
|
+
get 'schema', to: 'pages#schema', as: 'schema'
|
|
10
|
+
post 'actions', to: 'pages#post_actions', as: 'actions'
|
|
13
11
|
|
|
14
|
-
|
|
15
|
-
get 'logs', to: 'pages#logs', as: 'logs'
|
|
16
|
-
get 'logs/:md5', to: 'pages#log', as: 'log'
|
|
17
|
-
get 'logs/:md5/:var', to: 'pages#log_var', as: 'log_var'
|
|
18
|
-
|
|
19
|
-
root :to => redirect('dashboard')
|
|
12
|
+
root :to => redirect('models')
|
|
20
13
|
end
|
|
@@ -5,9 +5,11 @@ module Localtower
|
|
|
5
5
|
include Thor::Actions
|
|
6
6
|
|
|
7
7
|
no_commands do
|
|
8
|
+
# data = {last_migration_file: "", column_type: "", table_name: "", column: "", nullable: true, index: true}
|
|
8
9
|
def migration_add_column(data)
|
|
9
10
|
file = data["last_migration_file"]
|
|
10
11
|
|
|
12
|
+
# Special case for array
|
|
11
13
|
if %w(array).include?(data["column_type"])
|
|
12
14
|
line = " add_column :#{data['table_name']}, :#{data['column']}, :text"
|
|
13
15
|
line << ", default: []"
|
|
@@ -134,14 +136,12 @@ module Localtower
|
|
|
134
136
|
'change_column_type',
|
|
135
137
|
'add_index_to_column',
|
|
136
138
|
'belongs_to',
|
|
137
|
-
# 'add_index_to_column_combined',
|
|
138
139
|
'remove_index_to_column',
|
|
139
|
-
# 'create_table',
|
|
140
140
|
'drop_table',
|
|
141
141
|
].freeze
|
|
142
142
|
|
|
143
143
|
DEFAULTS = [
|
|
144
|
-
"true", "false", "nil"
|
|
144
|
+
"true", "false", "nil", "0"
|
|
145
145
|
]
|
|
146
146
|
|
|
147
147
|
# @opts =
|
|
@@ -150,21 +150,12 @@ module Localtower
|
|
|
150
150
|
@opts = JSON[opts.to_json]
|
|
151
151
|
end
|
|
152
152
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
content_schema = """
|
|
157
|
-
ActiveRecord::Schema.define(version: 0) do
|
|
158
|
-
end
|
|
159
|
-
"""
|
|
160
|
-
|
|
161
|
-
File.open("#{Rails.root}/db/schema.rb", "w") do |f|
|
|
162
|
-
f.write(content_schema)
|
|
163
|
-
end
|
|
164
|
-
end
|
|
165
|
-
|
|
153
|
+
# @opts['migrations'] = []
|
|
154
|
+
# @opts['run_migrate'] = true
|
|
166
155
|
def run
|
|
167
|
-
|
|
156
|
+
model_names = @opts['migrations'].map { |line| line['table_name'].camelize }.join
|
|
157
|
+
|
|
158
|
+
cmd = "Change#{model_names}#{@opts['migration_name']}At#{Time.now.to_i}"
|
|
168
159
|
::Localtower::Tools.perform_migration(cmd, true)
|
|
169
160
|
|
|
170
161
|
@opts['migrations'].each do |action_line|
|
|
@@ -188,7 +179,6 @@ end
|
|
|
188
179
|
'change_column_type' => -> { change_column_type(action_line) },
|
|
189
180
|
'add_index_to_column' => -> { add_index_to_column(action_line) },
|
|
190
181
|
'belongs_to' => -> { belongs_to(action_line) },
|
|
191
|
-
# 'add_index_to_column_combined' => -> { add_index_to_column_combined(action_line) },
|
|
192
182
|
'remove_index_to_column' => -> { remove_index_to_column(action_line) },
|
|
193
183
|
'create_table' => -> { create_table(action_line) },
|
|
194
184
|
'drop_table' => -> { drop_table(action_line) }
|
|
@@ -209,90 +199,41 @@ end
|
|
|
209
199
|
private
|
|
210
200
|
|
|
211
201
|
def add_column(data)
|
|
212
|
-
if not data["table_name"].present? \
|
|
213
|
-
or not data["column"].present? \
|
|
214
|
-
or not data["column_type"].present?
|
|
215
|
-
return nil
|
|
216
|
-
end
|
|
217
|
-
|
|
218
202
|
@thor.migration_add_column(data)
|
|
219
203
|
end
|
|
220
204
|
|
|
221
205
|
def remove_column(data)
|
|
222
|
-
if not data["table_name"].present? \
|
|
223
|
-
or not data["column"].present?
|
|
224
|
-
return nil
|
|
225
|
-
end
|
|
226
|
-
|
|
227
206
|
@thor.migration_remove_column(data)
|
|
228
207
|
end
|
|
229
208
|
|
|
230
209
|
def rename_column(data)
|
|
231
|
-
if not data["table_name"].present? \
|
|
232
|
-
or not data["column"].present? \
|
|
233
|
-
or not data["new_column_name"].present?
|
|
234
|
-
return nil
|
|
235
|
-
end
|
|
236
|
-
|
|
237
210
|
@thor.migration_rename_column(data)
|
|
238
211
|
end
|
|
239
212
|
|
|
240
213
|
def change_column_type(data)
|
|
241
|
-
if not data["table_name"].present? \
|
|
242
|
-
or not data["column"].present? \
|
|
243
|
-
or not data["new_column_type"].present?
|
|
244
|
-
return nil
|
|
245
|
-
end
|
|
246
|
-
|
|
247
214
|
@thor.migration_change_column_type(data)
|
|
248
215
|
end
|
|
249
216
|
|
|
250
217
|
def add_index_to_column(data)
|
|
251
|
-
if not data["table_name"].present? \
|
|
252
|
-
or not data["column"].present?
|
|
253
|
-
return nil
|
|
254
|
-
end
|
|
255
|
-
|
|
256
218
|
@thor.migration_add_index_to_column(data)
|
|
257
219
|
end
|
|
258
220
|
|
|
259
221
|
def belongs_to(data)
|
|
260
|
-
if not data["table_name"].present? and data["belongs_to"].present?
|
|
261
|
-
return nil
|
|
262
|
-
end
|
|
263
|
-
|
|
264
222
|
data["column"] = data["belongs_to"].underscore.singularize
|
|
265
223
|
data['column_type'] = "references"
|
|
266
224
|
|
|
267
225
|
@thor.migration_belongs_to(data)
|
|
268
226
|
end
|
|
269
227
|
|
|
270
|
-
# def add_index_to_column_combined(data)
|
|
271
|
-
# @thor.migration_add_index_to_column_combined(data)
|
|
272
|
-
# end
|
|
273
|
-
|
|
274
228
|
def remove_index_to_column(data)
|
|
275
|
-
if not data["table_name"].present? \
|
|
276
|
-
or not data["column"].present?
|
|
277
|
-
return nil
|
|
278
|
-
end
|
|
279
|
-
|
|
280
229
|
@thor.migration_remove_index_to_column(data)
|
|
281
230
|
end
|
|
282
231
|
|
|
283
232
|
def create_table(data)
|
|
284
|
-
if not data["table_name"].present?
|
|
285
|
-
return nil
|
|
286
|
-
end
|
|
287
|
-
|
|
288
233
|
@thor.migration_create_table(data)
|
|
289
234
|
end
|
|
290
235
|
|
|
291
236
|
def drop_table(data)
|
|
292
|
-
if not data["table_name"].present?
|
|
293
|
-
return nil
|
|
294
|
-
end
|
|
295
|
-
|
|
296
237
|
@thor.migration_drop_table(data)
|
|
297
238
|
end
|
|
298
239
|
|