Sunday 28 February 2021

Template literals/strings with \n and spaces compiled by closure compiler

Some pieces of HTML are injected in the DOM by one of our js library compiled by Closure Compiler.

We use template literals/strings to dynamically change the HTML and also to ease maintenance by keeping indented HTML in our js files.

Unfortunately, it means that our minified file contains a lot of useless '\n' and spaces in the strings corresponding to these template literals (no surprise, this is as per ES6)

Is there a way to not have all the useless \n and spaces in the minified file?

Example of source code:

this.root.append(`
  <div>
    <a href="#">
      <span>${someText}</span>
    </a>
    <div class="dialog"></div>
  </div>`);

The corresponding compiled code looks like:

...;this.h.append("\n  <div>\n    <a href="#">\n      <span>"+z+"</span>\n    </a>\n    <div class="dialog"></div>\n  </div>");...


from Template literals/strings with \n and spaces compiled by closure compiler

LSTM Model Conversion to TFLite Work Fine, but Error When Importing to Android Project

I have read here that now tensorflow lite is able to convert from tensorflow and keras LSTM models.

Everything works fine until the model is converted and I have the model.tflite file. I already tried to follow this and this to add the model to my android project. How ever everything produce the same error which is java.lang.IllegalArgumentException: ByteBuffer is not a valid flatbuffer model

the code for building the model

model = Sequential()
model.add(LSTM(128, input_shape=(3000,5), return_sequences=True))
model.add(Dropout(0.2))
model.add(BatchNormalization())

model.add(LSTM(128, return_sequences=True))
model.add(Dropout(0.2))
model.add(BatchNormalization())

model.add(LSTM(128))
model.add(Dropout(0.1))
model.add(BatchNormalization())

model.add(Dense(64))
model.add(Dropout(0.2))

model.add(Dense(1, activation="sigmoid"))

opt = tf.keras.optimizers.Adam(lr=0.001, decay=1e-6)
model.compile(loss="binary_crossentropy",
             optimizer=opt,
             metrics=["accuracy"])


history = model.fit(X,
                   y,
                   batch_size=64,
                   epochs=10,
                   callbacks=[callbacks],
                   verbose=1)

Full error logs

E/ModelResourceManager: Error preloading model resource
    com.google.firebase.ml.common.FirebaseMLException: Local model load failed with the model options: Local model path: drowsy-detector-v21.tflite. Remote model name: unspecified. 
        at com.google.firebase.ml.common.internal.modeldownload.zzj.zza(com.google.firebase:firebase-ml-common@@22.1.0:36)
        at com.google.android.gms.internal.firebase_ml.zzrj.zza(com.google.firebase:firebase-ml-model-interpreter@@22.0.2:111)
        at com.google.android.gms.internal.firebase_ml.zzrj.zzol(com.google.firebase:firebase-ml-model-interpreter@@22.0.2:107)
        at com.google.android.gms.internal.firebase_ml.zzqr.zzf(com.google.firebase:firebase-ml-common@@22.1.0:53)
        at com.google.android.gms.internal.firebase_ml.zzqr$zza.zzoo(com.google.firebase:firebase-ml-common@@22.1.0:7)
        at com.google.android.gms.internal.firebase_ml.zzqr$zza.call(com.google.firebase:firebase-ml-common@@22.1.0:24)
        at com.google.android.gms.internal.firebase_ml.zzpx.zza(com.google.firebase:firebase-ml-common@@22.1.0:32)
        at com.google.android.gms.internal.firebase_ml.zzpw.run(Unknown Source:4)
        at android.os.Handler.handleCallback(Handler.java:873)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at com.google.android.gms.internal.firebase_ml.zze.dispatchMessage(com.google.firebase:firebase-ml-common@@22.1.0:6)
        at android.os.Looper.loop(Looper.java:201)
        at android.os.HandlerThread.run(HandlerThread.java:65)
     Caused by: java.lang.IllegalArgumentException: ByteBuffer is not a valid flatbuffer model
        at org.tensorflow.lite.NativeInterpreterWrapper.createModelWithBuffer(Native Method)
        at org.tensorflow.lite.NativeInterpreterWrapper.<init>(NativeInterpreterWrapper.java:59)
        at org.tensorflow.lite.Interpreter.<init>(Interpreter.java:207)
        at com.google.android.gms.internal.firebase_ml.zzrj.zzb(com.google.firebase:firebase-ml-model-interpreter@@22.0.2:174)
        at com.google.android.gms.internal.firebase_ml.zzrl.zzc(Unknown Source:0)
        at com.google.android.gms.internal.firebase_ml.zzrj.zza(com.google.firebase:firebase-ml-model-interpreter@@22.0.2:170)
        at com.google.android.gms.internal.firebase_ml.zzrk.zza(Unknown Source:6)
        at com.google.firebase.ml.common.internal.modeldownload.zzj.zzb(com.google.firebase:firebase-ml-common@@22.1.0:61)
        at com.google.firebase.ml.common.internal.modeldownload.zzj.zza(com.google.firebase:firebase-ml-common@@22.1.0:21)
        at com.google.android.gms.internal.firebase_ml.zzrj.zza(com.google.firebase:firebase-ml-model-interpreter@@22.0.2:111) 
        at com.google.android.gms.internal.firebase_ml.zzrj.zzol(com.google.firebase:firebase-ml-model-interpreter@@22.0.2:107) 
        at com.google.android.gms.internal.firebase_ml.zzqr.zzf(com.google.firebase:firebase-ml-common@@22.1.0:53) 
        at com.google.android.gms.internal.firebase_ml.zzqr$zza.zzoo(com.google.firebase:firebase-ml-common@@22.1.0:7) 
        at com.google.android.gms.internal.firebase_ml.zzqr$zza.call(com.google.firebase:firebase-ml-common@@22.1.0:24) 
        at com.google.android.gms.internal.firebase_ml.zzpx.zza(com.google.firebase:firebase-ml-common@@22.1.0:32) 
        at com.google.android.gms.internal.firebase_ml.zzpw.run(Unknown Source:4) 
        at android.os.Handler.handleCallback(Handler.java:873) 
        at android.os.Handler.dispatchMessage(Handler.java:99) 
        at com.google.android.gms.internal.firebase_ml.zze.dispatchMessage(com.google.firebase:firebase-ml-common@@22.1.0:6) 
        at android.os.Looper.loop(Looper.java:201) 
        at android.os.HandlerThread.run(HandlerThread.java:65)

Environment

  • OS Platform: Google Colab, Android 9 (Poco F1)
  • TensorFlow version: 2.2.0-rc3 (also tf-nightly installed via pip)
  • firebase ml model interpreter version: firebase-ml-model-interpreter:22.0.2



Any idea I would much appreciated as this project is quite important now. Thank you



from LSTM Model Conversion to TFLite Work Fine, but Error When Importing to Android Project

Workmanager with multiple roomdatabase

I'm creating a room database for each user log in which is singleton and trying to push data to server using WorkManager.

I'm able to save data to corresponding user database, but when i'm trying to fetch in my workmanager, db instance always points to first created db.

Is their a way to access particular db in workmanager?.

here is ApplicationComponent

    @Singleton
@Component(
    dependencies = [RoomComponent::class],
    modules = [
        ApplicationModule::class,
        AndroidInjectionModule::class,
        SubViewModelModule::class,
        LogRoomModule::class,
        WelcomeActivityModule::class]
)
interface ApplicationComponent {
    @Component.Builder
    interface Builder {
        @BindsInstance
        fun application(application: Application): Builder
        fun build(): ApplicationComponent
    }

    fun inject(application: Application)

  
    fun roomComponent():RoomComponent

}

and i'm injecting in application class

    daggerComponent = DaggerApplicationComponent.builder().application(this).build()
ApplicationInjector.init(this) { application ->
            daggerComponent?.inject(application)
        }

Any help is appreciated.

Thanks in advance.



from Workmanager with multiple roomdatabase

How to asynchronously distribute product-yielding from a dataframe in scrapy spider

Is there a way to utilize Scrapy's asynchronous architecture when yielding products from a dataframe?


Overview

I have a spider in one of my Scrapy projects that differs from your typical logic of a spider as follows:

  1. Crawls an online file directory to get the most recent versions of two zip files that both contain multiple csv files
  2. Extracts the csv files to the current working directory
  3. Utilizes pandas.read_csv to read each csv into its own dataframe
  4. Performs pandas.merge operations to combine the data into a two final dataframes (one is the main dataframe and the other is a supporting dataframe where there's a one-to-many (main-to-supporting) row relationship
  5. Finally, the spider loops through the main dataframe, starts populating a scrapy item, then gathers the additional data from the supporting dataframe, and yields a complete item

The logic works, but the process takes about 5 1/2 hours to complete since it's dealing with 500k items and essentially becomes synchronous once it starts yielding items from the dataframes.

Below is the code I'm using to accomplish all of this. The bottleneck happens in the process_csvs function.

from ..items.redacted import Loader, REDACTEDItem
from scrapy.exceptions import CloseSpider
from datetime import datetime
import pandas as pd
import numpy as np
import zipfile
import scrapy
import json
import os


class REDACTEDSpider(scrapy.Spider):
    name = 'REDACTED'
    allowed_domains = ['REDACTED']
    start_urls = ['https://REDACTED/datasets/']
    # custom_settings = dict(TESTING_MODE=True, LOG_LEVEL='DEBUG')
    zip_filename = 'temp_redacted_data.zip'

    def parse(self, response):
        main_file_date = supporting_file_date = datetime.min
        main_file = supporting_file = None
        for link in response.xpath('//a[contains(@href, "primary_csv")]/@href').getall():
            link_date = datetime.strptime(link.rstrip('.zip')[-10:], '%Y-%m-%d')
            if link_date > main_file_date:
                main_file = link
                main_file_date = link_date
        if not main_file:
            raise CloseSpider('primary_csv zip file not found')
        self.logger.info('Found latest primary_csv file link (%s)' % main_file)
        main_file = f"https://REDACTED/datasets/{main_file}"
        for link in response.xpath('//a[contains(@href, "supporting_csv")]/@href').getall():
            link_date = datetime.strptime(link.rstrip('.zip')[-10:], '%Y-%m-%d')
            if link_date > supporting_file_date:
                supporting_file = link
                supporting_file_date = link_date
        if not supporting_file:
            raise CloseSpider('supporting_csv zip file not found')
        self.logger.info('Found latest supporting_csv file link (%s)' % supporting_file)
        supporting_file = f"https://REDACTED/datasets/{supporting_file}"

        # we pass supporting_file to essentially download the files sequentially
        # and so that we can make sure the files are downloaded before moving on to ingesting them
        self.logger.info('Downloading primary_csv zip file')
        yield scrapy.Request(main_file, callback=self.handle_zip, cb_kwargs=dict(supporting_file=supporting_file))

    def handle_zip(self, response, supporting_file=None):
        file_alias = 'primary_csv' if supporting_file else 'supporting_csv'
        # download zip - if this is the second time this function is called it will overwrite the first zip file
        # since we've already extracted the files we need from it
        self.logger.info(f"Saving {file_alias} zip file")
        with open(self.zip_filename, 'wb') as usda_file:
            usda_file.write(response.body)
        # extract zip contents
        self.logger.info(f"Extracting files from {file_alias} zip file")
        with zipfile.ZipFile(self.zip_filename, 'r') as zfile:
            if supporting_file:
                # we're extracting the first file, and still need to queue up the supporting_file
                zfile.extract('primary_csv_file_1.csv')
                zfile.extract('primary_csv_file_2.csv')
                zfile.extract('primary_csv_file_3.csv')
            else:
                # we're extracting the supporting_file now
                zfile.extract('supporting_csv_file.csv')

        if supporting_file:
            self.logger.info('Downloading supporting_csv zip file')
            yield scrapy.Request(supporting_file, callback=self.handle_zip)
        else:
            # remove the zipfile since we no longer need it
            # this will free up some storage space in case we need extra for the staging db
            os.remove(self.zip_filename)
            # both files have been unzipped, so we can move onto processing the csvs
            self.logger.info('Processing CSV files')
            
            # FIXME: This essentially bottlenecks into yielding items from a single thread
            yield from self.process_csvs()
    
    def process_csvs(self):
        primary_csv_file_1 = pd.read_csv('primary_csv_file_1.csv', usecols=[...], dtype=dict(...))
        primary_csv_file_2 = pd.read_csv('primary_csv_file_2.csv', usecols=[...], dtype=dict(...))
        primary_csv_file_3 = pd.read_csv('primary_csv_file_3.csv', usecols=[...], dtype=dict(...))
        supporting_csv_file = pd.read_csv('supporting_csv_file.csv', usecols=[...], dtype=dict(...))

        # Join the above four files into two pandas dataframes
        # Step 1: Join primary_csv_file_2.csv into primary_csv_file_1.csv
        primary_csv_file_1 = pd.merge(primary_csv_file_1, primary_csv_file_2, on='id', how='left')
        primary_csv_file_1.replace(np.nan, '', regex=True, inplace=True)
        # primary_csv_file_1 should now have most of the essential columns needed to create a full item
        # Step 2: Join supporting_csv_file.csv into primary_csv_file_3.csv
        primary_csv_file_3 = pd.merge(primary_csv_file_3, supporting_csv_file, left_on='supporting_id', right_on='id', how='left')
        primary_csv_file_3.replace(np.nan, '', regex=True, inplace=True)
        # primary_csv_file_3 should now have an additional column from supporting_csv_file

        # TODO: This is where I would like to fork the function in order to take full advantage of Scrapy's asynchronous processing
        for product in primary_csv_file_1.itertuples():
            loader = Loader(item=REDACTEDItem())
            loader.add_value('url', 'REDACTED')
            loader.add_value('category', product.category)
            loader.add_value('upc', product.upc)
            loader.add_value('brand', product.brand)
            loader.add_value('product_name', product.name)

            # Filter primary_csv_file_3 by id to get all nutrients and nutrient values for this product
            p_nutrients = primary_csv_file_3[primary_csv_file_3.id == product.supporting_id]
            nutrients = []
            for nutrient in p_nutrients.itertuples():
                nutrients.append(dict(
                    alias=nutrient.name,
                    value=nutrient.amount,
                    unit_of_measure=nutrient.units
                ))
            loader.add_value('nutrition', json.dumps(nutrients))

            yield loader.load_item()

        # remove the csv files to free up space
        os.remove('primary_csv_file_1.csv')
        os.remove('primary_csv_file_2.csv')
        os.remove('primary_csv_file_3.csv')
        os.remove('supporting_csv_file.csv')


from How to asynchronously distribute product-yielding from a dataframe in scrapy spider

Saving media file path or URI to SQLite and getting it, best practice

My goal is to:

  • Save media file to External Storage (in my case it's photo).
  • Get file path or URI of saved data.
  • Save it to SQLite (either file path or content URI or smth else).
  • Be able to get correct URI to this content at any point in the future.

It's very similar to what other very popular application do - they create their directory in 'Pictures' folder and store there photos and use them in their applications while they're also available for viewing using gallery/file explorer etc.

As I understand recommended way to save media content (image, f.e.) is to use MediaStore API and as a result I get content URI, which I can use later. But then I read that these content URIs might be changed after re-scan of Media happens, so it looks it's not reliable. (For example if SD card is used and it's taken out and inserted again)

At the same time usage of absolute file paths is not recommended and there's tendency to deprecate APIs which use absolute file paths to work with External Storage. So it doesn't look reliable either.

I can only imagine the following solution:

  • Use unique auto-generated file name while saving (like UUID).
  • When I need to get content URI (f.e. want to render photo in ImageView) - I can use ContentResolver and search for content URI using file name filter.

Problem with this approach is that I have a lot of photos (gallery) and querying it using ContentResolver can affect performance significantly.

I feel like I'm over complicating things and missing something.



from Saving media file path or URI to SQLite and getting it, best practice

Google play not accepting instant app due to digital asset link

I've been trying for a week to solve this issue with no luck! Google play is still not convinced that I have linked my website properly!, whenever I upload my instant app I get the usual:

Your site 'www.servstore.co' has not been linked through the Digital Asset Links protocol to your app. Please link your site through the Digital Asset Links protocol to your app.

Noting that both my instant app and installed app have the same code base (single module), and are actually 9.4 MB after minification.

I know this has been asked multiple times, and I've seen mutiple SO posts about this, however none of the resolutions I've read seem to work for me, I actually tried all of them so far with no luck, What I've done so far to debug this issue:

Website Side:

  1. Made sure assetlinks.json is uploaded to my website and administered with appropriate Content-Type header.

  2. Made sure the file is available with public permission (777)

  3. Made sure robots.txt allows crawling for the file, I actually only have the below in it:

User-Agent: *
Allow: /.well-known*
  1. Verified asset link https://digitalassetlinks.googleapis.com/v1/statements:list?source.web.site=https://www.servstore.co&relation=delegate_permission/common.handle_all_urls

  2. made sure the asset link is using the right SHA-256 (private key in Google Play), I also never use an upload key, I directly sign my app with the same key and have opted in to Google play signing using that key.

App Side:

  1. added asset_statements to my strings.xml and meta-data under application tag in AndroidManifest.xml

  2. Made sure the first intent-filter containing app link has auto-verify = true in my manifest, also tried to mark all 3 activities that have intent-filter URLs with auto-verify

  3. Added default-url in the manifest to all 3 activities and tried with only the main activity.

  4. Added networkSecurityConfig to xml resources and reference it in the manfiest:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config cleartextTrafficPermitted="false">
        <domain includeSubdomains="true">www.servstore.co</domain>
    </domain-config>
</network-security-config>

In Google Play:

  1. Enabled instant-app release type in new Google Play console.

  2. published the same code to standard release type in Google Play with version code higher than the one I use for my instant app.

I am ready to try anything ..

here is my manfiest file, removing unrelated activities:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:dist="http://schemas.android.com/apk/distribution"
    xmlns:tools="http://schemas.android.com/tools"
    package="co.servstore.client"
    android:targetSandboxVersion="2">

    <dist:module dist:instant="true" />

    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />

    <uses-feature
        android:glEsVersion="0x00020000"
        android:required="true"/>

    <application
        android:name=".ServStoreApp"
        android:allowBackup="false"
        android:icon="${appIcon}"
        android:label="@string/app_name"
        android:roundIcon="${appIconRound}"
        android:supportsRtl="true"
        android:theme="@style/Theme.ServeStore.NoActionBar"
        android:usesCleartextTraffic="true"
        tools:ignore="GoogleAppIndexingWarning"
        tools:replace="android:allowBackup,android:theme"
        android:networkSecurityConfig="@xml/network_security_config">

        <service
            android:name=".services.notifications.NotificationService"
            android:exported="false">
            <intent-filter>
                <action android:name="com.google.firebase.MESSAGING_EVENT" />
            </intent-filter>
        </service>

        <meta-data
            android:name="com.google.android.gms.version"
            android:value="@integer/google_play_services_version" />

        <meta-data
            android:name="com.google.android.geo.API_KEY"
            android:value="***" />

        <meta-data
            android:name="asset_statements"
            android:resource="@string/asset_statements" />

        <activity
            android:name=".ui.main.MainActivity"
            android:screenOrientation="nosensor"
            android:windowSoftInputMode="adjustResize|stateHidden">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            <intent-filter android:autoVerify="true">
                <action android:name="android.intent.action.VIEW" />

                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />

                <data
                    android:host="www.servstore.co"
                    android:scheme="https" />
                <data android:scheme="http" />
            </intent-filter>
            <meta-data
                android:name="default-url"
                android:value="https://www.servstore.co" />
        </activity>

        <activity
            android:name=".ui.orders.OrderDetailsActivity"
            android:screenOrientation="nosensor">
            <intent-filter android:autoVerify="true">
                <action android:name="android.intent.action.VIEW" />

                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />

                <data
                    android:host="www.servstore.co"
                    android:path="/businessOrders"
                    android:scheme="https" />
                <data android:scheme="http" />
            </intent-filter>
            <meta-data
                android:name="default-url"
                android:value="https://www.servstore.co" />
        </activity>
        <activity
            android:name=".ui.orders.CustOrderDetailsActivity"
            android:screenOrientation="nosensor">
            <intent-filter android:autoVerify="true">
                <action android:name="android.intent.action.VIEW" />

                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />

                <data
                    android:host="www.servstore.co"
                    android:path="/userOrders"
                    android:scheme="https" />
                <data android:scheme="http" />
            </intent-filter>
            <meta-data
                android:name="default-url"
                android:value="https://www.servstore.co" />
        </activity>
    </application>

</manifest>


from Google play not accepting instant app due to digital asset link

FastAPI: Having a dependency through Depends() and a schema refer to the same root level key without ending up with multiple body parameters

I have a situation where I want to authorize the active user against one of the values (Organization) in a FastAPI route. When an object of a particular type is being submitted, one of the keys (organization_id) should be present and the user should be verified as having access to the organization.

I've solved this as a dependency in the API signature to avoid having to replicate this code across all routes that needs access to this property:

def get_organization_from_body(organization_id: str = Body(None),
                               user: User = Depends(get_authenticated_user),
                               organization_service: OrganizationService = Depends(get_organization_service),
                               ) -> Organization:
    if not organization_id:
        raise HTTPException(status_code=400, detail='Missing organization_id.')

    organization = organization_service.get_organization_for_user(organization_id, user)

    if not organization:
        raise HTTPException(status_code=403, detail='Organization authorization failed.')

    return organization

This works fine, and if the API endpoint expects an organization through an organization_id key in the request, I can get the organization directly populated by introducing get_organization_from_body as a dependency in my route:

@router.post('', response_model=Bundle)
async def create_bundle([...]
                        organization: Organization = Depends(get_organization_from_body),
                        ) -> Model:
    

.. and if the user doesn't have access to the organization, an 403 exception is raised.

However, I also want to include my actual object on the root level through a schema model. So my first attempt was to make a JSON request as:

{
  'name': generated_name,
  'organization_id': created_organization['id_key']
}

And then adding my incoming Pydantic model:

@router.post('', response_model=Bundle)
async def create_bundle(bundle: BundleCreate,
                        organization: Organization = Depends(get_organization_from_body),
                        [...]
                        ) -> BundleModel:
    [...]
    return bundle

The result is the same whether the pydantic model / schema contains organization_id as a field or not:

class BundleBase(BaseModel):
    name: str

    class Config:
        orm_mode = True


class BundleCreate(BundleBase):
    organization_id: str
    client_id: Optional[str]

.. but when I introduce my get_organization_from_body dependency, FastAPI sees that I have another dependency that refers to a Body field, and the description of the bundle object has to be moved inside a bundle key instead (so instead of "validating" the organization_id field, the JSON layout needs to change - and since I feel that organization_id is part of the bundle description, it should live there .. if possible).

The error message tells me that bundle was expected as a separate field:

{'detail': [{'loc': ['body', 'bundle'], 'msg': 'field required', 'type': 'value_error.missing'}]}

And rightly so, when I move name inside a bundle key instead:

{
    'bundle': {
        'name': generated_name,
    },
    'organization_id': created_organization['id_key']
}

.. my test passes and the request is successful.

This might be slightly bike shedding, but if there's a quick fix to work around this limitation in any way I'd be interested to find a way to both achieve validation (either through Depends() or in some alternative way without doing it explicitly in each API route function that requires that functionality) and a flat JSON layout that matches my output format closer.



from FastAPI: Having a dependency through Depends() and a schema refer to the same root level key without ending up with multiple body parameters

How can i validate form fields based on button click?

I have 3 buttons. 2 is inside ng-repeat and one outside ng-repeat so I want to show the required field alert if the user clicks these buttons.

if the user clicks check 0 I have to validate only the first object and if any form data value missing I have to alert the user like 'this(username) is a required field.

if the user clicks the check 1 button I have to validate only the second object and if any form data value missing I have to alert the user like 'this(username) is a required field.

and if the user click check all button I have to check both the objects and if any field missing in both the objects I have to alert the field name with the object index.

How can I show the required field if the user clicks the check all button and check button please help me

Demo enter image description here

var app = angular.module("app", ['ngMessages']);
app.controller("myCtrl", function($scope) {
    $scope.users = [
        {
        "inputName":"aj",
        "inputPassword":"1234",
        "inputEmail":"aj@g.in",
        },{
        
        "inputName":"gj",
        "inputPassword":"1234",
        "inputEmail":"gj@g.in",
        }
    ];
     $scope.myFunc = function(formValidation) {
        console.log(formValidation)
    };
    $scope.checkall = function(formValidation) {
        console.log(formValidation)
    };
});
<body translate="no" >
<button ng-click="checkall(formValidation)">check all</button>
  <body ng-app="app" ng-controller="myCtrl" >
<div ng-repeat="user in users">
  <script type="text/ng-template" id="generic-messages">
    <p ng-message="required">This field is required.</p>
    <p ng-message="minlength">This field is too short.</p>
    <p ng-message="maxlength">This field is too long.</p>
  </script>


  <form name="formValidation">
<button ng-click="myFunc(formValidation)">check </button>
    <label>Username (Using Dirty)</label>
    <input type="text" name="username" ng-model="user.inputName" ng-minlength="6" ng-maxlength="12" ng-pattern="/^\w+$/" required>
    <div ng-messages="formValidation.username.$error" ng-show="formValidation.username.$dirty">
      <p ng-message="pattern">Username can only be alphanumeric with an optional underscore.</p>
      <p ng-message="maxlength">Username cannot be longer than 12 characters.</p>
      <div ng-messages-include="generic-messages"></div>
    </div>

    <label>Password (Using Touched)</label>
    <input type="text" name="userPassword" ng-model="user.inputPassword" ng-minlength="6" ng-maxlength="12" required>
    <div ng-messages="formValidation.userPassword.$error" ng-show="formValidation.userPassword.$touched">
      <div ng-messages-include="generic-messages"></div>
    </div>

    <label>Email (Using Dirty)</label>
    <input type="email" name="userEmail" ng-model="user.inputEmail" required>
    <div ng-messages="formValidation.userEmail.$error" ng-show="formValidation.userEmail.$dirty">
      <p ng-message="required">This field is required.</p>
      <p ng-message="email">Please enter a valid email address.</p>
    </div>
  </form>
  </div>
</body>


from How can i validate form fields based on button click?

How Do I Enable ADB Debugging on Chrome OS?

According to both Google and Google, if I enable Linux on Chrome OS, then in Settings' "Linux (Beta)" section, I should see a "Develop Android apps" option.

  • On an HP Chromebox G2 (Kench), I see this option and eventually got it activated.

  • On a Samsung Chromebook Plus (Kevin), I do not see this option, even with Chrome OS 88.0.4324.186.

  • On an ASUS Chromebook Tablet CT100 (scarlet), I see this option. This particular device is short on ports, though, so I'm going to be struggling to use it for what I need.

  • On an Acer Chromebook R11 (cyan), I do not see this option, even with Chrome OS 88.0.4324.186.

So... how do I enable ADB debugging on the Samsung or the Acer?

Or, another way to look at it: how do I know whether a given Chrome OS device model will or will not support ADB debugging, besides actually trying to set it up? It is difficult to plan on getting something else for testing if I do not know whether it will support ADB before buying it.



from How Do I Enable ADB Debugging on Chrome OS?

D3 link breaks during special removal case

I added a context menu in my graph, where I can use my add and removal function. A node which receives connections can´t be removed, a alert informs the user. Further I can "endless" add nodes. Now comes the interesting "problem" part.

Case 1: If nodes are removed ordered from highest to smallest and a new node is added afterwards, its fine. For example, remove node 8 and add a new node anywhere. Or remove node 8, 7, 6 and add a node afterwards will be also fine.

Case 2: Remove a node, which is not on the last array position and add a node anywhere afterwards. The connection will break. For example, remove node 5 and add a new node on 3. The connection of node 8 will break.

I am getting mental with this issue.

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <title>Playground D3v6</title>
    <!-- favcon -->
    <link rel="icon" href="https://networkrepository.com/favicon.png">
    <!-- call external d3.js framework -->
    <script src="https://d3js.org/d3.v6.js"></script>
    <!-- import multiselection framework -->
    <script src="https://d3js.org/d3-selection-multi.v1.js"></script>
    <!-- import "font awesome" stylesheet https://fontawesome.com/ -->
    <script src="https://kit.fontawesome.com/39094309d6.js" crossorigin="anonymous"></script>
</head>

<style>
    body {
        overflow: hidden;
        margin: 0px;
    }

    .canvas {
        background-color: rgb(220, 220, 220);
    }

    .link {
        stroke: rgb(0, 0, 0);
        stroke-width: 1px;
    }

    circle {
        background-color: whitesmoke;
    }

    .tooltip {
        font-family: "Open Sans", sans-serif;
        position: absolute;
        text-align: left;
        background: rgb(245, 245, 245);
        border: 2px;
        border-radius: 6px;
        border-color: rgb(255, 255, 255);
        border-style: solid;
        pointer-events: none;
        line-height: 150%;
        padding: 8px 10px;
    }

    #context-menu {
        font-family: "Open Sans", sans-serif;
        position: fixed;
        z-index: 10000;
        width: 190px;
        background: whitesmoke;
        border: 2px;
        border-radius: 6px;
        border-color: white;
        border-style: solid;
        transform: scale(0);
        transform-origin: top left;
    }

    #context-menu.active {
        transform: scale(1);
        transition: transform 200ms ease-in-out;
    }

    #context-menu .item {
        padding: 8px 10px;
        font-size: 15px;
        color: black;
    }

    #context-menu .item i {
        display: inline-block;
        margin-right: 5px;
    }

    #context-menu hr {
        margin: 5px 0px;
        border-color: whitesmoke;
    }

    #context-menu .item:hover {
        background: lightblue;
    }

