irie 0.0.36__py3-none-any.whl → 0.0.37__py3-none-any.whl

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.

Potentially problematic release.


This version of irie might be problematic. Click here for more details.

@@ -5,7 +5,7 @@
5
5
  #===----------------------------------------------------------------------===#
6
6
  from django import forms
7
7
  from django.forms import formset_factory
8
- from irie.apps.inventory.models import Asset, SensorGroup, Sensor
8
+ from irie.apps.inventory.models import Asset, SensorGroup, Sensor, Datum
9
9
 
10
10
  class AssetForm(forms.ModelForm):
11
11
  class Meta:
@@ -16,12 +16,18 @@ class SensorGroupForm(forms.ModelForm):
16
16
  class Meta:
17
17
  model = SensorGroup
18
18
  fields = ['name', 'datum']
19
+
20
+ def __init__(self, *args, asset=None, **kwargs):
21
+ super().__init__(*args, **kwargs)
22
+ if asset:
23
+ self.fields['datum'].queryset = Datum.objects.filter(asset=asset)
19
24
 
20
25
  class SensorForm(forms.ModelForm):
21
26
  class Meta:
22
27
  model = Sensor
23
- fields = ['x', 'y', 'z', 'dx', 'dy', 'dz']
28
+ fields = ['name', 'x', 'y', 'z', 'dx', 'dy', 'dz']
24
29
  labels = {
30
+ 'name': 'Name',
25
31
  'x': 'x',
26
32
  'y': 'y',
27
33
  'z': 'z',
@@ -0,0 +1,19 @@
1
+ # Generated by Django 5.1.2 on 2025-02-25 04:49
2
+
3
+ import django.db.models.deletion
4
+ from django.db import migrations, models
5
+
6
+
7
+ class Migration(migrations.Migration):
8
+
9
+ dependencies = [
10
+ ('irie_apps_inventory', '0004_datum_sensorgroup_sensor'),
11
+ ]
12
+
13
+ operations = [
14
+ migrations.AlterField(
15
+ model_name='sensor',
16
+ name='group',
17
+ field=models.ForeignKey(on_delete=django.db.models.deletion.RESTRICT, related_name='sensors', to='irie_apps_inventory.sensorgroup'),
18
+ ),
19
+ ]
@@ -0,0 +1,56 @@
1
+ # Generated by Django 5.1.2 on 2025-02-25 05:07
2
+
3
+ import django.db.models.deletion
4
+ from django.db import migrations, models
5
+
6
+
7
+ class Migration(migrations.Migration):
8
+
9
+ dependencies = [
10
+ ('irie_apps_inventory', '0005_alter_sensor_group'),
11
+ ]
12
+
13
+ operations = [
14
+ migrations.AddField(
15
+ model_name='datum',
16
+ name='asset',
17
+ field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.RESTRICT, to='irie_apps_inventory.asset'),
18
+ preserve_default=False,
19
+ ),
20
+ migrations.AddField(
21
+ model_name='datum',
22
+ name='locate_x',
23
+ field=models.CharField(default=0, max_length=240),
24
+ preserve_default=False,
25
+ ),
26
+ migrations.AddField(
27
+ model_name='datum',
28
+ name='locate_y',
29
+ field=models.CharField(default=0, max_length=240),
30
+ preserve_default=False,
31
+ ),
32
+ migrations.AddField(
33
+ model_name='datum',
34
+ name='locate_z',
35
+ field=models.CharField(default=0, max_length=240),
36
+ preserve_default=False,
37
+ ),
38
+ migrations.AddField(
39
+ model_name='datum',
40
+ name='orient_x',
41
+ field=models.CharField(default=0, max_length=240),
42
+ preserve_default=False,
43
+ ),
44
+ migrations.AddField(
45
+ model_name='datum',
46
+ name='orient_y',
47
+ field=models.CharField(default=0, max_length=240),
48
+ preserve_default=False,
49
+ ),
50
+ migrations.AddField(
51
+ model_name='datum',
52
+ name='orient_z',
53
+ field=models.CharField(default=0, max_length=240),
54
+ preserve_default=False,
55
+ ),
56
+ ]
@@ -0,0 +1,19 @@
1
+ # Generated by Django 5.1.2 on 2025-02-26 03:21
2
+
3
+ from django.db import migrations, models
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+
8
+ dependencies = [
9
+ ('irie_apps_inventory', '0006_datum_asset_datum_locate_x_datum_locate_y_and_more'),
10
+ ]
11
+
12
+ operations = [
13
+ migrations.AddField(
14
+ model_name='sensor',
15
+ name='name',
16
+ field=models.CharField(default=1, max_length=100),
17
+ preserve_default=False,
18
+ ),
19
+ ]
@@ -0,0 +1,43 @@
1
+ # Generated by Django 5.1.2 on 2025-02-26 07:05
2
+
3
+ from django.db import migrations, models
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+
8
+ dependencies = [
9
+ ('irie_apps_inventory', '0007_sensor_name'),
10
+ ]
11
+
12
+ operations = [
13
+ migrations.AlterField(
14
+ model_name='sensor',
15
+ name='dx',
16
+ field=models.DecimalField(decimal_places=2, max_digits=10),
17
+ ),
18
+ migrations.AlterField(
19
+ model_name='sensor',
20
+ name='dy',
21
+ field=models.DecimalField(decimal_places=2, max_digits=10),
22
+ ),
23
+ migrations.AlterField(
24
+ model_name='sensor',
25
+ name='dz',
26
+ field=models.DecimalField(decimal_places=2, max_digits=10),
27
+ ),
28
+ migrations.AlterField(
29
+ model_name='sensor',
30
+ name='x',
31
+ field=models.DecimalField(decimal_places=2, max_digits=10),
32
+ ),
33
+ migrations.AlterField(
34
+ model_name='sensor',
35
+ name='y',
36
+ field=models.DecimalField(decimal_places=2, max_digits=10),
37
+ ),
38
+ migrations.AlterField(
39
+ model_name='sensor',
40
+ name='z',
41
+ field=models.DecimalField(decimal_places=2, max_digits=10),
42
+ ),
43
+ ]
@@ -104,12 +104,18 @@ class Vulnerability: # (models.Model):
104
104
 
105
105
  class Datum(models.Model):
106
106
  name = models.CharField(max_length=100)
