Function bodies 95 total
dashboard function · python · L130-L134 (5 LOC)app/main.py
async def dashboard(request: FastAPIRequest):
return templates.TemplateResponse("dashboard.html", {
"request": request,
"google_maps_key": settings.google_maps_api_key,
})RiskLevel class · python · L4-L8 (5 LOC)app/models/enums.py
class RiskLevel(str, Enum):
LOW = "low"
MEDIUM = "medium"
HIGH = "high"
CRITICAL = "critical"CapabilityLevel class · python · L10-L15 (6 LOC)app/models/enums.py
class CapabilityLevel(str, Enum):
BASIC_EMOC = "basic_emoc"
COMPREHENSIVE_EMOC = "comprehensive_emoc"
BLOOD_TRANSFUSION = "blood_transfusion"
C_SECTION = "c_section"
NEONATAL_ICU = "neonatal_icu"FacilityType class · python · L17-L22 (6 LOC)app/models/enums.py
class FacilityType(str, Enum):
SUB_CENTRE = "sub_centre"
PHC = "phc"
CHC = "chc"
DISTRICT_HOSPITAL = "district_hospital"
MEDICAL_COLLEGE = "medical_college"ComplicationHistory class · python · L24-L29 (6 LOC)app/models/enums.py
class ComplicationHistory(str, Enum):
NONE = "none"
PREV_CSECTION = "prev_csection"
PREV_PPH = "prev_pph"
PREV_ECLAMPSIA = "prev_eclampsia"
MULTIPLE = "multiple"InterventionUrgency class · python · L31-L35 (5 LOC)app/models/enums.py
class InterventionUrgency(str, Enum):
ROUTINE = "routine"
SOON = "soon"
URGENT = "urgent"
EMERGENCY = "emergency"BloodBankStatus class · python · L37-L40 (4 LOC)app/models/enums.py
class BloodBankStatus(str, Enum):
AVAILABLE = "available"
LOW_STOCK = "low_stock"
UNAVAILABLE = "unavailable"Repobility (the analyzer behind this table) · https://repobility.com
RiskFactors class · python · L19-L38 (20 LOC)app/models/schemas.py
class RiskFactors(BaseModel):
age: int = Field(ge=12, le=55)
parity: int = Field(ge=0, le=15)
hemoglobin: float = Field(ge=3.0, le=20.0, description="Hemoglobin in g/dL")
bp_systolic: int = Field(ge=60, le=250)
bp_diastolic: int = Field(ge=30, le=160)
gestational_weeks: int = Field(ge=1, le=45)
height_cm: float = Field(ge=100, le=220)
weight_kg: float = Field(ge=25, le=200)
complication_history: ComplicationHistory
@field_validator("bp_diastolic")
@classmethod
def diastolic_less_than_systolic(cls, v: int, info) -> int:
systolic = info.data.get("bp_systolic")
if systolic is not None and v >= systolic:
raise ValueError(
f"bp_diastolic ({v}) must be less than bp_systolic ({systolic})"
)
return vdiastolic_less_than_systolic method · python · L32-L38 (7 LOC)app/models/schemas.py
def diastolic_less_than_systolic(cls, v: int, info) -> int:
systolic = info.data.get("bp_systolic")
if systolic is not None and v >= systolic:
raise ValueError(
f"bp_diastolic ({v}) must be less than bp_systolic ({systolic})"
)
return vRiskResult class · python · L41-L47 (7 LOC)app/models/schemas.py
class RiskResult(BaseModel):
risk_score: float
risk_level: RiskLevel
alpha: float
beta: float
interventions: list[str]
risk_factors_summary: dict[str, str]ReferralRequest class · python · L50-L54 (5 LOC)app/models/schemas.py
class ReferralRequest(BaseModel):
latitude: float = Field(ge=6.0, le=38.0, description="Latitude within India bounds")
longitude: float = Field(ge=68.0, le=98.0, description="Longitude within India bounds")
capability_required: CapabilityLevel
risk_level: RiskLevelReferralResult class · python · L57-L68 (12 LOC)app/models/schemas.py
class ReferralResult(BaseModel):
facility_name: str
facility_type: FacilityType
distance_km: float
eta_minutes: float
specialist_available: bool
blood_bank_status: BloodBankStatus
has_functional_ot: bool
contact_phone: str
backup_facility: Optional[ReferralResult] = None
model_config = {"from_attributes": True}AnemiaInput class · python · L71-L76 (6 LOC)app/models/schemas.py
class AnemiaInput(BaseModel):
initial_hb: float = Field(ge=3.0, le=20.0, description="Initial hemoglobin in g/dL")
gestational_weeks: int = Field(ge=1, le=45)
ifa_compliance: float = Field(ge=0.0, le=1.0, description="IFA tablet compliance rate")
dietary_score: float = Field(ge=0.0, le=1.0)
prev_anemia: boolAnemiaResult class · python · L79-L85 (7 LOC)app/models/schemas.py
class AnemiaResult(BaseModel):
current_hb: float
predicted_delivery_hb: float
trajectory: list[dict]
risk_level: RiskLevel
intervention_urgency: InterventionUrgency
compliance_impact: dictAssessmentRequest class · python · L88-L96 (9 LOC)app/models/schemas.py
class AssessmentRequest(BaseModel):
mother_name: str = Field(min_length=1, max_length=200)
asha_id: str = Field(min_length=1, max_length=50)
risk_factors: RiskFactors
latitude: float = Field(ge=6.0, le=38.0)
longitude: float = Field(ge=68.0, le=98.0)
ifa_compliance: float = Field(ge=0.0, le=1.0)
dietary_score: float = Field(ge=0.0, le=1.0)
prev_anemia: boolRepobility · code-quality intelligence platform · https://repobility.com
AssessmentResult class · python · L99-L108 (10 LOC)app/models/schemas.py
class AssessmentResult(BaseModel):
assessment_id: str
timestamp: datetime
mother_name: str
risk: RiskResult
anemia: Optional[AnemiaResult] = None
referral: Optional[ReferralResult] = None
alerts: list[str]
follow_up_date: str
recommendations: list[str]HealthCheck class · python · L111-L114 (4 LOC)app/models/schemas.py
class HealthCheck(BaseModel):
status: str
version: str
engines_loaded: dict[str, bool]haversine function · python · L121-L132 (12 LOC)app/precompute/generate_facility_graph.py
def haversine(lat1: float, lon1: float, lat2: float, lon2: float) -> float:
"""Calculate distance in km between two lat/lon points."""
R = 6371
dlat = math.radians(lat2 - lat1)
dlon = math.radians(lon2 - lon1)
a = (
math.sin(dlat / 2) ** 2
+ math.cos(math.radians(lat1))
* math.cos(math.radians(lat2))
* math.sin(dlon / 2) ** 2
)
return R * 2 * math.asin(math.sqrt(a))random_lat_lon function · python · L135-L139 (5 LOC)app/precompute/generate_facility_graph.py
def random_lat_lon() -> tuple[float, float]:
"""Generate a random lat/lon within Sitapur district bounds."""
lat = CENTER_LAT + random.uniform(-SPREAD, SPREAD)
lon = CENTER_LON + random.uniform(-SPREAD, SPREAD)
return round(lat, 6), round(lon, 6)random_phone function · python · L142-L148 (7 LOC)app/precompute/generate_facility_graph.py
def random_phone() -> str:
"""Generate a realistic Indian mobile number."""
prefixes = ["70", "72", "73", "74", "75", "76", "77", "78", "79", "80", "81",
"82", "83", "84", "85", "86", "87", "88", "89", "90", "91", "92",
"93", "94", "95", "96", "97", "98", "99"]
prefix = random.choice(prefixes)
return f"+91-{prefix}{random.randint(10000000, 99999999)}"generate_village_name function · python · L151-L153 (3 LOC)app/precompute/generate_facility_graph.py
def generate_village_name() -> str:
"""Generate a realistic Indian village name."""
return random.choice(VILLAGE_PREFIXES) + random.choice(VILLAGE_SUFFIXES)generate_facilities function · python · L156-L286 (131 LOC)app/precompute/generate_facility_graph.py
def generate_facilities() -> list[dict]:
"""Generate ~200 facilities with realistic hierarchy."""
facilities = []
used_village_names: set[str] = set()
facility_counter = 0
def next_id() -> str:
nonlocal facility_counter
facility_counter += 1
return f"FAC-STP-{facility_counter:04d}"
# --- 5 Medical Colleges ---
mc_names = [
"Government Medical College Sitapur",
"Shri Ram Murti Smarak Medical College",
"Prasad Institute of Medical Sciences Sitapur",
"Maharishi Devanand Medical College Sitapur",
"Dr. Ambedkar Memorial Medical College Sitapur",
]
for name in mc_names:
lat, lon = random_lat_lon()
# Medical colleges cluster closer to district center
lat = CENTER_LAT + random.uniform(-0.15, 0.15)
lon = CENTER_LON + random.uniform(-0.15, 0.15)
facilities.append({
"facility_id": next_id(),
"name": name,
"type": "medicalgrid_key function · python · L289-L291 (3 LOC)app/precompute/generate_facility_graph.py
def grid_key(lat: float, lon: float) -> str:
"""Convert lat/lon to grid cell key (0.1 degree resolution)."""
return f"{lat:.1f},{lon:.1f}"Repobility — the code-quality scanner for AI-generated software · https://repobility.com
precompute_shortest_path_trees function · python · L294-L360 (67 LOC)app/precompute/generate_facility_graph.py
def precompute_shortest_path_trees(
facilities: list[dict],
) -> dict[str, dict[str, dict]]:
"""Build shortest-path trees: for each capability, map every grid cell to its nearest facility.
Grid covers the Sitapur district bounding box at 0.1-degree resolution (~11 km cells).
"""
# Define grid bounds with some padding
lat_min = CENTER_LAT - SPREAD - 0.2
lat_max = CENTER_LAT + SPREAD + 0.2
lon_min = CENTER_LON - SPREAD - 0.2
lon_max = CENTER_LON + SPREAD + 0.2
# Generate all grid cell centers
grid_lats = []
lat = round(lat_min, 1)
while lat <= lat_max + 0.05:
grid_lats.append(round(lat, 1))
lat = round(lat + 0.1, 1)
grid_lons = []
lon = round(lon_min, 1)
while lon <= lon_max + 0.05:
grid_lons.append(round(lon, 1))
lon = round(lon + 0.1, 1)
spt: dict[str, dict[str, dict]] = {}
for capability in ALL_CAPABILITIES:
# Filter facilities that have this capability
capable main function · python · L363-L434 (72 LOC)app/precompute/generate_facility_graph.py
def main() -> None:
print("=" * 60)
print("Janani Suraksha - Facility Graph Generator")
print("District: Sitapur, Uttar Pradesh")
print("=" * 60)
print()
# Generate facilities
print("Generating facilities...")
facilities = generate_facilities()
# Print facility breakdown
type_counts: dict[str, int] = {}
for f in facilities:
ftype = f["type"]
type_counts[ftype] = type_counts.get(ftype, 0) + 1
print(f" Total facilities: {len(facilities)}")
for ftype in [
"medical_college",
"district_hospital",
"chc",
"phc",
"sub_centre",
]:
print(f" {ftype}: {type_counts.get(ftype, 0)}")
# Capability counts
print()
print("Capability coverage:")
for cap in ALL_CAPABILITIES:
count = sum(1 for f in facilities if cap in f.get("capabilities", []))
print(f" {cap}: {count} facilities")
# Precompute SPTs
print()
print("Precomputing shortesgenerate function · python · L38-L147 (110 LOC)app/precompute/generate_hb_trajectories.py
def generate() -> None:
engine = AnemiaPredictionEngine()
print(f"Generating hemoglobin trajectory profiles...")
print(f" Hb levels: {len(HB_LEVELS)} ({HB_LEVELS[0]:.1f} - {HB_LEVELS[-1]:.1f} g/dL)")
print(f" Gest weeks: {len(GEST_WEEKS)} ({GEST_WEEKS[0]} - {GEST_WEEKS[-1]})")
print(f" IFA compliance: {len(IFA_COMPLIANCE)}")
print(f" Dietary scores: {len(DIETARY_SCORES)}")
print(f" Prev anemia: {len(PREV_ANEMIA)}")
print(f" Expected total: {EXPECTED_TOTAL}")
print()
# Step 1: Compute all trajectory profiles keyed by discretized feature string
keyed_trajectories: list[tuple[str, dict]] = []
for hb in HB_LEVELS:
for gw in GEST_WEEKS:
for ifa in IFA_COMPLIANCE:
for diet in DIETARY_SCORES:
for anemia in PREV_ANEMIA:
key = engine._discretize_features(hb, gw, ifa, diet, anemia)
result = engine._compute_trajectory(clean function · python · L26-L29 (4 LOC)app/precompute/generate_real_facilities.py
def clean(val):
if not val or val == "NA":
return ""
return val.strip()fetch_state function · python · L32-L74 (43 LOC)app/precompute/generate_real_facilities.py
def fetch_state(state: str) -> list[dict]:
facilities = []
for resource_id in RESOURCES:
url = (
f"https://api.data.gov.in/resource/{resource_id}"
f"?api-key={DATA_GOV_API_KEY}&format=json&limit=500"
f"&filters%5Bstate%5D={urllib.parse.quote(state)}"
)
try:
resp = urllib.request.urlopen(url, timeout=30)
data = json.loads(resp.read())
for r in data.get("records", []):
name = clean(r.get("hospitalname") or r.get("hospital_name", ""))
if not name:
continue
facilities.append({
"name": name,
"category": clean(r.get("hospital_category", "")) or "General",
"care_type": clean(
r.get("hostipalcaretype") or
r.get("_hospital_care_type", "")),
"address": clean(
r.get("address_firmain function · python · L77-L101 (25 LOC)app/precompute/generate_real_facilities.py
def main():
print("Fetching real facility data from data.gov.in...")
print(f"API Key: {DATA_GOV_API_KEY[:10]}...")
print(f"States: {len(STATES)}")
print()
all_facilities = {}
total = 0
for state in STATES:
facilities = fetch_state(state)
if facilities:
all_facilities[state] = facilities
total += len(facilities)
print(f" {state}: {len(facilities)} facilities")
time.sleep(0.3)
out_path = Path(__file__).parent.parent.parent / "data" / "real_facilities.json"
out_path.parent.mkdir(parents=True, exist_ok=True)
with open(out_path, "w") as f:
json.dump(all_facilities, f, separators=(",", ":"))
size_kb = out_path.stat().st_size / 1024
print(f"\nTotal: {total} facilities across {len(all_facilities)} states")
print(f"Saved to {out_path} ({size_kb:.1f} KB)")main function · python · L19-L98 (80 LOC)app/precompute/generate_risk_table.py
def main() -> None:
engine = RiskScoringEngine()
# Dimension sizes (must match RiskScoringEngine bucket definitions)
n_age = len(engine.AGE_BUCKETS) # 5
n_parity = len(engine.PARITY_BUCKETS) # 4
n_hb = len(engine.HB_BUCKETS) # 5
n_bp = len(engine.BP_BUCKETS) # 5
n_gest = len(engine.GEST_BUCKETS) # 7
n_bmi = len(engine.BMI_BUCKETS) # 4
n_comp = len(engine.COMP_BUCKETS) # 5
total = n_age * n_parity * n_hb * n_bp * n_gest * n_bmi * n_comp
print(f"Generating {total:,} risk table entries...")
print(f" Dimensions: age={n_age} x parity={n_parity} x hb={n_hb} x bp={n_bp} "
f"x gest={n_gest} x bmi={n_bmi} x comp={n_comp}")
table: dict[str, dict] = {}
level_counts: Counter = Counter()
count = 0
t0 = time.time()
for age_idx in range(n_age):
for parity_idx in range(n_parity):
for hb_idx in range(n_hb):
for bp_idx in range(n_bp):
RateLimitMiddleware class · python · L12-L39 (28 LOC)app/security.py
class RateLimitMiddleware(BaseHTTPMiddleware):
"""Sliding window rate limiter per client IP."""
def __init__(self, app, max_requests: int = 100, window_seconds: int = 60):
super().__init__(app)
self.max_requests = max_requests
self.window_seconds = window_seconds
self._requests: dict[str, list[float]] = defaultdict(list)
async def dispatch(self, request: Request, call_next):
client_ip = request.client.host if request.client else "unknown"
now = time.time()
# Clean old entries
self._requests[client_ip] = [
t for t in self._requests[client_ip]
if now - t < self.window_seconds
]
if len(self._requests[client_ip]) >= self.max_requests:
logger.warning(f"Rate limit exceeded for {client_ip}")
return JSONResponse(
status_code=429,
content={"detail": "Rate limit exceeded. Try again later."}
)
self._reqAll rows above produced by Repobility · https://repobility.com
__init__ method · python · L15-L19 (5 LOC)app/security.py
def __init__(self, app, max_requests: int = 100, window_seconds: int = 60):
super().__init__(app)
self.max_requests = max_requests
self.window_seconds = window_seconds
self._requests: dict[str, list[float]] = defaultdict(list)dispatch method · python · L21-L39 (19 LOC)app/security.py
async def dispatch(self, request: Request, call_next):
client_ip = request.client.host if request.client else "unknown"
now = time.time()
# Clean old entries
self._requests[client_ip] = [
t for t in self._requests[client_ip]
if now - t < self.window_seconds
]
if len(self._requests[client_ip]) >= self.max_requests:
logger.warning(f"Rate limit exceeded for {client_ip}")
return JSONResponse(
status_code=429,
content={"detail": "Rate limit exceeded. Try again later."}
)
self._requests[client_ip].append(now)
return await call_next(request)SecurityHeadersMiddleware class · python · L42-L61 (20 LOC)app/security.py
class SecurityHeadersMiddleware(BaseHTTPMiddleware):
"""Add security headers to all responses (defense in depth)."""
async def dispatch(self, request: Request, call_next):
response = await call_next(request)
response.headers["X-Content-Type-Options"] = "nosniff"
response.headers["X-Frame-Options"] = "DENY"
response.headers["X-XSS-Protection"] = "1; mode=block"
response.headers["Referrer-Policy"] = "strict-origin-when-cross-origin"
response.headers["Permissions-Policy"] = "camera=(), microphone=(), geolocation=(self), fullscreen=(self)"
response.headers["Content-Security-Policy"] = (
"default-src 'self'; "
"script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.tailwindcss.com https://cdn.jsdelivr.net https://unpkg.com https://maps.googleapis.com https://maps.gstatic.com; "
"style-src 'self' 'unsafe-inline' https://cdn.tailwindcss.com https://cdn.jsdelivr.net https://fonts.googleapidispatch method · python · L45-L61 (17 LOC)app/security.py
async def dispatch(self, request: Request, call_next):
response = await call_next(request)
response.headers["X-Content-Type-Options"] = "nosniff"
response.headers["X-Frame-Options"] = "DENY"
response.headers["X-XSS-Protection"] = "1; mode=block"
response.headers["Referrer-Policy"] = "strict-origin-when-cross-origin"
response.headers["Permissions-Policy"] = "camera=(), microphone=(), geolocation=(self), fullscreen=(self)"
response.headers["Content-Security-Policy"] = (
"default-src 'self'; "
"script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.tailwindcss.com https://cdn.jsdelivr.net https://unpkg.com https://maps.googleapis.com https://maps.gstatic.com; "
"style-src 'self' 'unsafe-inline' https://cdn.tailwindcss.com https://cdn.jsdelivr.net https://fonts.googleapis.com; "
"font-src 'self' https://fonts.gstatic.com; "
"img-src 'self' data: https: https://maps.gAuditLogMiddleware class · python · L64-L83 (20 LOC)app/security.py
class AuditLogMiddleware(BaseHTTPMiddleware):
"""Log all API requests for audit trail."""
async def dispatch(self, request: Request, call_next):
start = time.time()
client_ip = request.client.host if request.client else "unknown"
response = await call_next(request)
duration_ms = (time.time() - start) * 1000
# Only log API calls, not static files
if request.url.path.startswith("/api/"):
logger.info(
f"AUDIT | {request.method} {request.url.path} | "
f"IP={client_ip} | Status={response.status_code} | "
f"Duration={duration_ms:.1f}ms"
)
return responsedispatch method · python · L67-L83 (17 LOC)app/security.py
async def dispatch(self, request: Request, call_next):
start = time.time()
client_ip = request.client.host if request.client else "unknown"
response = await call_next(request)
duration_ms = (time.time() - start) * 1000
# Only log API calls, not static files
if request.url.path.startswith("/api/"):
logger.info(
f"AUDIT | {request.method} {request.url.path} | "
f"IP={client_ip} | Status={response.status_code} | "
f"Duration={duration_ms:.1f}ms"
)
return responseformatRiskLevel function · javascript · L12-L20 (9 LOC)app/static/js/app.js
function formatRiskLevel(level) {
const map = {
'LOW': 'bg-green-100 text-green-800 border-green-300',
'MEDIUM': 'bg-yellow-100 text-yellow-800 border-yellow-300',
'HIGH': 'bg-orange-100 text-orange-800 border-orange-300',
'CRITICAL': 'bg-red-100 text-red-800 border-red-300'
};
return map[(level || '').toUpperCase()] || 'bg-gray-100 text-gray-800 border-gray-300';
}formatBloodBank function · javascript · L27-L35 (9 LOC)app/static/js/app.js
function formatBloodBank(status) {
const map = {
'available': 'Available',
'limited': 'Limited Stock',
'unavailable': 'Not Available',
'unknown': 'Unknown'
};
return map[(status || '').toLowerCase()] || status || 'Unknown';
}Repobility (the analyzer behind this table) · https://repobility.com
formatBloodBankColor function · javascript · L42-L50 (9 LOC)app/static/js/app.js
function formatBloodBankColor(status) {
const map = {
'available': 'bg-green-100 text-green-700',
'limited': 'bg-yellow-100 text-yellow-700',
'unavailable': 'bg-red-100 text-red-700',
'unknown': 'bg-gray-100 text-gray-700'
};
return map[(status || '').toLowerCase()] || 'bg-gray-100 text-gray-700';
}animateCounter function · javascript · L59-L85 (27 LOC)app/static/js/app.js
function animateCounter(element, target, duration, suffix) {
if (!element) return;
duration = duration || 1500;
suffix = suffix || '';
const startTime = performance.now();
const startValue = parseInt(element.textContent, 10) || 0;
const delta = target - startValue;
function easeOutCubic(t) {
return 1 - Math.pow(1 - t, 3);
}
function tick(now) {
const elapsed = now - startTime;
const progress = Math.min(elapsed / duration, 1);
const eased = easeOutCubic(progress);
const current = Math.floor(startValue + delta * eased);
element.textContent = current.toLocaleString('en-IN') + suffix;
if (progress < 1) {
requestAnimationFrame(tick);
} else {
element.textContent = target.toLocaleString('en-IN') + suffix;
}
}
requestAnimationFrame(tick);
}easeOutCubic function · javascript · L67-L69 (3 LOC)app/static/js/app.js
function easeOutCubic(t) {
return 1 - Math.pow(1 - t, 3);
}tick function · javascript · L71-L82 (12 LOC)app/static/js/app.js
function tick(now) {
const elapsed = now - startTime;
const progress = Math.min(elapsed / duration, 1);
const eased = easeOutCubic(progress);
const current = Math.floor(startValue + delta * eased);
element.textContent = current.toLocaleString('en-IN') + suffix;
if (progress < 1) {
requestAnimationFrame(tick);
} else {
element.textContent = target.toLocaleString('en-IN') + suffix;
}
}escapeHtml function · javascript · L92-L96 (5 LOC)app/static/js/app.js
function escapeHtml(text) {
var div = document.createElement('div');
div.appendChild(document.createTextNode(text));
return div.textContent;
}showNotification function · javascript · L104-L192 (89 LOC)app/static/js/app.js
function showNotification(message, type, durationMs) {
type = type || 'info';
durationMs = durationMs || 4000;
var container = document.getElementById('toast-container');
if (!container) {
console.warn('[JananiSuraksha] Toast container not found. Message:', message);
return;
}
var iconPaths = {
success: 'M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z',
error: 'M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z',
warning: 'M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z',
info: 'M18 10a8 8 0 11-16 0 8 8 0 01‹ prevpage 2 / 2