</style>

<body>
    <!-- right click context menu -->
    <div id="context-menu">
        <div id="addObject" class="item">
            <i class="fa fa-plus-circle"></i> Add Node
        </div>
        <div id="removeObject" class="item">
            <i class="fa fa-minus-circle"></i> Remove Node
        </div>
    </div>

    <svg id="svg"> </svg>


    <!-- call script where the main application is written -->
    <script>
        var graph = {
            "nodes": [{
                "id": 0,
                "type": "Company",
                "name": "Company",
                "icon": "\uf1ad",
                "parent": 0
            },
            {
                "id": 1,
                "type": "Software",
                "name": "Software_1",
                "icon": "\uf7b1",
                "parent": 0
            },
            {
                "id": 2,
                "type": "Software",
                "name": "Software_2",
                "icon": "\uf78d",
                "parent": 0
            },
            {
                "id": 3,
                "type": "Software",
                "name": "Software_3",
                "icon": "\ue084",
                "parent": 0
            },
            {
                "id": 4,
                "type": "Software",
                "name": "Software_4",
                "icon": "\ue084",
                "parent": 0
            },
            {
                "id": 5,
                "type": "Software",
                "name": "Software_5",
                "icon": "\ue084",
                "parent": 3
            },
            {
                "id": 6,
                "type": "Software",
                "name": "Software_6",
                "icon": "\ue084",
                "parent": 3
            },
            {
                "id": 7,
                "type": "Software",
                "name": "Software_7",
                "icon": "\ue084",
                "parent": 4
            },
            {
                "id": 8,
                "type": "Software",
                "name": "Software_8",
                "icon": "\ue084",
                "parent": 4
            }
            ],
            "links": [{
                "source": 1,
                "target": 0,
                "type": "uses"
            },
            {
                "source": 2,
                "target": 0,
                "type": "uses"
            },
            {
                "source": 3,
                "target": 0,
                "type": "uses"
            },
            {
                "source": 4,
                "target": 0,
                "type": "uses"
            },
            {
                "source": 5,
                "target": 3,
                "type": "uses"
            },
            {
                "source": 6,
                "target": 3,
                "type": "uses"
            },
            {
                "source": 7,
                "target": 4,
                "type": "uses"
            },
            {
                "source": 8,
                "target": 4,
                "type": "uses"
            }
            ]
        }

        // declare initial variables
        var svg = d3.select("svg")
        width = window.innerWidth
        height = window.innerHeight
        node = null
        link = null
        thisNode = null;
        d = null;
        isParent = false;

        // define cavnas area to draw everything
        svg = d3.select("svg")
            .attr("class", "canvas")
            .attr("width", width)
            .attr("height", height)
            .call(d3.zoom().on("zoom", function (event) {
                svg.attr("transform", event.transform)
            }))
            .append("g")

        // remove zoom on dblclick listener
        d3.select("svg").on("dblclick.zoom", null)

        // append markers to svg
        svg.append('defs').append('marker')
            .attrs({
                'id': 'arrowhead',
                'viewBox': '-0 -5 10 10',
                'refX': 14,
                'refY': 0,
                'orient': 'auto',
                'markerWidth': 30,
                'markerHeight': 30,
                'xoverflow': 'visible'
            })
            .append('svg:path')
            .attr('d', 'M 0,-2 L 4 ,0 L 0,2')
            .attr('fill', 'black')
            .style('stroke', 'none');

        var linksContainer = svg.append("g").attr("class", "linksContainer")
        var nodesContainer = svg.append("g").attr("class", "nodesContainer")

        // iniital force simulation
        var simulation = d3.forceSimulation()
            .force("link", d3.forceLink().id(function (d) {
                return d.id;
            }).distance(100))
            .force("charge", d3.forceManyBody().strength(-400))
            .force("center", d3.forceCenter(width / 2, height / 2))
            .force("attraceForce", d3.forceManyBody().strength(70));

        var tooltip = d3.select("body").append("div")
            .attr("class", "tooltip")
            .style("opacity", 0);

        //create links
        link = linksContainer.selectAll(".link")
            .data(graph.links, d => d.id)
            .enter()
            .append("line")
            .attr("class", "link")
            .style("pointer-events", "none")
            .attr('marker-end', 'url(#arrowhead)')

        node = nodesContainer.selectAll(".node")
            .data(graph.nodes, d => d.id)
            .enter()
            .append("g")
            .attr("class", "node")
            .attr("stroke", "white")
            .attr("stroke-width", "2px")
            .call(d3.drag()
            .on("start", dragStarted)
            .on("drag", dragged)
            .on("end", dragEnded)
            )
            

        node.append("circle")
            .attr("r", 30)
            .style("fill", "whitesmoke")
            .on("mouseenter", mouseEnter)
            .on("mouseleave", mouseLeave)
            .on("contextmenu", contextMenu)

        node.append("text")
            .style("class", "icon")
            .attr("font-family", "FontAwesome")
            .attr("dominant-baseline", "central")
            .attr("text-anchor", "middle")
            .attr("font-size", 30)
            .attr("fill", "black")
            .attr("stroke-width", "0px")
            .attr("pointer-events", "none")
            .text(function (d) {
                return d.id
            })

        simulation
            .nodes(graph.nodes)
            .on("tick", ticked);

        simulation
            .force("link")
            .links(graph.links)

            function mouseEnter(event, d) {
            thisNode = d

            d3.select(this)
                .style("fill", "lightblue")
            tooltip.transition()
                .style("opacity", 1)
            tooltip.html(
                "ID: " + d.id + "<br/>" +
                "Name: " + d.name + "<br/>" +
                "Typ: " + d.type + "<br/>" +
                "Parent: " + d.parent)
                .style("left", (event.pageX) + 30 + "px")
                .style("top", (event.pageY - 80) + "px");
        }

        function mouseLeave(d) {
            switch (d.name) {
                case ("power-plug"):
                    tooltip.transition()
                        .style("opacity", 0);

                    return
                default:
                    d3.select(this).style("fill", "whitesmoke")

                    tooltip.transition()
                        .style("opacity", 0);

            }
        }

        function contextMenu(event, d) {
            thisNode = d

            tooltip.transition()
                .style("opacity", 0);

            event.preventDefault()

            var contextMenu = document.getElementById("context-menu")
            contextMenu.style.top = event.clientY + "px"
            contextMenu.style.left = event.clientX + "px"
            contextMenu.classList.add("active")

            window.addEventListener("click", function () {
                contextMenu.classList.remove("active")
            })

            document.getElementById("addObject").addEventListener("click", addNodeClicked)
            document.getElementById("removeObject").addEventListener("click", removeNodeClicked)
        }

        function addNodeClicked() {

            addNode(thisNode)
        }

        function addNode(d) {
            var newID = Math.floor(Math.random()*100000)

            graph.nodes.push({
                "id": newID,
                "type": "software",
                "name": "Software_" + newID,
                "icon": "\ue084",
                "parent": d.id,
            })

            graph.links.push({
                source: newID,
                target: d.id,
                type: "uses"
            })

            link = linksContainer.selectAll(".link")
                .data(graph.links)
                .enter()
                .append("line")
                .attr("class", "link")
                .style("pointer-events", "none")
                .attr('marker-end', 'url(#arrowhead)')
                .style("display", "block")
                .merge(link)

            node = nodesContainer.selectAll(".node")
                .data(graph.nodes)
                .enter()
                .append("g")
                .attr("class", "node")
                .attr("stroke", "white")
                .attr("stroke-width", "2px")
                .call(d3.drag()
                .on("start", dragStarted)
                .on("drag", dragged)
                .on("end", dragEnded)
                )
                
                .merge(node)

            node.append("circle")
                .attr("r", 30)
                .style("fill", "whitesmoke")
                .on("click", addNodeClicked)
                .on("mouseenter", mouseEnter)
                .on("mouseleave", mouseLeave)
                .on("contextmenu", contextMenu)
                .merge(node)

            node.append("text")
                .style("class", "icon")
                .attr("font-family", "FontAwesome")
                .attr("dominant-baseline", "central")
                .attr("text-anchor", "middle")
                .attr("font-size", 30)
                .attr("fill", "black")
                .attr("stroke-width", "0px")
                .attr("pointer-events", "none")
                .text(function (d) {
                    return d.id
                })
                .merge(node)

            simulation.nodes(graph.nodes);
            simulation.force("link").links(graph.links);

            //reheat the simulation
            simulation.alpha(0.3).restart()
            
            /*
            
            console.log("addNode: ")
            console.log(graph.nodes)
            console.log("---------")
            
            console.log("addLink: ")
            console.log(graph.links)
            console.log("---------")
            */
        }

        function removeNodeClicked() {
            removeNode(thisNode)
        }

        function removeNode(d) {
            var hasNeighborNodes = false

            link.filter((l) => {
                if (d.id == l.target.id) {
                    hasNeighborNodes = true
                }

            })

            if (hasNeighborNodes) {
                alert("Object can´t be deleted, beause of incoming connections. Please re-arrange or delete incoming connections first.")
                hasNeighborNodes = false

            } else if (!hasNeighborNodes) {


                var indexOfNodes = graph.nodes.indexOf(d)

                var indexOfLinks = graph.links.findIndex(element => element.source.id == d.id)
                
                graph.links.splice(indexOfLinks, 1)
                
                linksContainer.selectAll(".link")
                .data(graph.links)
                .exit()
                .remove()
                

                graph.nodes.splice(indexOfNodes, 1)

                node
                    .data(graph.nodes, d => d.id)
                    .exit()
                    .remove()

                simulation.nodes(graph.nodes);
                simulation.force("link").links(graph.links);

                //reheat the simulation
                simulation.alpha(0.3).restart()

            }


        }



        function ticked() {
            // update link positions
            link
                .attr("x1", function (d) {
                    return d.source.x;
                })
                .attr("y1", function (d) {
                    return d.source.y;
                })
                .attr("x2", function (d) {
                    return d.target.x;
                })
                .attr("y2", function (d) {
                    return d.target.y;
                });

            // update node positions
            node
                .attr("transform", function (d) {
                    return "translate(" + d.x + ", " + d.y + ")";
                });

        }

        

        
        function dragStarted(event, d) {
            if (!event.active) simulation.alphaTarget(0.3).restart();
            d.fx = d.x;
            d.fy = d.y;
        }
        
        function dragged(event, d) {
            d.fx = event.x;
            d.fy = event.y;
        }
        
        function dragEnded(event, d) {
            if (!event.active) simulation.alphaTarget(0);
            d.fx = undefined;
            d.fy = undefined;
        }
        
        </script>