107
+ orient_x = models.CharField(max_length=240) # eg, longitudinal axis of the deck from west to east
108
+ locate_x = models.CharField(max_length=240) # eg, east abutment-to-deck interface
109
+ orient_y = models.CharField(max_length=240) # eg, transverse axis of the deck from north to south
110
+ locate_y = models.CharField(max_length=240) # eg, center of deck
111
+ orient_z = models.CharField(max_length=240) # eg, vertical upwards
112
+ locate_z = models.CharField(max_length=240) # eg, deck surface
113
+ asset = models.ForeignKey(Asset, on_delete=models.RESTRICT)
114
+
107
115
  def __str__(self):
108
116
  return f"{self.name}"
109
117
 
110
118
  class SensorGroup(models.Model):
111
- """
112
- """
113
119
  name = models.CharField(max_length=100)
114
120
  # sensors; access with .sensor_set.all()
115
121
  asset = models.ForeignKey(Asset, on_delete=models.RESTRICT)
@@ -123,15 +129,16 @@ class Sensor(models.Model):
123
129
  # class Status:
124
130
  # active: bool
125
131
 
126
- x = models.FloatField()
127
- y = models.FloatField()
128
- z = models.FloatField()
132
+ name = models.CharField(max_length=100)
133
+ x = models.DecimalField(decimal_places=2, max_digits=10)
134
+ y = models.DecimalField(decimal_places=2, max_digits=10)
135
+ z = models.DecimalField(decimal_places=2, max_digits=10)
129
136
 
130
- dx = models.FloatField()
131
- dy = models.FloatField()
132
- dz = models.FloatField()
137
+ dx = models.DecimalField(decimal_places=2, max_digits=10)
138
+ dy = models.DecimalField(decimal_places=2, max_digits=10)
139
+ dz = models.DecimalField(decimal_places=2, max_digits=10)
133
140
 
134
141
  group = models.ForeignKey(SensorGroup, related_name="sensors", on_delete=models.RESTRICT)
135
142
 
136
143
  def __str__(self):
137
- return f"Sensor {self.id} ({self.group.name})"
144
+ return f"{self.name} ({self.group.name})"
@@ -22,7 +22,7 @@ from django.forms import formset_factory
22
22
 
23
23
  from irie.apps.events.models import EventRecord
24
24
  from irie.apps.site.view_utils import raise404
25
- from irie.apps.inventory.models import Asset, SensorGroup, Sensor
25
+ from irie.apps.inventory.models import Asset, SensorGroup, Sensor, Datum
26
26
  from irie.apps.inventory.forms import SensorGroupForm, SensorForm, SensorFormSet
27
27
  from .filters import AssetFilter
28
28
  # Predictors
@@ -318,7 +318,10 @@ def _make_tables(asset):
318
318
  } for group in asset.nbi_data.values()
319
319
  ]
320
320
  tables.extend(nbi_data)
321
- tables = [tables[2], *tables[:2], *tables[3:]]
321
+ try:
322
+ tables = [tables[2], *tables[:2], *tables[3:]]
323
+ except:
324
+ pass
322
325
  condition = {}
323
326
  for table in tables:
324
327
  keys = set()
@@ -355,10 +358,13 @@ def asset_sensors(request, calid):
355
358
  @login_required(login_url="/login/")
356
359
  def sensor_upload(request, calid):
357
360
  asset = get_object_or_404(Asset, calid=calid) # Fetch the asset using calid
361
+ datums = Datum.objects.filter(asset=asset).values(
362
+ 'id', 'orient_x', 'locate_x', 'orient_y', 'locate_y', 'orient_z', 'locate_z'
363
+ )
358
364
  SensorFormSet = formset_factory(SensorForm, extra=1, can_delete=False)
359
365
 
360
366
  if request.method == "POST":
361
- group_form = SensorGroupForm(request.POST)
367
+ group_form = SensorGroupForm(request.POST, asset=asset)
362
368
  formset = SensorFormSet(request.POST)
363
369
 
364
370
  if group_form.is_valid() and formset.is_valid():
@@ -375,13 +381,14 @@ def sensor_upload(request, calid):
375
381
  return redirect('asset_sensors', calid=calid) # Redirect after successful submission
376
382
 
377
383
  else:
378
- group_form = SensorGroupForm()
384
+ group_form = SensorGroupForm(asset=asset)
379
385
  formset = SensorFormSet()
380
386
 
381
387
  return render(request, "inventory/sensor-upload.html", {
382
388
  "group_form": group_form,
383
389
  "formset": formset,
384
- "asset": asset # Pass asset to template if needed
390
+ "asset": asset,
391
+ "datums": list(datums)
385
392
  })
386
393
 
387
394
 
@@ -6,6 +6,10 @@
6
6
  {% endblock %}
7
7
 
8
8
  {% block stylesheets %}
9
+ {% if asset.rendering %}
10
+ <!-- <meta name="viewport" content="width=device-width, initial-scale=1.0"> -->
11
+ <script type="module" src="https://ajax.googleapis.com/ajax/libs/model-viewer/4.0.0/model-viewer.min.js"></script>
12
+ {% endif %}
9
13
  <style>
