Wednesday, October 17, 2018

react-native-background-geolocation not giving exact location while app is in background

Leave a Comment

I have used mauron85/react-native-background-geolocation for tracking the location of the user on my react native app. It is working fine while the app is on fore ground. The location is exact on regular interval. But if the app goes to background, the location is not the same, rather is moved from the previous location even though the device is not moved. Following is my configuration -

BackgroundGeolocation.configure({     desiredAccuracy: BackgroundGeolocation.HIGH_ACCURACY,     notificationTitle: 'Background tracking',     notificationText: 'enabled',     debug: false,     startOnBoot: false,     stopOnTerminate: false,     locationProvider: BackgroundGeolocation.ACTIVITY_PROVIDER,     interval: 40000,     fastestInterval: 5000,     activitiesInterval: 10000,     stopOnStillActivity: false,     url: 'http://192.168.81.15:3000/location',     httpHeaders: {         'X-FOO': 'bar'     },     // customize post properties     postTemplate: {         lat: '@latitude',         lon: '@longitude',         foo: 'bar' // you can also add your own properties     } }); 

What should I do to fix this issue?

1 Answers

Answers 1

According the documentation, the location provider you are using BackgroundGeolocation.ACTIVITY_PROVIDER is better suited as a foreground location provider:

ACTIVITY_PROVIDER:

This one is best to use as foreground location provider (but works in background as well). It uses Android FusedLocationProviderApi and ActivityRecognitionApi for maximum battery saving.

So I would try to use DISTANCE_FILTER_PROVIDER instead:

BackgroundGeolocation.configure({      locationProvider: BackgroundGeolocation.DISTANCE_FILTER_PROVIDER }); 

This provider seems to be better suited to be used as a background location provider:

DISTANCE_FILTER_PROVIDER

It's best to use this one as background location provider. It is using Stationary API and elastic distance filter to achieve optimal battery and data usage.

Source:

https://github.com/mauron85/react-native-background-geolocation/blob/master/PROVIDERS.md

Read More

Rails Devise API - Login route responds with `You need to sign in or sign up before continuing.`

1 comment

I'm currently using Devise with my Rails API app to authenticate users using devise-jwt.

This is what my User model looks like:

class User < ApplicationRecord   devise :database_authenticatable,          :registerable,          :jwt_authenticatable,          jwt_revocation_strategy: JWTBlackList end 

And config/routes.rb is set up like this:

Rails.application.routes.draw do   devise_for :users,          path: '',          path_names: {            sign_in: 'login',            sign_out: 'logout',            registration: 'signup'          },          controllers: {            sessions: 'sessions',            registrations: 'registrations'          } end 

This is the sessions controller:

class SessionsController < Devise::SessionsController    private    def respond_with(resource, _opts = {})     render json: resource   end    def response_to_on_destroy     head :no_content   end end 

and the registrations controller:

class RegistrationsController < Devise::RegistrationsController   respond_to :json    def create     build_resource(sign_up_params)      resource.save     render_resource(resource)   end end 

I ran some Rspec tests shown below which were successful -

require 'rails_helper'  RSpec.describe SessionsController, type: :request do   let(:user) { create(:user) }   let(:url) { '/login' }   let(:params) do     {       user: {         email: user.email,         password: user.password       }     }   end    context 'when params are correct' do     before do       post url, params: params     end      it 'returns 200' do       expect(response).to have_http_status(200)     end      it 'returns JTW token in authorization header' do       expect(response.headers['Authorization']).to be_present     end      it 'returns valid JWT token' do       decoded_token = decoded_jwt_token_from_response(response)       expect(decoded_token.first['sub']).to be_present     end   end end 

But when I run the following POST request to /login on Postman I get the following message:

postman request

On the right hand side you are able to see the rails console and server, showing the credentials are correct, but still we get 401

Any clues on what might be wrong? It's been difficult finding good resources on Devise using Rails API.

Thank you in advance

1 Answers

Answers 1

After digging through the SessionsController I found the reason it returned 401: warden was trying to authenticate an empty body. Fixed this by added Content-Type to the request header

Read More

Calling multiple methods with same name using SoapClient

Leave a Comment

I have a SOAP webservice and in SOAP UI I see that there are methods with the same name. So, for example, there are 2 CreateNewContact methods, one of which takes 3 parameters and the other 4. Below are the stubs generated by SOAP UI

Method 1 Stub:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:rfp="http://test.com/testWebservice/">    <soapenv:Header/>    <soapenv:Body>       <rfp:CreateNewContact_FullName>          <!--Optional:-->          <rfp:fullName>?</rfp:fullName>          <!--Optional:-->          <rfp:email>?</rfp:email>          <!--Optional:-->          <rfp:telNo>?</rfp:telNo>       </rfp:CreateNewContact_FullName>    </soapenv:Body> </soapenv:Envelope> 

Method 2 Stub:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:rfp="http://test.com/testWebservice/">    <soapenv:Header/>    <soapenv:Body>       <rfp:CreateNewContact_FirstLastName>          <!--Optional:-->          <rfp:firstName>?</rfp:firstName>          <!--Optional:-->          <rfp:lastName>?</rfp:lastName>          <!--Optional:-->          <rfp:email>?</rfp:email>          <!--Optional:-->          <rfp:telNo>?</rfp:telNo>       </rfp:CreateNewContact_FirstLastName>    </soapenv:Body> </soapenv:Envelope> 

When I call the CreateNewContact method with 4 parameters using PHP SoapClient, it looks like I'm getting the response from the other method.

How can I specify which method to use using SoapClient?

Thanks,

2 Answers

Answers 1

As you can read here:

If you are using WSDL based SOAP requests and you have more than one operation in your binding (with the same parameters), make sure the style is set to rpc, NOT body! When you specify 'body' here, all that will be transmitted in the request is the parameters for the function call, and SoapServer->handle() will use the first function it finds with the same parameter-makeup to handle the call. The actual method to call will only be included in the request when your type is set to 'rpc', resulting in the expected behavior

Therefore, you should check in your WSDL the operation element, which provides binding information from the abstract operation to the concrete SOAP operation.
For example:

<definitions ....>;     <binding .... >;         <operation .... >;            <soap12:operation soapAction="xs:anyURI" ?                               soapActionRequired="xs:boolean" ?                               style="rpc|document" ?                               wsdl:required="xs:boolean" ? /> ?         </soap12:operation>     </binding>; </definitions> 

The style attribute value, if present, is a string that specifies the style for the operation. The style attribute indicates whether the operation is RPC-oriented (a messages containing parameters and return values) or document-oriented (a message containing documents). If the style attribute is omitted from the soap12:operation element, then the operation inherits the style specified or implied by the soap12:binding element in the containing wsdl:binding element.
So, in short, to solve your problem you should change the operation style from "document" to "rpc" in your WSDL.
As a further reference: https://bugs.php.net/bug.php?id=49169

Answers 2

I have faced the same with travelport universal API, I ended up modifying my local wsdl file to use different name for each method and it worked perfectly.

Read More

Android location manager error 'Exiting with error onLocationChanged line 152 “1”'

1 comment

I have a location manager in my Android app that sometimes works. Sometimes I'll run the app and it will get location updates (with some errors). Sometimes I'll run it and it will just throw this error every couple seconds without receiving any location updates:

E/IzatSvc_PassiveLocListener: Exiting with error onLocationChanged line 152 "1" 

Here is my class for managing location events:

package com.company.AppName;  import android.app.job.JobParameters; import android.app.job.JobService; import android.content.Context; import android.content.Intent; import android.location.Criteria; import android.location.Location; import android.location.LocationManager; import android.os.Bundle; import android.util.Log;  public class LocationListenerService extends JobService {   private static final String TAG = "LocationListenerService";   private LocationManager locationManager = null;   private LocationListener locationListener = null;   private String locationProvider = null;    public LocationListenerService() {}    @Override   public int onStartCommand(Intent intent, int flags, int startId) {     return START_STICKY;   }    @Override   public boolean onStartJob(JobParameters params) {     Log.i(TAG, "onStartJob");     startLocationManager(params);     return true;   }    @Override   public boolean onStopJob(JobParameters params) {     Log.i(TAG, "onStopJob");     return false;   }    public void startLocationManager(JobParameters params) {     if(locationManager != null) return;      Criteria criteria = new Criteria();     criteria.setAccuracy(Criteria.ACCURACY_FINE);   //    criteria.setPowerRequirement(Criteria.POWER_LOW);     criteria.setAltitudeRequired(false);     criteria.setBearingRequired(false);      locationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE);     locationProvider = locationManager.getBestProvider(criteria, true);     locationListener = new LocationListener();      if (locationProvider != null) {       Log.v(TAG, "Location provider: " + locationProvider);     } else {       Log.e(TAG, "Location provider is null. Location events will not work.");       return;     }      if (locationListener == null) {       Log.e(TAG, "Location listener is null. Location events will not work.");       return;     }      // Finish job after first time updating location with the server     NativeApp.shared().getLocationData((NativeApp app, String response) -> {       Log.i(TAG, "Received location data response. Finishing job.");       jobFinished(params, true);     });      try {       locationManager.requestLocationUpdates(locationProvider, 0, 0, locationListener);     } catch (java.lang.SecurityException ex) {       Log.e(TAG, "fail to request location update, ignore", ex);     } catch (IllegalArgumentException ex) {       Log.e(TAG, "network provider does not exist, " + ex.getMessage());     }   }    private class LocationListener implements android.location.LocationListener {     @Override     public void onLocationChanged(Location location) {       if(location == null) {         Log.w(TAG, "onLocationChanged skipped: null location");         return;       }       Log.i(TAG, "onLocationChanged: " + location.toString());       NativeApp.shared().updateLocation(location);     }      @Override     public void onProviderDisabled(String provider) {       Log.i(TAG, "onProviderDisabled: " + provider);     }      @Override     public void onProviderEnabled(String provider) {       Log.i(TAG, "onProviderEnabled: " + provider);     }      @Override     public void onStatusChanged(String provider, int status, Bundle extras) {       Log.i(TAG, "onStatusChanged: " + provider);     }   } } 

Why is this happening? Why do location updates work sometimes but not other times?

EDIT: After giving up for a few hours and rerunning, the app is still throwing the error repeatedly, but after about 10 seconds logs this and starts receiving location updates:

E/XTCC-6.1.2.10: [FDAL_OSListener] handleLocationUpdate:  failed: 2 D/LocationManagerService: incoming location: gps I/LgeGnssLocationProvider: Intent - android.location.GPS_FIX_CHANGE D/LgeGnssLocationProvider: GPS_FIX_CHANGE_ACTION! , mGpsNavigating =true D/LocationManagerService: incoming location: gps 

2 Answers

Answers 1

long milliseconds = 5000; // 5 seconds float minimusDistance = 5.5; // 5.5m distance from current location locationManager.requestLocationUpdates(locationProvider, milliseconds, minimusDistance, locationListener); 

Try this snippet. Hope it will solve your problem.

This is happening only, for this reason, you're not providing a minimum interval and minimum distance to get location updates. That's why you're getting this error.

Here is the link check it out - requestLocationUpdates

Answers 2

This location update gets varies as per the android version. Recently Android introduce background location limits in oreo which says:

While your app is in the foreground, you should receive location updates as frequently as you requested. When your app goes in the background, your app will receive location updates only a few times each hour (the location update interval may be adjusted in the future based on system impact and feedback from developers).

Android recommend to use fused location APIs for below reason, you must consider it for your scenario which says:

If your app needs access to location history that contains time-frequent updates, use the batched version of the Fused Location Provider API elements, such as the FusedLocationProviderApi interface. When your app is running in the background, this API receives the user's location more frequently than the non-batched API. Keep in mind, however, that your app still receives updates in batches only a few times each hour.

Please refer below links for and better approach:

https://github.com/googlesamples/android-play-location/tree/master/LocationUpdatesForegroundService/app

https://codelabs.developers.google.com/codelabs/background-location-updates-android-o/index.html#0

Note: The "O" background location limits only kick in when your app is no longer in the foreground.

Please let me know if above two links not working for you.

Read More

Move IIS Logs to AWS s3 bucket

Leave a Comment

I have a requirement to upload IIS logs 7 days older to AWS S3 Bukcet. By using below code I am able to access AWS folders under bucket

Import-Module "C:\Program Files (x86)\AWS Tools\PowerShell\AWSPowerShell\AWSPowerShell.psd1" $AKey = "" $SKey = "" $source = "C:\inetpub\logs\LogFiles\*" $outputpath = "C:\scripts\Logs\logs3.txt" Set-AWSCredentials -AccessKey $AKey -SecretKey $SKey  function Get-Subdirectories {     param  (         [string] $BucketName,         [string] $KeyPrefix,         [bool] $Recurse     )      @(Get-S3Object -BucketName $BucketName -KeyPrefix $KeyPrefix -Delimiter '/') | Out-Null      if ($AWSHistory.LastCommand.Responses.Last.CommonPrefixes.Count -eq 0) {         return     }      $AWSHistory.LastCommand.Responses.Last.CommonPrefixes      if ($Recurse) {         $AWSHistory.LastCommand.Responses.Last.CommonPrefixes | ForEach-Object { Get-Subdirectories -BucketName $BucketName -KeyPrefix $_ -Recurse $Recurse }     } }  function Get-S3Directories {     param  (         [string] $BucketName,         [bool] $Recurse = $false     )     Get-Subdirectories -BucketName $BucketName -KeyPrefix '/' -Recurse $Recurse  } 

Now if I type Get-S3Directories -BucketName backups I get the following output:

SERVER-xxx-OLogs/ SERVER-xxx-untime-logs / SERVER-xxx-FRLogs/ SERVER-oooooRLogs/ SERVER-IISLogFiles/ 

Now the challenge is I have to move IIS older than 7 days under SERVER-IISLogFiles/ Directory

So I have created this

$sfolder = Get-S3Directories -BucketName Backups Foreach ($folder in $sfolder) {     $wc = New-Object System.Net.WebClient      Set-AWSCredentials -AccessKey $AKey -SecretKey $SKey -StoreAs For_Move     Initialize-AWSDefaults -ProfileName For_Move -Region US-east-1      Start-Transcript -path $outputpath -Force     foreach ($i in Get-ChildItem $source -include *.log -recurse) {         if ($i.CreationTime -lt ($(Get-Date).AddDays(-7))) {             $fileName = (Get-ChildItem $i).Name             $parentFolderName = Split-Path (Split-Path $i -Parent) -Leaf             Write-S3Object -BucketName $folder -File $i         }     } } Stop-Transcript 

I am not entirely sure whether its going to move to SERVER-IISLogFiles/ Directory, not sure if I am missing anything here apart from this, I doubt its going to keep the folder structure of local IIS folder on IIS

1 Answers

Answers 1

UPDATE:

You could try and use the following method to create your folder structure within you S3 Bucket. Using the Key Prefix parameter and splitting your path to your folders should work.

$Params = @{     BucketName = 'backup'     Folder = '$Source or whatever path'     KeyPrefix = (Split-Path -Path 'C:\PATHTO\SOURCE\DIRECTORY' -Leaf).TrimEnd('\')     Recurse = $true     Region = 'REGION' } Write-S3Object @Params 
Read More

Tuesday, October 16, 2018

Hide Navigation Controller Search Bar & opened Large Title programmatically

Leave a Comment

I have a tableView. I set the all settings about searchController ( Search Bar in Large Navigation Bar ) - ( open / close when scroll tableview ). I implemented rightBarButtonItem which name is 'Close' . I want to hide/close tableView and Search Bar with programmatically. I can hide tableView but not SearchBar.

When I do isHidden for SearchBar , The Large Navigation Bar doesnt shrink to normal size.

Pic 1. Opened search bar with scroll down.

enter image description here

Pic 2. Not Hidden Large Navigation Bar with programmatically ( searchar.isHidden not implemented here )

enter image description here

Thanks in advance.

I tried this before but not run

tableView.setContentOffset(.zero, animated: false) navigationController?.navigationBar.prefersLargeTitles = false 

2 Answers

Answers 1

I tried to find a proper way to hide search bar, but I didn't find. But I found a workaround to hide your search bar which is change content offset your table view.

You may try this function to hide your table view and search bar.

func hide() {     tableView.isHidden = true     let point = tableView.contentOffset     let searchBarFrame = self.navigationItem.searchController?.searchBar.frame     let newPoint = CGPoint(x: point.x, y: point.y + searchBarFrame!.height)     tableView.setContentOffset(newPoint, animated: true) } 

Answers 2

Just try this:

 navigationItem.searchController = nil 

This is all my test code:

@IBOutlet weak var tableView: UITableView!  @IBOutlet weak var leftBarButtonItem: UIBarButtonItem!  var isHidden = false  var searchController: UISearchController {      let search = UISearchController(searchResultsController: nil)      search.searchBar.placeholder = "hello world"      search.obscuresBackgroundDuringPresentation = false      return search }   override func viewDidLoad() {     super.viewDidLoad()      self.navigationItem.title = "Test"      tableView.delegate = self      tableView.dataSource = self      showSearchController() }  @IBAction func isHiddenAction(_ sender: UIBarButtonItem) {     isHidden = !isHidden      self.tableView.isHidden = isHidden      if isHidden {         leftBarButtonItem.title = "Show"         hiddenSearchController()      } else {         leftBarButtonItem.title = "Hidden"         showSearchController()     } }  func hiddenSearchController() {     navigationItem.searchController = nil }  func showSearchController() {      navigationItem.searchController = searchController      navigationItem.hidesSearchBarWhenScrolling = true      definesPresentationContext = true } 

screenShots

Read More

Django: Sessions not working as expected on Heroku

Leave a Comment

Users keep getting logged out and sessions are not persisting on my Django app on Heroku. Users can log in, but they will be randomly logged out—even on the /admin/ site.

Is there anything I'm doing wrong with my Django/Heroku config?

Currently running Django 1.11.16 on Standard Dynos.

settings.py

SECRET_KEY = os.environ.get("SECRET_KEY", "".join(random.choice(string.printable) for i in range(40)))  SESSION_COOKIE_DOMAIN = ".appname.com" CSRF_COOKIE_DOMAIN = ".appname.com"  SECURE_SSL_REDIRECT = True  # ...  MIDDLEWARE_CLASSES = [     'django.middleware.security.SecurityMiddleware',     'django.contrib.sessions.middleware.SessionMiddleware',     'django.middleware.common.CommonMiddleware',     'django.middleware.csrf.CsrfViewMiddleware',     'django.contrib.auth.middleware.AuthenticationMiddleware',     'django.contrib.auth.middleware.SessionAuthenticationMiddleware',     'django.contrib.messages.middleware.MessageMiddleware',     'django.middleware.clickjacking.XFrameOptionsMiddleware', ]   TEMPLATES = [     {         'BACKEND': 'django.template.backends.django.DjangoTemplates',         'DIRS': [os.path.join(BASE_DIR, 'templates/')],         'APP_DIRS': True,         'OPTIONS': {             'context_processors': [                 'django.template.context_processors.debug',                 'django.template.context_processors.request',                 'django.template.context_processors.csrf',                 'django.contrib.auth.context_processors.auth',                 'django.contrib.messages.context_processors.messages',             ],         },     }, ]  # ...  DATABASES = {     'default': {         'ENGINE': 'django.db.backends.postgresql_psycopg2',         'NAME': 'appname',     } }  # https://devcenter.heroku.com/articles/python-concurrency-and-database-connections db_from_env = dj_database_url.config(conn_max_age=500) DATABASES['default'].update(db_from_env) 

1 Answers

Answers 1

The problem was that SECRET_KEY was not static on Heroku. The SECRET_KEY changing was breaking sessions. The fix is to add a static SECRET_KEY to Heroku config:

heroku config:set SECRET_KEY=`openssl rand -base64 32` 
Read More

How to connect two random people in a single thread using Laravel Broadcasting

Leave a Comment

I'm creating a random real-time chat, like Omegle.

I'm having trouble to connect two random people in a private thread using a wait list. What would be the best way to do it using Laravel Broadcasting and Laravel Job?

For example:

Route::get('/start', function () {     // add me to the wait list     // wait for another person     // find another person     // remove me and another person from the wait list      // dispatch event     App\Events\AnotherPersonFound::dispatch($anotherPerson, $threadId); }); 

0 Answers

Read More

Call to undefined function Illuminate\Filesystem\finfo_file()

Leave a Comment

I have the following error showing up in my laravel.log file on a website I have running. How can I pin down where the error originates from? As the stack trace is so short I am unsure where to start.

[2017-07-03 16:05:13] production.ERROR: exception 'Symfony\Component\Debug\Exception\FatalErrorException' with message 'Call to undefined function Illuminate\Filesystem\finfo_file()' in /home/uksacbor/laravel-projects/attestation/vendor/laravel/framework/src/Illuminate/Filesystem/Filesystem.php:254 Stack trace: #0 {main}

I've ran a search on the site's folder using sublime's global search for when finfo_file() is used and I've used it in a helper in a test...

private function prepareFileUpload($path, $name) {     TestCase::assertFileExists($path);      $pathInfo = pathinfo($path);      $copyPath = $pathInfo['dirname'] . $pathInfo['filename'] . '_copy' . $pathInfo['extension'];      \File::copy($path, $copyPath);      $finfo = finfo_open(FILEINFO_MIME_TYPE);      $mime = finfo_file($finfo, $copyPath);      return new \Illuminate\Http\UploadedFile($copyPath, $name, $mime, filesize($copyPath), null, true); } 

Currently, my tests are all passing.

Any ideas?

5 Answers

Answers 1

As Michael Hamisi said, it's a method that is declared by a PECL PHP Extension named fileinfo that is commonly present on PHP installations.

it is used in Laravel to get information about files especially in upload cases.

you should check that the extension is enabled on your installations. usually, when you do composer install, an error will be triggered telling you to activated the missing extension.

/**  * (PHP >= 5.3.0, PECL fileinfo >= 0.1.0)  * Return information about a file  * @link http://php.net/manual/en/function.finfo-file.php 

Answers 2

When you are managing the server yourself you should run

sudo pecl install fileinfo 

from the commandline and edit php.ini (probably located at /etc/php.ini)

to contain the line

extension=fileinfo.so

don't forget to restart the web server. Depending on your os and web stack this is something like

  • service apache restart
  • service httd restart
  • service nginx restart

When using a shared hosting, you probably have an option in the webinterface to enable it from there. For example in directadmin

Advanced features > Select PHP version

enter image description here

And then

Tick the checkbox next to fileinfo

enter image description here

Don't forget to click save

Answers 3

You are supposed to activate finfo_file()

[check this link]

Answers 4

As others have already pointed out how to fix the error itself I'm going to answer your question about how you can find out where the error originates from.

The error message tells us that you are not calling finfo_file() directly but that you are calling a method of Illuminate/Filesystem/Filesystem which uses it at line 254. So you need to search for where you are using this method from Illuminate/Filesystem/Filesystem.

If you are not using this method directly you could be using it indirectly through a dependency of yours. In this case you would need to search in your vendor directory for the usage of the method from Illuminate/Filesystem/Filesystem.

Answers 5

You need to enable fileinfo extension.

please refer to this : https://stackoverflow.com/a/24565508/7171624

Read More

Improving Postgres performance on graph-like queries of multi-level self-joins (comparison to Neo4j)

Leave a Comment

One of the claims Neo4j makes in their marketing is that relational databases aren't good at doing multi-level self-join queries:

enter image description here

I found the code repository corresponding to the book that claim is taken from, and translated it to Postgres:

CREATE TABLE t_user (   id bigserial PRIMARY KEY,   name text NOT NULL );  CREATE TABLE t_user_friend (   id bigserial PRIMARY KEY,   user_1 bigint NOT NULL REFERENCES t_user,   user_2 bigint NOT NULL REFERENCES t_user );  CREATE INDEX idx_user_friend_user_1 ON t_user_friend (user_1); CREATE INDEX idx_user_friend_user_2 ON t_user_friend (user_2);  /* Create 1M users, each getting a random 10-character name */ INSERT INTO t_user (id, name)   SELECT x.id, substr(md5(random()::text), 0, 10)   FROM generate_series(1,1000000) AS x(id);  /* For each user, create 50 random friendships for a total of 50M friendship records */ INSERT INTO t_user_friend (user_1, user_2)   SELECT g1.x AS user_1, (1 + (random() * 999999)) :: int AS user_2   FROM generate_series(1, 1000000) as g1(x), generate_series(1, 50) as g2(y); 

And these are the queries at various depths Neo4j is comparing against:

/* Depth 2 */  SELECT   COUNT(DISTINCT f2.user_2) AS cnt  FROM   t_user_friend f1    INNER JOIN     t_user_friend f2      ON f1.user_2 = f2.user_1  WHERE   f1.user_1 = 1;  /* Depth 3 */  SELECT   COUNT(DISTINCT f3.user_2) AS cnt  FROM   t_user_friend f1    INNER JOIN     t_user_friend f2      ON f1.user_2 = f2.user_1    INNER JOIN     t_user_friend f3      ON f2.user_2 = f3.user_1  WHERE   f1.user_1 = 1;  /* Depth 4 */  SELECT   COUNT(DISTINCT f4.user_2) AS cnt  FROM   t_user_friend f1    INNER JOIN     t_user_friend f2      ON f1.user_2 = f2.user_1    INNER JOIN     t_user_friend f3      ON f2.user_2 = f3.user_1    INNER JOIN     t_user_friend f4      ON f3.user_2 = f4.user_1  WHERE   f1.user_1 = 1;  /* Depth 5 */  SELECT   COUNT(DISTINCT f5.user_2) AS cnt  FROM   t_user_friend f1    INNER JOIN     t_user_friend f2      ON f1.user_2 = f2.user_1    INNER JOIN     t_user_friend f3      ON f2.user_2 = f3.user_1    INNER JOIN     t_user_friend f4      ON f3.user_2 = f4.user_1    INNER JOIN     t_user_friend f5      ON f4.user_2 = f5.user_1  WHERE   f1.user_1 = 1; 

I was roughly able to reproduce the book's claimed results, getting these sorts of execution times against the 1M users, 50M friendships:

| Depth | Count(*) | Time (s) | |-------|----------|----------| | 2     | 2497     | 0.067    | | 3     | 117301   | 0.118    | | 4     | 997246   | 8.409    | | 5     | 999999   | 214.56   | 

(Here's an EXPLAIN ANALYZE of a depth 5 query)

My question is, is there a way to improve the performance of these queries to meet or exceed Neo4j's execution time of ~2s at depth level 5?

I tried with this recursive CTE:

WITH RECURSIVE chain(user_2, depth) AS (   SELECT t.user_2, 1 as depth   FROM t_user_friend t   WHERE t.user_1 = 1 UNION   SELECT t.user_2, c.depth + 1 as depth   FROM t_user_friend t, chain c   WHERE t.user_1 = c.user_2   AND depth < 4 ) SELECT COUNT(*) FROM (SELECT DISTINCT user_2 FROM chain) AS temp; 

However it's still pretty slow, with a depth 4 taking 5s and a depth 5 taking 48s (EXPLAIN ANALYZE)

1 Answers

Answers 1

I'd like to note from the start that comparing relational and non-relation databases are not like-for-like comparison.

It is likely that non-relation database maintains some extra pre-calculated structures as the data is updated. This makes updates somewhat slower and requires more disk space. Pure relational schema that you use don't have anything extra, which makes updates as fast as possible and keeps disk usage to the minimum.

I'll focus on what could be done with the given schema.


At first I'd make a composite index

CREATE INDEX idx_user_friend_user_12 ON t_user_friend (user_1, user_2); 

One such index should be enough.

Then, we know that there are only 1M users in total, so final result can't be more than 1M.

The 5-level query ends up generating 312.5M rows (50*50*50*50*50). This is way more than maximum possible result, which means that there are a lot of duplicates.

So, I'd try to materialize intermediate results and eliminate duplicates early in the process.

We know that Postgres materializes CTEs, so I'd try to use that.

Something like this:

WITH CTE12 AS (     SELECT         DISTINCT f2.user_2     FROM         t_user_friend f1          INNER JOIN t_user_friend f2 ON f1.user_2 = f2.user_1     WHERE         f1.user_1 = 1 ) ,CTE3 AS (     SELECT         DISTINCT f3.user_2     FROM         CTE12         INNER JOIN t_user_friend f3 ON CTE12.user_2 = f3.user_1 ) ,CTE4 AS (     SELECT         DISTINCT f4.user_2     FROM         CTE3         INNER JOIN t_user_friend f4 ON CTE3.user_2 = f4.user_1 ) SELECT     COUNT(DISTINCT f5.user_2) AS cnt FROM     CTE4     INNER JOIN t_user_friend f5 ON CTE4.user_2 = f5.user_1 ; 

Most likely SELECT DISTINCT would require sorts, which would allow to use merge joins.


As far as I could understand from the execution plan for the query above https://explain.depesz.com/s/Sjov , Postgres is not smart enough and does some unnecessary sorts. Also, it uses hash aggregate for some SELECT DISTINCT, which requires extra sort.

So, the next attempt would be to use temporary tables with proper indexes for each step explicitly.

Also, I'd define the idx_user_friend_user_12 index as unique. It may provide an extra hint to optimizer.

It would be interesting to see how the following performs.

CREATE TABLE temp12 (     user_2 bigint NOT NULL PRIMARY KEY ); CREATE TABLE temp3 (     user_2 bigint NOT NULL PRIMARY KEY ); CREATE TABLE temp4 (     user_2 bigint NOT NULL PRIMARY KEY );  INSERT INTO temp12(user_2) SELECT     DISTINCT f2.user_2 FROM     t_user_friend f1      INNER JOIN t_user_friend f2 ON f1.user_2 = f2.user_1 WHERE     f1.user_1 = 1 ;  INSERT INTO temp3(user_2) SELECT     DISTINCT f3.user_2 FROM     temp12     INNER JOIN t_user_friend f3 ON temp12.user_2 = f3.user_1 ;  INSERT INTO temp4(user_2) SELECT     DISTINCT f4.user_2 FROM     temp3     INNER JOIN t_user_friend f4 ON temp3.user_2 = f4.user_1 ;  SELECT     COUNT(DISTINCT f5.user_2) AS cnt FROM     temp4     INNER JOIN t_user_friend f5 ON temp4.user_2 = f5.user_1 ;  DROP TABLE temp12; DROP TABLE temp3; DROP TABLE temp4; 

As an added bonus of explicit temp tables you can measure how much time each extra level takes.

Read More

Constant Validation Accuracy with a high loss in machine learning

Leave a Comment

I'm currently trying to do create an image classification model using Inception V3 with 2 classes. I have 1428 images which are balanced about 70/30. When I run my model I get a pretty high loss of as well as a constant validation accuracy. What might be causing this constant value?

data = np.array(data, dtype="float")/255.0 labels = np.array(labels,dtype ="uint8")  (trainX, testX, trainY, testY) = train_test_split(                             data,labels,                              test_size=0.2,                              random_state=42)   img_width, img_height = 320, 320 #InceptionV3 size  train_samples =  1145  validation_samples = 287 epochs = 20  batch_size = 32  base_model = keras.applications.InceptionV3(         weights ='imagenet',         include_top=False,          input_shape = (img_width,img_height,3))  model_top = keras.models.Sequential() model_top.add(keras.layers.GlobalAveragePooling2D(input_shape=base_model.output_shape[1:], data_format=None)), model_top.add(keras.layers.Dense(350,activation='relu')) model_top.add(keras.layers.Dropout(0.2)) model_top.add(keras.layers.Dense(1,activation = 'sigmoid')) model = keras.models.Model(inputs = base_model.input, outputs = model_top(base_model.output))   for layer in model.layers[:30]:   layer.trainable = False  model.compile(optimizer = keras.optimizers.Adam(                     lr=0.00001,                     beta_1=0.9,                     beta_2=0.999,                     epsilon=1e-08),                     loss='binary_crossentropy',                     metrics=['accuracy'])  #Image Processing and Augmentation  train_datagen = keras.preprocessing.image.ImageDataGenerator(           zoom_range = 0.05,           #width_shift_range = 0.05,            height_shift_range = 0.05,           horizontal_flip = True,           vertical_flip = True,           fill_mode ='nearest')   val_datagen = keras.preprocessing.image.ImageDataGenerator()   train_generator = train_datagen.flow(         trainX,          trainY,         batch_size=batch_size,         shuffle=True)  validation_generator = val_datagen.flow(                 testX,                 testY,                 batch_size=batch_size)  history = model.fit_generator(     train_generator,      steps_per_epoch = train_samples//batch_size,     epochs = epochs,      validation_data = validation_generator,      validation_steps = validation_samples//batch_size,     callbacks = [ModelCheckpoint]) 

This is my log when I run my model:

Epoch 1/20 35/35 [==============================]35/35[==============================] - 52s 1s/step - loss: 0.6347 - acc: 0.6830 - val_loss: 0.6237 - val_acc: 0.6875  Epoch 2/20 35/35 [==============================]35/35 [==============================] - 14s 411ms/step - loss: 0.6364 - acc: 0.6756 - val_loss: 0.6265 - val_acc: 0.6875  Epoch 3/20 35/35 [==============================]35/35 [==============================] - 14s 411ms/step - loss: 0.6420 - acc: 0.6743 - val_loss: 0.6254 - val_acc: 0.6875  Epoch 4/20 35/35 [==============================]35/35 [==============================] - 14s 414ms/step - loss: 0.6365 - acc: 0.6851 - val_loss: 0.6289 - val_acc: 0.6875  Epoch 5/20 35/35 [==============================]35/35 [==============================] - 14s 411ms/step - loss: 0.6359 - acc: 0.6727 - val_loss: 0.6244 - val_acc: 0.6875  Epoch 6/20 35/35 [==============================]35/35 [==============================] - 15s 415ms/step - loss: 0.6342 - acc: 0.6862 - val_loss: 0.6243 - val_acc: 0.6875 

2 Answers

Answers 1

I think you have too low learning rate and too few epochs. try with lr = 0.001 and epochs = 100.

Answers 2

Your accuracy is 68.25%. Given that your classes are split roughly 70/30 it is likely that your model is just predicting the same thing every time, ignoring the input. That would give the accuracy you are seeing. Your model has not yet learned from your data.

As Novak said, your learning rate seems very low, so maybe try increasing that first to see if that helps.

Read More

VBA, Date formatting issue

Leave a Comment

I have a code that

1) compares dates from Col X to Col Y.

2)paste dates to col Y if there is no match between columns.

Column X my format looks like

08/15/2013 09/12/2013 10/03/2013 

But when it pastes to column Y it goes,

15/08/2013 12/09/2013 03/10/2013 

How can I format my paste to go to dd/mm/yyyy.

Added more code to show array:

   ReDim PasteArr(1 To 1, 1 To 6)     subcount = 1      For Cell1 = 1 To UBound(DataArr(), 1)         For Each Cell2 In BusDates()             If DataArr(Cell1, 1) Like Cell2 Then                 Matched = True                 Exit For                                      'if it matches it will exit             ElseIf Cell2 Like BusDates(UBound(BusDates), 1) Then 'if it gets to the end, it's truly unique and needs to be added                  For index = 1 To 6                     PasteArr(subcount, index) = DataArr(Cell1, index)                 Next index                  subcount = subcount + 1                  PasteArr = Application.Transpose(PasteArr)                 ReDim Preserve PasteArr(1 To 6, 1 To subcount)                 PasteArr = Application.Transpose(PasteArr)                  Matched = False              End If         Next Cell2          If Matched = False Then             BusDates = Application.Transpose(BusDates)             ReDim Preserve BusDates(1 To UBound(BusDates) + 1)             BusDates = Application.Transpose(BusDates)             BusDates(UBound(BusDates), 1) = DataArr(Cell1, 1)         End If      Next Cell1     Worksheets("stacks").Range("M" & LastRow + 1 & ":" & Cells(LastRow + UBound(PasteArr, 1) - 1, 18).Address).Value = PasteArr 

What i've tried: Changing the format of cells

enter image description here

15/08/2013 12/09/2013 03/10/2013 

which is now the correct format for column X.

But this is pasting into column Y as:

enter image description here

which is

15/08/2013 - correct 09/12/2013 - incorrect 10/03/2013 - incorrect. 

4 Answers

Answers 1

Check your cell format. It should be:

Number   Custom     dd/mm/yyyy (depending on your locale, in my case (Dutch) it's dd/mm/jjjj) 

Answers 2

Use dd/MM/yyyy as cell format. Lowercase m stands for minutes, uppercase M for months.

Answers 3

Per my comment above, given you're using arrays and not copying ranges/cells directly. If your arrays are declared as string arrays, you will get the issue of transposed days/months. For example:

enter image description here

Could that be the issue?

Answers 4

I live in Portugal and sometimes I have issues of the same nature regarding the date formatting options. Usually, what I do (and normally it works), is using and abusing of the DateSerial function. For instance, if I wanted to populate your PasteArr array I would do:

PasteArr(subcount, index) = DateSerial(Year(DataArr(Cell1, index)), Month(DataArr(Cell1, index)), Day(DataArr(Cell1, index))) 

To write a date on a cell I do the following:

Worksheets("stacks").cells("M" & LastRow + 1).formulaR1C1 = DateSerial(Year(PasteArr(subcount, index)), Month(PasteArr(subcount, index)), Day(PasteArr(subcount, index))) 

Honesty the previous procedure seems a little bit silly. Really, it does! However it solves the problem with the date formatting dd/mm/yyyy vs mm/dd/yyyy problem. If you ask me why, I don't know exactly how it works! But it works every time!

Read More

componentOne windows flexgrid automation using CodedUI C#

Leave a Comment

I have only compiled exe application which i need to automate. It has c1.win.c1flexgrid of ComponentOne as Grid. I am using CodedUI to automate this application.

When using Coded UI Record & Playback, it do not highlight or find any row or column but only outer body of this flexgrid which is grid name. If i try to get its children, it return zero whereas, i can see there are lot of rows and columns in this FlexGrid.

I tried to get current patterns of this control using AutomationElement object and it returned me following two patterns as mentioned below.

It has only two patterns implemented.

  1. LegacyIAccessiblePatternIdentifiers.Pattern
  2. ScrollPatternIdentifiers.Pattern

I would like to know how i can automate this type of grid which do not have implemented any other automation pattern and is third party control.

I will be thankful to you if you can share sample or directions.

Regards,

0 Answers

Read More

Monday, October 15, 2018

Google Play and Launcher launched separated activities

Leave a Comment

Let's say I have a simple app, with a SplashScreenActivity and a MainActivity.
Below is part of my AndroidManifest.xml:

    <activity         android:name=".front.activities.splashscreen.SplashScreenActivity"         android:launchMode="standard"         android:screenOrientation="portrait"         android:theme="@style/SplashTheme">         <intent-filter>             <action android:name="android.intent.action.MAIN" />              <category android:name="android.intent.category.LAUNCHER" />         </intent-filter>     </activity>     <activity         android:name=".front.activities.main.MainActivity"         android:configChanges="keyboardHidden|orientation|screenSize"         android:label="@string/Main_Title"         android:launchMode="singleTop"         android:screenOrientation="portrait"/> 

And my SplashScreenActivity opens MainActivity in onCreate().

The Problem

If the app is launched from Google Play instead of launcher, if I pressed home and click the app icon in the launcher, one more SplashScreenActivity is launched again and therefore one more MainActivity on the backstack.

Steps to reproduce

  1. Kill the app if it is opened.
  2. Open the app from Google Play.
  3. Press Home button
  4. Open the app from launcher. You will know notice that SplashScreenActivity has been launched again (Or by looking at logs)
  5. Repeat step 3-4. Each time you repeat, one more SplashScreenActivity and MainActivity is launched.

After several trials, if we press back button, we will notice that there are multiple MainActivity in the back stack.

More information

  1. If the app is not started from Google Play, but from launcher at the very first time (step 2), this cannot be reproduced.
  2. Not only Google play, but any other app that sends an intent to start the app can reproduce this.
  3. If I first launch from launcher, and then from Google Play, 2 SplashScreenActivity will be launched. But if I press app icon from launcher again, it will not create a 3rd SplashScreenActivity. It will bring the first launched MainActivity to the top.

What have I tried

  1. Make SplashScreenActivity to android:launchMode="singleTask". Does not help.
  2. Make MainActivity to android:launchMode="singleTask". This will prevent multiple MainActivity from being created, but does not solve the problem of starting SplashScreenActivity multiple times. You may also assume MainActivity should not be set to singleTask.

What I expected

By clicking on the app icon in the launcher, Android should be able to find out that in my task manager, the app is already launched and will simply bring it to the top.

How can I fix this?

2 Answers

Answers 1

Some launchers have this bug: when app is started from home screen, new instance of initial activity is created instead of resuming the app. It can be fixed by adding

if (!isTaskRoot()) {     finish();     return; } 

to onCreate() of the initial activity. See also:

Resume last activity when launcher icon is clicked,

Resume the Top Activity instead of starting the Launcher Activity

Answers 2

add android:noHistory="true"

tag to splash screen activity. It always populates one instance and it is not stored in the back stack as well.

Read More

Remove one of the two play button on google drive iframe embed

Leave a Comment

Can anybody help me on this, when I embed a google drive video using an iframe it has two play button, how to remove one of this? This happens only in Chrome and Safari so please test it on those browsers.

<iframe src="https://drive.google.com/file/d/1mNaIx2U3m7zL9FW-wksaI1m_rL5Oh47v/preview" width="400" height="300" allowfullscreen="true"></iframe> 

As you can see on the iframe that you have to click the play button twice.

Also I cannot use html5 player since most of the videos are large.

here is my fiddle https://jsfiddle.net/1tav74q8/

2 Answers

Answers 1

As far as i am aware of you can not edit iframe content which does not originate on your own server. But i am not sure..

Check this post for a sample

Courseweb

Stackoverflow

Also interesting from this link:

stackoverflow

  1. Get the unique video identifier (0B6VvIWR7judDX25yUGxVNERWUj)
  2. Put into this html:

Answers 2

If your iframe and the host have the same origin (domain), interaction between them is easy, simply access the document object to get the element. Example using jQuery:

  • To hide a button on host element from iframe, use:
    window.parent.jQuery('button').hide().
  • To hide a button on iframe element from host, use:
    jQuery('iframe')[0].contentWindow.jQuery('button').hide()

HOWEVER, if the host and the iframe doesn't have same origin, interaction between each of them are strictly limited. you cannot instruct certain operation directly from the host to the iframe's javascript window or document, and vice versa. And from that, it's safe to say that accessing directly the iframe's DOM element from the host is definitely impossible.

Explanation about Cross-origin script API accessSection from MDN.

JavaScript APIs such as iframe.contentWindow, window.parent, window.open and window.opener allow documents to directly reference each other. When the two documents do not have the same origin, these references provide very limited access to Window and Location objects, as described in the next two sections.

To communicate further between documents from different origins, use window.postMessage.

You can use the window.postMessage function and "message" event listener, to send and receive a message between host and iframe (and vice versa). In your case you would need to sent a message from host to instruct the iframe to hide a button. Then on the receiver end (iframe), get the desired button then hide it. But this technique only works if you own those two origin, you need to declare the "message" event on the iframe end, and since your iframe source is drive.google.com which I assume you are not the owner, then it's definitely impossible.

More explanation: https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage

Read More

How to ignore the specific CSS codes coming from the WordPress plugin stylesheet?

Leave a Comment

I am working on a WordPress website built on custom theme in which I want to ignore some specific CSS codes coming from wordpress plugin style sheet.

Here is the link for that wordpress plugin style sheet.

The CSS codes from the above Wordpress plugin style sheet which I want to ignore is:

@media screen and (max-width: 575.98px) .gv-table-view tr:first-of-type {     border-top: 1px solid #ccc; }  @media screen and (max-width: 575.98px) .gv-table-view tr {     display: block;     position: relative;     padding: 1.2em 0;     overflow-x: auto; }   .gv-table-view th, .gv-table-view td {         padding: .3em;     }   @media screen and (max-width: 575.98px) .gv-table-view tr td {     display: table-row; }  @media screen and (max-width: 575.98px) .gv-table-view tr td:before {     content: attr(data-label);     font-weight: bold;     display: table-cell;     padding: 0.2em 0.6em 0.2em 0;     text-align: right;     width: 40%; } 


Problem Statement:

I want to ignore the above CSS codes in the mobile version of the following website url which is coming from wordpress plugin style-sheet. I am wondering where I need to go in my wordpress website in order to achieve that ?

If I take the above url in the mobile view, we can see the CSS codes mentioned above the problem statement.

8 Answers

Answers 1

You can't exactly ignore a stylesheet that comes with a plugin that you wish to use. You could try overwriting the plugins stylesheet with your own styles, but if you plan to update that plugin it could cause trouble.

A lot of people have been stating to use important and I wouldn't do that. You should leverage CSS cascading ability and write your own css reset for those classes:

A CSS Reset is a short, often compressed (minified) set of CSS rules that resets the styling of all HTML elements to a consistent baseline.

What you would need to do is change the style you want to change and reset the styles you don't, but you must implement these changes after the original style occurs to leverage CSS cascading ability. For example:

Reset Method

//Original @media screen and (max-width: 575.98px) .gv-table-view tr:first-of-type {     border-top: 1px solid #ccc; } //Reset must come after the plugins original style @media screen and (max-width: 575.98px) .gv-table-view tr:first-of-type {     border-top: none; } 

Make sure the stylesheet you're using to reset the plugins styles comes/loads after the plugins stylesheet.

It is only when you can't reset, or override a style through CSS cascading nature you should use important. More on that here.

In your <head> make sure your style.css folder is coming after the gravity views plugin stylesheet

Your Current Head

<head>     <link rel="stylesheet" id="twentysixteen-style-css" href="http://test.caubo.ca/wp-content/themes/caubo/style.css?ver=4.9.8" type="text/css" media="all">      <link rel="stylesheet" id="gravityview_font-css" href="http://test.caubo.ca/wp-content/plugins/gravityview/assets/css/font.css?ver=2.1.0.3" type="text/css" media="all"> </head> 

What it needs to look like

<head>     <link rel="stylesheet" id="gravityview_font-css" href="http://test.caubo.ca/wp-content/plugins/gravityview/assets/css/font.css?ver=2.1.0.3" type="text/css" media="all">      <link rel="stylesheet" id="twentysixteen-style-css" href="http://test.caubo.ca/wp-content/themes/caubo/style.css?ver=4.9.8" type="text/css" media="all"> </head> 

You can give your stylesheets priority in your functions.php file. For more information please check here.

Answers 2

I'd say you should check the handle of the plugin's stylesheet. Look into the wp_enqueue_style part and find out that handle, and then add your own styleshet AFTER that handle by using that handle as a dependency. For example, put this in your theme's function.php:

wp_enqueue_style( 'your_own_handle', 'path/to/your/overwrite_stylesheet.css', array('handle_of_plugin1','handle_of_plugin2')) 

With that done, you could overwrite all the plugin css either in whole or in parts.

Answers 3

To overwriting the plugin CSS you can use !important; for particular class

@media screen and (max-width: 575.98px) .gv-table-view tr:first-of-type { border-top: 10px solid #000000!important; } 

If their available id it that div you can use id rather than !important; and it will work if The developer of the plugin was not using !important throughout the plugin CSS

Answers 4

Override the rule in your Custom stylesheet and set properties to !important tag. Or override the rule on bottom of stylesheet file. Because is a cascading style and last properties executed that stay

.example{    Width:300px !important! } 

Answers 5

This could be done with the help of javascript also, but you could override the WP theme also using the appropriate media queries for the mobile version that adds those classes.

function isMobile() {    if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|ipad|iris|kindle|Android|Silk|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(navigator.userAgent) || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(navigator.userAgent.substr(0,4))) {          return true;      } else {          return false;      }   }      if(isMobile()) {   let matches = document.querySelectorAll(".mobile");   matches.forEach(function(item) {   if(item.classList.contains('mobile')) {   item.classList.remove('mobile')   }   });   }   
.mobile {  font-style:italic;  text-transform: uppercase;  color: red;  }  p {  font-style:normal;  text-transform: capitalize;  color: blue;  }
<p class="mobile">Lorem ipsum dolor sit amet...</p>

You may check this in jsFiddle

Answers 6

Your additional CSS has still got priority but the plugin stylesheet (/plugins/gravityview/templates/css/table-view.css I guess) classes are more specific and therefore win, for example:

.gv-table-view tr td from the plugin wins over your .gv-container-2777 td you could just copy their css or change yours to be more specific e.g .gv-container-2777 tr td

Answers 7

Have you checked where is the wp_enqueue_style() in the plugin for the table-view.css style sheet is?

I would first locate the wp_enqueue_style() in the plugin itself to locate the handle script. Let's say the enqueue in the plugin is as follows:

wp_enqueue_style('gravityview_style_default_table', 'path-to-file.css', [], '2.1.0.3'); 

In your theme than you would need to wp_deregister_style() refering to the same handle, and create a new stylesheet 'gavityview-style.css' in your theme with the css you want from that plugin stylesheet as follows:

function manage_theme_styles() {   wp_deregister_style( 'gravityview_style_default_table',);    wp_enqueue_script( 'my-gravityview-style', get_template_directory_uri() . '/gavityview-style.css', array(), '1.0.0', true ); } add_action( 'wp_enqueue_scripts', 'wpdocs_theme_name_scripts', 99 ); 

Having said that every time you update the plugin you have to check the plugin's css and update your stylesheet with any changes made to the plugin. But since you are dealing with a plugin you have to check your css even if you choose to tackle your problem with other solutions.

Answers 8

You can achieve this in 2 ways.

Solution 1: All good plugins will define CSS handle for each of their CSS and its gravityview_style_default_table in your case. Just add the function given below in your theme's 'functions.php' to remove the particular CSS. Please note that this will remove the entire CSS and not the 'media queries' alone. You can then add the required CSS classes to your theme's stylesheet.

function remove_gravityview_table_style() {     //check if mobile device     $useragent=$_SERVER['HTTP_USER_AGENT'];     if(preg_match('/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i',$useragent)||preg_match('/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i',substr($useragent,0,4))) {         //remove css         wp_dequeue_style('gravityview_style_default_table');         wp_deregister_style('gravityview_style_default_table');     } } add_action('wp_print_styles', 'remove_gravityview_table_style'); 

Solution 2: You can override the particular CSS file in your theme by copying it to [theme]/gravityview/css/table-view.css and make necessary changes (i.e. remove 'media queries').

Read More

'commit' changes on webserver to Github repo using PHP not working

Leave a Comment

I'm trying to write a little PHP script that can spot all the changes to a local git repo on my web server and push them up to my (private) Github repo. Pushing and pulling from the Github repo using Atom works perfectly, pushing changes to the web server using a webhook works perfectly, pushing and pulling updates on the web server via the command line works perfectly, my problem is trying to commit and push updates on the web server to my Github repo using PHP. How do you do this?

If I have to change, add or even delete an entire template on the server manually I can commit those changes and push them up to Github using the command line like this no problem:

git add --all git commit -m "from server" git push -u origin master 

But when I try to do this using a PHP script it never works and I get no error message (I even try with pauses):

$output = `git add --all`; echo $output; sleep(1);  $output = `git commit -m "from server"`; echo $output; sleep(3);  $output = `git push -u origin master`; echo $output; sleep(3); 

If I run something simple like 'git --version', 'git config --list' or 'git status' it works perfectly from these scripts, so I'm at a loss.

4 Answers

Answers 1

When you run a script with php it is run by a user www-data(by default). When you connect to git repository you need to do auth. Most likely it will be done using ssh key. So you need authorize user www-data with the ssh key to allow him accessing the remote repository.

So the steps.

  1. Generate key
  2. Add the key to the remote repository
  3. Add the key to ssh agent locally for user www-data
  4. Check the enviroment where you run the command
  5. Enjoy

Useful link: https://help.github.com/articles/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent/

There's also an option to use authentication via https with skipping putting credentials. You can see more here

Moreover, there's the library that does such things you may check it as well

Answers 2

You says:

But when I try to do this using a PHP script it never works and I get no error message (I even try with pauses):

$output = `git add --all`; echo $output; sleep(1);  $output = `git commit -m "from server"`; echo $output; sleep(3);  $output = `git push -u origin master`; echo $output; sleep(3); 

If I run something simple like 'git --version', 'git config --list' or 'git status' it works perfectly from these scripts, so I'm at a loss.

It seems like you have no write permission here.

You can easily run following commands to check permission for git repo, login user and owner of web server.

Run command whoami or id to identify login user.

$ whoami gasolwu $ id uid=501(gasolwu) gid=20(staff) groups=20(staff),501(access_bpf),12(everyone),61(localaccounts),79(_appserverusr),80(admin),81(_appserveradm),98(_lpadmin),33(_appstore),100(_lpoperator),204(_developer),250(_analyticsusers),395(com.apple.access_ftp),398(com.apple.access_screensharing),399(com.apple.access_ssh),701(com.apple.sharepoint.group.1) 

List directory to check owner and permissions for given path (git repo)

$ ls -al /path/to/repo total 16 drwxr-xr-x   5 gasolwu  staff  160 Oct 15 21:50 ./ drwxr-xr-x   5 gasolwu  staff  160 Oct 15 21:48 ../ drwxr-xr-x  13 gasolwu  staff  416 Oct 15 21:53 .git/ -rw-r--r--   1 gasolwu  staff  196 Oct 15 21:50 git.php* -rw-r--r--   1 gasolwu  staff   79 Oct 15 21:49 git.sh* 

Show process status to check user whom runs web server

$ ps auxwww | grep 'httpd\|nginx\|apache' _www              1139   0.0  0.0  4342760   3692   ??  S     9:51PM   0:00.01 /usr/sbin/httpd -D FOREGROUND _www              1138   0.0  0.0  4351976   3692   ??  S     9:51PM   0:00.02 /usr/sbin/httpd -D FOREGROUND _www              1137   0.0  0.0  4317160   1988   ??  S     9:51PM   0:00.01 /usr/sbin/httpd -D FOREGROUND _www              1129   0.0  0.0  4334568   2300   ??  S     9:51PM   0:00.01 /usr/sbin/httpd -D FOREGROUND root              1119   0.0  0.1  4316156  11772   ??  Ss    9:51PM   0:00.51 /usr/sbin/httpd -D FOREGROUND gasolwu           1465   0.0  0.0  4268036    824 s000  S+   10:19PM   0:00.00 grep --color=auto -d skip httpd\|nginx\|apache 

or check user of php-fpm if you run web sever with PHP-FPM

$ ps auxwww | grep php-fpm gasolwu           1761   0.0  0.0  4268036    812 s000  S+   10:33PM   0:00.00 grep --color=auto -d skip php-fpm nobody            1737   0.0  0.0  4323216    724   ??  S    10:33PM   0:00.00 php-fpm nobody            1736   0.0  0.0  4323216    732   ??  S    10:33PM   0:00.00 php-fpm root              1735   0.0  0.0  4323216    920   ??  Ss   10:33PM   0:00.00 php-fpm 

As you can see, It also has permission problem here, The .git directory can only be written by user gasolwu, not web user _www. So when you run git operation via php script through web server. .It can't do git operation (add/commit) without write permission.

The shell_exec (is identical to the backtick operator) function only returns stdout, It's empty here when error occurs, The stderr will be redirected to error log base on your environment, You will get similar error message log in Apache or PHP.

$ cat /var/log/apache2/error_log Mon Oct 15 21:51:06.734474 2018] [mpm_prefork:notice] [pid 1119] AH00163: Apache/2.4.34 (Unix) PHP/7.1.19 configured -- resuming normal operations [Mon Oct 15 21:51:06.734572 2018] [core:notice] [pid 1119] AH00094: Command line: '/usr/sbin/httpd -D FOREGROUND' fatal: Unable to create '/path/to/repo/.git/index.lock': Permission denied fatal: Unable to create '/path/to/repo/.git/index.lock': Permission denied error: could not lock config file .git/config: Permission denied error: Unable to write upstream branch configuration hint: hint: After fixing the error cause you may try to fix up hint: the remote tracking information by invoking hint: "git branch --set-upstream-to=origin/master". error: update_ref failed for ref 'refs/remotes/origin/master': cannot lock ref 'refs/remotes/origin/master': Unable to create '/path/to/repo/.git/refs/remotes/origin/master.lock': Permission denied Everything up-to-date error: remote unpack failed: unable to create temporary object directory To /tmp/git  ! [remote rejected] master -> master (unpacker error) error: failed to push some refs to '/tmp/git' 

Let's fix it by given write permission to right user (_www here).

chown -R _www /path/to/repo 

After that, you can send request to http://example.com/git.php to add files, commit with message "from server" then push them to GitHub.

CAVEAT: There is some security concern for this methodology without authentication.

Answers 3

The problem is with the authentication. The first solution is to do like Robert said. But I think that no need to Reinvent the wheel, try to see this package :

https://github.com/kbjr/Git.php

Everything is already there.

Answers 4

You are literally just echoing strings, not running them.

Instead of echo(), you can use exec(), shell_exec():

http://php.net/manual/en/function.exec.php

http://php.net/manual/en/function.shell-exec.php

Here are the PHP commands that allow you to execute programs on the server:

http://php.net/manual/en/ref.exec.php

Read More

DialogFragment with multiple fragments/views

Leave a Comment

How can I display a dialogfragment with multiple fragments one after the other with animation?

The use case I have is:

  1. DialogFragment is showing with fragment 1. It has a "next" button
  2. User clicks next
  3. The same dialogFragment displays fragment 2 with a slide in animation.

Any pointers would help.

Thank you in advance.

This is the base dialogfragment I am using

public class BaseDialogFragment extends DialogFragment {      public BaseDialogFragment () {      }      public static BaseDialogFragment newInstance(String title) {         BaseDialogFragment frag = new BaseDialogFragment ();         Bundle args = new Bundle();         args.putString("title", title);         frag.setArguments(args);         return frag;     }      @Override     public View onCreateView(LayoutInflater inflater, ViewGroup container,             Bundle savedInstanceState) {         return inflater.inflate(R.layout.fragment, container);     }      @Override     public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {         super.onViewCreated(view, savedInstanceState);           getDialog().getWindow().setSoftInputMode(             WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);     } } 

Here is how the behaviour is. It is BottomNavigation activity that is displaying dialog with flow. The next/previous dialog comes in with slide in/out navigation.

enter image description here

I am open to other suggestions too such as dialog-Themed activity

4 Answers

Answers 1

As far as i understand, you would like to have one parent dialog fragment which is managing two child fragments. To do so, you have to follow those steps.

  1. Create parent dialog fragment
  2. Create two child fragment
  3. Add first fragment to parent fragment
  4. Add call back from first child fragment to parent to replace it with second child fragment
  5. Add functionality to parent fragment to replace child fragment

Lets start with first step. We are going to create a container dialog fragment:

class ContainerDialogFragment extends DialogFragment {     @Override     public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {         return inflater.inflate(R.layout.container_fragment, container, false);     } } 

Our container_fragment xml will look like:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"         android:id="@+id/fragment_container"         android:layout_width="match_parent"         android:layout_height="match_parent" /> 

Then we create two child fragment:

class ChildFragment1 extends Fragment {     //...the content is up to you... } 

and

class ChildFragment2 extends Fragment {     //...the content is up to you... } 

We add first fragment to our container dialog fragment:

class ContainerDialogFragment extends DialogFragment {     @Override     public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {         return inflater.inflate(R.layout.container_fragment, container, false);     }      @Override     public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {         FragmentTransaction transaction = getChildFragmentManager().beginTransaction();         ChildFragment1 childFragment1 = new ChildFragment1();         transaction.replace(R.id.fragment_container, childFragment1);         transaction.commit();     } } 

Now we have to add an interface to communicate between parent and child fragment to replace it:

class ChildFragment1 extends Fragment {     interface ChildFragment1Listener {         void onButtonPressed();     }      //you have to call this method when user pressed to button     void onButtonPressed() {         ChildFragment1Listener listener = (ChildFragment1Listener) getParentFragment();         listener.onButtonPressed();     } } 

Finally, we have to implement this interface in our container dialog fragment and add replace functionality:

class ContainerDialogFragment extends DialogFragment implements ChildFragment1.ChildFragment1Listener {     @Override     public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {         return inflater.inflate(R.layout.container_fragment, container, false);     }      @Override     public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {         FragmentTransaction transaction = getChildFragmentManager().beginTransaction();         ChildFragment1 childFragment1 = new ChildFragment1();         transaction.replace(R.id.fragment_container, childFragment1);         transaction.commit();     }      @Override     void onButtonPressed() {         FragmentTransaction transaction = getChildFragmentManager().beginTransaction();         //Out of simplicity, i am creating ChildFragment2 every time user presses the button.          //However, you should keep the instance somewhere to avoid creation.         ChildFragment2 childFragment2 = new ChildFragment2();         transaction.replace(R.id.fragment_container, childFragment2);         //You can add here as well your fragment in and out animation how you like.         transaction.addToBackStack("childFragment2");         transaction.commit();     } } 

Thats it.

Answers 2

What I would do:

1) Create parent dialog fragment without any content

2) Create 3 Fragments representing each of the state of the dialog

3) Show content fragments and implement navigation between them in the context of ParentDialogFragment::childFragmentManager

Answers 3

I managed to have custom dialog fragments with animations by using normal fragments in the following way.

Add the id to the root layout of your activity

<?xml version="1.0" encoding="utf-8"?> <FrameLayout     xmlns:android="http://schemas.android.com/apk/res/android"     xmlns:tools="http://schemas.android.com/tools"     xmlns:app="http://schemas.android.com/apk/res-auto"     android:id="@+id/root_layout"     android:layout_width="match_parent"     android:layout_height="match_parent"> 

In your activity class retrieve root_layout with findViewById() and add the following method:

public void showFragment(BaseDialogFragment fragment, @AnimatorRes @AnimRes int enter,                              @AnimatorRes @AnimRes int exit) {         FragmentManager manager = getSupportFragmentManager();         String fragmentName = fragment.getClass().getName();         if (manager.findFragmentByTag(fragmentName) == null) {             FragmentTransaction transaction = manager.beginTransaction();             transaction.setCustomAnimations(enter, exit, enter, exit);             transaction.add(R.id.root_layout, fragment, fragmentName);             transaction.addToBackStack(fragmentName);             transaction.commit();         }     } 

Where enter and exit arguments accept xml anim files like anim/slide_in.xml:

<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"     android:shareInterpolator="false" >     <translate android:duration="300" android:fromXDelta="-100%" android:toXDelta="0%"/> </set> 

And anim/slide_out.xml:

<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"     android:shareInterpolator="false" >     <translate android:duration="300" android:fromXDelta="0%" android:toXDelta="-100%"/> </set> 

Then create a base class for dialogs which allow to dismiss the dialog:

public abstract class BaseDialogFragment extends Fragment {      public void dismiss() {         getActivity().getSupportFragmentManager()                 .popBackStack(getClass().getName(), FragmentManager.POP_BACK_STACK_INCLUSIVE);     } } 

Back key is also working because the fragment is in the back stack. Now create your dialogs extending from the BaseDialogFragment class and show them calling showFragment(dialogFragment, R.anim.slide_in, R.anim.slide_out); from your activity.

If you have to start Dialog2 from Dialog1, simply use ((YourActivity)getActivity).showFragment(dialogFragment, R.anim.slide_in, R.anim.slide_out).

Answers 4

Search in Youtube "Fragment Tricks (Google I/O '17)" If you want to understand how it works.

Solution is simple addToBackStack

For animation: you can set your custom animation -> transaction.setCustomAnimations(R.anim.first, R.anim.second...);

I suggest to watch the google presentation, you will be amazed, hope so.

Read More

TeamCity prevent simultaneous branch builds

Leave a Comment

I have a Git setup with the typical master --> develop --> feature structure. I have 5 TeamCity (v8.1) build agents. Is it possible to configure TeamCity so that if multiple people commit to develop at the same time, the develop branch won't run concurrent builds? Part of our CI process is deploy-on-success, so I don't want two builds to be deploying to the same endpoint at the same time.

(I would want this setup for all branches, not just develop)

3 Answers

Answers 1

On the General Settings configuration page you can set the number of simultaneous builds to 1 instead of 0 for unlimited. This means that it am queue up say 5 builds but only 1 will run at a time.

Answers 2

Are you trying to prevent multiple check-ins to the same branch from generating multiple builds for that branch? You can do this without changing the concurrency settings by settings some options on the VCS Trigger portion of your build configuration. There is a 'Quiet Period' setting that waits for X seconds before doing a build, just in case several commits come in at once.

Here's a screenshot of the relevant menu in TeamCity 8.x:

Screenshot of the TeamCity menu for configuration the quiet period on a build configuration.

EDIT: Another option is the Build Features -> Shared Resource feature. This allows you to create a lock, associate it with one or more projects, and have them use it. This is useful to prevent 1+ projects from building at the same time. This is more reliable than the quiet time feature since there is an actual lock and not just a delay, though the quiet time does help collect multiple near-simultaneous checkins and so is independently useful.

Answers 3

Combining a quiet period long enough, but not too long :), and 1 build max at same time, you should be able to get what you want. It's what we use here, quiet period from 120 to 180 seconds, and it works well.

Read More

How to align a View to center without changing children's position?

Leave a Comment
<View style={{height: '100%', width: '100%'}}>    {OtherContent}    <ScrollView>       <View style={{flexDirection: 'row', flexWrap: 'wrap', padding: 20}}>            {children}       </View>    <ScrollView>  </View> 

I want the View inside ScrollView to be in center of the screen without changing it's children position

Children:

<View style={Styles.docsContainer}>             {arr.map((document, index) => {                 return (                     <TouchableOpacity key={index} style={[Style.docStyle} onPress={null}>                         <Icon name='file-text-o'/>                         <Text>{document.name}</Text>                     </TouchableOpacity>                 );             })} </View> const Styles: {     docsContainer: {        flexDirection: 'row',        flexWrap: 'wrap',        padding: 20,     },     docStyle: {       alignItems: 'center',        padding: 20,       margin: 5,       marginBottom: 10,       borderRadius: 8,       width: 170     } 

}

3 Answers

Answers 1

Indeed, we don't need parent View, we just need scrollView as flewGrow 1 which makes scrollView have full height and width as per device.

My approach:

   <ScrollView contentContainerStyle={{ flexGrow: 1, justifyContent: 'center', alignItems: 'center' }}>     <View style={{       alignItems: 'center',       justifyContent: 'center',       flex: 1,     }}>       <Text>mahesh nandam</Text>     </View>   </ScrollView> 

Try this.

Answers 2

The Viewis your ScrollView's immediate children. So you can style ScrollView using contentContainerStyle and align it in center like this.

<View style={{height: '100%', width: '100%'}}>     <ScrollView          contentContainerStyle={{              flexGrow: 1,              justifyContent: 'center',              alignItems: 'center',          }}     >      <View style={{flexDirection: 'row', flexWrap: 'wrap', padding: 20}}>          {children}      </View>     <ScrollView>  </View> 

I guess it's what you're loooking for.

Answers 3

Center Horizontally

If you only want to center the View horizontally, you can set alignItems: 'center' to ScrollView's contentContainerStyle.

<View style={{ height: '100%', width: '100%' }}>   <Text>Other content</Text>   <ScrollView contentContainerStyle={{ alignItems: 'center' }}>     <View style={{ flexDirection: 'row', flexWrap: 'wrap', padding: 20, backgroundColor: 'red' }}>       <Text>children</Text>     </View>   </ScrollView>  </View> 

The inner View is highlighted in red.

center horizontally

Center Horizontally and Vertically

In this case, you can set { flex: 1, justifyContent: 'center', alignItems: 'center' } for the same contentContainerStyle.

<View style={{ height: '100%', width: '100%' }}>   <Text>Other content</Text>   <ScrollView contentContainerStyle={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>     <View style={{ flexDirection: 'row', flexWrap: 'wrap', padding: 20, backgroundColor: 'red' }}>       <Text>children</Text>     </View>   </ScrollView>  </View> 

center horizontally and vertically

If what you expect is different layout than in either of the screenshots, please share a simple sketch of the layout.

Read More

use webpack plugin with Mocha tests

Leave a Comment

I've used create-react-app to create an app, and ejected the config. In webpack.config.dev.js and webpack.config.prod.js, I've configured the NormalModuleReplacementPlugin like so:

new webpack.NormalModuleReplacementPlugin(/(.*)CUSTOMER(\.*)/, function(resource) {   const customerName = process.env.REACT_APP_CUSTOMER;   resource.request = resource.request.replace(/CUSTOMER/, customerName); }) 

The purpose of this is to replace imports such as

import config from '../config/customer/CUSTOMER'; 

with

import config from '../config/customer/foo'; 

when the value of the REACT_APP_CUSTOMER variable is set to "foo".

This works fine when the app runs, but I have some Mocha tests that are run via a test-mocha script in package.json

"scripts": {   "test-mocha": "NODE_ENV=test node_modules/.bin/mocha --require babel-register --recursive test" } 

When this test runs, the import replacement doesn't happen. It seems either of the following would solve the problem:

  • configure the NormalModuleReplacementPlugin to be used when the tests are run
  • find a way to provide a mock for config when the tests are run

5 Answers

Answers 1

Take a look at mocha-webpack. As mentioned in the docs, it basically runs webpack test.js output.js && mocha output.js with some optimizations. So, after npm i -D mocha-webpack, your scripts should look like:

"scripts": {   "test-mocha": "NODE_ENV=test node_modules/.bin/mocha-webpack --recursive test" } 

Another option you could try is to make use of mock-require, which is responsible for mocking node.js modules. In your case you'll need to require mock-helper.js:

"test-mocha": "NODE_ENV=test node_modules/.bin/mocha -r babel-register -r ./test/mock-helper.js --recursive test"

And ./test/mock-helper.js should be something like:

const mock = require('mock-require'); const defaultCustomer = require('../config/customer/default'); const fooCustomer = require('../config/customer/foo');  const customerMock = (function () {   switch (process.env.REACT_APP_CUSTOMER) {     case 'foo': return fooCustomer;     default: return defaultCustomer;   } }())  mock('../config/customer/CUSTOMER', customerMock); 

Hope it helps.

Answers 2

I settled on a simple/obvious solution:

Create a dummy file config/customer/CUSTOMER.js that contains the minimum expected configuration, e.g.

export default {   customerName: 'Dummy' } 

when the tests are run, an import such as

import config from '../config/customer/CUSTOMER'; 

will no longer fail because this module now exists.

Answers 3

I would suggest you to use Karmajs

Karmajs is a test runner, so you can configure it to use mocha for running tests, also you can pre-process your tests with webpack, so all the pre-processing (for NormalModuleReplacementPlugin and any other) which was done via webpack configuration is available when you're executing tests with Karma.

Basically, Install Karma and its associated Packages in your Application

yarn add karma karma-chai-plugins karma-chrome-launcher karma-cli karma-coverage karma-mocha karma-mocha-reporter karma-sinon-chai karma-sourcemap-loader karma-webpack 

Create karma.conf.js

const webpackConfig = require('./webpack.config'); const webpack = require('webpack'); webpackConfig.devtool = 'inline-source-map'; webpackConfig.plugins = [   new webpack.ProvidePlugin({     'es6-promise': 'es6-promise',   }), ];  module.exports = function (config) {   config.set({     browsers: [ 'Chrome' ],     // karma only needs to know about the test bundle     files: [       '../node_modules/babel-polyfill/dist/polyfill.js',       'karma.globals.js',       'tests.bundle.js',     ],     frameworks: [ 'chai', 'mocha' ],     // run the bundle through the webpack and sourcemap plugins     preprocessors: {       'tests.bundle.js': [ 'webpack', 'sourcemap' ],     },     // reporters: [ 'mocha', 'coverage' ],     reporters: [ 'mocha' ],     // coverageReporter: {     //   type: 'text-summary',     //   includeAllSources: true     // },     singleRun: false,     autoWatch: true,     // webpack config object     webpack: webpackConfig,     webpackMiddleware: {       noInfo: true,     },   }); }; 

Create tests.bundle.js for running tests for all your test files, in this example, all our tests files have a file extension .spec.js and are located inside ./src directory.

tests.bundle.js

const context = require.context('./src', true, /\.spec\.js$/); context.keys().forEach(context);  export default context; 

For setting up Global variables which need to be available across all your app/tests can be set with karma.globals.js file.

karma.globals.js

const __DEV__ = false;  const INITIAL_STATE = {   name: 'My App',   version: 'v2.5.6' }; 

Once the above is configured, you can run all your tests from the directory where you have created karma.config.js and package.json by executing the following command.

yarn karma start 

Note: Tests can be configured to execute in Headless Browsers (like phantomjs) as well, in this example we are using Chrome Browser to run our tests.

Answers 4

Probably, you would like to use mocha-webpack util

Answers 5

You can add this to your test script:

REACT_APP_CUSTOMER=foo 

So your test script becomes:

"test-mocha": "NODE_ENV=test REACT_APP_CUSTOMER=foo node_modules/.bin/mocha --require babel-register --recursive test" 

This will work because it sets the value you want in your process.env, and I'm not sure but I think this is the only reasonable way because you are mocking your environment when running a test.

Read More