</body>

</html>


from D3 link breaks during special removal case

Quick and resilient way to expose a python library API over the network as well as locally

I'm looking for an easy and dependency-light way of wrapping a python library to expose it over:

a) The network, either via HTTP or some other custom protocol, it doesn't matter that much, and encryption isn't required. b) The local machine, the main purpose here is to avoid library import overhead, ideally, this would happen via an efficient mechanism ala pipes or shared memory to minimize the number of data copies and [de]serialization.

It seems like it's an easy enough job to just create a class that runs constantly, with e.g. an HTTP interface mirroring the library functionality and returning e.g. pickled objects corresponding to the answers. But getting it to work efficiently and cover various edge-cases seems tedious and I'm wondering if there's a better way to do this, ideally one that's built into python itself.

Ray seems to have some functionality for this using Actors, but it seems rather heavy-weight and prone to fail when being installed, so I'm curios what alternatives exist.

Also, might be too much of a "library question", if you think it's better suited for another stack exchange website please tell me which and I'll remove it from here.



from Quick and resilient way to expose a python library API over the network as well as locally

Android Studio runs old code BUT JUST SOMETIMES. It is fricking annoying

I use Android Studio 4.1.1

Sometimes when I edit/add new code to my project, it doesn't refresh. AS simply runs the old code. Sometimes I have to add empty new lines and run it again to make my modifications effect.