10
14
  .ct-series-a .ct-point, .ct-series-a .ct-line, .ct-series-a .ct-bar, .ct-series-a .ct-slice-donut{
11
15
  stroke: #506690;
@@ -60,15 +64,21 @@
60
64
  <div class="tab-content" id="pills-tabContent">
61
65
  <div class="tab-pane fade show active"
62
66
  id="pills-rendering" role="tabpanel">
63
- {% if asset.is_complete %}
64
- {% with cesmd=asset.cesmd %}
65
- {% with filename="bridges/InteractiveTwin-"|add:asset.cesmd|add:".html" %}
66
- {% include filename %}
67
- {% endwith %}
68
- {% endwith %}
67
+ {% if asset.rendering %}
68
+ <model-viewer
69
+ id="viewer"
70
+ src="{{ asset.rendering }}"
71
+ alt="3D Model"
72
+ auto-rotate
73
+ camera-controls
74
+ interaction-prompt="none"
75
+ camera-orbit="0deg 75deg 2m"
76
+ field-of-view="30deg"
77
+ style="width: 100%; height: 400px;">
78
+ </model-viewer>
69
79
  {% endif %}
70
80
  </div>
71
- <div class="tab-pane fade show {% if not asset.is_complete %}active{% endif %}"
81
+ <div class="tab-pane fade show {% if not asset.rendering %}active{% endif %}"
72
82
  id="pills-sensors" role="tabpanel">
73
83
  <img src="{{ ASSETS_ROOT }}/inventory/ll{{ asset.cesmd|slice:"2:" }}.svg">
74
84
  </div>
@@ -129,7 +129,7 @@
129
129
  <div class="btn-toolbar mb-2 mb-md-0">
130
130
  <a role="button"
131
131
  href="/inventory/{{ asset.calid }}/predictors/"
132
- class="btn btn-sm btn-outline-primary d-inline-flex align-items-center">
132
+ class="btn btn-sm btn-outline-primary d-inline-flex align-items-center mx-1">
133
133
  <svg class="icon icon-xs me-2" fill="none"
134
134
  stroke="currentColor" viewBox="0 0 24 24"
135
135
  xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path></svg>
@@ -137,7 +137,7 @@
137
137
  </a>
138
138
  <a role="button"
139
139
  href="{% url 'asset_sensors' calid=asset.calid %}"
140
- class="btn btn-sm btn-outline-primary d-inline-flex align-items-center">
140
+ class="btn btn-sm btn-outline-primary d-inline-flex align-items-center mx-1">
141
141
  <svg class="icon icon-xs me-2" fill="none"
142
142
  stroke="currentColor" viewBox="0 0 24 24"
143
143
  xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path></svg>
@@ -145,7 +145,7 @@
145
145
  </a>
146
146
  </div>
147
147
  </div>
148
- {% if True %}
148
+ {% if asset.nbi_data.NBI_BRIDGE %}
149
149
  <div class="col-10">
150
150
  <p>
151
151
  {% if asset.id|divisibleby:3 %}
@@ -22,20 +22,39 @@ Chrystal Chern, Spring 2025
22
22
  href="{% url 'sensor_upload' calid=asset.calid %}" class="me-1">Add SensorGroup</a>
23
23
  </div>
24
24
 
25
-
26
- <div class="col-10">
25
+ <div class="col-lg-10">
27
26
  {% for group in groups %}
28
- <div class="card">
29
- <div class="card-header">
30
- {{group.name}}
31
- </div>
27
+ <div class="card shadow-lg mb-4">
28
+ <div class="card-header bg-dark text-white fw-bold d-flex justify-content-between align-items-center">
29
+ <span>{{ group.name }}</span>
30
+ <span class="badge bg-gray text-white px-2 py-1 fs-6">Datum: {{ group.datum.name }}</span>
31
+ </div>
32
32
  <div class="card-body">
33
- <table>
34
- {% for sensor in group.sensors.all %}
35
- <tr>
36
- <td>{{ sensor }} </td><td>{{sensor.x}}</td><td>{{sensor.y}}</td><td>{{sensor.z}}</td>
37
- </tr>
38
- {% endfor %}
33
+ <table class="table table-striped table-hover table-bordered">
34
+ <thead class="table-dark">
35
+ <tr>
36
+ <th>Sensor</th>
37
+ <th>x</th>
38
+ <th>y</th>
39
+ <th>z</th>
40
+ <th>dx</th>
41
+ <th>dy</th>
42
+ <th>dz</th>
43
+ </tr>
44
+ </thead>
45
+ <tbody>
46
+ {% for sensor in group.sensors.all %}
47
+ <tr>
48
+ <td class="fw-bold">{{ sensor.name }}</td>
49
+ <td>{{ sensor.x }}</td>
50
+ <td>{{ sensor.y }}</td>
51
+ <td>{{ sensor.z }}</td>
52
+ <td>{{ sensor.dx }}</td>
53
+ <td>{{ sensor.dy }}</td>
54
+ <td>{{ sensor.dz }}</td>
55
+ </tr>
56
+ {% endfor %}
57
+ </tbody>
39
58
  </table>
40
59
  </div>
41
60
  </div>
@@ -9,18 +9,57 @@ Chrystal Chern, Spring 2025
9
9
 
10
10
  -->
11
11
  {% extends "layouts/base.html" %}
12
+
13
+ {% block stylesheets %}
14
+ <style>
15
+ input[type="number"] {
16
+ -moz-appearance: textfield; /* Firefox */
17
+ appearance: textfield; /* Standard */
18
+ }
19
+ input[type="number"]::-webkit-inner-spin-button,
20
+ input[type="number"]::-webkit-outer-spin-button {
21
+ -webkit-appearance: none;
22
+ margin: 0;
23
+ }
24
+ </style>
25
+ <script type="importmap">
26
+ {
27
+ "imports": {
28
+ "three": "https://cdn.jsdelivr.net/npm/three@0.172.0/build/three.module.js",
29
+ "three/addons/": "https://cdn.jsdelivr.net/npm/three@0.172.0/examples/jsm/"
30
+ }
31
+ }
32
+ </script>
33
+ {% endblock stylesheets %}
34
+
12
35
  {% block title %} Add Sensor Group to {{ asset.calid }} {% endblock %}
13
36
 
14
37
  {% block content %}
15
-
16
38
  <h1>Add Sensor Group to <code>{{ asset.calid }}</code></h1>
17
39
 
40
+ <div class="py-4 align-right">
41
+ <a role="button" class="button btn btn-outline-primary"
42
+ href="{% url 'asset_profile' calid=asset.calid %}" class="me-1">Back to Structure</a>
43
+ <a role="button" class="button btn btn-outline-primary"
44
+ href="{% url 'asset_sensors' calid=asset.calid %}" class="me-1">Back to Sensors</a>
45
+ </div>
46
+
47
+
48
+ <div class="container">
49
+ <div class="row align-right">
50
+
51
+ <!-- Left Side: Sensor Form -->
52
+ <div class="col-md-6" >
18
53
  <form method="post">
19
54
  {% csrf_token %}
20
55
 
21
- <fieldset>
56
+ <fieldset class="mb-4">
22
57
  <legend>Sensor Group</legend>
23
58
  {{ group_form.as_p }}
59
+ <div id="datum-info" class="mb-4 p-2 border rounded bg-light" style="display: none;">
60
+ <strong>Datum Location (x;y;z):</strong> <span id="datum-location">_, _, _</span> <br>
61
+ <strong>Datum Orientation (dx;dy;dz):</strong> <span id="datum-orientation">_, _, _</span>
62
+ </div>
24
63
  </fieldset>
25
64
 
26
65
  <fieldset>
@@ -28,30 +67,39 @@ Chrystal Chern, Spring 2025
28
67
  {{ formset.management_form }}
29
68
  <div id="formset-container" class="container">
30
69
  {% for form in formset %}
31
- <div class="sensor-form">
32
- <div class="row"><div class="col-md-6 d-flex align-items-center mb-3">
70
+ <div class="sensor-form mb-4">
71
+ <div class="row mb-3">
33
72
  <div class="input-group">
34
- <span class="input-group-text col-md-2">{{ form.x.label }}</span>
35
- <input id="{{form.x.html_name}}" type="number" name="{{form.x.html_name}}" class="form-control col-md-4"></input>
73
+ <span class="input-group-text col-md-2 text-dark border-dark">{{ form.name.label }}</span>
74
+ <input id="{{form.name.html_name}}" type="text" name="{{form.name.html_name}}" class="form-control col-md-4 text-dark border-dark" required></input>
36
75
  </div>
76
+ </div>
77
+ <div class="row"><div class="col-md-12 d-flex align-items-center mb-3">
37
78
  <div class="input-group">
38
- <span class="input-group-text col-md-2">{{ form.y.label }}</span>
39
- <input id="{{form.y.html_name}}" type="number" name="{{form.y.html_name}}" class="form-control col-md-4"></input>
79
+ <span class="input-group-text col-md-4 text-gray">{{ form.x.label }}</span>
80
+ <input id="{{form.x.html_name}}" type="number" step="any" name="{{form.x.html_name}}" class="form-control col-md-8 text-gray" required></input>
40
81
  </div>
41
82
  <div class="input-group">
42
- <span class="input-group-text col-md-2">{{ form.z.label }}</span>
43
- <input id="{{form.z.html_name}}" type="number" name="{{form.z.html_name}}" class="form-control col-md-4"></input>
83
+ <span class="input-group-text col-md-4 text-gray">{{ form.y.label }}</span>
84
+ <input id="{{form.y.html_name}}" type="number" step="any" name="{{form.y.html_name}}" class="form-control col-md-8 text-gray" required></input>
85
+ </div>
86
+ <div class="input-group">
87
+ <span class="input-group-text col-md-4 text-gray">{{ form.z.label }}</span>
88
+ <input id="{{form.z.html_name}}" type="number" step="any" name="{{form.z.html_name}}" class="form-control col-md-8 text-gray" required></input>
44
89
  </div>
45
90
  </div></div>
46
- <div class="row"><div class="col-md-4 d-flex align-items-center mb-3">
47
- <div class="form-group">
48
- {{ form.dx.label }}: {{ form.dx }}
91
+ <div class="row"><div class="col-md-12 d-flex align-items-center mb-3">
92
+ <div class="input-group">
93
+ <span class="input-group-text col-md-5 text-gray">{{ form.dx.label }}</span>
94
+ <input id="{{form.dx.html_name}}" type="number" step="any" name="{{form.dx.html_name}}" class="form-control col-md-8 text-gray" required></input>
49
95
  </div>
50
- <div class="form-group">
51
- {{ form.dy.label }}: {{ form.dy }}
96
+ <div class="input-group">
97
+ <span class="input-group-text col-md-5 text-gray">{{ form.dy.label }}</span>
98
+ <input id="{{form.dy.html_name}}" type="number" step="any" name="{{form.dy.html_name}}" class="form-control col-md-8 text-gray" required></input>
52
99
  </div>
53
- <div class="form-group">
54
- {{ form.dz.label }}: {{ form.dz }}
100
+ <div class="input-group">
101
+ <span class="input-group-text col-md-5 text-gray">{{ form.dz.label }}</span>
102
+ <input id="{{form.dz.html_name}}" type="number" step="any" name="{{form.dz.html_name}}" class="form-control col-md-8 text-gray" required></input>
55
103
  </div>
56
104
  </div></div>
57
105
 
@@ -60,14 +108,91 @@ Chrystal Chern, Spring 2025
60
108
  {% endfor %}
61
109
  </div>
62
110
 
63
- <button id="add-form" class="btn btn-sm button btn-outline-white btn-gray-600 text-white">Add Sensor</button>
111
+ <button id="add-form" class="btn btn-sm button btn-outline-primary mb-3">Add Sensor</button>
64
112
  </fieldset>
113
+
114
+ <button type="button" id="plot-btn" class="btn btn-info btn-sm mb-3">Plot</button>
65
115
 
66
- <button type="submit" class="btn btn-sm button btn-success btn-outline-white ">Submit</button>
116
+ <button type="submit" class="btn btn-sm button btn-success mb-3">Submit</button>
67
117
  </form>
118
+ </div>
119
+ <!-- Right Side: Asset Geometry -->
120
+ <div class="col-md-6">
121
+ <h4>Geometry</h4>
122
+ {%if false %}
123
+ {% if asset.cesmd %}
124
+ <div id="sensors" class="card bg-white-100 border-1 rounded-0 shadow mb-3">
125
+ <div class="card-body text-center p-2">
126
+ <img src="{{ ASSETS_ROOT }}/inventory/ll{{ asset.cesmd|slice:"2:" }}.svg" class="img-fluid">
127
+ </div>
128
+ <div class="card-footer text-center">
129
+ <span class="small">
130
+ Source: <a rel="nofollow noreferrer" href="https://www.strongmotioncenter.org/cgi-bin/CESMD/stationhtml.pl?stationID={{asset.cesmd}}&network=CGS">CGS</a>
131
+ </span>
132
+ </div>
133
+ </div>
134
+ {% endif %}
135
+
136
+ <div id="rendering" class="card bg-white-100 border-1 rounded-0 shadow">
137
+ <div class="card-body text-center">
138
+ <model-viewer
139
+ id="irie-viewer"
140
+ alt="3D Model"
141
+ {% if asset.rendering %}
142
+ src="{{ asset.rendering }}"
143
+ {% else %}
144
+ src="{{ ASSETS_ROOT }}/inventory/empty.glb"
145
+ {% endif %}
146
+ camera-controls
147
+ interaction-prompt="none"
148
+ camera-orbit="0deg 75deg 2m"
149
+ field-of-view="30deg"
150
+ style="width: 100%; height: 300px; background-color: #f0f0f0;">
151
+ </model-viewer>
152
+ </div>
153
+ <div class="card-footer text-center">
154
+ Powered by <a href="https://veux.io/">veux</a>
155
+ </div>
156
+ </div>
157
+ {% else %}
158
+ {% if asset.cesmd %}
159
+ <div id="sensors" class="card bg-white-100 border-1 rounded-0 shadow mb-3">
160
+ <div class="card-body text-center p-2">
161
+ <img src="{{ ASSETS_ROOT }}/inventory/ll{{ asset.cesmd|slice:"2:" }}.svg" class="img-fluid">
162
+ </div>
163
+ <div class="card-footer text-center">
164
+ <span class="small">
165
+ Source: <a rel="nofollow noreferrer" href="https://www.strongmotioncenter.org/cgi-bin/CESMD/stationhtml.pl?stationID={{asset.cesmd}}&network=CGS">CGS</a>
166
+ </span>
167
+ </div>
168
+ </div>
169
+ {% endif %}
170
+
171
+ <div id="rendering" class="card bg-white-100 border-1 rounded-0 shadow">
172
+ <div class="card-body text-center" style="background-color: #f0f0f0;">
173
+ <!-- Our Three.js container -->
174
+ <div id="threejs-container"
175
+ style="width: 100%; height: 300px; background-color: #f0f0f0; margin: 0 auto;">
176
+ </div>
177
+ </div>
178
+ <div class="card-footer text-center">
179
+ Powered by <a href="https://veux.io/">veux</a>
180
+ </div>
181
+ </div>
182
+ {% endif %}
183
+ </div>
184
+
185
+ </div>
186
+ </div>
187
+ <!--
188
+ <div id="plot-container" style="display: none;">
189
+ <h3>3D Sensor Plot</h3>
190
+ <div id="sensor-plot"></div>
191
+ </div> -->
68
192
  {%endblock content %}
69
- {% block javascripts %}
70
193
 
194
+
195
+ {% block javascripts %}
71
196
  <script>
72
197
  document.addEventListener("DOMContentLoaded", () => {
73
198
  const formsetContainer = document.getElementById("formset-container");
@@ -116,4 +241,212 @@ document.addEventListener("DOMContentLoaded", () => {
116
241
  updateRemoveButtons();
117
242
  });
118
243
  </script>
244
+ <script>
245
+ document.addEventListener("DOMContentLoaded", function () {
246
+ const datumSelect = document.getElementById("id_datum");
247
+ const datumInfoDiv = document.getElementById("datum-info");
248
+ const locationSpan = document.getElementById("datum-location");
249
+ const orientationSpan = document.getElementById("datum-orientation");
250
+
251
+ // Store datum data from Django
252
+ const datums = {{ datums|safe }};
253
+
254
+ datumSelect.addEventListener("change", function () {
255
+ const selectedDatumId = this.value;
256
+ const selectedDatum = datums.find(d => d.id == selectedDatumId);
257
+
258
+ if (selectedDatum) {
259
+ locationSpan.textContent = `${selectedDatum.locate_x}; ${selectedDatum.locate_y}; ${selectedDatum.locate_z}`;
260
+ orientationSpan.textContent = `${selectedDatum.orient_x}; ${selectedDatum.orient_y}; ${selectedDatum.orient_z}`;
261
+ datumInfoDiv.style.display = "block"; // Show info box
262
+ } else {
263
+ datumInfoDiv.style.display = "none"; // Hide if no datum selected
264
+ }
265
+ });
266
+ });
267
+ </script>
268
+ <script type="module">
269
+
270
+ import * as THREE from 'three';
271
+ import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
272
+ import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
273
+
274
+ function createArrow(origin, direction, length, color, headLength, headWidth, shaftRadius) {
275
+ const dir = direction.clone().normalize();
276
+
277
+ const shaftLength = length - headLength;
278
+
279
+ const arrowGroup = new THREE.Group();
280
+
281
+ const shaftGeometry = new THREE.CylinderGeometry(shaftRadius, shaftRadius, shaftLength, 16);
282
+ const shaftMaterial = new THREE.MeshStandardMaterial({ color: color });
283
+ const shaftMesh = new THREE.Mesh(shaftGeometry, shaftMaterial);
284
+
285
+ // CylinderGeometry is oriented along the Y-axis.
286
+ // Rotate it so it aligns with the group's local +Y (arrow "up").
287
+ // Then rotate the entire group to match `dir`.
288
+ shaftMesh.position.y = shaftLength / 2; // move it so its base starts at y=0
289
+ arrowGroup.add(shaftMesh);
290
+
291
+ const headGeometry = new THREE.ConeGeometry(shaftRadius * 2, headLength, 16);
292
+ const headMaterial = new THREE.MeshStandardMaterial({ color: color });
293
+ const headMesh = new THREE.Mesh(headGeometry, headMaterial);
294
+
295
+ headMesh.position.y = shaftLength + headLength / 2;
296
+ arrowGroup.add(headMesh);
297
+
298
+ arrowGroup.position.copy(origin);
299
+
300
+ // 5) Rotate the entire group so that +Y in local space points along `dir`
301
+ const up = new THREE.Vector3(0, 1, 0);
302
+ const quaternion = new THREE.Quaternion().setFromUnitVectors(up, dir);
303
+ arrowGroup.quaternion.copy(quaternion);
304
+
305
+ return arrowGroup;
306
+ }
307
+
308
+ document.addEventListener('DOMContentLoaded', () => {
309
+ const container = document.getElementById('threejs-container');
310
+ // Fallback or real path
311
+ const modelPath = `{{ asset.rendering|default_if_none:"" }}`;
312
+
313
+ // 1) SETUP SCENE
314
+ const scene = new THREE.Scene();
315
+ scene.background = new THREE.Color(0xf0f0f0);
316
+
317
+ // 2) SETUP RENDERER
318
+ const renderer = new THREE.WebGLRenderer({ antialias: true });
319
+ renderer.setPixelRatio(window.devicePixelRatio);
320
+ renderer.setSize(container.clientWidth, container.clientHeight);
321
+ // renderer.outputEncoding = THREE.sRGBEncoding;
322
+ container.appendChild(renderer.domElement);
323
+
324
+ // 3) SETUP CAMERA
325
+ const camera = new THREE.PerspectiveCamera(
326
+ 30, // fov
327
+ container.clientWidth / container.clientHeight, // aspect
328
+ 0.1, // near
329
+ 1000 // far
330
+ );
331
+ // Position: "0deg 75deg 2m" => we can interpret as an angle from horizontal
332
+ // Place the camera a bit above and away from the origin.
333
+ camera.position.set(0, 2, 2);
334
+ camera.lookAt(0, 0, 0);
335
+
336
+ // 4) ORBIT CONTROLS
337
+ const controls = new OrbitControls(camera, renderer.domElement);
338
+ controls.enableDamping = true;
339
+ controls.dampingFactor = 0.05;
340
+ controls.target.set(0, 0, 0);
341
+
342
+ // 5) LIGHTING (basic environment)
343
+ const ambientLight = new THREE.HemisphereLight(0xffffff, 0x444444, 1.2);
344
+ scene.add(ambientLight);
345
+
346
+ const globalLight = new THREE.AmbientLight(0xffffff, 0.4);
347
+ scene.add(globalLight);
348
+
349
+ const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
350
+ directionalLight.position.set(5, 10, 7.5);
351
+ scene.add(directionalLight);
352
+
353
+ // 6) LOAD THE GLB MODEL (if asset.rendering is not empty)
354
+ if (modelPath) {
355
+ const loader = new GLTFLoader();
356
+ loader.load(modelPath, (gltf) => {
357
+ const model = gltf.scene;
358
+ scene.add(model);
359
+
360
+ // Compute bounding box
361
+ const box = new THREE.Box3().setFromObject(model);
362
+ const size = box.getSize(new THREE.Vector3()).length();
363
+ const center = box.getCenter(new THREE.Vector3());
364
+
365
+ // Adjust camera clipping
366
+ camera.near = size / 100;
367
+ camera.far = size * 100;
368
+ camera.updateProjectionMatrix();
369
+
370
+ // Move camera so the model is nicely framed
371
+ camera.position.copy(center);
372
+ // Move the camera out some distance (play with the multiplier)
373
+ camera.position.x += size;
374
+ camera.position.y += size;
375
+ camera.position.z += size;
376
+ camera.lookAt(center);
377
+
378
+
379
+ controls.target.copy(center);
380
+ controls.update();
381
+ },
382
+ undefined,
383
+ (error) => {
384
+ console.error('Error loading GLB:', error);
385
+ });
386
+ } else {
387
+ const axesHelper = new THREE.AxesHelper(1);
388
+ scene.add(axesHelper);
389
+ }
390
+
391
+ // 7) HANDLE WINDOW RESIZE
392
+ window.addEventListener('resize', onWindowResize, false);
393
+ function onWindowResize() {
394
+ camera.aspect = container.clientWidth / container.clientHeight;
395
+ camera.updateProjectionMatrix();
396
+ renderer.setSize(container.clientWidth, container.clientHeight);
397
+ }
398
+
399
+ // 8) ANIMATE LOOP
400
+ function animate() {
401
+ requestAnimationFrame(animate);
402
+ controls.update();
403
+ renderer.render(scene, camera);
404
+ }
405
+ animate();
406
+
407
+ const arrowObjects = [];
408
+
409
+ //
410
+ // Plot Button
411
+ //
412
+ const plotButton = document.getElementById('plot-btn');
413
+ plotButton.addEventListener('click', function () {
414
+ arrowObjects.forEach(arrow => {
415
+ scene.remove(arrow);
416
+ });
417
+ arrowObjects.length = 0;
418
+
419
+ // Grab sensor forms
420
+ const sensorForms = document.querySelectorAll('.sensor-form');
421
+ sensorForms.forEach((form) => {
422
+ const x = parseFloat(form.querySelector("input[name*='x']").value) || 0;
423
+ const y = parseFloat(form.querySelector("input[name*='y']").value) || 0;
424
+ const z = parseFloat(form.querySelector("input[name*='z']").value) || 0;
425
+ const dx = parseFloat(form.querySelector("input[name*='dx']").value) || 0;
426
+ const dy = parseFloat(form.querySelector("input[name*='dy']").value) || 0;
427
+ const dz = parseFloat(form.querySelector("input[name*='dz']").value) || 0;
428
+
429
+ // Create a direction vector from dx,dy,dz
430
+ const direction = new THREE.Vector3(dx, dy, dz);
431
+ const length = direction.length() || 0.1; // arrow length
432
+ direction.normalize();
433
+
434
+ const origin = new THREE.Vector3(x, y, z);
435
+ const color = 0xff0000;
436
+ const arrow = createArrow(
437
+ origin,
438
+ direction,
439
+ length,
440
+ color,
441
+ 0.3*length, // head length
442
+ 0.2*length, // head width
443
+ 0.1*length // shaft radius
444
+ );
445
+
446
+ scene.add(arrow);
447
+ arrowObjects.push(arrow);
448
+ });
449
+ });
450
+ });
451
+ </script>
119
452
  {% endblock javascripts %}
@@ -1,13 +1,14 @@
1
1
  <!DOCTYPE html>
2
2
  <html lang="en">
3
3
  <head>
4
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
4
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5
5
  <title>{% block title %}{% endblock %} | BRACE2</title>
6
6
 
7
7
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
8
8
  <meta name="title" content="BRACE2 - Sign up page">
9
9
  <meta name="author" content="PEER">
10
10
  <meta name="description" content="BRACE2 is a platform for structural health monitoring.">
11
+ <link rel="canonical" href="https://structures.live{{ request.path }}">
11
12
 
12
13
  <!-- Open Graph / Facebook -->
13
14
  <meta property="og:type" content="website">
@@ -44,12 +45,10 @@
44
45
 
45
46
  </head>
46
47
  <body>
47
-
48
48
  {% block content %}{% endblock content %}
49
49
 
50
50
  {% include 'includes/scripts.html' %}
51
51
 
52
- {% block javascripts %}{% endblock javascripts %}
53
-
52
+ {% block javascripts %}{% endblock javascripts %}
54
53
  </body>
55
54
  </html>
@@ -219,7 +219,7 @@ td.left-text{vertical-align:middle}
219
219
  <div class="col-lg-5 order-lg-2 mb-5 mb-lg-0">
220
220
  <h2 class="h1">Digital Twins</h2>
221
221
  <p class="mb-4">The <em>IRiE</em> engine is used to realize high-fidelity digital twins that are backed by
222
- state-of-the-art analysis platforms like <a href="https://pypi.org/project/opensees">OpenSees</a> for nonlinear finite element analysis and <em><a href="https://chrystalchern.github.io/mdof">mdof</a></em> for system identification.</p>
222
+ state-of-the-art analysis platforms like <a href="https://pypi.org/project/sees">OpenSees</a> for nonlinear finite element analysis and <em><a href="https://chrystalchern.github.io/mdof">mdof</a></em> for system identification.</p>
223
223
  </div>
224
224
  <div class="col-lg-4 order-lg-1 card shadow"><img src="{{ ASSETS_ROOT }}/img/twin.png"
225
225
  alt="Digital twins"></div>
@@ -258,7 +258,7 @@ td.left-text{vertical-align:middle}
258
258
  <a href="https://stairlab.berkeley.edu/software/opensees/">
259
259
  <img class="first-column-layout"
260
260
  src="{{ ASSETS_ROOT }}/content_images/brace/opensees.jpg" alt="opensees"></a></td>
261
- <td class=full-center-text><a href="https://pypi.org/project/opensees" >sees</a></td>
261
+ <td class=full-center-text><a href="https://pypi.org/project/sees" >sees</a></td>
262
262
  <td class=left-text>Direct and idiomatic bindings to <a href="https://github.com/claudioperez/OpenSeesRT" >
263
263
  <samp>OpenSeesRT</samp></a> kernel for finite element analysis.</td>
264
264
  </tr>
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: irie
3
- Version: 0.0.36
3
+ Version: 0.0.37
4
4
  Summary: An infrastructure resilience engine
5
5
  Author-email: "Claudio M. Perez" <50180406+claudioperez@users.noreply.github.com>
6
6
  Project-URL: Repository, https://github.com/STAIRLab
@@ -62,18 +62,22 @@ irie/apps/inventory/apps.py,sha256=bZ6qYIwPMG4_4IeLfg9N4WuZAEgEVj84oOswV-7_MAI,4
62
62
  irie/apps/inventory/calid.py,sha256=3L8MbPIGOE3kzDnqeyY055pRBiF2O2l0cmpuDbTsdTg,3014
63
63
  irie/apps/inventory/fields.py,sha256=J3nTImPsuCeiOWBizSL4tnuKs36sPfXALNTKEZY-wVg,79
64
64
  irie/apps/inventory/filters.py,sha256=8ge94J5OlGhLRIo6EtBYVe2c9QxW7YCBLxJzfoFHzSg,2185
65
- irie/apps/inventory/forms.py,sha256=0caWKxq7cU_z7XM2jZLqsGNDL01IlltWvFCCi9a0Wzc,1005
66
- irie/apps/inventory/models.py,sha256=WQaRQR4S9Qca00nHH8a-ZsYHEd7uupBUgNIe0H3ss2c,4638
65
+ irie/apps/inventory/forms.py,sha256=y8tcIGInXDg7KCf1OWd1jtc4umJsm8rf8-4O8nDhNd4,1244
66
+ irie/apps/inventory/models.py,sha256=sYDGpFK41Ga7JXvD5kV6hLc4zr77XFqu7t9IHHO86dQ,5424
67
67
  irie/apps/inventory/sitemaps.py,sha256=Nha1MTsIH_ad7JyoxwonPytp7MNuEhDNszkEUOmlN0o,826
68
68
  irie/apps/inventory/tables.py,sha256=vZdPOcbN1ibuWXqLwbBUoQw9iavwa1GJ5fd83k8bu7Y,27874
69
69
  irie/apps/inventory/traffic.py,sha256=B3PHqn2Pm4AEdUZ_tuA16fuFruo2rm5waMBwLQyF-9g,4490337
70
70
  irie/apps/inventory/urls.py,sha256=bH63Y2jk-DzDDTiFdCDb5YLXFvq3sRyJrMAz0z_niKs,1476
71
- irie/apps/inventory/views.py,sha256=vlNzf_vClNekT6n4SPjpmNSMxMrTPAPTeltGY8JJjgw,19178
71
+ irie/apps/inventory/views.py,sha256=riKKJjTWBJScn_VAvh2krvbZgNHZv0lDdY5GJQ1A3Zk,19396
72
72
  irie/apps/inventory/archive/arcGIS.py,sha256=vcfsy1be4edOXD1Z3rkUnq9QmCTol7dypdF816Q3B_w,34893
73
73
  irie/apps/inventory/migrations/0001_initial.py,sha256=PwTHv4Q3gqWFha--8Zp9kUOh-cYalB14jXj7RVJUVnw,1786
74
74
  irie/apps/inventory/migrations/0002_alter_asset_bridge_sensors_and_more.py,sha256=rPzWHkjg-ZCorVA_gv6MVb5F6LTLHcwlPwhBR1PxVr0,842
75
75
  irie/apps/inventory/migrations/0003_asset_notes.py,sha256=N3p8PdRlwlED7z5gPAVVcDVsAjSLx-e0D4bx5eEwGlQ,436
76
76
  irie/apps/inventory/migrations/0004_datum_sensorgroup_sensor.py,sha256=Jk_GdHN33ymWM6As1K95WC5JPdMg4bLNdWunVw6vEm4,1712
77
+ irie/apps/inventory/migrations/0005_alter_sensor_group.py,sha256=fW_qIR78n0UkxKmCFpQIPhOtXUgXeBax9drZTzIiwJ0,530
78
+ irie/apps/inventory/migrations/0006_datum_asset_datum_locate_x_datum_locate_y_and_more.py,sha256=yCjupVpwQ1qof3grjCo7wL3wIRJWWnMatlPPR1wrMXA,1738
79
+ irie/apps/inventory/migrations/0007_sensor_name.py,sha256=b98wYN1XApHniMkTvrgvTjtxiSlzt966QMMftMzpNZA,474
80
+ irie/apps/inventory/migrations/0008_alter_sensor_dx_alter_sensor_dy_alter_sensor_dz_and_more.py,sha256=y99Ro9cTl9UphgVeILO7YIEVQ1wi0k2RhXqYnBg_ZzY,1255
77
81
  irie/apps/inventory/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
78
82
  irie/apps/inventory/templatetags/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
79
83
  irie/apps/inventory/templatetags/get.py,sha256=ZVjFYv1uhjhcOQ8I5ukz7DuR6TXnbYuijPWKkgxacOM,134
@@ -391,17 +395,17 @@ irie/apps/templates/includes/scripts.html,sha256=1Up6xJJSTpdLTJp0tDAa3JubevvSlic
391
395
  irie/apps/templates/includes/settings-box.html,sha256=_YubYOyAJ8IldTgVlXP2wLLXpKpInp8hJ88FN6i6rmw,2488
392
396
  irie/apps/templates/includes/sidebar.html,sha256=m2TahYwFnysqcLkK4ANYZhUf8xGVId_tiJFBKrQD4Cw,12386
393
397
  irie/apps/templates/inventory/asset-evals.html,sha256=KzbdJJ7ildMpfO4IQDuXqGBcPzUTlYpJ_Y3Wg4payVc,2700
394
- irie/apps/templates/inventory/asset-event-summary.html,sha256=r_Zl74thZlhUZiJYStycAhLFrq5DJ_YXJnmNG4yUHj0,50935
395
- irie/apps/templates/inventory/asset-profile.html,sha256=_4xm-1OojZkSVtYSzYjAnD9Glvgcnpwpq4zCR0f0DGM,14104
396
- irie/apps/templates/inventory/asset-sensors.html,sha256=ydAp4kPOiCitjd0wrUNjekcsvMS9bbW0VH-2BxGtxxo,1382
398
+ irie/apps/templates/inventory/asset-event-summary.html,sha256=5G7uZVf7kVL0wBaAfsEtTEEA5HRuBCzx8NrgDFheWI4,51357
399
+ irie/apps/templates/inventory/asset-profile.html,sha256=K7D1D-ApjyEV05AyYxGnGs6B0sNq11jKusdPDwubmFA,14135
400
+ irie/apps/templates/inventory/asset-sensors.html,sha256=Ugfdc79WqrHDvzAPi2o8HkjYz5nD7w5S5wZSknQNjxA,2184
397
401
  irie/apps/templates/inventory/asset-table.html,sha256=Ak_N_QDUgWzyffBBidJ8H0wLR3zX3wNHQm6MnZYbruQ,12589
398
402
  irie/apps/templates/inventory/bridge-dashboard.html,sha256=67zrDlih3LOi9xFVwPVZZkgRT3DO-lE_qRL7q8Uz9GY,45472
399
403
  irie/apps/templates/inventory/bridge.html,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
400
404
  irie/apps/templates/inventory/dashboard.html,sha256=_qhFiPP6xN-UzZj5NuM5e9NxsgDHJkQ89oXN1cBwhj0,7505
401
405
  irie/apps/templates/inventory/preamble.tex,sha256=TmRhIWg2-Pxj_e2OBctANRZPwU8RWMT3EZJFSa3R8HY,3547
402
406
  irie/apps/templates/inventory/report.tex,sha256=A1XKpwknlBrAZjFzzxVIDwypjXteqzoCQiuo1tQANfw,45228
403
- irie/apps/templates/inventory/sensor-upload.html,sha256=v-FOU9nyQUx5OgRCluaoYV1rmo9T0dMZscFSxH6hBKw,4769
404
- irie/apps/templates/layouts/base-fullscreen.html,sha256=rDKXBySGTF65SUYc7YkrdbVqFFT_6a9HEvUcOQCetTg,2513
407
+ irie/apps/templates/inventory/sensor-upload.html,sha256=w-stoKgcEoonoV-_7IFJUrQ6w2Ww5DTErWNzbO5R_-g,18285
408
+ irie/apps/templates/layouts/base-fullscreen.html,sha256=q1nKewLnQ8inBxsUcHlq2Iv_s_qrw6k6bumX7mLR1mI,2579
405
409
  irie/apps/templates/layouts/base.html,sha256=phiHZX_CjuOhmkJgqyMAGTPdwm0qqrJCKZZwKLGTtQY,2387
406
410
  irie/apps/templates/layouts/json-form.html,sha256=cT6Pd2168Z3p8RODS7SulUC79LnuzSs0EVLVxkGOXAo,1333
407
411
  irie/apps/templates/networks/corridor_table.html,sha256=SW6WMmxGsw2li1BXqvCRj1CFJ3IPUulfk-KHJBIMFx0,876
@@ -419,7 +423,7 @@ irie/apps/templates/prediction/hazus/history.js,sha256=blHRXzlEfMBCezPE-2dZCpt2r
419
423
  irie/apps/templates/site/about.html,sha256=5hS5taj3XF-F8z-uIn53ZFXVHVS4apLRMg39OyvMvRs,610
420
424
  irie/apps/templates/site/asset_map.html,sha256=rnTjeYMc8NESIo6Uuq8fgZ_xcKNuKdt4zcqoUTDI8Xg,387
421
425
  irie/apps/templates/site/components-forms.html,sha256=FKOiR-3e9iw-xOHeaP2RB3O2gP10R-Mt8wdXfb1rDBQ,13865
422
- irie/apps/templates/site/index.html,sha256=v0xQ6hqbu9RDMcZ0vSC7KSR52dlBeTHuNklo-DZCNGo,16988
426
+ irie/apps/templates/site/index.html,sha256=Sat1nNPmc1lR4qxpiMnYyPBHI3h1K7PN8GDg901Eiew,16980
423
427
  irie/apps/templates/site/json-form.html,sha256=ZrRWy5xnGBOqG51b6mdVGI0Io5X1z47DTFB9wW6ZQYA,1785
424
428
  irie/apps/templates/site/page-403.html,sha256=caU6t3fsCJiAIuZvRQekK2UemdZSNxc3l80ceSz0mp0,1289
425
429
  irie/apps/templates/site/page-404-sidebar.html,sha256=krMA-iYHaJNfXSwY7H_epZycWLiIb_bBbuWTmqC4ca4,1581
@@ -465,8 +469,8 @@ irie/init/management/commands/init_corridors.py,sha256=EzLk0HUiFxlco-2u0rypewOc9
465
469
  irie/init/management/commands/init_predictors.py,sha256=jdD7rd8l2qxuUuR5GOYuHXp-ZQkAK477TefksBMdlOw,2362
466
470
  irie/rest/__main__.py,sha256=6Nf_-Rr9zGmMyp_wqCFDO7ls9QPnPd9UyUgN17rIGYw,3680
467
471
  irie/usgs/__main__.py,sha256=HiSvPn5IW5IqRiCk1qRRq5dCy3-7iISw7v1P_w2rLrk,5049
468
- irie-0.0.36.dist-info/METADATA,sha256=prWBuMtqwIbh_eTlkxOyMcr30NG93g29Dc-Bf0K0TvQ,3207
469
- irie-0.0.36.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
470
- irie-0.0.36.dist-info/entry_points.txt,sha256=A_3h9wPBGfxGQ78_MGa-nO6Z0foxOYeAnIE47jxEztg,44
471
- irie-0.0.36.dist-info/top_level.txt,sha256=zVCxi5E2nkISZPzKq8VEhWe_dGuPcefLYV1tYqQdwlY,5
472
- irie-0.0.36.dist-info/RECORD,,
472
+ irie-0.0.37.dist-info/METADATA,sha256=XvXazQgq6UwvY3TfdB8ymOG1UUkrkwoBNbK92HmwUOg,3207
473
+ irie-0.0.37.dist-info/WHEEL,sha256=jB7zZ3N9hIM9adW7qlTAyycLYW9npaWKLRzaoVcLKcM,91
474
+ irie-0.0.37.dist-info/entry_points.txt,sha256=A_3h9wPBGfxGQ78_MGa-nO6Z0foxOYeAnIE47jxEztg,44
475
+ irie-0.0.37.dist-info/top_level.txt,sha256=zVCxi5E2nkISZPzKq8VEhWe_dGuPcefLYV1tYqQdwlY,5
476
+ irie-0.0.37.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.8.0)
2
+ Generator: setuptools (75.8.2)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5