I would like to turn off every caching and smart speed run bs in order to make this laughable death star IDE work for once in the life, doing one thing properly, instead of doing 1000 things badly.

How is it possible that when they make an update, fixing/adding 2 new things but make worse/broke 3 old ones?

I tried to turn off instant run but it is not even among options.

Thanks in advance.



from Android Studio runs old code BUT JUST SOMETIMES. It is fricking annoying

Accessing the event path of any fired event of many event types when watching files in Gulp

With Gulp, you can access the path of a fired event by using the watch().on() method for each event type:

const { watch } = require('gulp');

watch('*.js').on('change', (path, stats) => {
  console.log(`File ${path} was changed`);
});

watch('*.js').on('add', (path, stats) => {
  console.log(`File ${path} was added`);
});

You can also watch for multiple event types using the events option, but you don't get access to the path of a fired event:

watch('*.js', { events: ['change', 'add'] }, cb => {
  // body omitted
  cb();
});

Is there a way to access the path of a fired event from a single anonymous handler when watching for multiple event types?



from Accessing the event path of any fired event of many event types when watching files in Gulp

Saturday 27 February 2021

In Objection.js, how can I include a virtual column with my query?

I would like to create an expired_bool virtual column.

I have the following 3 tables:

subscriptions:

id duration price
1 30 0.99
2 360 1.99

invoices:

id user_id purchase_date
1 34 2020-01-01 01:21:01
2 42 2021-02-19 19:19:19

invoice_items:

id user_id invoice_id subscription_id activation_date
1 34 1 1 2020-05-15 12:51:51
2 34 1 2 2021-02-20 20:20:12
3 42 2 1 NULL
4 42 2 2 2021-02-20 20:20:12

This is how the User, Invoice, and InvoiceItems tables are modeled in Objection.js:

class User extends Model {
  static get tableName() {
    return "users";
  }

  static get relationMappings() {
    return {
 
      invoices: {
        relation: Model.HasManyRelation,
        modelClass: Invoice,
        join: {
          from: "users.id",
          to: "invoices.user_id",
        },
      },

      invoiceItems: {
        relation: Model.HasManyRelation,
        modelClass: InvoiceItem,
        join: {
          from: "users.id",
          to: "invoice_items.user_id",
        },
      },

    };
  }
}

class Invoice extends Model {
  static get tableName() {
    return "invoices";
  }

  static get relationMappings() {
    return {
      user: {
        relation: Model.BelongsToOneRelation,
        modelClass: User,
        join: {
          from: "invoices.user_id",
          to: "users.id",
        },
      },

      invoiceItems: {
        relation: Model.HasManyRelation,
        modelClass: InvoiceItem,
        join: {
          from: "invoices.id",
          to: "invoice_items.invoice_id",
        },
      },
    };
  }
}

class InvoiceItem extends Model {
  static get tableName() {
    return "invoice_items";
  }

  static get relationMappings() {
    return {
      invoice: {
        relation: Model.BelongsToOneRelation,
        modelClass: Invoice,
        join: {
          from: "invoice_items.invoice_id",
          to: "invoice.id",
        },
      },

      user: {
        relation: Model.BelongsToOneRelation,
        modelClass: User,
        join: {
          from: "invoice_items.user_id",
          to: "users.id",
        },
      },

      subscription: {
        relation: Model.HasOneRelation,
        modelClass: Subscription,
        join: {
          from: "invoice_items.subscription_id",
          to: "subscriptions.id",
        },
      },
    };
  }
}

And this is how I'm Querying for the user and his/her purchases:

async function getUserAllWithPasswordByIdAsync(userId) {
  try {
    const query = await User.query()
      .findById(userId)
      .withGraphFetched("invoiceItems.subscription")
      .withGraphFetched("invoices")

    return query;
  }
  catch (error) {
    console.log(error)
  }
}

Just as an aside, the expired_bool virtual column is determined by checking the activation date of invoiceItems and adding the duration from the subscriptions table, and making sure that date is in the future from today's date.

So in summary, how can I determine if the invoiceItem is expired automatically (by use of a virtual column, which should be added to the invoiceItems table), and ensure that this is included with my query of User?



from In Objection.js, how can I include a virtual column with my query?

Determine maximum width a DOM element might grow to be?

I'm interested in querying the maximum size that a DOM element in a browser might grow to be. It is well known that an empty DOM element (without styling) has .clientWidth of 0, but adding text/images/etc. to the element might cause its width to grow. Take for instance the DOM element thisOne in the structure below:

<table style="padding: 20px; border-spacing: 100px">
   <tr>
       <td></td>
       <td>
            <div id="thisOne"></div>
       </td>
   </tr>
</table>

Currently #thisOne.clientWidth === 0 but if I append a large amount of text to it, its width will grow and grow, but not until it reaches document.body.clientWidth because of the columns, padding classes, etc. I am wondering how I can figure out the current maximum width of the object without doing something like:

const thisOne = document.getElementById('thisOne');
thisOne.style.visibility = 'hidden';  // do not display to user.
thisOne.innerHTML = 'blah '.repeat(2000);
const maxWidth = thisOne.clientWidth;
thisOne.innerHTML = '';
thisOne.style.visibility = 'visible';

JQuery based answers are fine, though knowing a pure HTML/JS version would be better.

(In case anyone's wondering, I'm planning on placing an SVG of music notation into the div, but I want it to have nice wrapping onto additional lines by giving the renderer a width to fit before adding it)



from Determine maximum width a DOM element might grow to be?

How to use sqlite acorss multiple (spawned) python processes via sqlalchemy

I have a file called db.py with the following code:

from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker


engine = create_engine('sqlite:///my_db.sqlite')
session = scoped_session(sessionmaker(bind=engine,autoflush=True))

I am trying to import this file in various subprocesses started using a spawn context (potentially important, since various fixes that worked for fork don't seem to work for spawn)

The import statement is something like:

from db import session

and then I use this session ad libitum without worrying about concurrency, assuming SQLite's internal locking mechanism will order transactions as to avoid concurrency error, I don't really care about transaction order.

This seems to result in errors like the following: sqlite3.ProgrammingError: SQLite objects created in a thread can only be used in that same thread. The object was created in thread id 139813508335360 and this is thread id 139818279995200.

Mind you, this doesn't directly seem to affect my program, every transaction goes through just fine, but I am still worried about what's causing this.

My understanding was that scoped_session was thread-local, so I could import it however I want without issues. Furthermore, my assumption was that sqlalchemy will always handle the closing of connections and that sqllite will handle ordering (i.e. make a session wait for another seesion to end until it can do any transaction).

Obviously one of these assumptions is wrong, or I am misunderstanding something basic about the mechanism here, but I can't quite figure out what. Any suggestions would be useful.



from How to use sqlite acorss multiple (spawned) python processes via sqlalchemy

Room DAO with multiple non-obligatory filters

In my app user can filter their data using multiple filters in every combination (apply just one, multiple or none).

Before that, I only had one filter so every time it was applied, i was switching the DAO method. Now I have 6 filters so there are dozens of combinations so creating a method for every combination is impossible. I cannot also modify my database a lot, because it is already available to the users.

My current code looks like this:

@Query("SELECT id, name, date FROM UserData")
fun getAll(): DataSource.Factory<Int, UserItem> //no filters

@Query("SELECT id, name, date FROM UserData WHERE name LIKE '%' || :search  || '%'")
fun getAllFiltered(query: String): DataSource.Factory<Int, UserItem> //one filter applied

Is there a way to modify the query so that there is one method for all filters combinations?

Update:

This is my data class, which instances I would like to filter:

@Entity(tableName = "UserItem")
data class UserItem(

    @PrimaryKey(autoGenerate = true)
    @ColumnInfo(name = "id")
    val id: Long? = null,

    @ColumnInfo(name = "created_at")
    val createdAt: Date,

    @ColumnInfo(name = "is_uploaded")
    val isUploaded: Boolean,

    @ColumnInfo(name = "name")
    val name: String,

    @ColumnInfo(name = "item_sum")
    val sum: Int = 0,

    @ColumnInfo(name = "tags")
    val tags: List<String> = listOf(),
)

I would like to filter/check numerac and boolean properties' equality, check whether list properties contain specified string. Basically I would like to have the ability to filter everything I could. If it is not possible, I would be satisfied with at least some filters.



from Room DAO with multiple non-obligatory filters

What should be returned when a property does not have a value in a REST api?

When there is no value assigned to a property, should it be returned as null or REST API should entirely skip such properties?

Consider an example of user object which has first_name and last_name. (In the below example, last_name need not be an empty string specifically. Consider it was never received from the end user.)

{
   first_name: "Bob",
   last_name: "",
}

Now since the client is aware of User schema, should last_name be returned or simply dropped from response so that client can automatically set a default value.(i.e empty string "")

In case null has to be returned, does it make sense to return null when it has got a special meaning in some cases.(i.e null means something and different from undefined)



from What should be returned when a property does not have a value in a REST api?

Issue with Upgrading TinyMCE version to 5 on FormBuilder

We have been using FormBuilder to build forms wherein we use TextArea with TinyMCE (version 4.* by default).

We tried to upgrade the TinyMCE library by replacing the existing TinyMCE CDN link - with version 5.* CDN link - in to form-builder.min.js.

this.js=["https://cdn.tinymce.com/4/tinymce.min.js"]

to

this.js=["https://cdn.tiny.cloud/1/no-api-key/tinymce/5/tinymce.min.js"]

After upgrade, it started giving issues when we have multiple TinyMCE elements on a single page as shown in the image:

TinyMCE with Form Builder

Have also tried to include self hosted TinyMCE library which is also giving the same issue. The TinyMCE version 4 was working fine when we use from CDN, but including local libraries for TinyMCE 4.* and using CDN for TinyMCE 5.* is also not working.

Looking for help to correctly upgrade the TinyMCE version on FormBuilder.

Thanks.



from Issue with Upgrading TinyMCE version to 5 on FormBuilder

how to emulate a user clicking on the scroll navigation

I'm updating this question to be more inline with what I have now found to be the requirement.

Previously I used setintervalTimer to create a scroll event, using window.scrollTo, this is not an option as the currently running JavaScript on the page causes the scroll to be very laggy.

Is this possible?

  1. I am hoping to find a way to interact with the browser by simulating the user clicking on the browser scroll bar and it being dragged to the bottom of the page. This is to screen record the whole website and all its interactions.

If there is another way this can be achieved (please rember JS is not a performant option right now) - then please let me know.

Thanks - Wally



from how to emulate a user clicking on the scroll navigation

Exoplayer in recyclerview with images and video like instagram but stop only last video other still playing after backpressed in android

I tried all StackOverflow answers and youtube solutions but cannot found anything suitable that's why I post my question in it.

I want to make an app like Instagram which I show images and video but the issue is

  1. when I swipe up in recycler view all video play automatically not only single shown screen.
  2. when I back pressed the button then only the last video stop with audio other videos(audio) still playing in the background until kill the app.

What I want to do is.

  1. single video play at a time which is shown on screen other video stores in cache like TikTok then after swipe I watch these videos.

  2. after back pressed all video with audio stopped

  3. onclicklistener with mute/unmute and double clicklistener.

here is my code...

Main Activity.class

public class MainActivity extends AppCompatActivity {
ActivityMainBinding mainBinding;
Toolbar toolbar;
String JSON_URl = "https://wasisoft.com/dev/index.php";
List<newsFeedModel> feedModels = new ArrayList<>();
newsFeedAdapter imageAdapter;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mainBinding = ActivityMainBinding.inflate(getLayoutInflater());
    setContentView(mainBinding.getRoot());
    toolbar = findViewById(R.id.mews_feed_toolbar);
    toolbar.setTitle("NewsFeed");
    toolbar.setTitleTextColor(Color.WHITE);
    showList();

}

void showList() {
    AndroidNetworking.get(JSON_URl)
            .setPriority(Priority.LOW)
            .build()
            .getAsJSONArray(new JSONArrayRequestListener() {
                @Override
                public void onResponse(JSONArray response) {
                    // do anything with response
                    if (response != null) {
                        for (int i = 0; i < response.length(); i++) {
                            try {
                                JSONObject object = response.getJSONObject(i);
                                newsFeedModel FeedModel = new newsFeedModel();
                                FeedModel.setTitleName(object.getString("account_name"));
                                FeedModel.setLike(object.getString("likes"));
                                FeedModel.setDescrption(object.getString("media_type"));
                                FeedModel.setVideo(object.getString("media"));
                                FeedModel.setViewImg(object.getString("media"));
                                feedModels.add(FeedModel);
                                String res = object.getString("media");
                                Log.d("TAG", "onResponse: " + res);

                            } catch (JSONException e) {
                                e.printStackTrace();
                            }
                        }
                        imageADD(feedModels);
                    } else {
                        Toast.makeText(MainActivity.this, "None ", Toast.LENGTH_SHORT).show();
                    }
                }

                @Override
                public void onError(ANError error) {
                    // handle error
                    Toast.makeText(MainActivity.this, "No Value " + error.getErrorBody(), Toast.LENGTH_SHORT).show();
                    Log.d("TAG", "onError: " + error);
                }
            });
}

void imageADD(List<newsFeedModel> feedModel) {
    imageAdapter = new newsFeedAdapter(this, feedModel, this::videoPlayBack);
    LinearLayoutManager manager = new LinearLayoutManager(this);
    manager.setSmoothScrollbarEnabled(true);
    imageAdapter.notifyDataSetChanged();
    mainBinding.newsFeedRecycler.setAdapter(imageAdapter);
    mainBinding.newsFeedRecycler.setHasFixedSize(true);
    mainBinding.newsFeedRecycler.setLayoutManager(manager);


}
void videoPlayBack(PlayerView player, Uri videoUrl,int position) {
    BandwidthMeter meter = new DefaultBandwidthMeter();
    TrackSelector track = new DefaultTrackSelector(
            new AdaptiveTrackSelection.Factory(meter)
    );
    imageAdapter.exoPlayer = ExoPlayerFactory.newSimpleInstance(this, track);
    DefaultHttpDataSourceFactory factory = new DefaultHttpDataSourceFactory("video");
    ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();
    MediaSource mediaSource = new ExtractorMediaSource(videoUrl, factory, extractorsFactory, null, null);
    player.setPlayer(imageAdapter.exoPlayer);
    player.setKeepScreenOn(true);
    imageAdapter.exoPlayer.prepare(mediaSource);
    imageAdapter.exoPlayer.setPlayWhenReady(true);
    player.setUseController(true);

}

@Override
public void onDestroy() {
    imageAdapter.releasePlayer();
    super.onDestroy();
}

@Override
protected void onPause() {
    super.onPause();
    imageAdapter.pausePlayer();
}
}

Adapter class

public class newsFeedAdapter extends RecyclerView.Adapter {
public static final int imageFeed = 0;
public static final int videoFeed = 1;
public SimpleExoPlayer exoPlayer;
Context context;
videoCallBack callBack;
List<newsFeedModel> feedModels;
videoNewsFeed videoNews;
newsFeedModel model;
String Json_Url = "https://wasisoft.com/dev/";

public newsFeedAdapter(Context context, List<newsFeedModel> feedModels, videoCallBack callBack) {
    this.context = context;
    this.feedModels = feedModels;
    this.callBack = callBack;
}

public newsFeedAdapter() {
}

@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    if (viewType == 0) {
        View view = LayoutInflater.from(context).inflate(R.layout.images_news_feed, parent, false);
        return new imageNewsFeed(view);
    } else {

        View view = LayoutInflater.from(context).inflate(R.layout.video_news_feed, parent, false);
        return new videoNewsFeed(view);
    }
}

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
    if (holder.getItemViewType() == 0) {
        newsFeedModel feed = feedModels.get(position);
        imageNewsFeed imageNews = (imageNewsFeed) holder;

        Glide
                .with(context)
                .load(Json_Url + feed.getViewImg())
                .centerCrop()
                .into(imageNews.viewPager);
        Log.d("TAG", "onBindViewHolder: " + feed.getViewImg());

        imageNews.title.setText(feed.getTitleName());
        imageNews.likes.setText(feed.getLike());
        imageNews.description.setText(feed.getDescription());

    } else {

        model = feedModels.get(position);
        videoNews = (videoNewsFeed) holder;
        videoNews.videoLikes.setText(model.getLike());
        videoNews.videoTitle.setText(model.getTitleName());
        videoNews.videoDescription.setText(model.getDescription());
        callBack.onSuccessPlay(videoNews.videoView, Uri.parse(Json_Url + model.getVideo()), position);
    }
}

@Override
public int getItemViewType(int position) {
    if (feedModels.get(position).getDescription().contains("picture")) {
        return imageFeed;
    } else
        return videoFeed;
}

@Override
public int getItemCount() {
    return feedModels.size();
}


public void releasePlayer() {
    if (exoPlayer != null) {
        videoNews.videoView.setPlayer(null);
        exoPlayer.setPlayWhenReady(true);
        exoPlayer.getPlaybackState();
        exoPlayer.release();
        exoPlayer = null;
    }
}

public void pausePlayer() {
    if (exoPlayer != null) {
        videoNews.videoView.setPlayer(null);
        exoPlayer.setPlayWhenReady(false);
        exoPlayer.getPlaybackState();
    }
}



public static class imageNewsFeed extends RecyclerView.ViewHolder {
    ImageView dpImage, viewPager;
    TextView title, likes, description;

    public imageNewsFeed(@NonNull View itemView) {
        super(itemView);
        dpImage = itemView.findViewById(R.id.profile_image_images_news_feed);
        viewPager = itemView.findViewById(R.id.profile_image_viewPage_news_feed);
        title = itemView.findViewById(R.id.profile_image_name_news_feed);
        likes = itemView.findViewById(R.id.profile_image_like_count_news_feed);
        description = itemView.findViewById(R.id.profile_image_comments_news_feed);
    }
}

public static class videoNewsFeed extends RecyclerView.ViewHolder {
    public PlayerView videoView;
    TextView videoTitle, videoLikes, videoDescription;

    public videoNewsFeed(@NonNull View itemView) {
        super(itemView);
        videoView = itemView.findViewById(R.id.item_video_exoplayer);
        videoTitle = itemView.findViewById(R.id.profile_video_name_news_feed);
        videoLikes = itemView.findViewById(R.id.profile_video_like_count_news_feed);
        videoDescription = itemView.findViewById(R.id.profile_video_comments_news_feed);
    }
    }
    }

videoFeed.xml

   <?xml version="1.0" encoding="utf-8"?>
   <androidx.constraintlayout.widget.ConstraintLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
   xmlns:tools="http://schemas.android.com/tools"
   android:layout_width="match_parent"
   android:layout_height="wrap_content">

   <de.hdodenhof.circleimageview.CircleImageView
    android:id="@+id/profile_video_image_news_feed"
    android:layout_width="@dimen/_40sdp"
    android:layout_height="@dimen/_40sdp"
    android:layout_margin="@dimen/_8sdp"
    android:src="@drawable/ic_profile"
    app:civ_border_color="@color/black"
    app:civ_border_width="@dimen/_1sdp"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

<TextView
    android:id="@+id/profile_video_name_news_feed"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginStart="@dimen/_8sdp"
    android:text="@string/app_name"
    android:textColor="@color/black"
    android:textSize="@dimen/_12ssp"
    app:layout_constraintBottom_toBottomOf="@id/profile_video_image_news_feed"
    app:layout_constraintStart_toEndOf="@id/profile_video_image_news_feed"
    app:layout_constraintTop_toTopOf="@id/profile_video_image_news_feed" />


<FrameLayout
    android:id="@+id/profile_video_video_news_feed"
    android:layout_width="match_parent"
    android:layout_height="@dimen/_300sdp"
    android:layout_marginTop="@dimen/_8sdp"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@id/profile_video_image_news_feed">

    <com.google.android.exoplayer2.ui.PlayerView
        android:id="@+id/item_video_exoplayer"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"

        app:layout_constraintTop_toTopOf="parent"
        app:resize_mode="fill"
        app:show_buffering="when_playing"
        app:surface_type="texture_view" />

    <!--  <ImageView
          android:id="@+id/img_vol"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:layout_gravity="right|bottom"
          android:layout_margin="8dp"
          android:src="@drawable/ic_unmute" />-->
</FrameLayout>

<ImageView
    android:id="@+id/profile_video_like_news_feed"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginStart="@dimen/_12sdp"
    android:layout_marginTop="@dimen/_12sdp"
    android:src="@drawable/ic_like"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@id/profile_video_video_news_feed"
    app:tint="@color/black" />

<ImageView
    android:id="@+id/profile_video_message_news_feed"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginStart="@dimen/_12sdp"
    android:layout_marginTop="@dimen/_12sdp"
    android:rotation="290"
    android:src="@drawable/ic_message"
    app:layout_constraintStart_toEndOf="@id/profile_video_like_news_feed"
    app:layout_constraintTop_toBottomOf="@id/profile_video_video_news_feed" />

<ImageView
    android:id="@+id/profile_video_share_news_feed"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginStart="@dimen/_12sdp"
    android:layout_marginTop="@dimen/_12sdp"
    android:src="@drawable/ic_send"
    app:layout_constraintStart_toEndOf="@id/profile_video_message_news_feed"
    app:layout_constraintTop_toBottomOf="@id/profile_video_video_news_feed" />

<TextView
    android:id="@+id/profile_video_like_count_news_feed"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginTop="@dimen/_8sdp"
    android:text="@string/profileCount"
    android:textColor="@color/black"
    android:textSize="@dimen/_11ssp"
    app:layout_constraintStart_toStartOf="@id/profile_video_like_news_feed"
    app:layout_constraintTop_toBottomOf="@id/profile_video_like_news_feed" />

<TextView
    android:id="@+id/profile_video_like_text_news_feed"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginStart="@dimen/_4sdp"
    android:text="@string/like"
    android:textColor="@color/black"
    android:textSize="@dimen/_11ssp"
    app:layout_constraintEnd_toEndOf="@id/profile_video_name_comment_news_feed"
    app:layout_constraintStart_toEndOf="@id/profile_video_like_count_news_feed"
    app:layout_constraintTop_toTopOf="@id/profile_video_like_count_news_feed" />

<TextView
    android:id="@+id/profile_video_name_comment_news_feed"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginTop="@dimen/_4sdp"
    android:text="@string/app_name"
    android:textColor="@color/black"
    android:textSize="@dimen/_11ssp"
    android:textStyle="bold"
    app:layout_constraintStart_toStartOf="@id/profile_video_like_count_news_feed"
    app:layout_constraintTop_toBottomOf="@id/profile_video_like_count_news_feed" />

<TextView
    android:id="@+id/profile_video_comments_news_feed"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:ellipsize="end"
    android:ems="19"
    android:justificationMode="inter_word"
    android:maxLines="2"
    android:text="@string/dummy_text"
    android:textColor="@color/text_color"
    android:textSize="@dimen/_11ssp"
    android:textStyle="normal"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toEndOf="@id/profile_video_name_comment_news_feed"
    app:layout_constraintTop_toTopOf="@id/profile_video_name_comment_news_feed"
    tools:ignore="UnusedAttribute" />

   </androidx.constraintlayout.widget.ConstraintLayout>


from Exoplayer in recyclerview with images and video like instagram but stop only last video other still playing after backpressed in android

Issue about the percentage of falling of height of Likelihood when I project the edge 1 C.L sigma joint distribution on the 1D Likelihood

  1. I have currently an issue about the height at which the projection of 1 sigma edges in 2D contour should intersect the associated Likelihood.

Here a figure (called "triplot") to illustrate my issue :

Issue of intersection on the likelihood

At bottom left is represented the joint distribution (shaded blue = contours at 2 sigma (95% C.L) and classic blue = contours at 1 sigma (68% C.L) of the 2 parameters considered (w0 and wa).

On the top is represented the normalized Likelihood of w0 parameter.

In all contours (with all triplot representing other parameters) and in all tripltot of thesis documents I have seen, the projection from the edge of 1 sigma contours on the likelihood intersects the likelihood at a height relatively low (on my scheme, roughly at 25%-30%, at first sight, of the maximum height of the likelihood).

However, a colleague told me that Likelihood should be intersected by the 1 sigma edge of joint distribution at roughly 70% of the maximum height of Likelihood (green bar and text on my figure)

For this, he justifies like this :

Concerning \Delta\chi2, distribution function is a \chi2 law with 2 freedom degrees ; pdf is written as :

f(delta(chi2))=1/2 exp^(-delta(chi2)/2)

So for a fixed confidence level C.L, we have :

1-CL=\int_{delta(chi2)_{CL}}^{+\infty}1/2 exp^(-delta(chi2)/2) d chi2

=exp^{-delta(chi2)_{CL}/2}`

and taking CL=0.68, we get :

delta(chi2)_{CL}=-2\ln(1-CL)

delta(chi2)_{CL}=2.28

And Finally, he concludes by saying that Maximum of Likelihood shoud fall from about 30% , i.e :

exp(-2.3/2) = 0.31 
  1. So I don't know why I get a falling of about 70% ~ (1-0.31) and not only of 31% ~ 0.3 like one says on my figure (red line on my figure above).

MOST RECENT EDIT IMPORTANT : I think my colleague is wrong since the 1 sigma on Gaussian Likelihood covers a larger 1 sigma than the projection of 1 C.L edges of 2D contours, so I think we can expect a max height for the intersection of exp(-2.28/2) ~ 0.32 ~ 30% and not a height of 70% : what do you think about this ?

ADDING FURTHER OLD DCUMENTATION : I tried below to give documentation and links to justify an intersection at 70% of the max height of Likelihood Gaussian but this statement seems to be wrong as indicated above in MOSST RECENT EDIT IMPORTANT.

ps1 : I give you a small tutorial about chi2 distribution and Likelihood for Fisher formalism Area of ellipse

ps2 : I have seen an ineresting remark on https://docs.scipy.org/doc//numpy-1.10.4/reference/generated/numpy.random.normal.html which suggests a maximum at 60.7% of the max, which is not really what I expect (~ 70%).

ps3 : I have also found another interesting page, maybe more important since it talks about multivariate distribution :

https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.multivariate_normal.html

  1. Here too, I give you what it seeems to me to be a justification of my reasoning :

Analytical justification

Any help is welcome.



from Issue about the percentage of falling of height of Likelihood when I project the edge 1 C.L sigma joint distribution on the 1D Likelihood

ReplaySubject it is not updating the array when new object is added Angular

I am dealing with an error which when I try to create new page Object, it send to backend but it is not updating the array, I need to reload the page to see the all the array.

I am using Observable within async in the frontend. I tried to console.log the ngOnInit of the page.component.ts but when I add new page and navigate to pages then the ngOnInit it isn't calling.

On Create new page it happens this. It sends me to the route of pages where there I show all the list of pages. But when I create new Page it is returningback an error which says. ERROR Error: Error trying to diff 'Here is the name of the object'. Only arrays and iterables are allowed.

Update: as Marco said this happens because I mix page as Object instead I am iterating through array But I am unable to resolve it and i need your help. In the page.service.ts at pageModel when I add new Object it is returning me only the added Object not the whole array and there is the problem I think, but I don't know how to fix. But If I reload page then I see all my Array.

This is my updated code.

This is my code.

  export class PagesService {
  public baseUrl = environment.backend;
  private data = new ReplaySubject<any>();
  public userID = this.authService.userID;
  public editDataDetails: any = [];
  public subject = new Subject<any>();
  private messageSource = new BehaviorSubject(this.editDataDetails);
  getPageID = this.messageSource.asObservable();

  constructor(private http: HttpClient, private authService: AuthService) { }

  public getPages() {
    return this.http.get<any>(`${this.baseUrl}/pages/${this.userID}`).subscribe(res => this.data.next(res));
  }
  public pageModel(): Observable<Page[]> {
    return this.data.asObservable(); // Here it throws error
  }
  public getPage(id): Observable<any> {
    return this.http.get(`${this.baseUrl}/page/${id}`);
  }

  public setPage(page: Page, id: string) {
    const api = `${this.baseUrl}/page`;
    const user_id = id;
    this.http.post<any>(api, page, {
      headers: { user_id }
    }).subscribe(res => this.data.next(res));
  }

  changeMessage(message: string) {
    this.messageSource.next(message)
  }

  public updateDate(id: string, page: Page) {
    const api = `${this.baseUrl}/page/${id}`;
    return this.http.put<any>(api, page).subscribe(res => this.data.next(res.data));
  }

Updated Code from Answer.

  public updateDate(id: string, page: Page) {
    const api = `${this.baseUrl}/page/${id}`;
    return this.http.put<any>(api, page).subscribe(res => {
      this.lastSetOfData = res;
      this.data.next(this.lastSetOfData);
    });
  }    
}




export class Page {
  _id = "";
  name = "";
  slogan = "";
  description = "";
  url = "";
  telephone: number;
  pageUrl: string;
  website: string;
  founded: number;
  organization: number;
  email: string;
  coverImage: string;
  profileImage: string;
  specialty?: Specialty[];
  branches: Branches[];
  locations?: Location[];
  phone?:Phone;
  userRole?: string;
  roles?: Roles[];
}
export class Roles {
  role= "";
  userID = "";
}

This is the HTML of page.component .

  <div class="main" *ngIf="!showWeb">
    <div *ngFor="let page of pages$ | async" class="card width-900">
      <app-pages-list class="d-flex width-900" [page]="page" [details]="'details'"></app-pages-list>
    </div>
    <div>
    </div>
  </div>

This is the TS file.

public pages$: Observable<Page[]>;
ngOnInit(): void {    
this.pageService.getPages();
this.pages$ = this.pageService.pageModel();
}

And this is the code when I create new Page.

  export class CreatePageComponent implements OnInit {
  public page = new Page();
  search;
  public branch = [];

  constructor(public router: Router,
    public branchesService: BranchesService,
    public authService: AuthService,
      public pageService: PagesService,
      public shareData: SenderService) { }

  ngOnInit(): void {
  }
  createPage() {
    this.page.url = this.page.name;
    this.page.branches = this.branch;
    this.page.locations = [];
    this.page.specialty = [];
    this.page.roles = [];
    this.page.phone = this.page.phone;
    this.page.pageUrl = `${this.page.name.replace(/\s/g, "")}${"-Page"}${Math.floor(Math.random() * 1000000000)}`;
    this.pageService.setPage(this.page, this.authService.userID);
  }
  addBranch(event) {
      this.branch.push(event);
      this.search = "";
  }
  removeBranch(index) {
      this.branch.splice(index, 1);
  }

}


from ReplaySubject it is not updating the array when new object is added Angular

How to use the PostGIS aggregate function ST_AsMVT with Django ORM

Problem

I would like to create a Mapbox vector tile (MVT) in Django, using the ORM. In SQL (PostgreSQL, PostGIS) the SQL query looks like this for the tile with zoom=8, x=137, y=83:

SELECT ST_AsMVT(tile)
FROM (SELECT id, ST_AsMVTGeom(geometry, ST_TileEnvelope(8, 137, 83)) AS "mvt_geom"
      FROM geomodel
      WHERE ST_Intersects(geometry, ST_TileEnvelope(8, 137, 83))
     ) AS tile;

ST_AsMVT aggregates all rows and the output is a binary Field (bytea) which can be sent as response.

As GeoDjango does not include the specific PostGIS functions I created custom functions for them:

class TileEnvelope(Func):
    function = "ST_TileEnvelope"
    arity = 3
    output_field = models.GeometryField()


class AsMVTGeom(GeoFunc):
    function = "ST_AsMVTGeom"
    arity = 2
    output_field = models.GeometryField()

I managed to create the inner subquery and it works:

tile_envelope = TileEnvelope(8, 137, 83)
tile_geometries = GeoModel.objects.filter(geometry__intersects=tile_envelope)
tile_geometries_mvt = tile_geometries.annotate(mvt_geom=AsMVTGeom("geometry", tile_envelope))
tile_geometries_mvt = tile_geometries_mvt.values("id", "mvt_geom")

print(tile_geometries_mvt)
>> <QuerySet [{'id': 165, 'mvt_geom': <Point object at 0x7f552f9d3490>}, {'id': 166, 'mvt_geom': <Point object at 0x7f552f9d3590>},...>

Now the last part is missing. I would like run ST_AsMVT on tile_geometries_mvt:

SELECT ST_AsMVT(tile)
FROM 'tile_geometries_mvt' AS tile;

Question

I tried to create a custom Aggregate function for ST_AsMVT, but was not successful. Normally aggregate functions like MAX, for example, expect one column as input, whereas ST_AsMVT expects an anyelement set row.

How can I turn ST_AsMVT into a Django Aggregate (similar to this SO question)?

I know, that I can use raw_sql queries in Django, but this question is explicitly about solving it with the Django ORM.



from How to use the PostGIS aggregate function ST_AsMVT with Django ORM

Prevent child component from unmounting and remounting if parent component changes

Problem:

In the code below, when the Toggle ParentA/B button is clicked, the <Child /> component will be unmounted and remounted again, only though effectively only the Parent component changed.

How do I prevent Child from unmounting and remounting in such a situation?

import React, { useState } from "react"

const App = () => {
    const [a, setA] = useState(true)
    return (
        <div>
            <button onClick={() => setA(!a)}>Toggle ParentA/B</button>
            {a ? <ParentA><Child /></ParentA> : <ParentB><Child /></ParentB>}
        </div>
    )
}
const ParentA = ({ children }) => <div>parentA{children}</div>
const ParentB = ({ children }) => <div>parentB{children}</div>

class Child extends React.Component {
    componentDidMount() {
        console.log('child did mount')
    }

    componentWillUnmount() {
        console.log('child will unmount')

    }

    render() {
        return (
            <div>child</div>
        )
    }

}

export default App

Replies to potential answers:

Why not just let the Child component remount since it's only a <div> element?

Normally this wouldn't matter if the Child component renders cheaply. However, in my case, the Child component takes very long to mount, so I cannot afford a remounting every time the Parent component changes.

You could pass the parentA or parentB string as props to a generic Parent component.

const App = () => {
    const [a, setA] = useState(true)
    return (
        <div>
            <button onClick={() => setA(!a)}>Toggle ParentA/B</button>
            <ParentGeneric content={a? 'parentA': 'parentB'}><Child /></ParentGeneric>
        </div>
    )
}
const ParentGeneric = ({children, content}) => <div>{content}{children}</div>

class Child extends React.Component {
    ...
}

This would work. Unfortunately, this restricts my Parent component's JSX structure to be identical. In other words, if my ParentA and ParentB's JSX structure were different, then I'm not sure how to pass the difference as props.

For example:

const ParentA = ({ children }) => <div><div><h1>parentA{children}</h1></div></div>
const ParentB = ({ children }) => <div>parentB{children}</div>

If parentA and parentB are defined this way, would it still be possible to abstract these two components into a ParentGeneric component and simply passing the structural difference between ParentA and ParentB as props?



from Prevent child component from unmounting and remounting if parent component changes